untunneled.dev 0.3.4 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -208,7 +208,7 @@ var TunnelUI = ({
208
208
  /* @__PURE__ */ jsx4(Text4, { color: "cyan", bold: true, children: LOGO }),
209
209
  /* @__PURE__ */ jsxs4(Box4, { justifyContent: "space-between", paddingX: 1, children: [
210
210
  /* @__PURE__ */ jsx4(ConnectionStatus, { status: connectionStatus }),
211
- /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "v0.3.4" })
211
+ /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "v0.3.6" })
212
212
  ] })
213
213
  ] }),
214
214
  /* @__PURE__ */ jsxs4(
@@ -359,10 +359,6 @@ function validatePort(port) {
359
359
  }
360
360
  return portNum;
361
361
  }
362
- function parseAllowList(allow) {
363
- if (!allow) return void 0;
364
- return allow.split(",").map((email) => email.trim().toLowerCase()).filter((email) => email.length > 0);
365
- }
366
362
  var TIMEOUTS = {
367
363
  RELAY_REQUEST: 3e4,
368
364
  WEBSOCKET_PING: 3e4,
@@ -405,8 +401,7 @@ var RelayTunnel = class extends EventEmitter {
405
401
  try {
406
402
  this.ws = new WebSocket(wsUrl, {
407
403
  headers: {
408
- "X-Tunnel-Auth": this.options.password || "",
409
- "X-Tunnel-Allow": this.options.allowList?.join(",") || ""
404
+ "X-Tunnel-Auth": this.options.password || ""
410
405
  }
411
406
  });
412
407
  const connectionTimeout = setTimeout(() => {
@@ -688,8 +683,9 @@ import crypto from "crypto";
688
683
  import fs from "fs";
689
684
  import os from "os";
690
685
  import path2 from "path";
691
- var POSTHOG_API_KEY = process.env["POSTHOG_API_KEY"] || "phc_placeholder";
692
- var POSTHOG_HOST = process.env["POSTHOG_HOST"] || "https://app.posthog.com";
686
+ var POSTHOG_API_KEY = "phc_oB9sTloW28uJQ7HGYDRZRQ23JaQApZ57LrrPFVd796S";
687
+ var POSTHOG_HOST = "https://us.i.posthog.com";
688
+ var TELEMETRY_DEBUG = process.env["UNTUNNELED_TELEMETRY_DEBUG"] === "1" || process.env["UNTUNNELED_TELEMETRY_DEBUG"] === "true";
693
689
  var Analytics = class {
694
690
  posthog = null;
695
691
  enabled;
@@ -703,6 +699,17 @@ var Analytics = class {
703
699
  flushAt: 10,
704
700
  flushInterval: 1e4
705
701
  });
702
+ if (TELEMETRY_DEBUG) {
703
+ console.log("[Telemetry] Enabled", {
704
+ host: POSTHOG_HOST,
705
+ keyPrefix: POSTHOG_API_KEY.slice(0, 6)
706
+ });
707
+ }
708
+ } else if (TELEMETRY_DEBUG) {
709
+ console.log("[Telemetry] Disabled", {
710
+ enabled: this.enabled,
711
+ hasKey: POSTHOG_API_KEY !== "phc_placeholder"
712
+ });
706
713
  }
707
714
  }
708
715
  async track(event, properties) {
@@ -713,16 +720,23 @@ var Analytics = class {
713
720
  event,
714
721
  properties: {
715
722
  ...properties,
716
- version: process.env["UNTUNNELED_VERSION"] || process.env["npm_package_version"] || "0.3.4",
723
+ version: "0.3.6",
717
724
  cli: true
718
725
  }
719
726
  });
727
+ if (TELEMETRY_DEBUG) {
728
+ console.log("[Telemetry] Captured", { event });
729
+ }
720
730
  } catch (_) {
721
731
  }
722
732
  }
723
733
  async shutdown() {
724
734
  if (!this.posthog) return;
725
735
  try {
736
+ if (TELEMETRY_DEBUG) {
737
+ console.log("[Telemetry] Flushing");
738
+ }
739
+ await this.posthog.flush();
726
740
  await this.posthog.shutdown();
727
741
  } catch (_) {
728
742
  }
@@ -773,7 +787,7 @@ async function startCommand(port, options) {
773
787
  enabled: options.telemetry !== false
774
788
  });
775
789
  await analytics.track("tunnel_start", {
776
- has_auth: !!options.password || !!options.allow,
790
+ has_auth: !!options.password,
777
791
  node_version: process.version,
778
792
  platform: process.platform
779
793
  });
@@ -782,7 +796,6 @@ async function startCommand(port, options) {
782
796
  tunnelId,
783
797
  tunnelUrl,
784
798
  password: options.password,
785
- allowList: parseAllowList(options.allow),
786
799
  verbose: options.verbose
787
800
  });
788
801
  try {
@@ -844,8 +857,8 @@ async function stopCommand(tunnelId) {
844
857
 
845
858
  // src/index.ts
846
859
  var program = new Command();
847
- program.name("untunneled").description("Fast, free localhost tunneling").version("0.3.4");
848
- program.argument("<port>", "Local port to tunnel").option("--qr", "Open the QR code modal on start").option("--password <password>", "Password protect the tunnel").option("--allow <emails>", "Email whitelist (comma-separated)").option("--verbose", "Show detailed logs").option("--no-telemetry", "Disable anonymous usage tracking").action(startCommand);
860
+ program.name("untunneled").description("Fast, free localhost tunneling").version("0.3.6");
861
+ program.argument("<port>", "Local port to tunnel").option("--qr", "Open the QR code modal on start").option("--password <password>", "Password protect the tunnel").option("--verbose", "Show detailed logs").option("--no-telemetry", "Disable anonymous usage tracking").action(startCommand);
849
862
  program.command("list").description("List active tunnels").action(listCommand);
850
863
  program.command("stop").argument("<tunnel-id>", "Tunnel ID to stop").description("Stop a running tunnel").action(stopCommand);
851
864
  program.parse();
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/commands/start.ts","../src/ui/TunnelUI.tsx","../src/ui/QRCode.tsx","../src/ui/RequestLog.tsx","../src/ui/ConnectionStatus.tsx","../src/tunnel/relay.ts","../src/config.ts","../src/analytics.ts","../src/commands/list.ts","../src/commands/stop.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { startCommand, listCommand, stopCommand } from './commands/index.js';\n\nconst program = new Command();\n\nprogram.name('untunneled').description('Fast, free localhost tunneling').version('0.3.4');\n\nprogram\n .argument('<port>', 'Local port to tunnel')\n .option('--qr', 'Open the QR code modal on start')\n .option('--password <password>', 'Password protect the tunnel')\n .option('--allow <emails>', 'Email whitelist (comma-separated)')\n .option('--verbose', 'Show detailed logs')\n .option('--no-telemetry', 'Disable anonymous usage tracking')\n .action(startCommand);\n\nprogram.command('list').description('List active tunnels').action(listCommand);\n\nprogram\n .command('stop')\n .argument('<tunnel-id>', 'Tunnel ID to stop')\n .description('Stop a running tunnel')\n .action(stopCommand);\n\nprogram.parse();\n","import { render } from 'ink';\nimport React from 'react';\nimport { TunnelUI } from '../ui/TunnelUI.js';\nimport { RelayTunnel } from '../tunnel/relay.js';\nimport { Analytics } from '../analytics.js';\nimport {\n generateTunnelId,\n getProjectName,\n getTunnelUrl,\n validatePort,\n parseAllowList,\n} from '../config.js';\nimport type { StartOptions } from '../types.js';\n\nexport async function startCommand(port: string, options: StartOptions): Promise<void> {\n let localPort: number;\n\n try {\n localPort = validatePort(port);\n } catch (error) {\n console.error((error as Error).message);\n process.exit(1);\n }\n\n const projectName = getProjectName();\n const tunnelId = generateTunnelId(projectName);\n const tunnelUrl = getTunnelUrl(tunnelId);\n\n const analytics = new Analytics({\n enabled: options.telemetry !== false,\n });\n\n await analytics.track('tunnel_start', {\n has_auth: !!options.password || !!options.allow,\n node_version: process.version,\n platform: process.platform,\n });\n\n const relayTunnel = new RelayTunnel({\n localPort,\n tunnelId,\n tunnelUrl,\n password: options.password,\n allowList: parseAllowList(options.allow),\n verbose: options.verbose,\n });\n\n try {\n await relayTunnel.connect();\n\n if (options.verbose) {\n console.log(`Tunnel URL: ${tunnelUrl}`);\n console.log(`Forwarding to localhost:${localPort}`);\n }\n } catch (error) {\n console.error('Failed to connect to relay server:', (error as Error).message);\n await analytics.shutdown();\n process.exit(1);\n }\n\n const { waitUntilExit } = render(\n React.createElement(TunnelUI, {\n tunnelUrl,\n localPort,\n showQR: options.qr,\n relayTunnel,\n })\n );\n\n const cleanup = async () => {\n const duration = relayTunnel.getDuration();\n const requests = relayTunnel.getRequestCount();\n\n await analytics.track('tunnel_end', {\n duration_seconds: duration,\n requests: requests,\n });\n\n const summary = relayTunnel.getMetricsSummary();\n await analytics.track('session_summary', summary);\n\n await relayTunnel.disconnect();\n await analytics.shutdown();\n };\n\n process.on('SIGINT', async () => {\n await cleanup();\n process.exit(0);\n });\n\n process.on('SIGTERM', async () => {\n await cleanup();\n process.exit(0);\n });\n\n await waitUntilExit();\n}\n","import React, { useState, useEffect } from 'react';\nimport { Box, Text, useApp, useInput } from 'ink';\nimport { QRCode } from './QRCode.js';\nimport { RequestLog } from './RequestLog.js';\nimport { ConnectionStatus } from './ConnectionStatus.js';\nimport type { RelayTunnel } from '../tunnel/relay.js';\nimport type { RequestLog as RequestLogType, TunnelStats } from '../types.js';\n\ninterface TunnelUIProps {\n tunnelUrl: string;\n localPort: number;\n showQR?: boolean;\n relayTunnel: RelayTunnel;\n}\n\nconst MAX_LOGS = 10;\n\nconst LOGO = `\n ╦ ╦╔╗╔╔╦╗╦ ╦╔╗╔╔╗╔╔═╗╦ ╔═╗╔╦╗ ╔╦╗╔═╗╦ ╦\n ║ ║║║║ ║ ║ ║║║║║║║║╣ ║ ║╣ ║║ ║║║╣ ╚╗╔╝\n ╚═╝╝╚╝ ╩ ╚═╝╝╚╝╝╚╝╚═╝╩═╝╚═╝═╩╝o═╩╝╚═╝ ╚╝ \n`;\n\nconst formatUptime = (ms: number) => {\n const seconds = Math.floor(ms / 1000);\n const minutes = Math.floor(seconds / 60);\n const hours = Math.floor(minutes / 60);\n return `${hours}h ${minutes % 60}m ${seconds % 60}s`;\n};\n\nexport const TunnelUI: React.FC<TunnelUIProps> = ({\n tunnelUrl,\n localPort,\n showQR,\n relayTunnel,\n}) => {\n useApp();\n const [requests, setRequests] = useState<RequestLogType[]>([]);\n const [stats, setStats] = useState<TunnelStats>({\n total: 0,\n startTime: Date.now(),\n });\n const [relayConnected, setRelayConnected] = useState(relayTunnel.isConnected());\n const [uptime, setUptime] = useState(0);\n const [isModalOpen, setIsModalOpen] = useState(Boolean(showQR));\n\n useInput((input, key) => {\n if (input === 'q' || input === 'c' || input === 'Q' || input === 'C') {\n setIsModalOpen((prev) => !prev);\n }\n if (key.escape) {\n setIsModalOpen(false);\n }\n });\n\n useEffect(() => {\n const handleRequest = (req: RequestLogType) => {\n setRequests((prev) => [...prev.slice(-(MAX_LOGS - 1)), req]);\n setStats((prev) => ({\n ...prev,\n total: prev.total + 1,\n }));\n };\n\n const handleRelayConnected = () => setRelayConnected(true);\n const handleRelayDisconnected = () => setRelayConnected(false);\n\n relayTunnel.on('request', handleRequest);\n relayTunnel.on('connected', handleRelayConnected);\n relayTunnel.on('disconnected', handleRelayDisconnected);\n\n const uptimeTimer = setInterval(() => {\n setUptime(Date.now() - stats.startTime);\n }, 1000);\n\n return () => {\n relayTunnel.off('request', handleRequest);\n relayTunnel.off('connected', handleRelayConnected);\n relayTunnel.off('disconnected', handleRelayDisconnected);\n clearInterval(uptimeTimer);\n };\n }, [relayTunnel, stats.startTime]);\n\n const connectionStatus = relayConnected ? 'connected' : 'connecting';\n const accentColor = relayConnected ? 'cyan' : 'yellow';\n\n return (\n <Box flexDirection=\"column\" paddingX={2} paddingY={1}>\n {/* Header */}\n <Box flexDirection=\"column\" marginBottom={1}>\n <Text color=\"cyan\" bold>\n {LOGO}\n </Text>\n <Box justifyContent=\"space-between\" paddingX={1}>\n <ConnectionStatus status={connectionStatus} />\n <Text dimColor>v0.3.4</Text>\n </Box>\n </Box>\n\n {/* Main Connection Info */}\n <Box\n borderStyle=\"round\"\n borderColor={accentColor}\n paddingX={2}\n paddingY={1}\n flexDirection=\"column\"\n >\n <Box>\n <Text bold>Public URL: </Text>\n <Text bold color=\"black\" backgroundColor=\"cyan\">\n {' '}\n {tunnelUrl}{' '}\n </Text>\n </Box>\n <Box marginTop={1}>\n <Text dimColor>Forwarding: </Text>\n <Text color=\"yellow\">http://localhost:{localPort}</Text>\n <Text dimColor> → </Text>\n <Text color=\"cyan\">{tunnelUrl}</Text>\n </Box>\n </Box>\n\n {/* Stats Bar */}\n <Box marginTop={1} paddingX={1} gap={4}>\n <Box>\n <Text dimColor>Requests: </Text>\n <Text color=\"white\" bold>\n {stats.total}\n </Text>\n </Box>\n <Box>\n <Text dimColor>Uptime: </Text>\n <Text color=\"white\" bold>\n {formatUptime(uptime)}\n </Text>\n </Box>\n <Box>\n <Text dimColor>Latency: </Text>\n <Text color=\"white\" bold>\n {requests.length > 0 ? `${requests[requests.length - 1]?.duration}ms` : '-'}\n </Text>\n </Box>\n </Box>\n\n {/* Request Log */}\n <Box marginTop={1} flexDirection=\"column\">\n <Box marginBottom={1}>\n <Text bold color=\"cyan\">\n ─── Recent Requests ───\n </Text>\n </Box>\n <RequestLog requests={requests} />\n </Box>\n\n {/* Footer */}\n <Box\n marginTop={1}\n borderStyle=\"single\"\n borderTop={true}\n borderBottom={false}\n borderLeft={false}\n borderRight={false}\n borderColor=\"gray\"\n paddingTop={1}\n >\n <Box flexGrow={1} gap={2}>\n <Box>\n <Text dimColor>Press </Text>\n <Text color=\"yellow\" bold>\n Ctrl+C\n </Text>\n <Text dimColor> to stop</Text>\n </Box>\n <Box>\n <Text dimColor>Press </Text>\n <Text color=\"yellow\" bold>\n Q\n </Text>\n <Text dimColor> for QR</Text>\n </Box>\n </Box>\n <Box>\n <Text dimColor>Sponsor: </Text>\n <Text color=\"magenta\" bold>\n untunneled.dev/sponsor\n </Text>\n </Box>\n </Box>\n\n {isModalOpen && (\n <Box\n position=\"absolute\"\n width=\"100%\"\n height=\"100%\"\n alignItems=\"center\"\n justifyContent=\"center\"\n >\n <Box\n flexDirection=\"column\"\n alignItems=\"center\"\n borderStyle=\"round\"\n borderColor=\"cyan\"\n padding={1}\n backgroundColor=\"black\"\n >\n <Box marginBottom={1}>\n <Text bold color=\"cyan\">\n Scan to Open URL\n </Text>\n </Box>\n <QRCode url={tunnelUrl} />\n <Box marginTop={1}>\n <Text dimColor>Press </Text>\n <Text color=\"yellow\" bold>\n ESC\n </Text>\n <Text dimColor> or </Text>\n <Text color=\"yellow\" bold>\n Q\n </Text>\n <Text dimColor> to close</Text>\n </Box>\n </Box>\n </Box>\n )}\n </Box>\n );\n};\n","import React, { useState, useEffect } from 'react';\nimport { Box, Text } from 'ink';\nimport qrcode from 'qrcode-terminal';\n\ninterface QRCodeProps {\n url: string;\n}\n\nexport const QRCode: React.FC<QRCodeProps> = ({ url }) => {\n const [qrString, setQrString] = useState('');\n\n useEffect(() => {\n qrcode.generate(url, { small: true }, (qr: string) => {\n setQrString(qr);\n });\n }, [url]);\n\n if (!qrString) {\n return (\n <Box>\n <Text dimColor>Generating QR code...</Text>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"single\" paddingX={1}>\n <Text dimColor>Scan with mobile:</Text>\n <Text>{qrString}</Text>\n </Box>\n );\n};\n","import React from 'react';\nimport { Box, Text } from 'ink';\nimport type { RequestLog as RequestLogType } from '../types.js';\n\ninterface RequestLogProps {\n requests: RequestLogType[];\n}\n\nconst getStatusColor = (status: number): string => {\n if (status >= 500) return 'red';\n if (status >= 400) return 'yellow';\n if (status >= 300) return 'cyan';\n if (status >= 200) return 'green';\n return 'gray';\n};\n\nconst getMethodColor = (method: string): string => {\n switch (method.toUpperCase()) {\n case 'GET':\n return 'cyan';\n case 'POST':\n return 'green';\n case 'PUT':\n return 'yellow';\n case 'DELETE':\n return 'red';\n case 'PATCH':\n return 'magenta';\n default:\n return 'white';\n }\n};\n\nexport const RequestLog: React.FC<RequestLogProps> = ({ requests }) => {\n if (requests.length === 0) {\n return (\n <Box\n borderStyle=\"single\"\n borderColor=\"gray\"\n flexDirection=\"column\"\n alignItems=\"center\"\n paddingX={3}\n paddingY={1}\n width={40}\n alignSelf=\"center\"\n >\n <Text color=\"cyan\">⏳ Waiting for requests...</Text>\n <Box height={1} />\n <Text dimColor>Open the URL in your browser</Text>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\">\n {requests.map((req) => {\n const time = new Date(req.timestamp).toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: false,\n });\n\n return (\n <Box key={req.id} gap={1}>\n <Text dimColor>[{time}]</Text>\n <Box width={8}>\n <Text color={getMethodColor(req.method)} bold>\n {req.method.padEnd(7)}\n </Text>\n </Box>\n <Box flexGrow={1}>\n <Text>{req.path.length > 40 ? req.path.substring(0, 37) + '...' : req.path}</Text>\n </Box>\n <Box width={6}>\n <Text color={getStatusColor(req.status)} bold>\n {req.status}\n </Text>\n </Box>\n <Box width={10} justifyContent=\"flex-end\">\n <Text color={req.duration > 500 ? 'yellow' : 'gray'}>\n {req.duration.toString().padStart(4)}ms\n </Text>\n </Box>\n </Box>\n );\n })}\n </Box>\n );\n};\n","import React, { useState, useEffect } from 'react';\nimport { Box, Text } from 'ink';\nimport type { ConnectionStatus as ConnectionStatusType } from '../types.js';\n\ninterface ConnectionStatusProps {\n status: ConnectionStatusType;\n}\n\nconst SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n\nconst getStatusIndicator = (\n status: ConnectionStatusType,\n frame: string\n): { color: string; symbol: string; label: string } => {\n switch (status) {\n case 'connected':\n return { color: 'green', symbol: '✔', label: 'CONNECTED' };\n case 'connecting':\n return { color: 'yellow', symbol: frame, label: 'CONNECTING' };\n case 'disconnected':\n return { color: 'gray', symbol: '○', label: 'DISCONNECTED' };\n case 'error':\n return { color: 'red', symbol: '✘', label: 'ERROR' };\n default:\n return { color: 'white', symbol: '?', label: String(status).toUpperCase() };\n }\n};\n\nexport const ConnectionStatus: React.FC<ConnectionStatusProps> = ({ status }) => {\n const [frameIndex, setFrameIndex] = useState(0);\n\n useEffect(() => {\n if (status !== 'connecting') return;\n\n const timer = setInterval(() => {\n setFrameIndex((prev) => (prev + 1) % SPINNER_FRAMES.length);\n }, 80);\n\n return () => clearInterval(timer);\n }, [status]);\n\n const frame = SPINNER_FRAMES[frameIndex] ?? ' ';\n const indicator = getStatusIndicator(status, frame);\n\n return (\n <Box>\n <Text color={indicator.color} bold>\n {indicator.symbol} {indicator.label}\n </Text>\n </Box>\n );\n};\n","import { WebSocket } from 'ws';\nimport { EventEmitter } from 'node:events';\nimport { getRelayUrl, TIMEOUTS } from '../config.js';\nimport type {\n RelayFrame,\n WsOpen,\n WsMessage,\n WsClose,\n RelayResponse,\n RequestLog,\n} from '../types.js';\n\ninterface RelayTunnelOptions {\n localPort: number;\n tunnelId: string;\n tunnelUrl: string;\n password?: string;\n allowList?: string[];\n verbose?: boolean;\n}\n\nexport class RelayTunnel extends EventEmitter {\n private ws: WebSocket | null = null;\n private localPort: number;\n private tunnelId: string;\n private tunnelUrl: string;\n private options: RelayTunnelOptions;\n private startTime: number = 0;\n private requestCount: number = 0;\n private bytesIn: number = 0;\n private bytesOut: number = 0;\n private statusCounts = { ok: 0, clientError: 0, serverError: 0, other: 0 };\n private latencySamples: number[] = [];\n private reconnectAttempts: number = 0;\n private isClosing: boolean = false;\n private pingInterval: NodeJS.Timeout | null = null;\n private activeWebSockets: Map<string, WebSocket> = new Map();\n\n constructor(options: RelayTunnelOptions) {\n super();\n this.options = options;\n this.localPort = options.localPort;\n this.tunnelId = options.tunnelId;\n this.tunnelUrl = options.tunnelUrl;\n }\n\n async connect(): Promise<void> {\n this.startTime = Date.now();\n this.isClosing = false;\n\n const wsUrl = getRelayUrl(this.tunnelId);\n\n if (this.options.verbose) {\n console.log(`[Relay] Connecting to ${wsUrl}`);\n }\n\n return new Promise((resolve, reject) => {\n try {\n this.ws = new WebSocket(wsUrl, {\n headers: {\n 'X-Tunnel-Auth': this.options.password || '',\n 'X-Tunnel-Allow': this.options.allowList?.join(',') || '',\n },\n });\n\n const connectionTimeout = setTimeout(() => {\n if (this.ws && this.ws.readyState !== WebSocket.OPEN) {\n this.ws.terminate();\n reject(new Error('Connection timeout'));\n }\n }, TIMEOUTS.RELAY_REQUEST);\n\n this.ws.on('open', () => {\n clearTimeout(connectionTimeout);\n this.reconnectAttempts = 0;\n\n if (this.options.verbose) {\n console.log('[Relay] Connected');\n }\n\n this.setupPing();\n this.emit('connected');\n resolve();\n });\n\n this.ws.on('error', (err) => {\n clearTimeout(connectionTimeout);\n\n if (this.options.verbose) {\n console.error('[Relay] WebSocket error:', err.message);\n }\n\n this.emit('error', err);\n reject(err);\n });\n\n this.ws.on('close', () => {\n this.clearPing();\n\n if (!this.isClosing) {\n this.emit('disconnected');\n this.attemptReconnect();\n }\n });\n\n this.ws.on('message', async (data) => {\n await this.handleRelayFrame(data);\n });\n } catch (error) {\n reject(error);\n }\n });\n }\n\n private async handleRelayFrame(data: Buffer | ArrayBuffer | Buffer[]): Promise<void> {\n let frame: RelayFrame;\n\n try {\n frame = JSON.parse(String(data)) as RelayFrame;\n } catch {\n if (this.options.verbose) {\n console.error('[Relay] Invalid frame data');\n }\n return;\n }\n\n switch (frame.type) {\n case 'http_request':\n await this.handleHttpRequest(frame);\n break;\n case 'ws_open':\n await this.handleWsOpen(frame);\n break;\n case 'ws_message':\n await this.handleWsMessage(frame);\n break;\n case 'ws_close':\n await this.handleWsClose(frame);\n break;\n }\n }\n\n private async handleHttpRequest(request: RelayFrame & { type: 'http_request' }): Promise<void> {\n const startTime = Date.now();\n const requestBytes = request.body ? Buffer.byteLength(request.body, 'utf8') : 0;\n\n try {\n const url = `http://127.0.0.1:${this.localPort}${request.path}`;\n\n const fetchOptions: RequestInit = {\n method: request.method,\n headers: request.headers,\n };\n\n if (request.body && !['GET', 'HEAD'].includes(request.method)) {\n fetchOptions.body = request.body;\n }\n\n const response = await fetch(url, fetchOptions);\n const body = await response.text();\n const duration = Date.now() - startTime;\n const responseBytes = Buffer.byteLength(body, 'utf8');\n\n const relayResponse: RelayResponse = {\n type: 'http_response',\n id: request.id,\n status: response.status,\n statusText: response.statusText,\n headers: Object.fromEntries(response.headers.entries()),\n body,\n };\n\n this.ws?.send(JSON.stringify(relayResponse));\n\n const log: RequestLog = {\n id: request.id,\n timestamp: Date.now(),\n method: request.method,\n path: request.path,\n status: response.status,\n duration,\n };\n\n this.recordMetrics(duration, response.status, requestBytes, responseBytes);\n\n this.emit('request', log);\n this.requestCount++;\n } catch (error) {\n const err = error as any;\n const duration = Date.now() - startTime;\n\n if (this.options.verbose || err.code === 'ECONNREFUSED') {\n console.error(`[Relay] Proxy error: ${err.message}`);\n }\n\n const errorResponse: RelayResponse = {\n type: 'http_response',\n id: request.id,\n status: 502,\n statusText: 'Bad Gateway',\n headers: {},\n body: `Error: ${err.message}`,\n };\n\n this.recordMetrics(duration, 502, requestBytes, 0);\n\n this.ws?.send(JSON.stringify(errorResponse));\n }\n }\n\n private recordMetrics(duration: number, status: number, bytesIn: number, bytesOut: number): void {\n this.bytesIn += bytesIn;\n this.bytesOut += bytesOut;\n\n if (status >= 200 && status < 300) this.statusCounts.ok += 1;\n else if (status >= 400 && status < 500) this.statusCounts.clientError += 1;\n else if (status >= 500 && status < 600) this.statusCounts.serverError += 1;\n else this.statusCounts.other += 1;\n\n if (this.latencySamples.length < 500) {\n this.latencySamples.push(duration);\n } else {\n const total = this.requestCount + 1;\n const index = Math.floor(Math.random() * total);\n if (index < this.latencySamples.length) {\n this.latencySamples[index] = duration;\n }\n }\n }\n\n private async handleWsOpen(frame: WsOpen): Promise<void> {\n const localUrl = `ws://127.0.0.1:${this.localPort}${frame.url}`;\n\n if (this.options.verbose) {\n console.log(`[Relay] Opening WebSocket to ${localUrl}`);\n }\n\n const protocolHeader =\n frame.headers['sec-websocket-protocol'] || frame.headers['Sec-WebSocket-Protocol'];\n const filteredHeaders = Object.fromEntries(\n Object.entries(frame.headers).filter(([key]) => {\n const header = key.toLowerCase();\n return (\n header !== 'connection' &&\n header !== 'upgrade' &&\n header !== 'host' &&\n !header.startsWith('sec-websocket')\n );\n })\n );\n\n const localOrigin = `http://127.0.0.1:${this.localPort}`;\n filteredHeaders['origin'] = localOrigin;\n if (filteredHeaders['referer']) {\n filteredHeaders['referer'] = `${localOrigin}${frame.url}`;\n }\n\n const protocols = protocolHeader\n ? protocolHeader\n .split(',')\n .map((value) => value.trim())\n .filter(Boolean)\n : undefined;\n\n const localWs = protocols?.length\n ? new WebSocket(localUrl, protocols, { headers: filteredHeaders })\n : new WebSocket(localUrl, { headers: filteredHeaders });\n\n this.activeWebSockets.set(frame.id, localWs);\n\n localWs.on('message', (data, isBinary) => {\n const message: WsMessage = {\n type: 'ws_message',\n id: frame.id,\n data: isBinary ? (data as Buffer).toString('base64') : data.toString(),\n isBinary,\n };\n this.ws?.send(JSON.stringify(message));\n });\n\n localWs.on('close', () => {\n const closeFrame: WsClose = {\n type: 'ws_close',\n id: frame.id,\n };\n this.ws?.send(JSON.stringify(closeFrame));\n this.activeWebSockets.delete(frame.id);\n });\n\n localWs.on('error', (err) => {\n if (this.options.verbose) {\n console.error(`[Relay] Local WebSocket error (${frame.id}):`, err.message);\n }\n localWs.close();\n });\n }\n\n private async handleWsMessage(frame: WsMessage): Promise<void> {\n const localWs = this.activeWebSockets.get(frame.id);\n if (localWs && localWs.readyState === WebSocket.OPEN) {\n const data = frame.isBinary ? Buffer.from(frame.data, 'base64') : frame.data;\n localWs.send(data);\n }\n }\n\n private async handleWsClose(frame: WsClose): Promise<void> {\n const localWs = this.activeWebSockets.get(frame.id);\n if (localWs) {\n localWs.close();\n this.activeWebSockets.delete(frame.id);\n }\n }\n\n private setupPing(): void {\n this.pingInterval = setInterval(() => {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n this.ws.ping();\n }\n }, TIMEOUTS.WEBSOCKET_PING);\n }\n\n private clearPing(): void {\n if (this.pingInterval) {\n clearInterval(this.pingInterval);\n this.pingInterval = null;\n }\n }\n\n private async attemptReconnect(): Promise<void> {\n if (this.isClosing) return;\n\n this.reconnectAttempts++;\n const delay = Math.min(\n TIMEOUTS.RECONNECT_BASE * Math.pow(2, this.reconnectAttempts - 1),\n TIMEOUTS.RECONNECT_MAX\n );\n\n if (this.options.verbose) {\n console.log(`[Relay] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);\n }\n\n setTimeout(async () => {\n if (this.isClosing) return;\n\n try {\n await this.connect();\n } catch (_) {}\n }, delay);\n }\n\n async disconnect(): Promise<void> {\n this.isClosing = true;\n this.clearPing();\n\n for (const ws of this.activeWebSockets.values()) {\n ws.close();\n }\n this.activeWebSockets.clear();\n\n if (this.ws) {\n this.ws.close(1000, 'Client closing');\n this.ws = null;\n }\n }\n\n getDuration(): number {\n if (this.startTime === 0) return 0;\n return Math.floor((Date.now() - this.startTime) / 1000);\n }\n\n getRequestCount(): number {\n return this.requestCount;\n }\n\n getMetricsSummary(): {\n total_requests: number;\n total_bytes_in: number;\n total_bytes_out: number;\n latency_avg_ms: number;\n latency_p50_ms: number;\n latency_p90_ms: number;\n latency_p99_ms: number;\n status_2xx: number;\n status_4xx: number;\n status_5xx: number;\n status_other: number;\n } {\n const samples = [...this.latencySamples].sort((a, b) => a - b);\n const avg = samples.length\n ? Math.round(samples.reduce((sum, value) => sum + value, 0) / samples.length)\n : 0;\n\n const percentile = (p: number) => {\n if (samples.length === 0) return 0;\n const index = Math.min(samples.length - 1, Math.floor(p * (samples.length - 1)));\n return samples[index] ?? 0;\n };\n\n return {\n total_requests: this.requestCount,\n total_bytes_in: this.bytesIn,\n total_bytes_out: this.bytesOut,\n latency_avg_ms: avg,\n latency_p50_ms: percentile(0.5),\n latency_p90_ms: percentile(0.9),\n latency_p99_ms: percentile(0.99),\n status_2xx: this.statusCounts.ok,\n status_4xx: this.statusCounts.clientError,\n status_5xx: this.statusCounts.serverError,\n status_other: this.statusCounts.other,\n };\n }\n\n isConnected(): boolean {\n return this.ws !== null && this.ws.readyState === WebSocket.OPEN;\n }\n\n getTunnelUrl(): string {\n return this.tunnelUrl;\n }\n}\n","import { nanoid } from 'nanoid';\nimport path from 'node:path';\n\nexport const RELAY_DOMAIN = 'relay.untunneled.dev';\nexport const TUNNEL_DOMAIN = 'untunneled.dev';\n\nexport const getRelayUrl = (tunnelId: string): string => {\n const host = process.env['UNTUNNELED_RELAY_HOST'] || RELAY_DOMAIN;\n const protocol = host.includes('localhost') ? 'ws' : 'wss';\n return `${protocol}://${host}/${tunnelId}`;\n};\n\nexport const getTunnelUrl = (tunnelId: string): string => {\n const domain = process.env['UNTUNNELED_TUNNEL_DOMAIN'] || TUNNEL_DOMAIN;\n return `https://${tunnelId}.${domain}`;\n};\n\nexport function getProjectName(): string {\n const cwd = process.cwd();\n const folderName = path.basename(cwd);\n\n return (\n folderName\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '')\n .slice(0, 20) || 'tunnel'\n );\n}\n\nexport function generateTunnelId(projectName?: string): string {\n const name = projectName || getProjectName();\n const suffix = nanoid(6).toLowerCase();\n return `${name}-${suffix}`;\n}\n\nexport function validatePort(port: string | number): number {\n const portNum = typeof port === 'string' ? parseInt(port, 10) : port;\n\n if (isNaN(portNum) || portNum < 1 || portNum > 65535) {\n throw new Error(`Invalid port number: ${port}. Must be between 1 and 65535.`);\n }\n\n return portNum;\n}\n\nexport function parseAllowList(allow?: string): string[] | undefined {\n if (!allow) return undefined;\n\n return allow\n .split(',')\n .map((email) => email.trim().toLowerCase())\n .filter((email) => email.length > 0);\n}\n\nexport const TIMEOUTS = {\n RELAY_REQUEST: 30000,\n WEBSOCKET_PING: 30000,\n RECONNECT_BASE: 1000,\n RECONNECT_MAX: 30000,\n};\n","import { PostHog } from 'posthog-node';\nimport crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nconst POSTHOG_API_KEY = process.env['POSTHOG_API_KEY'] || 'phc_placeholder';\nconst POSTHOG_HOST = process.env['POSTHOG_HOST'] || 'https://app.posthog.com';\n\ninterface AnalyticsOptions {\n enabled: boolean;\n}\n\ntype EventName = 'tunnel_start' | 'tunnel_end' | 'session_summary';\n\ninterface EventProperties {\n tunnel_start: {\n has_auth: boolean;\n node_version: string;\n platform: string;\n };\n tunnel_end: {\n duration_seconds: number;\n requests: number;\n };\n session_summary: {\n total_requests: number;\n total_bytes_in: number;\n total_bytes_out: number;\n latency_avg_ms: number;\n latency_p50_ms: number;\n latency_p90_ms: number;\n latency_p99_ms: number;\n status_2xx: number;\n status_4xx: number;\n status_5xx: number;\n status_other: number;\n };\n}\n\nexport class Analytics {\n private posthog: PostHog | null = null;\n private enabled: boolean;\n private distinctId: string;\n\n constructor(options: AnalyticsOptions) {\n this.enabled = options.enabled;\n this.distinctId = this.getRotatingDistinctId();\n\n if (this.enabled && POSTHOG_API_KEY && POSTHOG_API_KEY !== 'phc_placeholder') {\n this.posthog = new PostHog(POSTHOG_API_KEY, {\n host: POSTHOG_HOST,\n flushAt: 10,\n flushInterval: 10000,\n });\n }\n }\n\n async track<E extends EventName>(event: E, properties?: EventProperties[E]): Promise<void> {\n if (!this.posthog || !this.enabled) return;\n\n try {\n this.posthog.capture({\n distinctId: this.distinctId,\n event,\n properties: {\n ...properties,\n version:\n process.env['UNTUNNELED_VERSION'] || process.env['npm_package_version'] || '0.3.4',\n cli: true,\n },\n });\n } catch (_) {}\n }\n\n async shutdown(): Promise<void> {\n if (!this.posthog) return;\n\n try {\n await this.posthog.shutdown();\n } catch (_) {}\n }\n\n isEnabled(): boolean {\n return this.enabled && this.posthog !== null;\n }\n\n private getRotatingDistinctId(): string {\n const anonId = this.getAnonymousId();\n const now = new Date();\n const rotationKey = `${anonId}:${now.getUTCFullYear()}-${now.getUTCMonth() + 1}`;\n return crypto.createHash('sha256').update(rotationKey).digest('hex').slice(0, 32);\n }\n\n private getAnonymousId(): string {\n const baseDir =\n process.env['XDG_CONFIG_HOME'] ||\n process.env['APPDATA'] ||\n path.join(os.homedir(), '.config');\n const configDir = path.join(baseDir, 'untunneled.dev');\n const idPath = path.join(configDir, 'anon_id');\n\n try {\n if (!fs.existsSync(configDir)) {\n fs.mkdirSync(configDir, { recursive: true });\n }\n\n if (fs.existsSync(idPath)) {\n const existing = fs.readFileSync(idPath, 'utf8').trim();\n if (existing) return existing;\n }\n\n const newId = crypto.randomUUID();\n fs.writeFileSync(idPath, newId, 'utf8');\n return newId;\n } catch {\n return crypto.randomUUID();\n }\n }\n}\n","export async function listCommand(): Promise<void> {\n console.log('Active tunnels:');\n console.log(' (No active tunnels)');\n console.log('');\n console.log('Note: Tunnel list feature coming soon.');\n}\n","export async function stopCommand(tunnelId: string): Promise<void> {\n console.log(`Stopping tunnel: ${tunnelId}`);\n console.log('');\n console.log('Note: Remote stop feature coming soon.');\n}\n"],"mappings":"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","names":["React","useState","useEffect","Box","Text","Box","Text","jsx","jsxs","useState","useEffect","Box","Text","jsx","jsxs","jsx","jsxs","useState","useEffect","Box","Text","path","React"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/start.ts","../src/ui/TunnelUI.tsx","../src/ui/QRCode.tsx","../src/ui/RequestLog.tsx","../src/ui/ConnectionStatus.tsx","../src/tunnel/relay.ts","../src/config.ts","../src/analytics.ts","../src/commands/list.ts","../src/commands/stop.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { startCommand, listCommand, stopCommand } from './commands/index.js';\n\nconst program = new Command();\n\nprogram\n .name('untunneled')\n .description('Fast, free localhost tunneling')\n .version(process.env.UNTUNNELED_VERSION || '0.3.6');\n\nprogram\n .argument('<port>', 'Local port to tunnel')\n .option('--qr', 'Open the QR code modal on start')\n .option('--password <password>', 'Password protect the tunnel')\n .option('--verbose', 'Show detailed logs')\n .option('--no-telemetry', 'Disable anonymous usage tracking')\n .action(startCommand);\n\nprogram.command('list').description('List active tunnels').action(listCommand);\n\nprogram\n .command('stop')\n .argument('<tunnel-id>', 'Tunnel ID to stop')\n .description('Stop a running tunnel')\n .action(stopCommand);\n\nprogram.parse();\n","import { render } from 'ink';\nimport React from 'react';\nimport { TunnelUI } from '../ui/TunnelUI.js';\nimport { RelayTunnel } from '../tunnel/relay.js';\nimport { Analytics } from '../analytics.js';\nimport { generateTunnelId, getProjectName, getTunnelUrl, validatePort } from '../config.js';\nimport type { StartOptions } from '../types.js';\n\nexport async function startCommand(port: string, options: StartOptions): Promise<void> {\n let localPort: number;\n\n try {\n localPort = validatePort(port);\n } catch (error) {\n console.error((error as Error).message);\n process.exit(1);\n }\n\n const projectName = getProjectName();\n const tunnelId = generateTunnelId(projectName);\n const tunnelUrl = getTunnelUrl(tunnelId);\n\n const analytics = new Analytics({\n enabled: options.telemetry !== false,\n });\n\n await analytics.track('tunnel_start', {\n has_auth: !!options.password,\n node_version: process.version,\n platform: process.platform,\n });\n\n const relayTunnel = new RelayTunnel({\n localPort,\n tunnelId,\n tunnelUrl,\n password: options.password,\n verbose: options.verbose,\n });\n\n try {\n await relayTunnel.connect();\n\n if (options.verbose) {\n console.log(`Tunnel URL: ${tunnelUrl}`);\n console.log(`Forwarding to localhost:${localPort}`);\n }\n } catch (error) {\n console.error('Failed to connect to relay server:', (error as Error).message);\n await analytics.shutdown();\n process.exit(1);\n }\n\n const { waitUntilExit } = render(\n React.createElement(TunnelUI, {\n tunnelUrl,\n localPort,\n showQR: options.qr,\n relayTunnel,\n })\n );\n\n const cleanup = async () => {\n const duration = relayTunnel.getDuration();\n const requests = relayTunnel.getRequestCount();\n\n await analytics.track('tunnel_end', {\n duration_seconds: duration,\n requests: requests,\n });\n\n const summary = relayTunnel.getMetricsSummary();\n await analytics.track('session_summary', summary);\n\n await relayTunnel.disconnect();\n await analytics.shutdown();\n };\n\n process.on('SIGINT', async () => {\n await cleanup();\n process.exit(0);\n });\n\n process.on('SIGTERM', async () => {\n await cleanup();\n process.exit(0);\n });\n\n await waitUntilExit();\n}\n","import React, { useState, useEffect } from 'react';\nimport { Box, Text, useApp, useInput } from 'ink';\nimport { QRCode } from './QRCode.js';\nimport { RequestLog } from './RequestLog.js';\nimport { ConnectionStatus } from './ConnectionStatus.js';\nimport type { RelayTunnel } from '../tunnel/relay.js';\nimport type { RequestLog as RequestLogType, TunnelStats } from '../types.js';\n\ninterface TunnelUIProps {\n tunnelUrl: string;\n localPort: number;\n showQR?: boolean;\n relayTunnel: RelayTunnel;\n}\n\nconst MAX_LOGS = 10;\n\nconst LOGO = `\n ╦ ╦╔╗╔╔╦╗╦ ╦╔╗╔╔╗╔╔═╗╦ ╔═╗╔╦╗ ╔╦╗╔═╗╦ ╦\n ║ ║║║║ ║ ║ ║║║║║║║║╣ ║ ║╣ ║║ ║║║╣ ╚╗╔╝\n ╚═╝╝╚╝ ╩ ╚═╝╝╚╝╝╚╝╚═╝╩═╝╚═╝═╩╝o═╩╝╚═╝ ╚╝ \n`;\n\nconst formatUptime = (ms: number) => {\n const seconds = Math.floor(ms / 1000);\n const minutes = Math.floor(seconds / 60);\n const hours = Math.floor(minutes / 60);\n return `${hours}h ${minutes % 60}m ${seconds % 60}s`;\n};\n\nexport const TunnelUI: React.FC<TunnelUIProps> = ({\n tunnelUrl,\n localPort,\n showQR,\n relayTunnel,\n}) => {\n useApp();\n const [requests, setRequests] = useState<RequestLogType[]>([]);\n const [stats, setStats] = useState<TunnelStats>({\n total: 0,\n startTime: Date.now(),\n });\n const [relayConnected, setRelayConnected] = useState(relayTunnel.isConnected());\n const [uptime, setUptime] = useState(0);\n const [isModalOpen, setIsModalOpen] = useState(Boolean(showQR));\n\n useInput((input, key) => {\n if (input === 'q' || input === 'c' || input === 'Q' || input === 'C') {\n setIsModalOpen((prev) => !prev);\n }\n if (key.escape) {\n setIsModalOpen(false);\n }\n });\n\n useEffect(() => {\n const handleRequest = (req: RequestLogType) => {\n setRequests((prev) => [...prev.slice(-(MAX_LOGS - 1)), req]);\n setStats((prev) => ({\n ...prev,\n total: prev.total + 1,\n }));\n };\n\n const handleRelayConnected = () => setRelayConnected(true);\n const handleRelayDisconnected = () => setRelayConnected(false);\n\n relayTunnel.on('request', handleRequest);\n relayTunnel.on('connected', handleRelayConnected);\n relayTunnel.on('disconnected', handleRelayDisconnected);\n\n const uptimeTimer = setInterval(() => {\n setUptime(Date.now() - stats.startTime);\n }, 1000);\n\n return () => {\n relayTunnel.off('request', handleRequest);\n relayTunnel.off('connected', handleRelayConnected);\n relayTunnel.off('disconnected', handleRelayDisconnected);\n clearInterval(uptimeTimer);\n };\n }, [relayTunnel, stats.startTime]);\n\n const connectionStatus = relayConnected ? 'connected' : 'connecting';\n const accentColor = relayConnected ? 'cyan' : 'yellow';\n\n return (\n <Box flexDirection=\"column\" paddingX={2} paddingY={1}>\n {/* Header */}\n <Box flexDirection=\"column\" marginBottom={1}>\n <Text color=\"cyan\" bold>\n {LOGO}\n </Text>\n <Box justifyContent=\"space-between\" paddingX={1}>\n <ConnectionStatus status={connectionStatus} />\n <Text dimColor>v0.3.6</Text>\n </Box>\n </Box>\n\n {/* Main Connection Info */}\n <Box\n borderStyle=\"round\"\n borderColor={accentColor}\n paddingX={2}\n paddingY={1}\n flexDirection=\"column\"\n >\n <Box>\n <Text bold>Public URL: </Text>\n <Text bold color=\"black\" backgroundColor=\"cyan\">\n {' '}\n {tunnelUrl}{' '}\n </Text>\n </Box>\n <Box marginTop={1}>\n <Text dimColor>Forwarding: </Text>\n <Text color=\"yellow\">http://localhost:{localPort}</Text>\n <Text dimColor> → </Text>\n <Text color=\"cyan\">{tunnelUrl}</Text>\n </Box>\n </Box>\n\n {/* Stats Bar */}\n <Box marginTop={1} paddingX={1} gap={4}>\n <Box>\n <Text dimColor>Requests: </Text>\n <Text color=\"white\" bold>\n {stats.total}\n </Text>\n </Box>\n <Box>\n <Text dimColor>Uptime: </Text>\n <Text color=\"white\" bold>\n {formatUptime(uptime)}\n </Text>\n </Box>\n <Box>\n <Text dimColor>Latency: </Text>\n <Text color=\"white\" bold>\n {requests.length > 0 ? `${requests[requests.length - 1]?.duration}ms` : '-'}\n </Text>\n </Box>\n </Box>\n\n {/* Request Log */}\n <Box marginTop={1} flexDirection=\"column\">\n <Box marginBottom={1}>\n <Text bold color=\"cyan\">\n ─── Recent Requests ───\n </Text>\n </Box>\n <RequestLog requests={requests} />\n </Box>\n\n {/* Footer */}\n <Box\n marginTop={1}\n borderStyle=\"single\"\n borderTop={true}\n borderBottom={false}\n borderLeft={false}\n borderRight={false}\n borderColor=\"gray\"\n paddingTop={1}\n >\n <Box flexGrow={1} gap={2}>\n <Box>\n <Text dimColor>Press </Text>\n <Text color=\"yellow\" bold>\n Ctrl+C\n </Text>\n <Text dimColor> to stop</Text>\n </Box>\n <Box>\n <Text dimColor>Press </Text>\n <Text color=\"yellow\" bold>\n Q\n </Text>\n <Text dimColor> for QR</Text>\n </Box>\n </Box>\n <Box>\n <Text dimColor>Sponsor: </Text>\n <Text color=\"magenta\" bold>\n untunneled.dev/sponsor\n </Text>\n </Box>\n </Box>\n\n {isModalOpen && (\n <Box\n position=\"absolute\"\n width=\"100%\"\n height=\"100%\"\n alignItems=\"center\"\n justifyContent=\"center\"\n >\n <Box\n flexDirection=\"column\"\n alignItems=\"center\"\n borderStyle=\"round\"\n borderColor=\"cyan\"\n padding={1}\n backgroundColor=\"black\"\n >\n <Box marginBottom={1}>\n <Text bold color=\"cyan\">\n Scan to Open URL\n </Text>\n </Box>\n <QRCode url={tunnelUrl} />\n <Box marginTop={1}>\n <Text dimColor>Press </Text>\n <Text color=\"yellow\" bold>\n ESC\n </Text>\n <Text dimColor> or </Text>\n <Text color=\"yellow\" bold>\n Q\n </Text>\n <Text dimColor> to close</Text>\n </Box>\n </Box>\n </Box>\n )}\n </Box>\n );\n};\n","import React, { useState, useEffect } from 'react';\nimport { Box, Text } from 'ink';\nimport qrcode from 'qrcode-terminal';\n\ninterface QRCodeProps {\n url: string;\n}\n\nexport const QRCode: React.FC<QRCodeProps> = ({ url }) => {\n const [qrString, setQrString] = useState('');\n\n useEffect(() => {\n qrcode.generate(url, { small: true }, (qr: string) => {\n setQrString(qr);\n });\n }, [url]);\n\n if (!qrString) {\n return (\n <Box>\n <Text dimColor>Generating QR code...</Text>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"single\" paddingX={1}>\n <Text dimColor>Scan with mobile:</Text>\n <Text>{qrString}</Text>\n </Box>\n );\n};\n","import React from 'react';\nimport { Box, Text } from 'ink';\nimport type { RequestLog as RequestLogType } from '../types.js';\n\ninterface RequestLogProps {\n requests: RequestLogType[];\n}\n\nconst getStatusColor = (status: number): string => {\n if (status >= 500) return 'red';\n if (status >= 400) return 'yellow';\n if (status >= 300) return 'cyan';\n if (status >= 200) return 'green';\n return 'gray';\n};\n\nconst getMethodColor = (method: string): string => {\n switch (method.toUpperCase()) {\n case 'GET':\n return 'cyan';\n case 'POST':\n return 'green';\n case 'PUT':\n return 'yellow';\n case 'DELETE':\n return 'red';\n case 'PATCH':\n return 'magenta';\n default:\n return 'white';\n }\n};\n\nexport const RequestLog: React.FC<RequestLogProps> = ({ requests }) => {\n if (requests.length === 0) {\n return (\n <Box\n borderStyle=\"single\"\n borderColor=\"gray\"\n flexDirection=\"column\"\n alignItems=\"center\"\n paddingX={3}\n paddingY={1}\n width={40}\n alignSelf=\"center\"\n >\n <Text color=\"cyan\">⏳ Waiting for requests...</Text>\n <Box height={1} />\n <Text dimColor>Open the URL in your browser</Text>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\">\n {requests.map((req) => {\n const time = new Date(req.timestamp).toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: false,\n });\n\n return (\n <Box key={req.id} gap={1}>\n <Text dimColor>[{time}]</Text>\n <Box width={8}>\n <Text color={getMethodColor(req.method)} bold>\n {req.method.padEnd(7)}\n </Text>\n </Box>\n <Box flexGrow={1}>\n <Text>{req.path.length > 40 ? req.path.substring(0, 37) + '...' : req.path}</Text>\n </Box>\n <Box width={6}>\n <Text color={getStatusColor(req.status)} bold>\n {req.status}\n </Text>\n </Box>\n <Box width={10} justifyContent=\"flex-end\">\n <Text color={req.duration > 500 ? 'yellow' : 'gray'}>\n {req.duration.toString().padStart(4)}ms\n </Text>\n </Box>\n </Box>\n );\n })}\n </Box>\n );\n};\n","import React, { useState, useEffect } from 'react';\nimport { Box, Text } from 'ink';\nimport type { ConnectionStatus as ConnectionStatusType } from '../types.js';\n\ninterface ConnectionStatusProps {\n status: ConnectionStatusType;\n}\n\nconst SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n\nconst getStatusIndicator = (\n status: ConnectionStatusType,\n frame: string\n): { color: string; symbol: string; label: string } => {\n switch (status) {\n case 'connected':\n return { color: 'green', symbol: '✔', label: 'CONNECTED' };\n case 'connecting':\n return { color: 'yellow', symbol: frame, label: 'CONNECTING' };\n case 'disconnected':\n return { color: 'gray', symbol: '○', label: 'DISCONNECTED' };\n case 'error':\n return { color: 'red', symbol: '✘', label: 'ERROR' };\n default:\n return { color: 'white', symbol: '?', label: String(status).toUpperCase() };\n }\n};\n\nexport const ConnectionStatus: React.FC<ConnectionStatusProps> = ({ status }) => {\n const [frameIndex, setFrameIndex] = useState(0);\n\n useEffect(() => {\n if (status !== 'connecting') return;\n\n const timer = setInterval(() => {\n setFrameIndex((prev) => (prev + 1) % SPINNER_FRAMES.length);\n }, 80);\n\n return () => clearInterval(timer);\n }, [status]);\n\n const frame = SPINNER_FRAMES[frameIndex] ?? ' ';\n const indicator = getStatusIndicator(status, frame);\n\n return (\n <Box>\n <Text color={indicator.color} bold>\n {indicator.symbol} {indicator.label}\n </Text>\n </Box>\n );\n};\n","import { WebSocket } from 'ws';\nimport { EventEmitter } from 'node:events';\nimport { getRelayUrl, TIMEOUTS } from '../config.js';\nimport type {\n RelayFrame,\n WsOpen,\n WsMessage,\n WsClose,\n RelayResponse,\n RequestLog,\n} from '../types.js';\n\ninterface RelayTunnelOptions {\n localPort: number;\n tunnelId: string;\n tunnelUrl: string;\n password?: string;\n verbose?: boolean;\n}\n\nexport class RelayTunnel extends EventEmitter {\n private ws: WebSocket | null = null;\n private localPort: number;\n private tunnelId: string;\n private tunnelUrl: string;\n private options: RelayTunnelOptions;\n private startTime: number = 0;\n private requestCount: number = 0;\n private bytesIn: number = 0;\n private bytesOut: number = 0;\n private statusCounts = { ok: 0, clientError: 0, serverError: 0, other: 0 };\n private latencySamples: number[] = [];\n private reconnectAttempts: number = 0;\n private isClosing: boolean = false;\n private pingInterval: NodeJS.Timeout | null = null;\n private activeWebSockets: Map<string, WebSocket> = new Map();\n\n constructor(options: RelayTunnelOptions) {\n super();\n this.options = options;\n this.localPort = options.localPort;\n this.tunnelId = options.tunnelId;\n this.tunnelUrl = options.tunnelUrl;\n }\n\n async connect(): Promise<void> {\n this.startTime = Date.now();\n this.isClosing = false;\n\n const wsUrl = getRelayUrl(this.tunnelId);\n\n if (this.options.verbose) {\n console.log(`[Relay] Connecting to ${wsUrl}`);\n }\n\n return new Promise((resolve, reject) => {\n try {\n this.ws = new WebSocket(wsUrl, {\n headers: {\n 'X-Tunnel-Auth': this.options.password || '',\n },\n });\n\n const connectionTimeout = setTimeout(() => {\n if (this.ws && this.ws.readyState !== WebSocket.OPEN) {\n this.ws.terminate();\n reject(new Error('Connection timeout'));\n }\n }, TIMEOUTS.RELAY_REQUEST);\n\n this.ws.on('open', () => {\n clearTimeout(connectionTimeout);\n this.reconnectAttempts = 0;\n\n if (this.options.verbose) {\n console.log('[Relay] Connected');\n }\n\n this.setupPing();\n this.emit('connected');\n resolve();\n });\n\n this.ws.on('error', (err) => {\n clearTimeout(connectionTimeout);\n\n if (this.options.verbose) {\n console.error('[Relay] WebSocket error:', err.message);\n }\n\n this.emit('error', err);\n reject(err);\n });\n\n this.ws.on('close', () => {\n this.clearPing();\n\n if (!this.isClosing) {\n this.emit('disconnected');\n this.attemptReconnect();\n }\n });\n\n this.ws.on('message', async (data) => {\n await this.handleRelayFrame(data);\n });\n } catch (error) {\n reject(error);\n }\n });\n }\n\n private async handleRelayFrame(data: Buffer | ArrayBuffer | Buffer[]): Promise<void> {\n let frame: RelayFrame;\n\n try {\n frame = JSON.parse(String(data)) as RelayFrame;\n } catch {\n if (this.options.verbose) {\n console.error('[Relay] Invalid frame data');\n }\n return;\n }\n\n switch (frame.type) {\n case 'http_request':\n await this.handleHttpRequest(frame);\n break;\n case 'ws_open':\n await this.handleWsOpen(frame);\n break;\n case 'ws_message':\n await this.handleWsMessage(frame);\n break;\n case 'ws_close':\n await this.handleWsClose(frame);\n break;\n }\n }\n\n private async handleHttpRequest(request: RelayFrame & { type: 'http_request' }): Promise<void> {\n const startTime = Date.now();\n const requestBytes = request.body ? Buffer.byteLength(request.body, 'utf8') : 0;\n\n try {\n const url = `http://127.0.0.1:${this.localPort}${request.path}`;\n\n const fetchOptions: RequestInit = {\n method: request.method,\n headers: request.headers,\n };\n\n if (request.body && !['GET', 'HEAD'].includes(request.method)) {\n fetchOptions.body = request.body;\n }\n\n const response = await fetch(url, fetchOptions);\n const body = await response.text();\n const duration = Date.now() - startTime;\n const responseBytes = Buffer.byteLength(body, 'utf8');\n\n const relayResponse: RelayResponse = {\n type: 'http_response',\n id: request.id,\n status: response.status,\n statusText: response.statusText,\n headers: Object.fromEntries(response.headers.entries()),\n body,\n };\n\n this.ws?.send(JSON.stringify(relayResponse));\n\n const log: RequestLog = {\n id: request.id,\n timestamp: Date.now(),\n method: request.method,\n path: request.path,\n status: response.status,\n duration,\n };\n\n this.recordMetrics(duration, response.status, requestBytes, responseBytes);\n\n this.emit('request', log);\n this.requestCount++;\n } catch (error) {\n const err = error as any;\n const duration = Date.now() - startTime;\n\n if (this.options.verbose || err.code === 'ECONNREFUSED') {\n console.error(`[Relay] Proxy error: ${err.message}`);\n }\n\n const errorResponse: RelayResponse = {\n type: 'http_response',\n id: request.id,\n status: 502,\n statusText: 'Bad Gateway',\n headers: {},\n body: `Error: ${err.message}`,\n };\n\n this.recordMetrics(duration, 502, requestBytes, 0);\n\n this.ws?.send(JSON.stringify(errorResponse));\n }\n }\n\n private recordMetrics(duration: number, status: number, bytesIn: number, bytesOut: number): void {\n this.bytesIn += bytesIn;\n this.bytesOut += bytesOut;\n\n if (status >= 200 && status < 300) this.statusCounts.ok += 1;\n else if (status >= 400 && status < 500) this.statusCounts.clientError += 1;\n else if (status >= 500 && status < 600) this.statusCounts.serverError += 1;\n else this.statusCounts.other += 1;\n\n if (this.latencySamples.length < 500) {\n this.latencySamples.push(duration);\n } else {\n const total = this.requestCount + 1;\n const index = Math.floor(Math.random() * total);\n if (index < this.latencySamples.length) {\n this.latencySamples[index] = duration;\n }\n }\n }\n\n private async handleWsOpen(frame: WsOpen): Promise<void> {\n const localUrl = `ws://127.0.0.1:${this.localPort}${frame.url}`;\n\n if (this.options.verbose) {\n console.log(`[Relay] Opening WebSocket to ${localUrl}`);\n }\n\n const protocolHeader =\n frame.headers['sec-websocket-protocol'] || frame.headers['Sec-WebSocket-Protocol'];\n const filteredHeaders = Object.fromEntries(\n Object.entries(frame.headers).filter(([key]) => {\n const header = key.toLowerCase();\n return (\n header !== 'connection' &&\n header !== 'upgrade' &&\n header !== 'host' &&\n !header.startsWith('sec-websocket')\n );\n })\n );\n\n const localOrigin = `http://127.0.0.1:${this.localPort}`;\n filteredHeaders['origin'] = localOrigin;\n if (filteredHeaders['referer']) {\n filteredHeaders['referer'] = `${localOrigin}${frame.url}`;\n }\n\n const protocols = protocolHeader\n ? protocolHeader\n .split(',')\n .map((value) => value.trim())\n .filter(Boolean)\n : undefined;\n\n const localWs = protocols?.length\n ? new WebSocket(localUrl, protocols, { headers: filteredHeaders })\n : new WebSocket(localUrl, { headers: filteredHeaders });\n\n this.activeWebSockets.set(frame.id, localWs);\n\n localWs.on('message', (data, isBinary) => {\n const message: WsMessage = {\n type: 'ws_message',\n id: frame.id,\n data: isBinary ? (data as Buffer).toString('base64') : data.toString(),\n isBinary,\n };\n this.ws?.send(JSON.stringify(message));\n });\n\n localWs.on('close', () => {\n const closeFrame: WsClose = {\n type: 'ws_close',\n id: frame.id,\n };\n this.ws?.send(JSON.stringify(closeFrame));\n this.activeWebSockets.delete(frame.id);\n });\n\n localWs.on('error', (err) => {\n if (this.options.verbose) {\n console.error(`[Relay] Local WebSocket error (${frame.id}):`, err.message);\n }\n localWs.close();\n });\n }\n\n private async handleWsMessage(frame: WsMessage): Promise<void> {\n const localWs = this.activeWebSockets.get(frame.id);\n if (localWs && localWs.readyState === WebSocket.OPEN) {\n const data = frame.isBinary ? Buffer.from(frame.data, 'base64') : frame.data;\n localWs.send(data);\n }\n }\n\n private async handleWsClose(frame: WsClose): Promise<void> {\n const localWs = this.activeWebSockets.get(frame.id);\n if (localWs) {\n localWs.close();\n this.activeWebSockets.delete(frame.id);\n }\n }\n\n private setupPing(): void {\n this.pingInterval = setInterval(() => {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n this.ws.ping();\n }\n }, TIMEOUTS.WEBSOCKET_PING);\n }\n\n private clearPing(): void {\n if (this.pingInterval) {\n clearInterval(this.pingInterval);\n this.pingInterval = null;\n }\n }\n\n private async attemptReconnect(): Promise<void> {\n if (this.isClosing) return;\n\n this.reconnectAttempts++;\n const delay = Math.min(\n TIMEOUTS.RECONNECT_BASE * Math.pow(2, this.reconnectAttempts - 1),\n TIMEOUTS.RECONNECT_MAX\n );\n\n if (this.options.verbose) {\n console.log(`[Relay] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);\n }\n\n setTimeout(async () => {\n if (this.isClosing) return;\n\n try {\n await this.connect();\n } catch (_) {}\n }, delay);\n }\n\n async disconnect(): Promise<void> {\n this.isClosing = true;\n this.clearPing();\n\n for (const ws of this.activeWebSockets.values()) {\n ws.close();\n }\n this.activeWebSockets.clear();\n\n if (this.ws) {\n this.ws.close(1000, 'Client closing');\n this.ws = null;\n }\n }\n\n getDuration(): number {\n if (this.startTime === 0) return 0;\n return Math.floor((Date.now() - this.startTime) / 1000);\n }\n\n getRequestCount(): number {\n return this.requestCount;\n }\n\n getMetricsSummary(): {\n total_requests: number;\n total_bytes_in: number;\n total_bytes_out: number;\n latency_avg_ms: number;\n latency_p50_ms: number;\n latency_p90_ms: number;\n latency_p99_ms: number;\n status_2xx: number;\n status_4xx: number;\n status_5xx: number;\n status_other: number;\n } {\n const samples = [...this.latencySamples].sort((a, b) => a - b);\n const avg = samples.length\n ? Math.round(samples.reduce((sum, value) => sum + value, 0) / samples.length)\n : 0;\n\n const percentile = (p: number) => {\n if (samples.length === 0) return 0;\n const index = Math.min(samples.length - 1, Math.floor(p * (samples.length - 1)));\n return samples[index] ?? 0;\n };\n\n return {\n total_requests: this.requestCount,\n total_bytes_in: this.bytesIn,\n total_bytes_out: this.bytesOut,\n latency_avg_ms: avg,\n latency_p50_ms: percentile(0.5),\n latency_p90_ms: percentile(0.9),\n latency_p99_ms: percentile(0.99),\n status_2xx: this.statusCounts.ok,\n status_4xx: this.statusCounts.clientError,\n status_5xx: this.statusCounts.serverError,\n status_other: this.statusCounts.other,\n };\n }\n\n isConnected(): boolean {\n return this.ws !== null && this.ws.readyState === WebSocket.OPEN;\n }\n\n getTunnelUrl(): string {\n return this.tunnelUrl;\n }\n}\n","import { nanoid } from 'nanoid';\nimport path from 'node:path';\n\nexport const RELAY_DOMAIN = 'relay.untunneled.dev';\nexport const TUNNEL_DOMAIN = 'untunneled.dev';\n\nexport const getRelayUrl = (tunnelId: string): string => {\n const host = process.env['UNTUNNELED_RELAY_HOST'] || RELAY_DOMAIN;\n const protocol = host.includes('localhost') ? 'ws' : 'wss';\n return `${protocol}://${host}/${tunnelId}`;\n};\n\nexport const getTunnelUrl = (tunnelId: string): string => {\n const domain = process.env['UNTUNNELED_TUNNEL_DOMAIN'] || TUNNEL_DOMAIN;\n return `https://${tunnelId}.${domain}`;\n};\n\nexport function getProjectName(): string {\n const cwd = process.cwd();\n const folderName = path.basename(cwd);\n\n return (\n folderName\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '')\n .slice(0, 20) || 'tunnel'\n );\n}\n\nexport function generateTunnelId(projectName?: string): string {\n const name = projectName || getProjectName();\n const suffix = nanoid(6).toLowerCase();\n return `${name}-${suffix}`;\n}\n\nexport function validatePort(port: string | number): number {\n const portNum = typeof port === 'string' ? parseInt(port, 10) : port;\n\n if (isNaN(portNum) || portNum < 1 || portNum > 65535) {\n throw new Error(`Invalid port number: ${port}. Must be between 1 and 65535.`);\n }\n\n return portNum;\n}\n\nexport const TIMEOUTS = {\n RELAY_REQUEST: 30000,\n WEBSOCKET_PING: 30000,\n RECONNECT_BASE: 1000,\n RECONNECT_MAX: 30000,\n};\n","import { PostHog } from 'posthog-node';\nimport crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nconst POSTHOG_API_KEY = process.env.POSTHOG_API_KEY || 'phc_placeholder';\nconst POSTHOG_HOST = process.env.POSTHOG_HOST || 'https://app.posthog.com';\nconst TELEMETRY_DEBUG =\n process.env['UNTUNNELED_TELEMETRY_DEBUG'] === '1' ||\n process.env['UNTUNNELED_TELEMETRY_DEBUG'] === 'true';\n\ninterface AnalyticsOptions {\n enabled: boolean;\n}\n\ntype EventName = 'tunnel_start' | 'tunnel_end' | 'session_summary';\n\ninterface EventProperties {\n tunnel_start: {\n has_auth: boolean;\n node_version: string;\n platform: string;\n };\n tunnel_end: {\n duration_seconds: number;\n requests: number;\n };\n session_summary: {\n total_requests: number;\n total_bytes_in: number;\n total_bytes_out: number;\n latency_avg_ms: number;\n latency_p50_ms: number;\n latency_p90_ms: number;\n latency_p99_ms: number;\n status_2xx: number;\n status_4xx: number;\n status_5xx: number;\n status_other: number;\n };\n}\n\nexport class Analytics {\n private posthog: PostHog | null = null;\n private enabled: boolean;\n private distinctId: string;\n\n constructor(options: AnalyticsOptions) {\n this.enabled = options.enabled;\n this.distinctId = this.getRotatingDistinctId();\n\n if (this.enabled && POSTHOG_API_KEY && POSTHOG_API_KEY !== 'phc_placeholder') {\n this.posthog = new PostHog(POSTHOG_API_KEY, {\n host: POSTHOG_HOST,\n flushAt: 10,\n flushInterval: 10000,\n });\n\n if (TELEMETRY_DEBUG) {\n console.log('[Telemetry] Enabled', {\n host: POSTHOG_HOST,\n keyPrefix: POSTHOG_API_KEY.slice(0, 6),\n });\n }\n } else if (TELEMETRY_DEBUG) {\n console.log('[Telemetry] Disabled', {\n enabled: this.enabled,\n hasKey: POSTHOG_API_KEY !== 'phc_placeholder',\n });\n }\n }\n\n async track<E extends EventName>(event: E, properties?: EventProperties[E]): Promise<void> {\n if (!this.posthog || !this.enabled) return;\n\n try {\n this.posthog.capture({\n distinctId: this.distinctId,\n event,\n properties: {\n ...properties,\n version: process.env.UNTUNNELED_VERSION || '0.3.6',\n cli: true,\n },\n });\n if (TELEMETRY_DEBUG) {\n console.log('[Telemetry] Captured', { event });\n }\n } catch (_) {}\n }\n\n async shutdown(): Promise<void> {\n if (!this.posthog) return;\n\n try {\n if (TELEMETRY_DEBUG) {\n console.log('[Telemetry] Flushing');\n }\n await this.posthog.flush();\n await this.posthog.shutdown();\n } catch (_) {}\n }\n\n isEnabled(): boolean {\n return this.enabled && this.posthog !== null;\n }\n\n private getRotatingDistinctId(): string {\n const anonId = this.getAnonymousId();\n const now = new Date();\n const rotationKey = `${anonId}:${now.getUTCFullYear()}-${now.getUTCMonth() + 1}`;\n return crypto.createHash('sha256').update(rotationKey).digest('hex').slice(0, 32);\n }\n\n private getAnonymousId(): string {\n const baseDir =\n process.env['XDG_CONFIG_HOME'] ||\n process.env['APPDATA'] ||\n path.join(os.homedir(), '.config');\n const configDir = path.join(baseDir, 'untunneled.dev');\n const idPath = path.join(configDir, 'anon_id');\n\n try {\n if (!fs.existsSync(configDir)) {\n fs.mkdirSync(configDir, { recursive: true });\n }\n\n if (fs.existsSync(idPath)) {\n const existing = fs.readFileSync(idPath, 'utf8').trim();\n if (existing) return existing;\n }\n\n const newId = crypto.randomUUID();\n fs.writeFileSync(idPath, newId, 'utf8');\n return newId;\n } catch {\n return crypto.randomUUID();\n }\n }\n}\n","export async function listCommand(): Promise<void> {\n console.log('Active tunnels:');\n console.log(' (No active tunnels)');\n console.log('');\n console.log('Note: Tunnel list feature coming soon.');\n}\n","export async function stopCommand(tunnelId: string): Promise<void> {\n console.log(`Stopping tunnel: ${tunnelId}`);\n console.log('');\n console.log('Note: Remote stop feature coming soon.');\n}\n"],"mappings":"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","names":["React","useState","useEffect","Box","Text","Box","Text","jsx","jsxs","useState","useEffect","Box","Text","jsx","jsxs","jsx","jsxs","useState","useEffect","Box","Text","path","React"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "untunneled.dev",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
4
4
  "description": "Fast, free localhost tunneling for developers",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",