UNPKG

mcpay

Version:

SDK and CLI for MCPay functionality - MCP servers with payment capabilities

449 lines 15 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.detectPlatform = detectPlatform; exports.generatePotentialUrls = generatePotentialUrls; exports.gatherPlatformInfo = gatherPlatformInfo; exports.isPlatform = isPlatform; exports.getRuntimeSummary = getRuntimeSummary; exports.clearDetectionCache = clearDetectionCache; function detectRuntime() { // Check for Edge Runtime first if (typeof globalThis !== 'undefined') { const edgeRuntime = globalThis.EdgeRuntime; if (typeof edgeRuntime === 'string') { return { name: 'Edge', version: edgeRuntime, isEdge: true }; } } // Check for specific runtimes if (typeof process !== 'undefined' && process.versions) { // Deno check const denoGlobal = globalThis.Deno; if (denoGlobal) { return { name: 'Deno', version: denoGlobal.version?.deno, isEdge: false }; } // Bun check const versions = process.versions; if ('bun' in versions && versions.bun) { return { name: 'Bun', version: versions.bun, isEdge: false }; } // Node.js check if (versions.node) { return { name: 'Node.js', version: versions.node, isEdge: false }; } } // Fallback: check for other edge indicators const hasWebStreams = typeof ReadableStream !== 'undefined' && typeof WritableStream !== 'undefined'; const hasServiceWorkerGlobals = typeof Request !== 'undefined' && typeof Response !== 'undefined' && typeof fetch !== 'undefined'; if (hasWebStreams && hasServiceWorkerGlobals && typeof process === 'undefined') { return { name: 'Edge', isEdge: true }; } return { name: 'Unknown', isEdge: false }; } const SIGNATURES = [ // Vercel - highest priority for Vercel-specific detection { platform: 'Vercel', signatureVars: ['VERCEL', 'VERCEL_ENV', 'VERCEL_URL', 'VERCEL_REGION', 'VERCEL_BRANCH_URL', 'VERCEL_PROJECT_PRODUCTION_URL'], url: (env) => { // Check if running on Vercel const isVercel = env.VERCEL === "1"; if (!isVercel) { return undefined; } // Vercel environment const vercelEnv = env.VERCEL_ENV; // For preview deployments, use the branch URL if available if (vercelEnv === "preview") { const branchUrl = env.VERCEL_BRANCH_URL; if (branchUrl) { return `https://${branchUrl}`; } // Fallback to the general deployment URL return env.VERCEL_URL ? `https://${env.VERCEL_URL}` : undefined; } // For production, use the production URL if available if (vercelEnv === "production") { const productionUrl = env.VERCEL_PROJECT_PRODUCTION_URL; if (productionUrl) { return `https://${productionUrl}`; } // Fallback to the general deployment URL return env.VERCEL_URL ? `https://${env.VERCEL_URL}` : undefined; } // Default fallback for other environments return env.VERCEL_URL ? `https://${env.VERCEL_URL}` : undefined; }, priority: 100 }, // Edge Runtime - detect if running in edge environment { platform: 'Edge Runtime', signatureVars: [], detect: () => { const runtime = detectRuntime(); return runtime.isEdge && runtime.name === 'Edge'; }, url: () => undefined, priority: 95 }, // Netlify { platform: 'Netlify', signatureVars: ['NETLIFY', 'NETLIFY_ENV', 'DEPLOY_URL', 'URL', 'SITE_NAME'], url: (env) => env.NETLIFY_URL ?? env.DEPLOY_URL ?? env.URL, priority: 90 }, // Cloudflare { platform: 'Cloudflare Pages', signatureVars: ['CF_PAGES', 'CF_PAGES_URL', 'CF_PAGES_BRANCH'], url: (env) => env.CF_PAGES_URL, priority: 90 }, { platform: 'Cloudflare Workers', signatureVars: ['CF_WORKER', 'CLOUDFLARE_WORKER'], detect: (env) => { // Additional heuristics for Workers return Boolean(env.CF_WORKER || env.CLOUDFLARE_WORKER || (typeof navigator !== 'undefined' && navigator.userAgent?.includes('Cloudflare-Workers'))); }, url: () => undefined, priority: 85 }, // Deno Deploy { platform: 'Deno Deploy', signatureVars: ['DENO_DEPLOYMENT_ID', 'DENO_REGION'], detect: () => { const runtime = detectRuntime(); return runtime.name === 'Deno' && Boolean(process.env.DENO_DEPLOYMENT_ID); }, url: () => undefined, priority: 85 }, // Supabase Edge Functions { platform: 'Supabase Edge Functions', signatureVars: ['SUPABASE_URL', 'SUPABASE_ANON_KEY', 'SUPABASE_SERVICE_ROLE_KEY'], detect: (env) => Boolean(env.SUPABASE_URL && (env.SUPABASE_ANON_KEY || env.SUPABASE_SERVICE_ROLE_KEY)), url: (env) => env.SUPABASE_URL, priority: 80 }, // AWS { platform: 'AWS Lambda', signatureVars: ['AWS_LAMBDA_FUNCTION_NAME', 'AWS_EXECUTION_ENV', 'LAMBDA_TASK_ROOT'], url: () => undefined, priority: 80 }, { platform: 'AWS Amplify', signatureVars: ['AWS_APP_ID', 'AWS_BRANCH', 'AWS_CLONE_URL'], url: (env) => env.AWS_CLONE_URL, priority: 75 }, { platform: 'AWS Elastic Beanstalk', signatureVars: ['EB_ENVIRONMENT_NAME'], url: () => undefined, priority: 70 }, // Railway { platform: 'Railway', signatureVars: ['RAILWAY_ENVIRONMENT', 'RAILWAY_PUBLIC_DOMAIN', 'RAILWAY_PROJECT_ID'], url: (env) => env.RAILWAY_PUBLIC_DOMAIN ? `https://${env.RAILWAY_PUBLIC_DOMAIN}` : undefined, priority: 75 }, // Render { platform: 'Render', signatureVars: ['RENDER', 'RENDER_EXTERNAL_URL', 'RENDER_SERVICE_ID'], url: (env) => env.RENDER_EXTERNAL_URL, priority: 75 }, // Heroku { platform: 'Heroku', signatureVars: ['HEROKU_APP_NAME', 'DYNO', 'HEROKU_DYNO_ID'], url: (env) => env.HEROKU_APP_NAME ? `https://${env.HEROKU_APP_NAME}.herokuapp.com` : undefined, priority: 75 }, // Fly.io { platform: 'Fly.io', signatureVars: ['FLY_APP_NAME', 'FLY_REGION'], url: (env) => env.FLY_APP_NAME ? `https://${env.FLY_APP_NAME}.fly.dev` : undefined, priority: 75 }, // DigitalOcean { platform: 'DigitalOcean App', signatureVars: ['DO_APP_NAME', 'DO_DEPLOYMENT_ID', 'DIGITALOCEAN_APP_NAME'], url: () => undefined, priority: 70 }, // GitHub/GitLab Pages { platform: 'GitHub Pages', signatureVars: ['GITHUB_PAGES', 'GITHUB_REPOSITORY'], detect: (env) => Boolean(env.GITHUB_PAGES || (env.GITHUB_REPOSITORY && env.GITHUB_ACTIONS)), url: (env) => { if (env.GITHUB_REPOSITORY) { const [owner, repo] = env.GITHUB_REPOSITORY.split('/'); return `https://${owner}.github.io/${repo}`; } return undefined; }, priority: 60 }, { platform: 'GitLab Pages', signatureVars: ['GITLAB_CI', 'CI_PAGES_URL'], detect: (env) => Boolean(env.GITLAB_CI && env.CI_PAGES_URL), url: (env) => env.CI_PAGES_URL, priority: 60 }, // Azure { platform: 'Azure Functions', signatureVars: ['FUNCTIONS_WORKER_RUNTIME', 'WEBSITE_SITE_NAME', 'AZURE_FUNCTIONS_ENVIRONMENT'], url: (env) => env.WEBSITE_SITE_NAME ? `https://${env.WEBSITE_SITE_NAME}.azurewebsites.net` : undefined, priority: 70 }, // GCP { platform: 'GCP Cloud Functions', signatureVars: ['FUNCTION_SIGNATURE_TYPE', 'K_SERVICE', 'FUNCTION_TARGET', 'GCP_PROJECT'], url: () => undefined, priority: 70 }, { platform: 'GCP Cloud Run', signatureVars: ['K_REVISION', 'CLOUD_RUN_JOB', 'K_CONFIGURATION'], url: () => undefined, priority: 70 }, // Kubernetes { platform: 'Kubernetes', signatureVars: ['KUBERNETES_SERVICE_HOST', 'KUBERNETES_PORT', 'KUBERNETES_PORT_443_TCP'], url: () => undefined, priority: 50 }, // Bun.sh (if it becomes a hosting platform) { platform: 'Bun.sh', signatureVars: ['BUN_ENV', 'BUN_DEPLOYMENT_ID'], detect: () => { const runtime = detectRuntime(); return runtime.name === 'Bun' && Boolean(process.env.BUN_DEPLOYMENT_ID); }, url: () => undefined, priority: 75 }, ].sort((a, b) => (b.priority || 0) - (a.priority || 0)); async function tryReadCgroup() { if (typeof process === 'undefined' || !process.versions?.node) return null; try { // Lazy import avoids breaking non‑Node runtimes like Workers / Deno const mod = await import('node:fs/promises'); return await mod.readFile('/proc/1/cgroup', 'utf8'); } catch { return null; } } function hasFetch() { return typeof fetch === 'function'; } function isEdgeRuntime() { const runtime = detectRuntime(); return runtime.isEdge; } // Enhanced container detection async function detectContainer() { const cgroup = await tryReadCgroup(); if (cgroup) { // More comprehensive container detection return /docker|kubepods|containerd|lxc|garden|podman/.test(cgroup); } // Additional container indicators if (typeof process !== 'undefined') { return Boolean(process.env.DOCKER_CONTAINER || process.env.KUBERNETES_SERVICE_HOST || process.env.container || process.env.CONTAINER_NAME); } return false; } // Cache for platform detection to avoid repeated expensive operations const detectionCache = new Map(); const cacheTimeout = 60000; // 1 minute let lastCacheTime = 0; async function detectPlatform(env = process.env) { // Check cache first const cacheKey = JSON.stringify(env); const now = Date.now(); if (detectionCache.has(cacheKey) && (now - lastCacheTime) < cacheTimeout) { return detectionCache.get(cacheKey); } let detectedPlatform = 'Unknown'; // 1. Signature-based detection (ordered by priority) for (const sig of SIGNATURES) { // Check environment variables const hasEnvVar = sig.signatureVars.some((v) => v in env); // Check custom detection logic const hasCustomDetection = sig.detect ? sig.detect(env) : false; if (hasEnvVar || hasCustomDetection) { detectedPlatform = sig.platform; break; } } // 2. Container runtime heuristics (if not already detected) if (detectedPlatform === 'Unknown') { const isContainer = await detectContainer(); if (isContainer) { detectedPlatform = 'Docker'; } } // 3. Cloud VM detection via metadata API (skip if no fetch or already detected) if (detectedPlatform === 'Unknown' && hasFetch()) { try { const controller = new AbortController(); setTimeout(() => controller.abort(), 500); // Increased timeout slightly const res = await fetch('http://169.254.169.254/latest/meta-data/', { signal: controller.signal }); if (res.ok) { detectedPlatform = 'Bare‑metal'; } } catch { // Ignore failures - this is just a heuristic } } // Cache the result detectionCache.set(cacheKey, detectedPlatform); lastCacheTime = now; return detectedPlatform; } function generatePotentialUrls(env = process.env) { const urls = new Set(); const defaultPort = 3000; // Get URLs from platform signatures for (const sig of SIGNATURES) { const url = sig.url(env, defaultPort); if (url) urls.add(url); } // Additional URL sources const additionalUrls = [ env.PUBLIC_URL, env.SITE_URL, env.BASE_URL, env.APP_URL, env.FRONTEND_URL ].filter(Boolean); additionalUrls.forEach(url => urls.add(url)); // Platform-specific URL generation if (env.FLY_APP_NAME) urls.add(`https://${env.FLY_APP_NAME}.fly.dev`); if (env.RAILWAY_PUBLIC_DOMAIN) urls.add(`https://${env.RAILWAY_PUBLIC_DOMAIN}`); if (env.RENDER_EXTERNAL_URL) urls.add(env.RENDER_EXTERNAL_URL); // Fallback URLs if (urls.size === 0) { urls.add(`http://localhost:${defaultPort}`); urls.add(`http://127.0.0.1:${defaultPort}`); } return [...urls]; } async function gatherPlatformInfo(env = process.env) { const [platform, isContainer, runtime] = await Promise.all([ detectPlatform(env), detectContainer(), Promise.resolve(detectRuntime()) ]); const urls = generatePotentialUrls(env); const isEdge = isEdgeRuntime(); const match = SIGNATURES.find((s) => s.platform === platform); const signatureEnv = {}; if (match) { for (const key of match.signatureVars) { if (env[key]) { signatureEnv[key] = env[key]; } } } // Detect if running on cloud VM (simplified heuristic) const isCloudVM = platform === 'Bare‑metal' || Boolean(env.AWS_INSTANCE_METADATA_DISABLED === 'false' || env.GOOGLE_CLOUD_PROJECT || env.AZURE_SUBSCRIPTION_ID); return { platform, runtime, signatureEnv, urls, isEdgeRuntime: isEdge, isContainer, isCloudVM }; } /** * Check if the current environment is a specific platform */ async function isPlatform(targetPlatform, env) { const platform = await detectPlatform(env); return platform === targetPlatform; } /** * Get a summary of the current runtime environment */ function getRuntimeSummary() { const runtime = detectRuntime(); const parts = [runtime.name]; if (runtime.version) { parts.push(`v${runtime.version}`); } if (runtime.isEdge) { parts.push('(Edge)'); } return parts.join(' '); } /** * Clear the platform detection cache (useful for testing) */ function clearDetectionCache() { detectionCache.clear(); lastCacheTime = 0; } //# sourceMappingURL=platform-detection.js.map