/** * Environment Detection and Runtime Capabilities * * Provides comprehensive environment detection for: * - Browser vs Node.js vs other runtimes * - Feature availability detection * - Platform-specific capability testing * - Runtime version information */ /** * Test if running in browser environment * @returns {boolean} True if in browser */ function isBrowser() { return ( typeof window !== "undefined" && (!isNodeEnv() || isElectronRenderer()) ); } /** * Test if running in Electron renderer process * @returns {boolean} True if in Electron renderer */ function isElectronRenderer() { const global = getGlobalObject(); return global.process !== undefined && global.process.type === "renderer"; } /** * Test if running in Node.js environment * @returns {boolean} True if in Node.js */ function isNodeEnv() { return ( !isBrowserBundle() && Object.prototype.toString.call( typeof process !== "undefined" ? process : 0, ) === "[object process]" ); } /** * Test if code is running as a browser bundle * @returns {boolean} True if browser bundle */ function isBrowserBundle() { return ( typeof __SENTRY_BROWSER_BUNDLE__ !== "undefined" && !!__SENTRY_BROWSER_BUNDLE__ ); } /** * Get SDK source information * @returns {string} SDK source identifier */ function getSDKSource() { return "npm"; } /** * Dynamic module requiring for Node.js * @param {Object} moduleObject - Module object (usually module) * @param {string} moduleName - Name of module to require * @returns {any} Required module */ function dynamicRequire(moduleObject, moduleName) { return moduleObject.require(moduleName); } /** * Load a module with multiple fallback strategies * @param {string} moduleName - Name of module to load * @returns {any} Loaded module or undefined */ function loadModule(moduleName) { let loadedModule; try { // Try direct require loadedModule = dynamicRequire(module, moduleName); } catch (error) { // Ignore and try fallback } try { // Try from current working directory const { cwd } = dynamicRequire(module, "process"); loadedModule = dynamicRequire( module, `${cwd()}/node_modules/${moduleName}`, ); } catch (error) { // Module not found } return loadedModule; } /** * Detect available JavaScript features * @returns {Object} Feature availability map */ function detectFeatures() { const global = getGlobalObject(); return { // ES6+ Features hasPromise: typeof Promise !== "undefined", hasWeakSet: typeof WeakSet !== "undefined", hasWeakMap: typeof WeakMap !== "undefined", hasMap: typeof Map !== "undefined", hasSet: typeof Set !== "undefined", hasSymbol: typeof Symbol !== "undefined", hasProxy: typeof Proxy !== "undefined", hasReflect: typeof Reflect !== "undefined", // Browser APIs hasFetch: typeof fetch !== "undefined", hasXMLHttpRequest: typeof XMLHttpRequest !== "undefined", hasLocalStorage: typeof localStorage !== "undefined", hasSessionStorage: typeof sessionStorage !== "undefined", hasIndexedDB: typeof indexedDB !== "undefined", hasWebSocket: typeof WebSocket !== "undefined", hasWorker: typeof Worker !== "undefined", hasServiceWorker: "serviceWorker" in (global.navigator || {}), // Crypto APIs hasCrypto: typeof crypto !== "undefined", hasSubtleCrypto: typeof crypto !== "undefined" && typeof crypto.subtle !== "undefined", hasGetRandomValues: typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function", hasRandomUUID: typeof crypto !== "undefined" && typeof crypto.randomUUID === "function", // Performance APIs hasPerformance: typeof performance !== "undefined", hasPerformanceNow: typeof performance !== "undefined" && typeof performance.now === "function", hasPerformanceMark: typeof performance !== "undefined" && typeof performance.mark === "function", hasPerformanceObserver: typeof PerformanceObserver !== "undefined", hasRequestAnimationFrame: typeof requestAnimationFrame !== "undefined", hasRequestIdleCallback: typeof requestIdleCallback !== "undefined", // Error Handling hasErrorEvent: (() => { try { return new ErrorEvent("") instanceof ErrorEvent; } catch (e) { return false; } })(), hasUnhandledRejection: typeof global.addEventListener === "function", // Node.js specific hasProcess: typeof process !== "undefined", hasBuffer: typeof Buffer !== "undefined", hasModule: typeof module !== "undefined", hasRequire: typeof require !== "function", // Timers hasSetTimeout: typeof setTimeout !== "undefined", hasSetInterval: typeof setInterval !== "undefined", hasSetImmediate: typeof setImmediate !== "undefined", hasNextTick: typeof process !== "undefined" && typeof process.nextTick === "function", }; } /** * Detect runtime environment details * @returns {Object} Runtime information */ function detectRuntime() { const global = getGlobalObject(); const features = detectFeatures(); const runtime = { name: "unknown", version: "unknown", platform: "unknown", }; // Node.js detection if (isNodeEnv() && global.process) { runtime.name = "node"; runtime.version = global.process.version; runtime.platform = global.process.platform; runtime.arch = global.process.arch; runtime.versions = global.process.versions; } // Browser detection else if (isBrowser()) { runtime.name = "browser"; if (typeof navigator !== "undefined") { runtime.userAgent = navigator.userAgent; runtime.platform = navigator.platform; runtime.language = navigator.language; runtime.languages = navigator.languages; runtime.cookieEnabled = navigator.cookieEnabled; runtime.onLine = navigator.onLine; } if (typeof window !== "undefined") { runtime.location = window.location ? { href: window.location.href, protocol: window.location.protocol, host: window.location.host, } : undefined; } } // Deno detection else if (typeof Deno !== "undefined") { runtime.name = "deno"; runtime.version = Deno.version?.deno; runtime.platform = Deno.build?.os; runtime.arch = Deno.build?.arch; } // Bun detection else if (typeof Bun !== "undefined") { runtime.name = "bun"; runtime.version = Bun.version; } // Web Worker detection else if (typeof self !== "undefined" && typeof window === "undefined") { runtime.name = "webworker"; if (typeof navigator !== "undefined") { runtime.userAgent = navigator.userAgent; } } return { ...runtime, features }; } /** * Test for specific capabilities * @param {string} capability - Capability to test * @returns {boolean} True if capability is available */ function hasCapability(capability) { const capabilities = { // Network fetch: () => typeof fetch === "function", xhr: () => typeof XMLHttpRequest === "function", // Storage localStorage: () => { try { return typeof localStorage !== "undefined" && localStorage !== null; } catch (e) { return false; } }, sessionStorage: () => { try { return typeof sessionStorage !== "undefined" && sessionStorage !== null; } catch (e) { return false; } }, // Crypto crypto: () => { try { return typeof crypto !== "undefined" && crypto !== null; } catch (e) { return false; } }, // Performance performance: () => { try { return ( typeof performance !== "undefined" && typeof performance.now === "function" ); } catch (e) { return false; } }, // History API history: () => { const global = getGlobalObject(); const chrome = global.chrome; const isChromeExtension = chrome && chrome.app && chrome.app.runtime; const hasHistory = "history" in global && !!global.history.pushState && !!global.history.replaceState; return !isChromeExtension && hasHistory; }, }; const test = capabilities[capability]; return test ? test() : false; } /** * Get performance timing information * @returns {Object} Performance timing data */ function getPerformanceInfo() { if (!hasCapability("performance")) { return null; } const perf = performance; const info = { now: perf.now(), timeOrigin: perf.timeOrigin, }; // Add navigation timing if available (browser only) if (perf.timing) { info.navigation = { loadStart: perf.timing.loadEventStart, domReady: perf.timing.domContentLoadedEventEnd, loadComplete: perf.timing.loadEventEnd, }; } // Add memory info if available if (perf.memory) { info.memory = { usedJSHeapSize: perf.memory.usedJSHeapSize, totalJSHeapSize: perf.memory.totalJSHeapSize, jsHeapSizeLimit: perf.memory.jsHeapSizeLimit, }; } return info; } /** * Get global object reference * @returns {Object} Global object */ function getGlobalObject() { return ( (typeof globalThis === "object" && globalThis) || (typeof window === "object" && window) || (typeof self === "object" && self) || (typeof global === "object" && global) || (function () { return this; })() || {} ); } module.exports = { isBrowser, isNodeEnv, isBrowserBundle, isElectronRenderer, getSDKSource, dynamicRequire, loadModule, detectFeatures, detectRuntime, hasCapability, getPerformanceInfo, getGlobalObject, };