import { checkNgrokApiReachability, checkNgrokAuthtokenConfigured, checkNgrokAvailable, startNgrokQuickTunnel, } from '../../ngrok-tunnel.js'; import { TUNNEL_INTENT_EPHEMERAL_PUBLIC, TUNNEL_MODE_QUICK, TUNNEL_PROVIDER_NGROK, TunnelServiceError, } from '../types.js'; import { getTunnelDependencyInstallInfo } from '../install-help.js'; export const ngrokTunnelProviderCapabilities = { provider: TUNNEL_PROVIDER_NGROK, defaults: { mode: TUNNEL_MODE_QUICK, optionDefaults: {}, }, modes: [ { key: TUNNEL_MODE_QUICK, label: 'Quick Tunnel', intent: TUNNEL_INTENT_EPHEMERAL_PUBLIC, requires: [], supports: ['sessionTTL'], stability: 'beta', }, ], }; export function createNgrokTunnelProvider() { return { id: TUNNEL_PROVIDER_NGROK, capabilities: ngrokTunnelProviderCapabilities, checkAvailability: async () => { const result = await checkNgrokAvailable(); if (result.available) { return { ...result, ...getTunnelDependencyInstallInfo(TUNNEL_PROVIDER_NGROK), }; } const installInfo = getTunnelDependencyInstallInfo(TUNNEL_PROVIDER_NGROK); return { ...result, ...installInfo, }; }, diagnose: async () => { const dependency = await checkNgrokAvailable(); const authtoken = await checkNgrokAuthtokenConfigured(dependency.path); const network = await checkNgrokApiReachability(); const installInfo = getTunnelDependencyInstallInfo(TUNNEL_PROVIDER_NGROK); const startupReady = dependency.available && authtoken.configured && network.reachable; const providerChecks = [ { id: 'dependency', label: 'ngrok installed', status: dependency.available ? 'pass' : 'fail', detail: dependency.available ? (dependency.version || dependency.path || 'ngrok available') : installInfo.message, }, { id: 'authtoken', label: 'ngrok authtoken configured', status: authtoken.configured ? 'pass' : 'fail', detail: authtoken.configured ? authtoken.detail : (authtoken.detail || 'Run: ngrok config add-authtoken '), }, { id: 'network', label: 'ngrok API reachable', status: network.reachable ? 'pass' : 'fail', detail: network.reachable ? (network.status ? `HTTP ${network.status}` : 'Reachable') : (network.error || 'Could not reach api.ngrok.com'), }, ]; return { providerChecks, modes: [ { mode: TUNNEL_MODE_QUICK, checks: [ { id: 'startup_readiness', label: 'Provider startup readiness', status: startupReady ? 'pass' : 'fail', detail: startupReady ? 'Provider dependency, auth, and network checks passed.' : 'Resolve provider checks before starting tunnels.', }, ], summary: { ready: startupReady, failures: startupReady ? 0 : 1, warnings: 0, }, ready: startupReady, blockers: startupReady ? [] : ['Resolve provider checks before starting tunnels.'], }, ], }; }, start: async (request, context = {}) => { if (request.mode !== TUNNEL_MODE_QUICK) { throw new TunnelServiceError('mode_unsupported', `Ngrok only supports '${TUNNEL_MODE_QUICK}' mode right now`); } return startNgrokQuickTunnel({ port: context.activePort }); }, stop: (controller) => { controller?.stop?.(); }, resolvePublicUrl: (controller) => controller?.getPublicUrl?.() ?? null, getMetadata: () => null, }; }