UNPKG

inapp-spy

Version:
1 lines 19.3 kB
{"version":3,"sources":["../src/utils.ts","../src/detectTelegram.ts","../src/detectClientSide.ts","../src/regexAppName.ts","../src/regexInApp.ts","../src/detectSafariPrivate.ts","../src/detectSFSVC.ts","../src/index.ts"],"sourcesContent":["import { AppKey, Skip } from \"./types\";\n\nexport const WIN_ERROR =\n \"Window is not available and no user agent was provided.\";\n\nexport const getUA = (): string => {\n if (typeof window !== \"undefined\") {\n const ua =\n window?.navigator?.userAgent ||\n window?.navigator?.vendor ||\n // @ts-ignore\n window?.opera;\n if (ua) return ua;\n }\n console.error(WIN_ERROR);\n return \"\";\n};\n\nexport const empty = {\n isInApp: false,\n appKey: undefined,\n appName: undefined,\n skipped: false,\n};\n\nexport const getIsAppleDevice = (ua: string) => {\n return ua.match(/(iPhone|iPad|iPod|Macintosh)/) !== null;\n};\n\nexport const checkSkip = ({\n skip,\n appKey,\n ua,\n}: {\n skip?: Skip;\n appKey: AppKey;\n ua: string;\n}) => {\n if (!skip || skip.length === 0) return false;\n const isApple = getIsAppleDevice(ua);\n return skip.some(\n ({ appKey: excludeAppKey, platform }) =>\n appKey === excludeAppKey &&\n (!platform ||\n (isApple && platform === \"apple\") ||\n (!isApple && platform === \"android\"))\n );\n};\n\n// True for Safari on iOS, iPadOS, macOS\nconst isSafariRegex = new RegExp(\n /Mozilla\\/5\\.0 \\([^\\)]+\\) AppleWebKit\\/[^\\s]+ \\(KHTML, like Gecko\\) Version\\/[^\\s]+ (Mobile\\/[^\\s]+ )?Safari\\/[^\\s]+$/\n);\n\nexport const getIsSafariUA = (ua: string) => {\n return isSafariRegex.test(ua);\n};\n\n// source https://github.com/bowser-js/bowser/issues/510\nexport const isiOS = (ua: string) => {\n return (\n [\n \"iPad Simulator\",\n \"iPhone Simulator\",\n \"iPod Simulator\",\n \"iPad\",\n \"iPhone\",\n \"iPod\",\n ].includes(ua) ||\n // iPad on iOS 13 detection\n (window &&\n window.document &&\n ua.includes(\"Mac\") &&\n \"ontouchend\" in window.document)\n );\n};\n\nexport const getSafariVersion = (ua: string) => {\n const match = [...ua.matchAll(/Version\\/([^\\s]+)/g)];\n return match[0][1]; // right now just returns 17 or 18 etc (major version) but could be more specific\n};\n\nexport const delay = (ms: number) => new Promise((res) => setTimeout(res, ms));\n\nexport async function waitForPageLoad() {\n return new Promise((resolve) => {\n if (window.document.readyState === \"complete\") {\n // Resolve immediately if readyState is already 'complete'\n resolve(true);\n } else {\n // Otherwise, listen for the load event\n const onLoad = () => {\n resolve(true);\n window.removeEventListener(\"load\", onLoad);\n };\n window.addEventListener(\"load\", onLoad);\n }\n });\n}\n\n// Function to poll for properties on the window object\nexport const pollForProperties = async ({\n maxTime,\n properties,\n interval,\n}: {\n properties: string[];\n maxTime: number;\n interval: number;\n}) => {\n let elapsed = 0;\n\n return new Promise((resolve) => {\n const intervalId = setInterval(() => {\n elapsed += interval;\n\n // Check if any of the properties exist on window\n for (const property of properties) {\n if (property in window) {\n clearInterval(intervalId);\n resolve(true); // Resolve if the property is found\n return;\n }\n }\n\n // If time exceeds the timeout, stop polling and resolve false\n if (elapsed >= maxTime) {\n clearInterval(intervalId);\n resolve(false);\n }\n }, interval);\n });\n};\n","export const getIsTelegram = () => {\n return (\n \"TelegramWebview\" in window || // Android\n \"TelegramWebviewProxy\" in window || // iPhone\n \"TelegramWebviewProxyProto\" in window // iPhone\n );\n};\n","import { getIsTelegram } from \"./detectTelegram\";\n\nexport const appNameCustom = {\n telegram: {\n name: \"Telegram\",\n },\n} as const;\n\nexport const getDetectClientSide = () => {\n if (typeof window === \"undefined\") return; // Skip if not in browser ie: server-side and only ua given\n if (getIsTelegram()) return \"telegram\";\n return;\n};\n\nexport const appKeysDetectByCustom = Object.keys(\n appNameCustom\n) as (keyof typeof appNameCustom)[];\n","// NOTE: Consider getting the versions of known in-app browsers\nexport const appNameRegExps = {\n messenger: {\n regex:\n /(\\bFB[\\w_]+\\/(Messenger))|(^(?!.*\\buseragents)(?!.*\\bIABMV).*(FB_IAB|FBAN).*)/i, // Experimental for newer UAs - don't have `\"useragents:\" or end in \"IABMV\"\n name: \"Facebook Messenger\",\n },\n instagram: {\n regex: /\\bInstagram/i,\n name: \"Instagram\",\n },\n facebook: {\n regex: /\\bFB[\\w_]+\\//,\n name: \"Facebook\",\n },\n twitter: {\n regex: /\\bTwitter/i,\n name: \"Twitter\",\n },\n line: {\n regex: /\\bLine\\//i,\n name: \"Line\",\n },\n wechat: {\n regex: /\\bMicroMessenger\\//i,\n name: \"WeChat\",\n },\n threads: {\n regex: /\\bBarcelona/i,\n name: \"Threads\",\n },\n tiktok: {\n regex: /musical_ly|Bytedance/i,\n name: \"TikTok\",\n },\n snapchat: {\n regex: /Snapchat/i,\n name: \"Snapchat\",\n },\n linkedin: {\n regex: /LinkedInApp/i,\n name: \"LinkedIn\",\n },\n gsa: {\n regex: /GSA/i,\n name: \"Google Search App\",\n },\n} as const;\n\nexport const appKeysDetectByUA = Object.keys(\n appNameRegExps\n) as (keyof typeof appNameRegExps)[];\n\nexport const getAppKey = (ua: string) => {\n return appKeysDetectByUA.find((appName) =>\n appNameRegExps[appName].regex.test(ua)\n );\n};\n","// Quick in-app detection - should cover all specific in-app cases\nconst inAppRegExps = [\n \"WebView\",\n // Apple devices but not with \"Safari/\" following\n \"(iPhone|iPod|iPad)(?!.*Safari/)\",\n \"Android.*wv\\\\)\",\n // Match Facebook FB_ or FB then word char (Android)\n \"FB_\\\\w|FB\\\\w\",\n // Can end in Safari (iPhone)\n \"Snapchat\",\n \"GSA\",\n \"Instagram\",\n] as const;\n\nexport const inappRegex = new RegExp(\n `${inAppRegExps.map((reg) => `(${reg})`).join(\"|\")}`,\n \"ig\"\n);\n","// Source: https://github.com/Joe12387/detectIncognito\n// - Pulled out relevant parts for iOS Safari 17+ incognito detection\n// - For greater private mode detection coverage, use the full library\n// - Detection only works over https \n\nconst currentSafariTest = async (): Promise<boolean> => {\n try {\n await navigator.storage.getDirectory();\n return false;\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n return msg.toLowerCase().includes(\"unknown transient reason\");\n }\n};\n\nconst safari13to18Test = (): Promise<boolean> => {\n let settled = false;\n return new Promise((resolve) => {\n const name = `idb${Math.random()}`;\n const openReq = indexedDB.open(name, 1);\n\n const finish = (isPrivate: boolean, db?: IDBDatabase) => {\n if (settled) return;\n settled = true;\n if (db) db.close();\n indexedDB.deleteDatabase(name);\n resolve(isPrivate);\n };\n\n openReq.onupgradeneeded = (ev) => {\n const db = (ev.target as IDBOpenDBRequest).result;\n const putReq = db\n .createObjectStore(\"t\", { autoIncrement: true })\n .put(new Blob());\n\n putReq.onerror = (event) => {\n const req = event.target as IDBRequest;\n const message = req.error?.message || \"\";\n finish(message.includes(\"are not yet supported\"), db);\n };\n putReq.onsuccess = () => finish(false, db);\n };\n\n openReq.onerror = () => finish(false);\n // optional safety net:\n openReq.onsuccess = () => finish(false, openReq.result);\n });\n};\n\nexport const getIsSafariPrivate = async (): Promise<boolean> => {\n if (typeof navigator === \"undefined\") return false;\n\n if (navigator.storage?.getDirectory !== undefined) {\n return await currentSafariTest();\n } else if (navigator.maxTouchPoints !== undefined) {\n return await safari13to18Test();\n }\n return false; // Fallback if neither method is available\n};\n","import { getIsSafariPrivate } from \"./detectSafariPrivate\";\nimport { getIsTelegram } from \"./detectTelegram\";\nimport {\n getIsSafariUA,\n getSafariVersion,\n getUA,\n isiOS,\n pollForProperties,\n waitForPageLoad,\n} from \"./utils\";\n\n// Good enough for our usage - no prerelease versions or alpha/beta versions\n// -1 if a < b, 0 if a == b, 1 if a > b\nconst compare = (a: string, b: string) => {\n return a.localeCompare(b, undefined, { numeric: true, sensitivity: \"base\" });\n};\n\nconst consoleDebug = ({\n note,\n debug,\n last,\n}: {\n note?: string;\n debug: boolean;\n last?: boolean;\n}) => {\n if (debug) {\n console.log(\n note,\n \"SchemaDataExtractor\" in window || \"MicrodataExtractor\" in window\n ? \"This is Safari\"\n : last\n ? \"Did not detect Safari - assuming SFSVC\"\n : \"Still checking if Safari\",\n performance.now()\n );\n }\n};\n\nconst minSafariVersion = \"17\"; // could possibly be lower would need to check 16\n\n/**\n * Experimental function to detect SFSVC (Safari View Controller)\n * - !!! Can give false positives !!!\n * - Feedback welcome for better detection or improvements\n * - Checks for `SchemaDataExtractor` or `MicrodataExtractor` in window to determine if it is Safari\n */\nexport const getSFSVCExperimental = async ({\n debug = false,\n maxVersion,\n maxTime = 300, // Max time to figure out if it is Safari (ie not SFSVC)\n}: {\n /** Turn on console logs while debugging */\n debug?: boolean;\n /** Increase polling to confirm this is Safari with the required window properties */\n maxTime?: number;\n /** Max Safari version you wish detect SFSVC - escape hatch for unpredictable Apple behavior */\n maxVersion?: string;\n} = {}) => {\n const ua = getUA();\n\n // Early exit checks\n if (!ua) return false; // No user agent\n if (!isiOS(ua)) return false; // iPad or iPhone\n if (!getIsSafariUA(ua)) return false; // Safari\n if (\"clearAppBadge\" in (window?.navigator || {})) return false; // PWAs\n const isSafariPrivate = await getIsSafariPrivate();\n if (isSafariPrivate) return false;\n if (getIsTelegram()) return false;\n\n // Targeted versions of Safari that we'll check\n const version = getSafariVersion(ua);\n if (compare(version, minSafariVersion) < 0) return false;\n if (\n maxVersion !== undefined &&\n (compare(maxVersion, minSafariVersion) < 0 ||\n compare(version, maxVersion) > 0)\n )\n return false;\n\n await waitForPageLoad();\n if (debug) consoleDebug({ note: \"Page loaded\", debug });\n\n const isSafari = await pollForProperties({\n interval: 60,\n maxTime,\n properties: [\"SchemaDataExtractor\", \"MicrodataExtractor\"],\n });\n\n if (debug) consoleDebug({ note: \"Extra polling done\", debug, last: true });\n\n return !isSafari;\n};\n","import { checkSkip, getUA } from \"./utils\";\nimport { appNameCustom, getDetectClientSide } from \"./detectClientSide\";\nimport { AppKey, AppName, Skip } from \"./types\";\nimport { empty } from \"./utils\";\nimport { appNameRegExps, getAppKey } from \"./regexAppName\";\nimport { inappRegex } from \"./regexInApp\";\nimport { getSFSVCExperimental } from \"./detectSFSVC\";\n\ndeclare const __GLOBAL__: boolean;\n\nconst InAppSpy = (\n options: {\n ua?: string;\n skip?: Skip;\n } = {}\n): {\n ua: string;\n isInApp: boolean;\n appKey: AppKey;\n appName: AppName;\n skipped: boolean; // a helper to know if we successfully skipped the app\n} => {\n const { skip, ua = \"\" } = options;\n const userAgent = ua || getUA();\n\n // No userAgent\n if (!userAgent)\n return {\n ...empty,\n ua: userAgent,\n };\n\n // If user provides a list of apps to skip\n const skipFn = (key: AppKey) =>\n checkSkip({ skip, appKey: key, ua: userAgent });\n\n // UA detection method (most common)\n // - This method should be used first - order matters\n if (userAgent.match(inappRegex) !== null) {\n const appKey = getAppKey(userAgent);\n if (skipFn(appKey)) return { ...empty, ua: userAgent, skipped: true };\n return {\n isInApp: true,\n appKey: appKey,\n appName: appKey ? appNameRegExps[appKey]!.name : undefined,\n ua: userAgent,\n skipped: false,\n };\n }\n\n // Client side only detections\n const appKey = getDetectClientSide();\n if (appKey) {\n if (skipFn(appKey)) return { ...empty, ua: userAgent, skipped: true };\n return {\n isInApp: true,\n appKey: appKey,\n appName: appNameCustom?.[appKey]?.name,\n ua: userAgent,\n skipped: false,\n };\n }\n\n // Didn't find anything\n return {\n ...empty,\n ua: userAgent,\n };\n};\n\n// Separate exports for experimental detection\nexport const SFSVCExperimental = getSFSVCExperimental;\nexport default InAppSpy;\n\n// Only attach if UMD build (CDN build)\nif (typeof window !== \"undefined\" && __GLOBAL__) {\n (window as any).InAppSpy = InAppSpy; // Default export\n (window as any).SFSVCExperimental = SFSVCExperimental; // Named export\n}\n"],"mappings":"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","names":["appKey"]}