UNPKG

@oxog/environment-detector

Version:

Comprehensive, zero-dependency environment detection for Node.js

1,457 lines (1,433 loc) 41 kB
#!/usr/bin/env node #!C:/Program Files/Git/usr/bin/env node/n "use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); // src/detectors/os.ts var os = __toESM(require("os")); // src/core/constants.ts var DEFAULT_CACHE_TIMEOUT = 6e4; var CI_ENV_VARS = Object.freeze({ CI: "CI", CONTINUOUS_INTEGRATION: "CONTINUOUS_INTEGRATION", BUILD_NUMBER: "BUILD_NUMBER", CI_NAME: "CI_NAME" }); var CI_PROVIDER_ENV_VARS = Object.freeze({ GITHUB_ACTIONS: "GITHUB_ACTIONS", GITLAB_CI: "GITLAB_CI", TRAVIS: "TRAVIS", CIRCLECI: "CIRCLECI", JENKINS_URL: "JENKINS_URL", BITBUCKET_BUILD_NUMBER: "BITBUCKET_BUILD_NUMBER", TEAMCITY_VERSION: "TEAMCITY_VERSION", APPVEYOR: "APPVEYOR", CODEBUILD_BUILD_ID: "CODEBUILD_BUILD_ID", TF_BUILD: "TF_BUILD" // Azure Pipelines }); var CLOUD_ENV_VARS = Object.freeze({ AWS_LAMBDA_FUNCTION_NAME: "AWS_LAMBDA_FUNCTION_NAME", AWS_EXECUTION_ENV: "AWS_EXECUTION_ENV", AWS_REGION: "AWS_REGION", FUNCTION_NAME: "FUNCTION_NAME", // Google Cloud Functions K_SERVICE: "K_SERVICE", // Google Cloud Run WEBSITE_SITE_NAME: "WEBSITE_SITE_NAME", // Azure Functions VERCEL: "VERCEL", VERCEL_ENV: "VERCEL_ENV", NETLIFY: "NETLIFY", CF_WORKER: "CF_WORKER" // Cloudflare Workers }); var CONTAINER_FILES = Object.freeze({ DOCKER_ENV: "/.dockerenv", DOCKER_INIT: "/.dockerinit", WSL_INTEROP: "/run/WSL", KUBERNETES_SERVICE: "/var/run/secrets/kubernetes.io" }); var WSL_INDICATORS = Object.freeze({ ENV_VAR: "WSL_DISTRO_NAME", PROC_VERSION: "Microsoft", PROC_SYS: "/proc/sys/fs/binfmt_misc/WSLInterop" }); var NODE_ENV_VALUES = Object.freeze({ DEVELOPMENT: "development", PRODUCTION: "production", TEST: "test", STAGING: "staging" }); // src/core/cache.ts var Cache = class _Cache { constructor() { this.store = /* @__PURE__ */ new Map(); this.enabled = true; } static getInstance() { if (!_Cache.instance) { _Cache.instance = new _Cache(); } return _Cache.instance; } get(key) { if (!this.enabled) { return void 0; } const entry = this.store.get(key); if (!entry) { return void 0; } const now = Date.now(); if (now - entry.timestamp > entry.timeout) { this.store.delete(key); return void 0; } return entry.value; } set(key, value, timeout = DEFAULT_CACHE_TIMEOUT) { if (!this.enabled) { return; } this.store.set(key, { value, timestamp: Date.now(), timeout }); } has(key) { if (!this.enabled) { return false; } const entry = this.store.get(key); if (!entry) { return false; } const now = Date.now(); if (now - entry.timestamp > entry.timeout) { this.store.delete(key); return false; } return true; } delete(key) { return this.store.delete(key); } clear() { this.store.clear(); } enable() { this.enabled = true; } disable() { this.enabled = false; this.clear(); } isEnabled() { return this.enabled; } size() { return this.store.size; } keys() { return Array.from(this.store.keys()); } }; // src/core/detector.ts var BaseDetector = class { constructor(options = {}) { this.cache = Cache.getInstance(); this.options = { cache: true, cacheTimeout: 6e4, async: false, ...options }; } detect() { if (this.options.async) { return this.detectAsync(); } return this.detectSync(); } reset() { this.cache.delete(this.getCacheKey()); } detectSync() { const cacheKey = this.getCacheKey(); if (this.options.cache) { const cached = this.cache.get(cacheKey); if (cached !== void 0) { return cached; } } const result = this.performDetection(); if (this.options.cache) { this.cache.set(cacheKey, result, this.options.cacheTimeout); } return result; } async detectAsync() { const cacheKey = this.getCacheKey(); if (this.options.cache) { const cached = this.cache.get(cacheKey); if (cached !== void 0) { return cached; } } const result = await this.performAsyncDetection(); if (this.options.cache) { this.cache.set(cacheKey, result, this.options.cacheTimeout); } return result; } async performAsyncDetection() { return this.performDetection(); } getCacheKey() { return `detector:${this.name}`; } }; // src/detectors/os.ts var OSDetector = class extends BaseDetector { constructor() { super(...arguments); this.name = "os"; } performDetection() { try { const platform5 = os.platform(); const release2 = os.release(); const version2 = os.version ? os.version() : release2; const arch3 = os.arch(); let type = "unknown"; let isWindows = false; let isMacOS = false; let isLinux = false; switch (platform5) { case "win32": type = "windows"; isWindows = true; break; case "darwin": type = "macos"; isMacOS = true; break; case "linux": type = "linux"; isLinux = true; break; } return { platform: platform5, type, version: version2, release: release2, arch: arch3, isWindows, isMacOS, isLinux }; } catch { return { platform: "linux", type: "unknown", arch: "unknown", release: "unknown", version: "unknown", isWindows: false, isMacOS: false, isLinux: false }; } } }; // src/detectors/container.ts var os3 = __toESM(require("os")); // src/utils/file.ts var fs = __toESM(require("fs")); function fileExists(path2) { try { fs.accessSync(path2, fs.constants.F_OK); return true; } catch { return false; } } function readFile(path2) { try { return fs.readFileSync(path2, "utf8"); } catch { return null; } } function isDirectory(path2) { try { const stats = fs.statSync(path2); return stats.isDirectory(); } catch { return false; } } // src/utils/process.ts var child_process = __toESM(require("child_process")); var os2 = __toESM(require("os")); function getEnv(key) { return process.env[key]; } function hasEnv(key) { return key in process.env; } function getEnvBoolean(key, defaultValue = false) { const value = getEnv(key); if (!value) { return defaultValue; } return value.toLowerCase() === "true" || value === "1"; } function execSync2(command) { try { return child_process.execSync(command, { encoding: "utf8", stdio: ["pipe", "pipe", "ignore"] }).trim(); } catch { return null; } } function getUID() { if (process.getuid) { return process.getuid(); } return void 0; } function getGID() { if (process.getgid) { return process.getgid(); } return void 0; } function getUsername() { try { return os2.userInfo().username; } catch { return void 0; } } function isRoot() { return getUID() === 0; } function parseNodeVersion() { const version2 = process.version; const [major, minor, patch] = version2.slice(1).split(".").map((v) => parseInt(v, 10)); return { version: version2, major: major || 0, minor: minor || 0, patch: patch || 0 }; } // src/detectors/container.ts var ContainerDetector = class extends BaseDetector { constructor() { super(...arguments); this.name = "container"; } performDetection() { const isDocker = this.detectDocker(); const wslInfo = this.detectWSL(); const isKubernetes = this.detectKubernetes(); const isContainer = isDocker || wslInfo.isWSL || isKubernetes; let containerType; if (isDocker) { containerType = "docker"; } else if (wslInfo.isWSL) { containerType = "wsl"; } else if (isKubernetes) { containerType = "kubernetes"; } return { isContainer, isDocker, isWSL: wslInfo.isWSL, isKubernetes, containerType, wslVersion: wslInfo.version, wslDistro: wslInfo.distro }; } detectDocker() { if (fileExists(CONTAINER_FILES.DOCKER_ENV) || fileExists(CONTAINER_FILES.DOCKER_INIT)) { return true; } const cgroupPath = "/proc/self/cgroup"; const cgroupContent = readFile(cgroupPath); if (cgroupContent && (cgroupContent.includes("docker") || cgroupContent.includes("containerd"))) { return true; } const initCgroupContent = readFile("/proc/1/cgroup"); if (initCgroupContent && (initCgroupContent.includes("docker") || initCgroupContent.includes("containerd"))) { return true; } const mountInfo = readFile("/proc/self/mountinfo"); if (mountInfo && mountInfo.includes("docker")) { return true; } return false; } detectWSL() { if (os3.platform() === "win32") { return { isWSL: false }; } const wslDistro = getEnv(WSL_INDICATORS.ENV_VAR); if (wslDistro) { return { isWSL: true, version: this.getWSLVersion(), distro: wslDistro }; } const procVersion = readFile("/proc/version"); if (procVersion && procVersion.toLowerCase().includes(WSL_INDICATORS.PROC_VERSION.toLowerCase())) { return { isWSL: true, version: this.getWSLVersion(), distro: this.getWSLDistro() }; } if (fileExists(WSL_INDICATORS.PROC_SYS) || isDirectory(CONTAINER_FILES.WSL_INTEROP)) { return { isWSL: true, version: this.getWSLVersion(), distro: this.getWSLDistro() }; } if (hasEnv("WSLENV") || hasEnv("WSL_INTEROP")) { return { isWSL: true, version: this.getWSLVersion(), distro: this.getWSLDistro() }; } return { isWSL: false }; } detectKubernetes() { if (isDirectory(CONTAINER_FILES.KUBERNETES_SERVICE)) { return true; } if (hasEnv("KUBERNETES_SERVICE_HOST") || hasEnv("KUBERNETES_PORT")) { return true; } const hostname2 = os3.hostname(); if (hostname2 && /^[a-z0-9]+-[a-z0-9]+-[a-z0-9]+(-[a-z0-9]+)*$/.test(hostname2)) { if (fileExists("/var/run/secrets/kubernetes.io/serviceaccount/token")) { return true; } } return false; } getWSLVersion() { const procVersion = readFile("/proc/version"); if (procVersion) { if (procVersion.includes("WSL2") || procVersion.includes("microsoft-standard-WSL2")) { return 2; } if (procVersion.includes("Microsoft") || procVersion.includes("WSL")) { const kernelMatch = procVersion.match(/(\d+)\.(\d+)\.(\d+)/); if (kernelMatch) { const majorVersion = parseInt(kernelMatch[1] || "0", 10); if (majorVersion >= 5) { return 2; } } return 1; } } return void 0; } getWSLDistro() { const envDistro = getEnv(WSL_INDICATORS.ENV_VAR); if (envDistro) { return envDistro; } const osRelease = readFile("/etc/os-release"); if (osRelease) { const nameMatch = osRelease.match(/^NAME="?(.+?)"?$/m); if (nameMatch) { return nameMatch[1]; } } return void 0; } }; // src/detectors/ci.ts var CIDetector = class extends BaseDetector { constructor() { super(...arguments); this.name = "ci"; } performDetection() { const isCI = this.detectCI(); if (!isCI) { return { isCI: false }; } const provider = this.detectCIProvider(); const name = this.getCIName(provider); const isPR = this.detectPullRequest(provider); return { isCI, name, isPR, provider }; } detectCI() { if (getEnvBoolean(CI_ENV_VARS.CI) || getEnvBoolean(CI_ENV_VARS.CONTINUOUS_INTEGRATION) || hasEnv(CI_ENV_VARS.BUILD_NUMBER) || hasEnv(CI_ENV_VARS.CI_NAME)) { return true; } for (const envVar of Object.values(CI_PROVIDER_ENV_VARS)) { if (hasEnv(envVar)) { return true; } } return false; } detectCIProvider() { if (getEnvBoolean(CI_PROVIDER_ENV_VARS.GITHUB_ACTIONS)) { return "github-actions"; } if (getEnvBoolean(CI_PROVIDER_ENV_VARS.GITLAB_CI)) { return "gitlab-ci"; } if (getEnvBoolean(CI_PROVIDER_ENV_VARS.TRAVIS)) { return "travis-ci"; } if (getEnvBoolean(CI_PROVIDER_ENV_VARS.CIRCLECI)) { return "circleci"; } if (hasEnv(CI_PROVIDER_ENV_VARS.JENKINS_URL)) { return "jenkins"; } if (getEnvBoolean(CI_PROVIDER_ENV_VARS.TF_BUILD)) { return "azure-pipelines"; } if (hasEnv(CI_PROVIDER_ENV_VARS.BITBUCKET_BUILD_NUMBER)) { return "bitbucket-pipelines"; } if (hasEnv(CI_PROVIDER_ENV_VARS.TEAMCITY_VERSION)) { return "teamcity"; } if (getEnvBoolean(CI_PROVIDER_ENV_VARS.APPVEYOR)) { return "appveyor"; } if (hasEnv(CI_PROVIDER_ENV_VARS.CODEBUILD_BUILD_ID)) { return "codebuild"; } return "unknown"; } getCIName(provider) { switch (provider) { case "github-actions": return "GitHub Actions"; case "gitlab-ci": return "GitLab CI"; case "travis-ci": return "Travis CI"; case "circleci": return "CircleCI"; case "jenkins": return "Jenkins"; case "azure-pipelines": return "Azure Pipelines"; case "bitbucket-pipelines": return "Bitbucket Pipelines"; case "teamcity": return "TeamCity"; case "appveyor": return "AppVeyor"; case "codebuild": return "AWS CodeBuild"; default: return getEnv(CI_ENV_VARS.CI_NAME) || "Unknown CI"; } } detectPullRequest(provider) { var _a; switch (provider) { case "github-actions": return getEnv("GITHUB_EVENT_NAME") === "pull_request"; case "gitlab-ci": return hasEnv("CI_MERGE_REQUEST_ID") || hasEnv("CI_EXTERNAL_PULL_REQUEST_IID"); case "travis-ci": return getEnv("TRAVIS_PULL_REQUEST") !== "false"; case "circleci": return hasEnv("CIRCLE_PULL_REQUEST") || hasEnv("CIRCLE_PR_NUMBER"); case "jenkins": return hasEnv("CHANGE_ID") || hasEnv("ghprbPullId"); case "azure-pipelines": return hasEnv("SYSTEM_PULLREQUEST_PULLREQUESTID"); case "bitbucket-pipelines": return hasEnv("BITBUCKET_PR_ID"); case "teamcity": return hasEnv("TEAMCITY_PULL_REQUEST_NUMBER"); case "appveyor": return hasEnv("APPVEYOR_PULL_REQUEST_NUMBER"); case "codebuild": return hasEnv("CODEBUILD_WEBHOOK_HEAD_REF") && ((_a = getEnv("CODEBUILD_WEBHOOK_HEAD_REF")) == null ? void 0 : _a.startsWith("refs/pull/")) || false; default: return hasEnv("PR_NUMBER") || hasEnv("PULL_REQUEST_ID") || hasEnv("PULL_REQUEST"); } } }; // src/detectors/cloud.ts var CloudDetector = class extends BaseDetector { constructor() { super(...arguments); this.name = "cloud"; } performDetection() { const provider = this.detectCloudProvider(); const isCloud = provider !== void 0; const isServerless = this.isServerlessEnvironment(provider); const functionName = this.getFunctionName(provider); const region = this.getRegion(provider); return { isCloud, provider, isServerless, functionName, region }; } detectCloudProvider() { if (hasEnv(CLOUD_ENV_VARS.AWS_LAMBDA_FUNCTION_NAME) || hasEnv(CLOUD_ENV_VARS.AWS_EXECUTION_ENV)) { return "aws-lambda"; } if (hasEnv(CLOUD_ENV_VARS.FUNCTION_NAME) || hasEnv(CLOUD_ENV_VARS.K_SERVICE)) { return "google-cloud-functions"; } if (hasEnv(CLOUD_ENV_VARS.WEBSITE_SITE_NAME) && hasEnv("FUNCTIONS_EXTENSION_VERSION")) { return "azure-functions"; } if (hasEnv(CLOUD_ENV_VARS.VERCEL) || hasEnv(CLOUD_ENV_VARS.VERCEL_ENV)) { return "vercel"; } if (hasEnv(CLOUD_ENV_VARS.NETLIFY) || hasEnv("NETLIFY_BUILD_BASE")) { return "netlify"; } if (hasEnv(CLOUD_ENV_VARS.CF_WORKER) || this.detectCloudflareWorkers()) { return "cloudflare-workers"; } if (this.detectAWS()) { return "aws-lambda"; } return void 0; } isServerlessEnvironment(provider) { if (!provider) { return false; } switch (provider) { case "aws-lambda": case "google-cloud-functions": case "azure-functions": case "cloudflare-workers": return true; case "vercel": case "netlify": return hasEnv("VERCEL_FUNCTION") || hasEnv("NETLIFY_FUNCTION_NAME") || hasEnv("NETLIFY_DEV"); default: return false; } } getFunctionName(provider) { if (!provider) { return void 0; } switch (provider) { case "aws-lambda": return getEnv(CLOUD_ENV_VARS.AWS_LAMBDA_FUNCTION_NAME); case "google-cloud-functions": return getEnv(CLOUD_ENV_VARS.FUNCTION_NAME) || getEnv(CLOUD_ENV_VARS.K_SERVICE); case "azure-functions": return getEnv(CLOUD_ENV_VARS.WEBSITE_SITE_NAME); case "vercel": return getEnv("VERCEL_FUNCTION"); case "netlify": return getEnv("NETLIFY_FUNCTION_NAME"); case "cloudflare-workers": return getEnv("CF_WORKER_NAME") || getEnv("WORKER_NAME"); default: return void 0; } } getRegion(provider) { if (!provider) { return void 0; } switch (provider) { case "aws-lambda": return getEnv(CLOUD_ENV_VARS.AWS_REGION) || getEnv("AWS_DEFAULT_REGION"); case "google-cloud-functions": return getEnv("FUNCTION_REGION") || getEnv("GCP_REGION"); case "azure-functions": return getEnv("REGION_NAME") || getEnv("AZURE_REGION"); case "vercel": return getEnv("VERCEL_REGION"); case "cloudflare-workers": return getEnv("CF_REGION"); default: return void 0; } } detectAWS() { if (hasEnv("AWS_EXECUTION_ENV") || hasEnv("AWS_LAMBDA_RUNTIME_API") || hasEnv("_HANDLER") || hasEnv("LAMBDA_TASK_ROOT") || hasEnv("LAMBDA_RUNTIME_DIR")) { return true; } if (hasEnv("ECS_CONTAINER_METADATA_URI") || hasEnv("ECS_CONTAINER_METADATA_URI_V4")) { return true; } if (fileExists("/sys/hypervisor/uuid")) { return true; } return false; } detectCloudflareWorkers() { if (typeof global !== "undefined" && "caches" in global && "default" in global.caches) { return true; } try { const globalAny = global; if (globalAny.CloudflareWorker || globalAny.MINIFLARE || globalAny.navigator && globalAny.navigator.userAgent === "Cloudflare-Workers") { return true; } } catch { } return false; } }; // src/detectors/node.ts var os4 = __toESM(require("os")); var NodeDetector = class extends BaseDetector { constructor() { super(...arguments); this.name = "node"; } performDetection() { const { version: version2, major, minor, patch } = parseNodeVersion(); const arch3 = os4.arch(); const platform5 = os4.platform(); return { version: version2, major, minor, patch, arch: arch3, platform: platform5 }; } }; var EnvironmentModeDetector = class extends BaseDetector { constructor() { super(...arguments); this.name = "mode"; } performDetection() { var _a; const nodeEnv = (_a = getEnv("NODE_ENV")) == null ? void 0 : _a.toLowerCase(); switch (nodeEnv) { case NODE_ENV_VALUES.PRODUCTION: return "production"; case NODE_ENV_VALUES.DEVELOPMENT: return "development"; case NODE_ENV_VALUES.TEST: return "test"; case NODE_ENV_VALUES.STAGING: return "staging"; default: return "development"; } } }; // src/detectors/privileges.ts var os5 = __toESM(require("os")); var PrivilegeDetector = class extends BaseDetector { constructor() { super(...arguments); this.name = "privileges"; } performDetection() { const platform5 = os5.platform(); const uid = getUID(); const gid = getGID(); const username = getUsername(); const isRootUser = isRoot(); const isAdminUser = this.isAdmin(platform5); const isElevated = isRootUser || isAdminUser; return { isElevated, isRoot: isRootUser, isAdmin: isAdminUser, uid, gid, username }; } isAdmin(platform5) { switch (platform5) { case "win32": return this.isWindowsAdmin(); case "darwin": case "linux": return this.isUnixAdmin(); default: return false; } } isWindowsAdmin() { try { const result = execSync2("net session 2>nul"); return result !== null; } catch { try { const whoami = execSync2("whoami /groups"); if (whoami) { return whoami.toLowerCase().includes("s-1-5-32-544") || whoami.toLowerCase().includes("administrators"); } } catch { } try { const systemDir = execSync2('dir "%SystemRoot%\\System32\\config" 2>nul'); return systemDir !== null; } catch { return false; } } } isUnixAdmin() { if (isRoot()) { return true; } try { const groups = execSync2("groups"); if (groups) { const groupList = groups.toLowerCase(); return groupList.includes("admin") || groupList.includes("sudo") || groupList.includes("wheel") || groupList.includes("root"); } } catch { try { const sudoCheck = execSync2("sudo -n true 2>/dev/null"); return sudoCheck !== null; } catch { return false; } } return false; } }; // src/plugins/base.ts var PluginContextImpl = class { constructor() { this.detectors = /* @__PURE__ */ new Map(); this.eventHandlers = /* @__PURE__ */ new Map(); } registerDetector(detector) { this.detectors.set(detector.name, detector); } unregisterDetector(name) { this.detectors.delete(name); } getDetector(name) { return this.detectors.get(name); } getAllDetectors() { return Array.from(this.detectors.values()); } emit(event, data) { const handlers = this.eventHandlers.get(event); if (handlers) { for (const handler of handlers) { try { const result = handler(data); if (result instanceof Promise) { result.catch((error) => { console.error(`Error in event handler for '${event}':`, error); }); } } catch (error) { console.error(`Error in event handler for '${event}':`, error); } } } } on(event, handler) { if (!this.eventHandlers.has(event)) { this.eventHandlers.set(event, []); } this.eventHandlers.get(event).push(handler); } off(event, handler) { const handlers = this.eventHandlers.get(event); if (handlers) { const index = handlers.indexOf(handler); if (index > -1) { handlers.splice(index, 1); } } } }; // src/plugins/manager.ts var PluginManagerImpl = class _PluginManagerImpl { constructor() { this.plugins = /* @__PURE__ */ new Map(); this.context = new PluginContextImpl(); } static getInstance() { if (!_PluginManagerImpl.instance) { _PluginManagerImpl.instance = new _PluginManagerImpl(); } return _PluginManagerImpl.instance; } async use(plugin) { var _a; if (this.plugins.has(plugin.name)) { throw new Error(`Plugin '${plugin.name}' is already installed`); } try { await ((_a = plugin.install) == null ? void 0 : _a.call(plugin, this.context)); this.plugins.set(plugin.name, plugin); this.context.emit("plugin:installed", { plugin }); } catch (error) { this.context.emit("plugin:error", { plugin, error }); throw new Error(`Failed to install plugin '${plugin.name}': ${error}`); } } async remove(pluginName) { var _a; const plugin = this.plugins.get(pluginName); if (!plugin) { throw new Error(`Plugin '${pluginName}' is not installed`); } try { for (const detector of plugin.detectors) { this.context.unregisterDetector(detector.name); } await ((_a = plugin.uninstall) == null ? void 0 : _a.call(plugin)); this.plugins.delete(pluginName); this.context.emit("plugin:removed", { plugin }); } catch (error) { this.context.emit("plugin:error", { plugin, error }); throw new Error(`Failed to remove plugin '${pluginName}': ${error}`); } } get(pluginName) { return this.plugins.get(pluginName); } getAll() { return Array.from(this.plugins.values()); } clear() { for (const pluginName of this.plugins.keys()) { try { this.remove(pluginName); } catch (error) { console.error(`Error removing plugin '${pluginName}':`, error); } } } getContext() { return this.context; } }; // src/version.ts var VERSION = "1.0.0"; var BUILD_DATE = (/* @__PURE__ */ new Date()).toISOString(); var NODE_VERSION = process.version; // src/index.ts var EnvironmentDetector = class { constructor(options) { this.osDetector = new OSDetector(); this.containerDetector = new ContainerDetector(); this.ciDetector = new CIDetector(); this.cloudDetector = new CloudDetector(); this.nodeDetector = new NodeDetector(); this.modeDetector = new EnvironmentModeDetector(); this.privilegeDetector = new PrivilegeDetector(); this.pluginManager = PluginManagerImpl.getInstance(); this.cache = Cache.getInstance(); if (options) { this.osDetector = new OSDetector(options); this.containerDetector = new ContainerDetector(options); this.ciDetector = new CIDetector(options); this.cloudDetector = new CloudDetector(options); this.nodeDetector = new NodeDetector(options); this.modeDetector = new EnvironmentModeDetector(options); this.privilegeDetector = new PrivilegeDetector(options); if (options.cache === false) { this.cache.disable(); } } } getEnvironmentInfo() { return { os: this.osDetector.detect(), container: this.containerDetector.detect(), ci: this.ciDetector.detect(), cloud: this.cloudDetector.detect(), node: this.nodeDetector.detect(), privileges: this.privilegeDetector.detect(), mode: this.modeDetector.detect() }; } async getEnvironmentInfoAsync() { const [os6, container, ci, cloud, node, privileges, mode] = await Promise.all([ Promise.resolve(this.osDetector.detect()), Promise.resolve(this.containerDetector.detect()), Promise.resolve(this.ciDetector.detect()), Promise.resolve(this.cloudDetector.detect()), Promise.resolve(this.nodeDetector.detect()), Promise.resolve(this.privilegeDetector.detect()), Promise.resolve(this.modeDetector.detect()) ]); return { os: os6, container, ci, cloud, node, privileges, mode }; } // Convenience getters for individual detections get isWindows() { return this.osDetector.detect().isWindows; } get isMacOS() { return this.osDetector.detect().isMacOS; } get isLinux() { return this.osDetector.detect().isLinux; } get isWSL() { return this.containerDetector.detect().isWSL; } get isDocker() { return this.containerDetector.detect().isDocker; } get isKubernetes() { return this.containerDetector.detect().isKubernetes; } get isContainer() { return this.containerDetector.detect().isContainer; } get isCI() { return this.ciDetector.detect().isCI; } get isCloud() { return this.cloudDetector.detect().isCloud; } get isServerless() { return this.cloudDetector.detect().isServerless; } get isElevated() { return this.privilegeDetector.detect().isElevated; } get isRoot() { return this.privilegeDetector.detect().isRoot; } get isAdmin() { return this.privilegeDetector.detect().isAdmin; } // Plugin system use(plugin) { this.pluginManager.use(plugin); } removePlugin(pluginName) { this.pluginManager.remove(pluginName); } // Cache management clearCache() { this.cache.clear(); } enableCache() { this.cache.enable(); } disableCache() { this.cache.disable(); } // Reset all detectors reset() { this.osDetector.reset(); this.containerDetector.reset(); this.ciDetector.reset(); this.cloudDetector.reset(); this.nodeDetector.reset(); this.modeDetector.reset(); this.privilegeDetector.reset(); } // Get version information getVersion() { return VERSION; } // Get detailed package information getPackageInfo() { return { version: VERSION, detectors: ["os", "container", "ci", "cloud", "node", "privileges", "mode"], cacheEnabled: this.cache.isEnabled() }; } // Quick environment summary getEnvironmentSummary() { const info = this.getEnvironmentInfo(); const parts = [info.os.type]; if (info.container.isContainer) { parts.push(info.container.containerType || "container"); } if (info.ci.isCI) { parts.push("ci"); } if (info.cloud.isCloud) { parts.push("cloud"); } if (info.privileges.isElevated) { parts.push("elevated"); } return parts.join("+"); } }; var env = new EnvironmentDetector(); // cli/index.ts var fs2 = __toESM(require("fs")); var path = __toESM(require("path")); var CLI = class { constructor() { this.env = new EnvironmentDetector(); this.options = {}; } async run() { this.parseArgs(); if (this.options.help) { this.showHelp(); return; } if (this.options.version) { this.showVersion(); return; } if (this.options.list) { this.listDetectors(); return; } if (this.options.plugin) { await this.loadPlugin(this.options.plugin); } if (this.options.benchmark) { await this.runBenchmark(); return; } if (this.options.check) { await this.checkEnvironment(this.options.check); return; } await this.showEnvironmentInfo(); } parseArgs() { const args = process.argv.slice(2); for (let i = 0; i < args.length; i++) { const arg = args[i]; switch (arg) { case "--json": this.options.json = true; break; case "--check": this.options.check = args[++i]; break; case "--list": this.options.list = true; break; case "--plugin": this.options.plugin = args[++i]; break; case "--verbose": this.options.verbose = true; break; case "--benchmark": this.options.benchmark = true; break; case "--help": case "-h": this.options.help = true; break; case "--version": case "-v": this.options.version = true; break; default: console.error(`Unknown option: ${arg}`); process.exit(1); } } } showHelp() { console.log(` @oxog/environment-detector CLI Usage: environment-detector [options] Options: --json Output full environment info as JSON --check <env> Check specific environment (returns exit code) --list List all available detectors --plugin <path> Load custom plugin --verbose Detailed detection process --benchmark Run performance benchmarks --help, -h Show this help message --version, -v Show version number Examples: environment-detector --json environment-detector --check docker environment-detector --check wsl environment-detector --list environment-detector --plugin ./my-plugin.js environment-detector --benchmark Check environment values: windows, macos, linux, wsl, docker, kubernetes, container, ci, cloud, serverless, elevated, root, admin Exit codes: 0 - Success (environment detected or general success) 1 - Failure (environment not detected or error) `); } showVersion() { try { const packageJson = JSON.parse( fs2.readFileSync(path.join(__dirname, "..", "package.json"), "utf8") ); console.log(packageJson.version); } catch { console.log("Unknown version"); } } listDetectors() { const detectors = [ "os - Operating system detection", "container - Container environment detection (Docker, WSL, Kubernetes)", "ci - CI/CD environment detection", "cloud - Cloud platform detection", "node - Node.js version and runtime info", "privileges - User privilege detection", "mode - Environment mode (development, production, etc.)" ]; console.log("Available detectors:"); detectors.forEach((detector) => console.log(` ${detector}`)); } async loadPlugin(pluginPath) { try { const resolvedPath = path.resolve(pluginPath); const plugin = await import(resolvedPath); if (plugin.default) { await this.env.use(plugin.default); if (this.options.verbose) { console.log(`Loaded plugin: ${plugin.default.name}`); } } else { throw new Error("Plugin must export a default plugin object"); } } catch (error) { console.error(`Failed to load plugin: ${error}`); process.exit(1); } } async runBenchmark() { console.log("Running performance benchmarks...\n"); const benchmarks = [ { name: "OS Detection", fn: () => this.env.isWindows }, { name: "Container Detection", fn: () => this.env.isContainer }, { name: "CI Detection", fn: () => this.env.isCI }, { name: "Cloud Detection", fn: () => this.env.isCloud }, { name: "Privilege Detection", fn: () => this.env.isElevated }, { name: "Full Environment Info", fn: () => this.env.getEnvironmentInfo() } ]; for (const benchmark of benchmarks) { const iterations = 1e3; const start = process.hrtime.bigint(); for (let i = 0; i < iterations; i++) { benchmark.fn(); } const end = process.hrtime.bigint(); const totalMs = Number(end - start) / 1e6; const avgMs = totalMs / iterations; console.log(`${benchmark.name}:`); console.log(` Total: ${totalMs.toFixed(2)}ms`); console.log(` Average: ${avgMs.toFixed(4)}ms per call`); console.log(` Rate: ${(1e3 / avgMs).toFixed(0)} calls/second `); } const memUsage = process.memoryUsage(); console.log("Memory Usage:"); console.log(` RSS: ${(memUsage.rss / 1024 / 1024).toFixed(2)} MB`); console.log(` Heap Used: ${(memUsage.heapUsed / 1024 / 1024).toFixed(2)} MB`); console.log(` Heap Total: ${(memUsage.heapTotal / 1024 / 1024).toFixed(2)} MB`); } async checkEnvironment(envCheck) { const env2 = envCheck.toLowerCase(); let result = false; let description = ""; switch (env2) { case "windows": result = this.env.isWindows; description = "Windows operating system"; break; case "macos": result = this.env.isMacOS; description = "macOS operating system"; break; case "linux": result = this.env.isLinux; description = "Linux operating system"; break; case "wsl": result = this.env.isWSL; description = "Windows Subsystem for Linux"; break; case "docker": result = this.env.isDocker; description = "Docker container"; break; case "kubernetes": result = this.env.isKubernetes; description = "Kubernetes pod"; break; case "container": result = this.env.isContainer; description = "Any container environment"; break; case "ci": result = this.env.isCI; description = "CI/CD environment"; break; case "cloud": result = this.env.isCloud; description = "Cloud platform"; break; case "serverless": result = this.env.isServerless; description = "Serverless environment"; break; case "elevated": result = this.env.isElevated; description = "Elevated privileges"; break; case "root": result = this.env.isRoot; description = "Root user"; break; case "admin": result = this.env.isAdmin; description = "Administrator user"; break; default: console.error(`Unknown environment check: ${envCheck}`); process.exit(1); } if (this.options.verbose) { console.log(`Checking for ${description}...`); } if (this.options.json) { console.log(JSON.stringify({ [env2]: result }, null, 2)); } else if (this.options.verbose) { console.log(result ? `\u2713 ${description} detected` : `\u2717 ${description} not detected`); } else { console.log(result.toString()); } process.exit(result ? 0 : 1); } async showEnvironmentInfo() { const info = this.env.getEnvironmentInfo(); if (this.options.json) { console.log(JSON.stringify(info, null, 2)); } else { this.printHumanReadable(info); } } printHumanReadable(info) { console.log("Environment Detection Results"); console.log("============================\n"); console.log("Operating System:"); console.log(` Platform: ${info.os.type} (${info.os.platform})`); console.log(` Version: ${info.os.version}`); console.log(` Architecture: ${info.os.arch} `); console.log("Container Environment:"); if (info.container.isContainer) { console.log(` Type: ${info.container.containerType}`); if (info.container.isWSL) { console.log(` WSL Version: ${info.container.wslVersion}`); if (info.container.wslDistro) { console.log(` WSL Distribution: ${info.container.wslDistro}`); } } } else { console.log(" No container environment detected"); } console.log(); console.log("CI/CD Environment:"); if (info.ci.isCI) { console.log(` Provider: ${info.ci.name} (${info.ci.provider})`); console.log(` Pull Request: ${info.ci.isPR ? "Yes" : "No"}`); } else { console.log(" No CI/CD environment detected"); } console.log(); console.log("Cloud Environment:"); if (info.cloud.isCloud) { console.log(` Provider: ${info.cloud.provider}`); console.log(` Serverless: ${info.cloud.isServerless ? "Yes" : "No"}`); if (info.cloud.functionName) { console.log(` Function: ${info.cloud.functionName}`); } if (info.cloud.region) { console.log(` Region: ${info.cloud.region}`); } } else { console.log(" No cloud environment detected"); } console.log(); console.log("Node.js Runtime:"); console.log(` Version: ${info.node.version}`); console.log(` Architecture: ${info.node.arch}`); console.log(` Platform: ${info.node.platform} `); console.log("User Privileges:"); console.log(` Elevated: ${info.privileges.isElevated ? "Yes" : "No"}`); console.log(` Root: ${info.privileges.isRoot ? "Yes" : "No"}`); console.log(` Admin: ${info.privileges.isAdmin ? "Yes" : "No"}`); if (info.privileges.username) { console.log(` Username: ${info.privileges.username}`); } if (info.privileges.uid !== void 0) { console.log(` UID: ${info.privileges.uid}`); } console.log(); console.log(`Environment Mode: ${info.mode}`); } }; var cli = new CLI(); cli.run().catch((error) => { console.error("CLI Error:", error); process.exit(1); }); //# sourceMappingURL=index.js.map