UNPKG

storybook-addon-useragent

Version:
1 lines 20.6 kB
{"version":3,"sources":["../src/core/constants.ts","../src/constants.ts","../src/core/detection.ts","../src/core/browser.ts","../src/core/manipulation.ts","../src/preview.ts"],"names":["ARG_KEY","PLATFORMS","ARCHITECTURES","BROWSER_MAPPING","REGEX","PARAM_KEY","detectPlatform","userAgent","detectPlatformVersion","platform","match","detectBitness","version","detectArchitecture","archMatch","archInfo","detectModel","category","detectWow64","isBrowserName","brand","parseBrowserBrands","brands","parseUserAgent","brandList","isMobile","parsedPlatform","parsedArchitecture","parsedModel","parsedPlatformVersion","parsedBitness","isWow64","result","initialized","beforeAgent","originalNavigator","seq","ensureInitialized","applyNavigator","my","userAgentData","parsed","error","proxy","target","prop","e","fallbackError","set","getFromArgs","args","preview","preview_default"],"mappings":"aAAO,IAAMA,CAAAA,CAAU,YAEVC,CAAAA,CAAY,CACvB,QAAS,SAAA,CACT,SAAA,CAAW,WAAA,CACX,KAAA,CAAO,OAAA,CACP,OAAA,CAAS,UACT,GAAA,CAAK,KACP,EAIaC,CAAAA,CAAgB,CAC3B,IAAK,KAAA,CACL,GAAA,CAAK,KAAA,CACL,KAAA,CAAO,OAAA,CACP,GAAA,CAAK,KACP,CAAA,CAIaC,CAAAA,CAAkB,CAC7B,MAAA,CAAQ,QAAA,CACR,SAAU,UAAA,CACV,IAAA,CAAM,MAAA,CACN,KAAA,CAAO,OAAA,CACP,KAAA,CAAO,QACP,OAAA,CAAS,SAAA,CACT,OAAQ,QAAA,CACR,mBAAA,CAAqB,mBACvB,CAAA,CAIaC,CAAAA,CAAQ,CACnB,MAAA,CAAQ,kCAAA,CACR,SAAA,CAAW,YACX,YAAA,CAAc,CACZ,MAAO,gEAAA,CACP,MAAA,CAAQ,uDACR,YAAA,CAAc,0DAAA,CACd,SAAA,CAAW,mCACb,CAAA,CACA,OAAA,CACE,iIACF,gBAAA,CAAkB,CAChB,QAAS,wBAAA,CACT,KAAA,CAAO,qCACP,GAAA,CAAK,qCAAA,CACL,OAAA,CAAS,oCACX,CAAA,CACA,OAAA,CAAS,CACP,KAAA,CAAO,kBAAA,CACP,OAAQ,SAAA,CACR,KAAA,CAAO,WACP,IAAA,CAAM,YAAA,CACN,KAAA,CAAO,cACT,CACF,CAAA,KCxDaC,CAAAA,CAAY,WAAA,CCMlB,SAASC,CAAAA,CAAeC,CAAAA,CAAyC,CAGtE,GAAI,UAAA,CAAW,IAAA,CAAKA,CAAS,CAAA,CAAG,OAAON,EAAU,OAAA,CACjD,GAAI,UAAA,CAAW,IAAA,CAAKM,CAAS,CAAA,CAAG,OAAON,CAAAA,CAAU,OAAA,CACjD,GAAI,mBAAA,CAAoB,IAAA,CAAKM,CAAS,CAAA,CAAG,OAAON,CAAAA,CAAU,GAAA,CAC1D,GAAI,YAAA,CAAa,KAAKM,CAAS,CAAA,CAAG,OAAON,CAAAA,CAAU,SAAA,CACnD,GAAI,QAAA,CAAS,IAAA,CAAKM,CAAS,CAAA,CAAG,OAAON,CAAAA,CAAU,KAEjD,CAEO,SAASO,EACdD,CAAAA,CACAE,CAAAA,CACoB,CAKpB,GAJKA,CAAAA,GACHA,CAAAA,CAAWH,CAAAA,CAAeC,CAAS,CAAA,CAAA,CAGjC,CAACE,CAAAA,CAAU,OAEf,IAAIC,CAAAA,CAEJ,OAAQD,GACN,KAAKR,CAAAA,CAAU,OAAA,CACb,OAAAS,CAAAA,CAAQH,EAAU,KAAA,CAAMH,CAAAA,CAAM,iBAAiB,OAAO,CAAA,CAC/CM,IAAQ,CAAC,CAAA,CAElB,KAAKT,CAAAA,CAAU,SAAA,CAEb,OADAS,EAAQH,CAAAA,CAAU,KAAA,CAAMH,EAAM,gBAAA,CAAiB,KAAK,EAChDM,CAAAA,GAAQ,CAAC,CAAA,CAEJA,CAAAA,CAAM,CAAC,CAAA,CAAE,QAAQ,IAAA,CAAM,GAAG,EAEnC,MAAA,CAEF,KAAKT,EAAU,GAAA,CAEb,OADAS,CAAAA,CAAQH,CAAAA,CAAU,KAAA,CAAMH,CAAAA,CAAM,iBAAiB,GAAG,CAAA,CAC9CM,IAAQ,CAAC,CAAA,CAEJA,EAAM,CAAC,CAAA,CAAE,OAAA,CAAQ,IAAA,CAAM,GAAG,CAAA,CAEnC,OAEF,KAAKT,CAAAA,CAAU,QACb,OAAAS,CAAAA,CAAQH,EAAU,KAAA,CAAMH,CAAAA,CAAM,gBAAA,CAAiB,OAAO,CAAA,CAC/CM,CAAAA,GAAQ,CAAC,CAAA,CAElB,QACE,MACJ,CACF,CAEO,SAASC,CAAAA,CAAcJ,CAAAA,CAAuC,CAYnE,GAVIH,CAAAA,CAAM,OAAA,CAAQ,MAAM,IAAA,CAAKG,CAAS,GAKlCH,CAAAA,CAAM,OAAA,CAAQ,OAAO,IAAA,CAAKG,CAAS,CAAA,EAKnCH,CAAAA,CAAM,OAAA,CAAQ,KAAA,CAAM,KAAKG,CAAS,CAAA,CACpC,OAAO,IAAA,CAST,GALIH,EAAM,OAAA,CAAQ,IAAA,CAAK,IAAA,CAAKG,CAAS,CAAA,EAKjCH,CAAAA,CAAM,QAAQ,KAAA,CAAM,IAAA,CAAKG,CAAS,CAAA,CACpC,OAAO,KAIT,IAAME,CAAAA,CAAWH,CAAAA,CAAeC,CAAS,CAAA,CACzC,GAAIE,IAAaR,CAAAA,CAAU,SAAA,EAAaQ,IAAaR,CAAAA,CAAU,GAAA,CAE7D,OAAO,IAAA,CAIT,GAAIQ,CAAAA,GAAaR,CAAAA,CAAU,OAAA,CAAS,CAElC,IAAMW,CAAAA,CAAUJ,CAAAA,CAAsBD,EAAWE,CAAQ,CAAA,CACzD,GAAIG,CAAAA,CAGF,OAFqB,QAAA,CAASA,CAAAA,CAAQ,KAAA,CAAM,GAAG,EAAE,CAAC,CAAA,CAAG,EAAE,CAAA,EAEnC,CAAA,CACX,KAGA,IAGb,CAGF,CAEO,SAASC,CAAAA,CACdN,CAAAA,CAC0B,CAC1B,IAAMO,CAAAA,CAAYV,EAAM,SAAA,CAAU,IAAA,CAAKG,CAAS,CAAA,CAChD,GAAI,CAACO,CAAAA,GAAY,CAAC,CAAA,CAChB,OAGF,IAAMC,CAAAA,CAAWD,EAAU,CAAC,CAAA,CAE5B,GAAIC,CAAAA,CAAS,QAAA,CAASb,CAAAA,CAAc,GAAG,CAAA,CAAG,OAAOA,EAAc,GAAA,CAC1D,GAAIa,EAAS,QAAA,CAASb,CAAAA,CAAc,GAAG,CAAA,CAAG,OAAOA,CAAAA,CAAc,GAAA,CAC/D,GAAIa,CAAAA,CAAS,SAASb,CAAAA,CAAc,KAAK,EAAG,OAAOA,CAAAA,CAAc,MACjE,GAAIa,CAAAA,CAAS,QAAA,CAASb,CAAAA,CAAc,GAAG,CAAA,CAAG,OAAOA,CAAAA,CAAc,GAGtE,CAEO,SAASc,CAAAA,CAAYT,EAAuC,CACjE,IAAA,IAAWU,CAAAA,IAAY,MAAA,CAAO,MAAA,CAAOb,CAAAA,CAAM,YAAY,CAAA,CAAG,CACxD,IAAMM,CAAAA,CAAQO,CAAAA,CAAS,KAAKV,CAAS,CAAA,CACrC,GAAIG,CAAAA,GAAQ,CAAC,CAAA,CACX,OAAOA,CAAAA,CAAM,CAAC,CAElB,CAGF,CAKO,SAASQ,EAAYX,CAAAA,CAA4B,CAGtD,OADiBD,CAAAA,CAAeC,CAAS,CAAA,GACxBN,EAAU,OAAA,CAClB,KAAA,CAIF,SAAS,IAAA,CAAKM,CAAS,CAChC,CC/IO,SAASY,CAAAA,CACdC,CAAAA,CACuC,CACvC,OAAOA,KAASjB,CAClB,CAEO,SAASkB,CAAAA,CAAmBd,CAAAA,CAA4B,CAC7D,IAAMe,CAAAA,CAAkB,EAAC,CACnBZ,CAAAA,CAAQH,CAAAA,CAAU,MAAMH,CAAAA,CAAM,OAAO,EAE3C,GAAI,CAACM,EACH,OAAOY,CAAAA,CAGT,GAAIZ,CAAAA,CAAM,CAAC,CAAA,EAAKA,EAAM,CAAC,CAAA,CAAG,CACxB,IAAMU,CAAAA,CAAQV,EAAM,CAAC,CAAA,CACfE,CAAAA,CAAUF,CAAAA,CAAM,CAAC,CAAA,CAEnBS,EAAcC,CAAK,CAAA,CACrBE,EAAO,IAAA,CAAK,CAAE,MAAOnB,CAAAA,CAAgBiB,CAAK,CAAA,CAAG,OAAA,CAAAR,CAAQ,CAAC,EAEtDU,CAAAA,CAAO,IAAA,CAAK,CAAE,KAAA,CAAO,UAAA,CAAY,QAAAV,CAAQ,CAAC,EAE9C,CAEA,OAAIF,CAAAA,CAAM,CAAC,CAAA,EAAKA,CAAAA,CAAM,CAAC,CAAA,EACrBY,CAAAA,CAAO,KAAK,CAAE,KAAA,CAAOnB,CAAAA,CAAgB,OAAA,CAAS,OAAA,CAASO,CAAAA,CAAM,CAAC,CAAE,CAAC,EAG/DA,CAAAA,CAAM,CAAC,GAAKA,CAAAA,CAAM,CAAC,CAAA,EACrBY,CAAAA,CAAO,IAAA,CAAK,CAAE,MAAOnB,CAAAA,CAAgB,MAAA,CAAQ,QAASO,CAAAA,CAAM,CAAC,CAAE,CAAC,CAAA,CAG9DA,CAAAA,CAAM,CAAC,CAAA,EAAKA,CAAAA,CAAM,CAAC,CAAA,EACrBY,CAAAA,CAAO,KAAK,CACV,KAAA,CAAOnB,EAAgB,mBAAmB,CAAA,CAC1C,OAAA,CAASO,CAAAA,CAAM,CAAC,CAClB,CAAC,CAAA,CAGIY,CACT,CA6CA,eAAsBC,CAAAA,CACpBhB,EACiC,CACjC,IAAMiB,CAAAA,CAAYH,CAAAA,CAAmBd,CAAS,CAAA,CACxCkB,EAAWrB,CAAAA,CAAM,MAAA,CAAO,KAAKG,CAAS,CAAA,CACtCmB,EAAiBpB,CAAAA,CAAeC,CAAS,CAAA,CACzCoB,CAAAA,CAAqBd,CAAAA,CAAmBN,CAAS,EACjDqB,CAAAA,CAAcZ,CAAAA,CAAYT,CAAS,CAAA,CACnCsB,CAAAA,CAAwBrB,EAC5BD,CAAAA,CACAmB,CACF,CAAA,CACMI,CAAAA,CAAgBnB,CAAAA,CAAcJ,CAAS,EACvCwB,CAAAA,CAAUb,CAAAA,CAAYX,CAAS,CAAA,CAE/ByB,CAAAA,CAAiC,CACrC,SAAA,CAAAzB,CAAAA,CACA,MAAA,CAAQkB,CAAAA,CACR,QAAA,CAAUC,CAAAA,CACV,aAAcC,CAAAA,CACd,KAAA,CAAOC,EACP,eAAA,CAAiBC,CAAAA,EAAyB,IAC1C,OAAA,CAASC,CAAAA,EAAiB,IAAA,CAC1B,KAAA,CAAOC,CACT,CAAA,CAEA,OAAAC,CAAAA,CAAO,MAAA,CAASR,CAAAA,CAChBQ,CAAAA,CAAO,eAAA,CAAkBR,CAAAA,CAElBQ,CACT,CC3HA,IAAIC,CAAAA,CAAc,KAAA,CACdC,CAAAA,CAAc,EAAA,CACdC,EACAC,CAAAA,CAAM,CAAA,CAEV,SAASC,CAAAA,EAA0B,CAC7BJ,GAAe,OAAO,MAAA,CAAW,GAAA,GACrCA,CAAAA,CAAc,IAAA,CACdC,CAAAA,CAAc,OAAO,SAAA,CAAU,SAAA,CAC/BC,EAAoB,MAAA,CAAO,SAAA,EAC7B,CAEA,eAAeG,CAAAA,CAAe/B,CAAAA,CAAkC,CAC9D,GAAI,OAAO,OAAW,GAAA,EAAe,CAAC4B,EAAmB,OAIzD,IAAMI,EAAK,EAAEH,CAAAA,CAETI,CAAAA,CACJ,GAAIL,CAAAA,CAAkB,aAAA,CACpB,GAAI,CACF,IAAMM,EAAS,MAAMlB,CAAAA,CAAehB,CAAS,CAAA,CAC7C,GAAIgC,CAAAA,GAAOH,CAAAA,CAAK,OAChBI,CAAAA,CAAgB,CACd,GAAGL,CAAAA,CAAkB,cACrB,GAAGM,CAAAA,CACH,qBAAsB,SAAYA,CACpC,EACF,CAAA,MAASC,CAAAA,CAAO,CACd,QAAQ,IAAA,CAAK,8CAAA,CAAgDA,CAAK,EACpE,CAGF,GAAIH,CAAAA,GAAOH,CAAAA,CAAK,OAIhB,IAAMO,CAAAA,CAAQ,IAAI,MAAMR,CAAAA,CAAmB,CACzC,IAAIS,CAAAA,CAAQC,CAAAA,CAAM,CAChB,OAAIA,CAAAA,GAAS,WAAA,CAAoBtC,CAAAA,CAC7BsC,CAAAA,GAAS,eAAA,EAAmBL,EAAsBA,CAAAA,CAC/C,OAAA,CAAQ,IAAII,CAAAA,CAAQC,CAAI,CACjC,CACF,CAAC,CAAA,CAED,GAAI,OAAO,MAAA,CAAO,WAAc,UAAA,CAEhC,GAAI,CACF,MAAA,CAAO,cAAA,CAAe,OAAQ,WAAA,CAAa,CACzC,KAAA,CAAOF,CAAAA,CACP,YAAA,CAAc,CAAA,CAAA,CACd,SAAU,CAAA,CACZ,CAAC,EACH,CAAA,MAASG,CAAAA,CAAG,CACV,OAAA,CAAQ,IAAA,CAAK,gDAAA,CAAkDA,CAAC,CAAA,CAGhE,GAAI,CACF,MAAA,CAAO,cAAA,CAAe,OAAO,SAAA,CAAW,WAAA,CAAa,CACnD,GAAA,CAAK,IAAMvC,CAAAA,CACX,YAAA,CAAc,CAAA,CAChB,CAAC,EACH,CAAA,MAASwC,CAAAA,CAAe,CACtB,OAAA,CAAQ,IAAA,CAAK,kCAAmCA,CAAa,EAC/D,CACF,CACF,CAEA,eAAsBC,EAAIzC,CAAAA,CAAmC,CACvD,OAAO,MAAA,CAAW,GAAA,GACtB8B,GAAkB,CAClB,MAAMC,CAAAA,CAAe/B,CAAAA,EAAa2B,CAAW,CAAA,EAC/C,CAEO,SAASe,CAAAA,CAAYC,EAA8B,CACxD,OAAOA,IAAOlD,CAAO,CAAA,EAAK,EAC5B,CC7EA,IAAMmD,CAAAA,CAAwC,CAC5C,OAAA,CAAS,CACP,MAAO,CAAE,IAAA,CAAAD,CAAK,CAAA,IACZ,MAAMF,CAAAA,CAAaC,CAAAA,CAAaC,CAAI,CAAC,EAC9B,EAAC,CAEZ,CAAA,CACA,cAAA,CAAgB,CAAE,CAAC7C,CAAS,EAAG,KAAM,CACvC,CAAA,CAEO+C,CAAAA,CAAQD","file":"preview.cjs","sourcesContent":["export const ARG_KEY = \"useragent\";\n\nexport const PLATFORMS = {\n WINDOWS: \"Windows\",\n MACINTOSH: \"Macintosh\",\n LINUX: \"Linux\",\n ANDROID: \"Android\",\n IOS: \"iOS\",\n} as const;\n\nexport type Platform = (typeof PLATFORMS)[keyof typeof PLATFORMS];\n\nexport const ARCHITECTURES = {\n X64: \"x64\",\n X86: \"x86\",\n ARM64: \"arm64\",\n ARM: \"arm\",\n} as const;\n\nexport type Architecture = (typeof ARCHITECTURES)[keyof typeof ARCHITECTURES];\n\nexport const BROWSER_MAPPING = {\n Chrome: \"Chrome\",\n Chromium: \"Chromium\",\n Edge: \"Edge\",\n Brave: \"Brave\",\n Opera: \"Opera\",\n Firefox: \"Firefox\",\n Safari: \"Safari\",\n \"Internet Explorer\": \"Internet Explorer\",\n} as const;\n\nexport type Browser = (typeof BROWSER_MAPPING)[keyof typeof BROWSER_MAPPING];\n\nexport const REGEX = {\n MOBILE: /Mobile|Android|iPhone|iPad|iPod/i,\n ARCH_INFO: /\\((.*?)\\)/,\n DEVICE_MODEL: {\n APPLE: /iPhone|iPad|iPod|MacBook|MacBook Pro|MacBook Air|iMac|Mac Pro/i,\n MOBILE: /Android|Windows Phone|BlackBerry|Nexus|Pixel|Galaxy/i,\n PHONE_BRANDS: /Xiaomi|Huawei|Sony|LG|OnePlus|OPPO|vivo|Realme|Motorola/i,\n PC_BRANDS: /Lenovo|Asus|Acer|Dell|HP|Surface/i,\n },\n BROWSER:\n /(Chrome|Chromium|Edge|Brave|Opera)\\/(\\d+\\.\\d+)|(Firefox)\\/(\\d+\\.\\d+)|(Version)\\/(\\d+\\.\\d+).*Safari|(MSIE|Trident)\\/(\\d+\\.\\d+)/i,\n PLATFORM_VERSION: {\n WINDOWS: /Windows NT (\\d+\\.\\d+)/i,\n MACOS: /Mac OS X (\\d+[._]\\d+(?:[._]\\d+)?)/i,\n IOS: /iPhone OS (\\d+[._]\\d+(?:[._]\\d+)?)/i,\n ANDROID: /Android (\\d+(?:\\.\\d+(?:\\.\\d+)?)?)/i,\n },\n BITNESS: {\n WIN64: /Win64|x64|WOW64/i,\n X86_64: /x86_64/i,\n ARM64: /aarch64/i,\n I686: /i686|i386/i,\n ARM32: /armv\\d+[^6]/i,\n },\n};\n","export { ARG_KEY } from \"./core/constants\";\n\nexport const PARAM_KEY = \"userAgent\";\nexport const ADDON_ID = \"storybook/user-agent\";\nexport const TOOL_ID = `${ADDON_ID}/tool`;\nexport const TOOL_TITLE = \"User-Agent\";\n","import {\n PLATFORMS,\n ARCHITECTURES,\n REGEX,\n Platform,\n Architecture,\n} from \"./constants\";\n\nexport function detectPlatform(userAgent: string): Platform | undefined {\n // Order matters: Android UA strings include \"Linux\", iOS UA strings include\n // \"Macintosh\"-like tokens — check the more specific platforms first.\n if (/Windows/i.test(userAgent)) return PLATFORMS.WINDOWS;\n if (/Android/i.test(userAgent)) return PLATFORMS.ANDROID;\n if (/iPhone|iPad|iPod/i.test(userAgent)) return PLATFORMS.IOS;\n if (/Macintosh/i.test(userAgent)) return PLATFORMS.MACINTOSH;\n if (/Linux/i.test(userAgent)) return PLATFORMS.LINUX;\n return undefined;\n}\n\nexport function detectPlatformVersion(\n userAgent: string,\n platform?: Platform,\n): string | undefined {\n if (!platform) {\n platform = detectPlatform(userAgent);\n }\n\n if (!platform) return undefined;\n\n let match;\n\n switch (platform) {\n case PLATFORMS.WINDOWS:\n match = userAgent.match(REGEX.PLATFORM_VERSION.WINDOWS);\n return match?.[1];\n\n case PLATFORMS.MACINTOSH:\n match = userAgent.match(REGEX.PLATFORM_VERSION.MACOS);\n if (match?.[1]) {\n // Convert 10_15_7 to 10.15.7\n return match[1].replace(/_/g, \".\");\n }\n return undefined;\n\n case PLATFORMS.IOS:\n match = userAgent.match(REGEX.PLATFORM_VERSION.IOS);\n if (match?.[1]) {\n // Convert 14_0 to 14.0\n return match[1].replace(/_/g, \".\");\n }\n return undefined;\n\n case PLATFORMS.ANDROID:\n match = userAgent.match(REGEX.PLATFORM_VERSION.ANDROID);\n return match?.[1];\n\n default:\n return undefined;\n }\n}\n\nexport function detectBitness(userAgent: string): string | undefined {\n // Windows or macOS with explicit 64-bit markers\n if (REGEX.BITNESS.WIN64.test(userAgent)) {\n return \"64\";\n }\n\n // Linux x86_64\n if (REGEX.BITNESS.X86_64.test(userAgent)) {\n return \"64\";\n }\n\n // ARM64/aarch64\n if (REGEX.BITNESS.ARM64.test(userAgent)) {\n return \"64\";\n }\n\n // 32-bit Intel\n if (REGEX.BITNESS.I686.test(userAgent)) {\n return \"32\";\n }\n\n // 32-bit ARM\n if (REGEX.BITNESS.ARM32.test(userAgent)) {\n return \"32\";\n }\n\n // Default for modern devices (most modern browsers and devices are 64-bit)\n const platform = detectPlatform(userAgent);\n if (platform === PLATFORMS.MACINTOSH || platform === PLATFORMS.IOS) {\n // Modern Apple devices are all 64-bit\n return \"64\";\n }\n\n // For other platforms, we're less certain but most modern devices are 64-bit\n if (platform === PLATFORMS.ANDROID) {\n // Android version-based detection\n const version = detectPlatformVersion(userAgent, platform);\n if (version) {\n const majorVersion = parseInt(version.split(\".\")[0], 10);\n // Android 5.0 and above are typically 64-bit\n if (majorVersion >= 5) {\n return \"64\";\n } else {\n // Older Android versions were typically 32-bit\n return \"32\";\n }\n }\n }\n\n return undefined;\n}\n\nexport function detectArchitecture(\n userAgent: string,\n): Architecture | undefined {\n const archMatch = REGEX.ARCH_INFO.exec(userAgent);\n if (!archMatch?.[1]) {\n return undefined;\n }\n\n const archInfo = archMatch[1];\n\n if (archInfo.includes(ARCHITECTURES.X64)) return ARCHITECTURES.X64;\n else if (archInfo.includes(ARCHITECTURES.X86)) return ARCHITECTURES.X86;\n else if (archInfo.includes(ARCHITECTURES.ARM64)) return ARCHITECTURES.ARM64;\n else if (archInfo.includes(ARCHITECTURES.ARM)) return ARCHITECTURES.ARM;\n\n return undefined;\n}\n\nexport function detectModel(userAgent: string): string | undefined {\n for (const category of Object.values(REGEX.DEVICE_MODEL)) {\n const match = category.exec(userAgent);\n if (match?.[0]) {\n return match[0];\n }\n }\n\n return undefined;\n}\n\n/**\n * Detects if the user agent is from a WOW64 environment (32-bit app on 64-bit Windows)\n */\nexport function detectWow64(userAgent: string): boolean {\n // Only relevant for Windows systems\n const platform = detectPlatform(userAgent);\n if (platform !== PLATFORMS.WINDOWS) {\n return false;\n }\n\n // Check for WOW64 marker\n return /WOW64/i.test(userAgent);\n}\n","import { BROWSER_MAPPING, REGEX } from \"./constants\";\nimport type { Brand, UserAgentData } from \"./types\";\nimport {\n detectPlatform,\n detectArchitecture,\n detectModel,\n detectPlatformVersion,\n detectBitness,\n detectWow64,\n} from \"./detection\";\n\nexport function isBrowserName(\n brand: string,\n): brand is keyof typeof BROWSER_MAPPING {\n return brand in BROWSER_MAPPING;\n}\n\nexport function parseBrowserBrands(userAgent: string): Brand[] {\n const brands: Brand[] = [];\n const match = userAgent.match(REGEX.BROWSER);\n\n if (!match) {\n return brands;\n }\n\n if (match[1] && match[2]) {\n const brand = match[1];\n const version = match[2];\n\n if (isBrowserName(brand)) {\n brands.push({ brand: BROWSER_MAPPING[brand], version });\n } else {\n brands.push({ brand: \"Chromium\", version });\n }\n }\n\n if (match[3] && match[4]) {\n brands.push({ brand: BROWSER_MAPPING.Firefox, version: match[4] });\n }\n\n if (match[5] && match[6]) {\n brands.push({ brand: BROWSER_MAPPING.Safari, version: match[6] });\n }\n\n if (match[7] && match[8]) {\n brands.push({\n brand: BROWSER_MAPPING[\"Internet Explorer\"],\n version: match[8],\n });\n }\n\n return brands;\n}\n\nexport async function getModernBrowserInfo(): Promise<\n { brands?: Brand[]; highEntropyValues?: Partial<UserAgentData> } | undefined\n> {\n if (typeof window === \"undefined\" || !window.navigator.userAgentData) {\n return undefined;\n }\n\n const brands =\n window.navigator.userAgentData.brands ||\n window.navigator.userAgentData.fullVersionList;\n\n let highEntropyValues: Partial<UserAgentData> | undefined;\n\n if (window.navigator.userAgentData.getHighEntropyValues) {\n try {\n highEntropyValues =\n await window.navigator.userAgentData.getHighEntropyValues([\n \"architecture\",\n \"bitness\",\n \"brands\",\n \"fullVersionList\",\n \"mobile\",\n \"model\",\n \"platform\",\n \"platformVersion\",\n \"wow64\",\n ]);\n } catch (error) {\n console.warn(\"Failed to get high entropy values:\", error);\n }\n }\n\n if (!brands && !highEntropyValues) return undefined;\n\n return {\n brands: brands?.map((brand) => ({\n brand: brand.brand,\n version: brand.version,\n })),\n highEntropyValues,\n };\n}\n\nexport async function parseUserAgent(\n userAgent: string,\n): Promise<Partial<UserAgentData>> {\n const brandList = parseBrowserBrands(userAgent);\n const isMobile = REGEX.MOBILE.test(userAgent);\n const parsedPlatform = detectPlatform(userAgent);\n const parsedArchitecture = detectArchitecture(userAgent);\n const parsedModel = detectModel(userAgent);\n const parsedPlatformVersion = detectPlatformVersion(\n userAgent,\n parsedPlatform,\n );\n const parsedBitness = detectBitness(userAgent);\n const isWow64 = detectWow64(userAgent);\n\n const result: Partial<UserAgentData> = {\n userAgent,\n mobile: isMobile,\n platform: parsedPlatform,\n architecture: parsedArchitecture,\n model: parsedModel,\n platformVersion: parsedPlatformVersion || \"0\",\n bitness: parsedBitness || \"64\",\n wow64: isWow64,\n };\n\n result.brands = brandList;\n result.fullVersionList = brandList;\n\n return result;\n}\n","import type { UserAgentData, UserAgentArgs } from \"./types\";\nimport { parseUserAgent } from \"./browser\";\nimport { ARG_KEY } from \"./constants\";\n\nlet initialized = false;\nlet beforeAgent = \"\";\nlet originalNavigator: Navigator | undefined;\nlet seq = 0;\n\nfunction ensureInitialized(): void {\n if (initialized || typeof window === \"undefined\") return;\n initialized = true;\n beforeAgent = window.navigator.userAgent;\n originalNavigator = window.navigator;\n}\n\nasync function applyNavigator(userAgent: string): Promise<void> {\n if (typeof window === \"undefined\" || !originalNavigator) return;\n\n // Tag this invocation. If a newer set() starts while we await below, we\n // discard our own result so the most recent call wins deterministically.\n const my = ++seq;\n\n let userAgentData: UserAgentData | undefined;\n if (originalNavigator.userAgentData) {\n try {\n const parsed = await parseUserAgent(userAgent);\n if (my !== seq) return;\n userAgentData = {\n ...originalNavigator.userAgentData,\n ...parsed,\n getHighEntropyValues: async () => parsed,\n };\n } catch (error) {\n console.warn(\"Failed to parse userAgent for userAgentData:\", error);\n }\n }\n\n if (my !== seq) return;\n\n // Always proxy the original navigator so repeated set() calls don't\n // accumulate proxy chains.\n const proxy = new Proxy(originalNavigator, {\n get(target, prop) {\n if (prop === \"userAgent\") return userAgent;\n if (prop === \"userAgentData\" && userAgentData) return userAgentData;\n return Reflect.get(target, prop);\n },\n });\n\n if (typeof window.Navigator !== \"function\") return;\n\n try {\n Object.defineProperty(window, \"navigator\", {\n value: proxy,\n configurable: true,\n writable: true,\n });\n } catch (e) {\n console.warn(\"Unable to replace navigator object with proxy:\", e);\n // Partial fallback: UA-only override on the existing navigator.\n // userAgentData stays untouched in this branch — see README/Troubleshooting.\n try {\n Object.defineProperty(window.navigator, \"userAgent\", {\n get: () => userAgent,\n configurable: true,\n });\n } catch (fallbackError) {\n console.warn(\"All UA spoofing methods failed:\", fallbackError);\n }\n }\n}\n\nexport async function set(userAgent?: string): Promise<void> {\n if (typeof window === \"undefined\") return;\n ensureInitialized();\n await applyNavigator(userAgent || beforeAgent);\n}\n\nexport function getFromArgs(args?: UserAgentArgs): string {\n return args?.[ARG_KEY] ?? \"\";\n}\n","import type { Renderer, ProjectAnnotations } from \"storybook/internal/types\";\nimport { PARAM_KEY } from \"./constants\";\nimport { setUserAgent, getUserAgent } from \"./core\";\n\nconst preview: ProjectAnnotations<Renderer> = {\n loaders: [\n async ({ args }) => {\n await setUserAgent(getUserAgent(args));\n return {};\n },\n ],\n initialGlobals: { [PARAM_KEY]: false },\n};\n\nexport default preview;\n"]}