/** * Cross-Platform Global Object Access * * Provides unified access to global objects across different JavaScript environments: * - Browser (window) * - Node.js (global) * - Web Workers (self) * - Modern environments (globalThis) * - Fallback for edge cases */ /** * Safely test if an object could be a global object * @param {any} obj - Object to test * @returns {any} The object if it has Math, undefined otherwise */ function testGlobalCandidate(obj) { return obj && obj.Math === Math ? obj : undefined; } /** * Cached reference to the global object * Uses a cascade of checks to find the appropriate global object: * 1. globalThis (ES2020 standard) * 2. window (browser) * 3. self (web workers, service workers) * 4. global (Node.js) * 5. Function constructor fallback * 6. Empty object fallback */ const GLOBAL_OBJ = (typeof globalThis === "object" && testGlobalCandidate(globalThis)) || (typeof window === "object" && testGlobalCandidate(window)) || (typeof self === "object" && testGlobalCandidate(self)) || (typeof global === "object" && testGlobalCandidate(global)) || (() => { try { // Use Function constructor to access global in strict mode return Function("return this")(); } catch (error) { // In case Function constructor is disabled (CSP, etc.) return {}; } })(); /** * Get the global object for the current environment * @returns {Object} Global object (window, global, self, etc.) */ function getGlobalObject() { return GLOBAL_OBJ; } /** * Get or create a singleton on the global object * Useful for ensuring single instances across different modules * @param {string} key - Key to store singleton under * @param {Function} factory - Factory function to create the singleton * @param {Object} target - Target object (defaults to global) * @returns {any} The singleton instance */ function getGlobalSingleton(key, factory, target) { const globalTarget = target || GLOBAL_OBJ; const sentryGlobals = (globalTarget.__SENTRY__ = globalTarget.__SENTRY__ || {}); return sentryGlobals[key] || (sentryGlobals[key] = factory()); } /** * Detect the current JavaScript environment * @returns {Object} Environment information */ function detectEnvironment() { const global = getGlobalObject(); return { // Environment types isBrowser: typeof window !== "undefined" && typeof window.document !== "undefined", isNode: typeof global !== "undefined" && global.process && global.process.versions && global.process.versions.node, isWebWorker: typeof self !== "undefined" && typeof window === "undefined", isServiceWorker: typeof self !== "undefined" && typeof self.serviceWorker !== "undefined", isDeno: typeof Deno !== "undefined", isBun: typeof Bun !== "undefined", // Browser specifics isElectron: typeof global !== "undefined" && global.process && global.process.type === "renderer", isWebView: typeof window !== "undefined" && (window.ReactNativeWebView || window.webkit?.messageHandlers || window.Android), // Runtime capabilities hasGlobalThis: typeof globalThis !== "undefined", hasWindow: typeof window !== "undefined", hasGlobal: typeof global !== "undefined", hasSelf: typeof self !== "undefined", hasDocument: typeof document !== "undefined", hasProcess: typeof process !== "undefined", // Console availability hasConsole: typeof console !== "undefined", // Global object used globalObjectName: typeof globalThis !== "undefined" ? "globalThis" : typeof window !== "undefined" ? "window" : typeof global !== "undefined" ? "global" : typeof self !== "undefined" ? "self" : "unknown", }; } /** * Get environment-specific information * @returns {Object} Detailed environment information */ function getEnvironmentInfo() { const env = detectEnvironment(); const global = getGlobalObject(); const info = { ...env }; // Add version information where available if (env.isNode) { info.nodeVersion = global.process?.versions?.node; info.v8Version = global.process?.versions?.v8; } if (env.isBrowser) { info.userAgent = typeof navigator !== "undefined" ? navigator.userAgent : undefined; info.language = typeof navigator !== "undefined" ? navigator.language : undefined; } if (env.isDeno) { info.denoVersion = Deno?.version?.deno; } if (env.isBun) { info.bunVersion = Bun?.version; } return info; } /** * Safely access nested properties on global object * @param {string} path - Dot-separated path to property * @returns {any} Property value or undefined */ function getGlobalProperty(path) { const parts = path.split("."); let current = getGlobalObject(); for (const part of parts) { if (current == null || typeof current !== "object") { return undefined; } current = current[part]; } return current; } /** * Safely set nested properties on global object * @param {string} path - Dot-separated path to property * @param {any} value - Value to set * @returns {boolean} True if successful */ function setGlobalProperty(path, value) { try { const parts = path.split("."); const propertyName = parts.pop(); let current = getGlobalObject(); for (const part of parts) { if (current[part] == null) { current[part] = {}; } current = current[part]; } current[propertyName] = value; return true; } catch (error) { return false; } } /** * Check if running in a sandboxed environment * @returns {boolean} True if environment appears sandboxed */ function isSandboxed() { const global = getGlobalObject(); // Check for common sandbox restrictions const restrictions = [ // No eval () => { try { eval("1"); return false; } catch (e) { return true; } }, // No Function constructor () => { try { new Function("return 1")(); return false; } catch (e) { return true; } }, // Limited global properties () => { const expectedProps = ["Object", "Array", "String", "Number", "Boolean"]; return !expectedProps.every((prop) => typeof global[prop] === "function"); }, ]; return restrictions.some((check) => { try { return check(); } catch (e) { return true; } }); } /** * Get safe globals that should be available in most environments * @returns {Object} Safe global references */ function getSafeGlobals() { const global = getGlobalObject(); return { Object: global.Object, Array: global.Array, String: global.String, Number: global.Number, Boolean: global.Boolean, Date: global.Date, RegExp: global.RegExp, JSON: global.JSON, Math: global.Math, parseInt: global.parseInt, parseFloat: global.parseFloat, isNaN: global.isNaN, isFinite: global.isFinite, console: global.console, setTimeout: global.setTimeout, clearTimeout: global.clearTimeout, setInterval: global.setInterval, clearInterval: global.clearInterval, }; } module.exports = { GLOBAL_OBJ, getGlobalObject, getGlobalSingleton, detectEnvironment, getEnvironmentInfo, getGlobalProperty, setGlobalProperty, isSandboxed, getSafeGlobals, };