feat: add Ngrok tunnel provider (#1415)
Adds Ngrok quick tunnel support Adds desktop tunnel docs across locales Improves tunnel settings provider and TTL labels
This commit is contained in:
committed by
GitHub
parent
25ed8e6abb
commit
00a7807168
@@ -10,6 +10,7 @@ This module contains tunnel provider orchestration for OpenChamber, including pr
|
||||
- `packages/web/server/lib/tunnels/routes.js`: tunnel API route registration and request orchestration runtime.
|
||||
- `packages/web/server/lib/tunnels/types.js`: tunnel constants, normalization, and shared type helpers.
|
||||
- `packages/web/server/lib/tunnels/providers/cloudflare.js`: Cloudflare tunnel provider implementation.
|
||||
- `packages/web/server/lib/tunnels/providers/ngrok.js`: Ngrok quick tunnel provider implementation.
|
||||
|
||||
## Public exports (routes.js)
|
||||
- `createTunnelRoutesRuntime(dependencies)`: creates tunnel routes runtime and helpers.
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
import {
|
||||
checkNgrokApiReachability,
|
||||
checkNgrokAuthtokenConfigured,
|
||||
checkNgrokAvailable,
|
||||
startNgrokQuickTunnel,
|
||||
} from '../../ngrok-tunnel.js';
|
||||
|
||||
import {
|
||||
TUNNEL_INTENT_EPHEMERAL_PUBLIC,
|
||||
TUNNEL_MODE_QUICK,
|
||||
TUNNEL_PROVIDER_NGROK,
|
||||
TunnelServiceError,
|
||||
} from '../types.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;
|
||||
}
|
||||
return {
|
||||
...result,
|
||||
message: 'ngrok is not installed. Install it with: brew install ngrok',
|
||||
};
|
||||
},
|
||||
diagnose: async () => {
|
||||
const dependency = await checkNgrokAvailable();
|
||||
const authtoken = await checkNgrokAuthtokenConfigured(dependency.path);
|
||||
const network = await checkNgrokApiReachability();
|
||||
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')
|
||||
: 'ngrok is not installed. Install it with: brew install ngrok',
|
||||
},
|
||||
{
|
||||
id: 'authtoken',
|
||||
label: 'ngrok authtoken configured',
|
||||
status: authtoken.configured ? 'pass' : 'fail',
|
||||
detail: authtoken.configured
|
||||
? authtoken.detail
|
||||
: (authtoken.detail || 'Run: ngrok config add-authtoken <your-ngrok-token>'),
|
||||
},
|
||||
{
|
||||
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,
|
||||
};
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
export const TUNNEL_PROVIDER_CLOUDFLARE = 'cloudflare';
|
||||
export const TUNNEL_PROVIDER_NGROK = 'ngrok';
|
||||
|
||||
export const TUNNEL_MODE_QUICK = 'quick';
|
||||
export const TUNNEL_MODE_MANAGED_REMOTE = 'managed-remote';
|
||||
@@ -34,6 +35,7 @@ export class TunnelServiceError extends Error {
|
||||
|
||||
const SUPPORTED_TUNNEL_PROVIDERS = new Set([
|
||||
TUNNEL_PROVIDER_CLOUDFLARE,
|
||||
TUNNEL_PROVIDER_NGROK,
|
||||
]);
|
||||
|
||||
export function normalizeTunnelProvider(value) {
|
||||
|
||||
Reference in New Issue
Block a user