@seedprotocol/gateway-hyper 0.7.5 → 0.7.6-next.957.g6bb7768

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"src-qIlmrs1H.js","names":["URL","fs","path","HyperDHT","ID","http","URL$1","toHex","buf","fromHex","hex","encodePublicKeyZ32","publicKey","decodePublicKey","trimmed","key","loadOrCreateOperatorKeypair","resolved","keyFile","raw","parsed","dir","kp","persisted","createEphemeralClientKeypair","MAX_FRAME_BYTES","WRITE_CHUNK_BYTES","StreamByteReader","stream","chunk","err","length","resolve","waiters","w","next","out","readers","getReader","reader","readExact","writeBuffer","cleanup","onDrain","onError","onClose","reject","assertFrameSize","writeFrame","payload","header","first","offset","readFrame","writeTunnelRequest","body","meta","readTunnelRequest","metaBuf","writeTunnelResponse","readTunnelResponse","flattenRequestHeaders","value","headers","filterResponseHeaders","skip","TunnelTimeoutError","timeoutMs","TunnelConnectTimeoutError","UpstreamTimeoutError","DEFAULT_UPSTREAM_TIMEOUT_MS","HOP_BY_HOP_HEADERS","upstreamRequestHeaders","named","token","host","lower","proxyTunnelRequest","base","upstreamBase","targetUrl","options","req","chunks","received","res","errorResponse","message","serveTunnelConnection","closed","onGone","socket","pendingRequest","result","upstream","serveTunnel","keypair","dht","server","stripMountPath","urlPath","qIndex","pathname","query","mount","mountPath","rest","readNodeBody","tunnelErrorStatus","tunnelErrorMessage","forwardNodeRequest","controller","responseMeta","responseBody","session","writeNodeResponse","forwardFetchRequest","url","request","bodyBuf","headerRecord","DEFAULT_REQUEST_TIMEOUT_MS","DEFAULT_CONNECT_TIMEOUT_MS","DEFAULT_MAX_STREAMS","abortError","reason","signal","raceAbort","onAbort","promise","createTunnelQueue","runGuarded","opts","requestTimeoutMs","getSocket","settled","timer","armTimer","abandon","fn","tunnelQueue","run","closedError","createTunnelPool","maxStreams","slots","waiting","addSlot","slot","openStream","takeSlot","idle","s","release","acquire","index","waiter","createTunnelSession","remotePublicKey","clientKey","connectTimeoutMs","pool","fail","onReady","runOnTunnel","connectTunnel","port","address","boundPort","baseUrl","localGatewayUrl","resolveProxyKey","createGatewayProxy","starting","ensureSession","proxy","DEFAULT_SEED_GATEWAY_HYPER_KEY"],"sources":["../src/keys.ts","../src/tunnel/protocol.ts","../src/tunnel/errors.ts","../src/tunnel/proxy.ts","../src/tunnel/serve.ts","../src/tunnel/mountPath.ts","../src/tunnel/forward.ts","../src/tunnel/session.ts","../src/tunnel/connect.ts","../src/tunnel/proxyApp.ts","../src/constants.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\nimport HyperDHT from 'hyperdht'\nimport ID from 'hypercore-id-encoding'\nimport type { OperatorKeyPair } from './types'\n\nexport interface PersistedKeyFile {\n publicKey: string\n secretKey: string\n encoding: 'hex'\n}\n\nfunction toHex(buf: Buffer): string {\n return buf.toString('hex')\n}\n\nfunction fromHex(hex: string): Buffer {\n return Buffer.from(hex, 'hex')\n}\n\nexport function encodePublicKeyZ32(publicKey: Buffer): string {\n return ID.encode(publicKey)\n}\n\nexport function decodePublicKey(key: string): Buffer {\n const trimmed = key.trim()\n if (!trimmed) {\n throw new Error('Gateway Hyper key is empty')\n }\n try {\n return Buffer.from(ID.decode(trimmed))\n } catch {\n if (/^[a-fA-F0-9]{64}$/.test(trimmed)) {\n return fromHex(trimmed)\n }\n throw new Error(`Invalid Gateway Hyper key (expected z32 or 64-char hex): ${trimmed.slice(0, 12)}…`)\n }\n}\n\nexport function loadOrCreateOperatorKeypair(keyFile: string): OperatorKeyPair {\n const resolved = path.resolve(keyFile)\n if (fs.existsSync(resolved)) {\n const raw = fs.readFileSync(resolved, 'utf8')\n const parsed = JSON.parse(raw) as PersistedKeyFile\n if (!parsed.publicKey || !parsed.secretKey) {\n throw new Error(`Invalid key file at ${resolved}: missing publicKey or secretKey`)\n }\n const publicKey = fromHex(parsed.publicKey)\n const secretKey = fromHex(parsed.secretKey)\n return {\n publicKey,\n secretKey,\n z32: encodePublicKeyZ32(publicKey),\n }\n }\n\n const dir = path.dirname(resolved)\n fs.mkdirSync(dir, { recursive: true })\n const kp = HyperDHT.keyPair()\n const persisted: PersistedKeyFile = {\n publicKey: toHex(kp.publicKey),\n secretKey: toHex(kp.secretKey),\n encoding: 'hex',\n }\n fs.writeFileSync(resolved, `${JSON.stringify(persisted, null, 2)}\\n`, { mode: 0o600 })\n return {\n publicKey: kp.publicKey,\n secretKey: kp.secretKey,\n z32: encodePublicKeyZ32(kp.publicKey),\n }\n}\n\nexport function createEphemeralClientKeypair(): OperatorKeyPair {\n const kp = HyperDHT.keyPair()\n return {\n publicKey: kp.publicKey,\n secretKey: kp.secretKey,\n z32: encodePublicKeyZ32(kp.publicKey),\n }\n}\n","import type { Readable, Writable } from 'node:stream'\nimport type { TunnelMeta, TunnelResponseMeta } from '../types'\n\n/** Maximum single frame payload (64 MiB). */\nexport const MAX_FRAME_BYTES = 64 * 1024 * 1024\n\n/** Largest single stream write. Secret-stream's limit is 16 MiB - 1. */\nexport const WRITE_CHUNK_BYTES = 1024 * 1024\n\ntype ByteWaiter = {\n length: number\n resolve: (buf: Buffer) => void\n reject: (err: Error) => void\n}\n\n/**\n * Per-stream byte buffer. HyperDHT duplexes do not reliably support `unshift`,\n * so we accumulate and slice locally instead of pushing leftovers back.\n *\n * Once the stream ends, errors or closes, every pending and later read that the\n * buffer cannot satisfy rejects. A destroyed stream emits `close` without `end`,\n * so listening for `end` alone would leave reads waiting forever.\n */\nclass StreamByteReader {\n private buffer = Buffer.alloc(0)\n private waiters: ByteWaiter[] = []\n private failure: Error | null = null\n\n constructor(stream: Readable) {\n stream.on('data', (chunk: Buffer) => {\n this.buffer = Buffer.concat([this.buffer, chunk])\n this.drain()\n })\n stream.on('error', (err: Error) => this.fail(err))\n stream.on('end', () => this.fail(new Error('Unexpected end of stream')))\n stream.on('close', () => this.fail(new Error('Stream closed')))\n }\n\n readExact(length: number): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n if (length === 0) {\n resolve(Buffer.alloc(0))\n return\n }\n this.waiters.push({ length, resolve, reject })\n this.drain()\n this.rejectWaiters()\n })\n }\n\n private fail(err: Error): void {\n this.failure ??= err\n this.drain()\n this.rejectWaiters()\n }\n\n private rejectWaiters(): void {\n if (!this.failure || this.waiters.length === 0) return\n const waiters = this.waiters.splice(0)\n for (const w of waiters) {\n w.reject(\n new Error(\n `${this.failure.message} (expected ${w.length} bytes, got ${this.buffer.length})`,\n ),\n )\n }\n }\n\n private drain(): void {\n while (this.waiters.length > 0) {\n const next = this.waiters[0]\n if (!next || this.buffer.length < next.length) break\n this.waiters.shift()\n const out = this.buffer.subarray(0, next.length)\n this.buffer = this.buffer.subarray(next.length)\n next.resolve(out)\n }\n }\n}\n\nconst readers = new WeakMap<Readable, StreamByteReader>()\n\nfunction getReader(stream: Readable): StreamByteReader {\n let reader = readers.get(stream)\n if (!reader) {\n reader = new StreamByteReader(stream)\n readers.set(stream, reader)\n }\n return reader\n}\n\nfunction readExact(stream: Readable, length: number): Promise<Buffer> {\n return getReader(stream).readExact(length)\n}\n\nfunction writeBuffer(stream: Writable, buf: Buffer): Promise<void> {\n return new Promise((resolve, reject) => {\n if (stream.destroyed) {\n reject(new Error('Stream closed'))\n return\n }\n // HyperDHT duplexes often never invoke write(callback). Use return value + drain.\n try {\n const ok = stream.write(buf)\n if (ok) {\n resolve()\n return\n }\n const cleanup = () => {\n stream.off('drain', onDrain)\n stream.off('error', onError)\n stream.off('close', onClose)\n }\n const onDrain = () => {\n cleanup()\n resolve()\n }\n const onError = (err: Error) => {\n cleanup()\n reject(err)\n }\n const onClose = () => {\n cleanup()\n reject(new Error('Stream closed'))\n }\n stream.once('drain', onDrain)\n stream.once('error', onError)\n stream.once('close', onClose)\n } catch (err) {\n reject(err instanceof Error ? err : new Error(String(err)))\n }\n })\n}\n\nfunction assertFrameSize(length: number): void {\n if (length > MAX_FRAME_BYTES) {\n throw new Error(`Frame too large: ${length} bytes (max ${MAX_FRAME_BYTES})`)\n }\n}\n\nexport async function writeFrame(stream: Writable, payload: Buffer): Promise<void> {\n assertFrameSize(payload.length)\n const header = Buffer.alloc(4)\n header.writeUInt32BE(payload.length, 0)\n // The header goes out with the first chunk. Secret-stream rejects any single write over\n // 16 MiB, so larger payloads are split, waiting for drain between chunks.\n const first = payload.subarray(0, WRITE_CHUNK_BYTES)\n await writeBuffer(stream, Buffer.concat([header, first]))\n for (let offset = first.length; offset < payload.length; offset += WRITE_CHUNK_BYTES) {\n await writeBuffer(stream, payload.subarray(offset, offset + WRITE_CHUNK_BYTES))\n }\n}\n\nexport async function readFrame(stream: Readable): Promise<Buffer> {\n const header = await readExact(stream, 4)\n const length = header.readUInt32BE(0)\n if (length === 0) {\n return Buffer.alloc(0)\n }\n assertFrameSize(length)\n return readExact(stream, length)\n}\n\nexport async function writeTunnelRequest(\n stream: Writable,\n meta: TunnelMeta,\n body: Buffer,\n): Promise<void> {\n // Check the body before writing meta so an oversized body leaves the stream in sync.\n assertFrameSize(body.length)\n const metaFrame = Buffer.from(JSON.stringify(meta), 'utf8')\n await writeFrame(stream, metaFrame)\n await writeFrame(stream, body)\n}\n\nexport async function readTunnelRequest(\n stream: Readable,\n): Promise<{ meta: TunnelMeta; body: Buffer }> {\n const metaBuf = await readFrame(stream)\n const meta = JSON.parse(metaBuf.toString('utf8')) as TunnelMeta\n if (!meta.method || !meta.path) {\n throw new Error('Invalid tunnel request meta: missing method or path')\n }\n meta.headers = meta.headers ?? {}\n const body = await readFrame(stream)\n return { meta, body }\n}\n\nexport async function writeTunnelResponse(\n stream: Writable,\n meta: TunnelResponseMeta,\n body: Buffer,\n): Promise<void> {\n // Check the body before writing meta so an oversized body leaves the stream in sync.\n assertFrameSize(body.length)\n const metaFrame = Buffer.from(JSON.stringify(meta), 'utf8')\n await writeFrame(stream, metaFrame)\n await writeFrame(stream, body)\n}\n\nexport async function readTunnelResponse(\n stream: Readable,\n): Promise<{ meta: TunnelResponseMeta; body: Buffer }> {\n const metaBuf = await readFrame(stream)\n const meta = JSON.parse(metaBuf.toString('utf8')) as TunnelResponseMeta\n if (typeof meta.status !== 'number') {\n throw new Error('Invalid tunnel response meta: missing status')\n }\n meta.headers = meta.headers ?? {}\n const body = await readFrame(stream)\n return { meta, body }\n}\n\n/** Normalize header values to strings for tunnel transport. */\nexport function flattenRequestHeaders(\n headers: Record<string, string | string[] | undefined>,\n): Record<string, string> {\n const out: Record<string, string> = {}\n for (const [key, value] of Object.entries(headers)) {\n if (value == null) continue\n out[key] = Array.isArray(value) ? value.join(', ') : value\n }\n return out\n}\n\n/** Pick response headers safe to forward to the local HTTP client. */\nexport function filterResponseHeaders(\n headers: Record<string, string | string[] | undefined>,\n): Record<string, string> {\n const skip = new Set([\n 'connection',\n 'keep-alive',\n 'transfer-encoding',\n 'upgrade',\n ])\n const out: Record<string, string> = {}\n for (const [key, value] of Object.entries(headers)) {\n if (skip.has(key.toLowerCase())) continue\n if (value == null) continue\n out[key] = Array.isArray(value) ? value.join(', ') : value\n }\n return out\n}\n","/** Client side: the tunnel stream was idle longer than `requestTimeoutMs`, so the request was abandoned. */\nexport class TunnelTimeoutError extends Error {\n readonly code = 'TUNNEL_TIMEOUT'\n\n constructor(readonly timeoutMs: number) {\n super(`No bytes sent or received on the tunnel for ${timeoutMs} ms`)\n this.name = 'TunnelTimeoutError'\n }\n}\n\n/** Client side: the HyperDHT connection to the operator did not open within `connectTimeoutMs`. */\nexport class TunnelConnectTimeoutError extends Error {\n readonly code = 'TUNNEL_CONNECT_TIMEOUT'\n\n constructor(readonly timeoutMs: number) {\n super(`Could not connect to the operator within ${timeoutMs} ms`)\n this.name = 'TunnelConnectTimeoutError'\n }\n}\n\n/** Operator side: the upstream socket was idle longer than `upstreamTimeoutMs`. */\nexport class UpstreamTimeoutError extends Error {\n readonly code = 'UPSTREAM_TIMEOUT'\n\n constructor(readonly timeoutMs: number) {\n super(`No response from upstream for ${timeoutMs} ms`)\n this.name = 'UpstreamTimeoutError'\n }\n}\n","import http from 'node:http'\nimport { URL } from 'node:url'\nimport { UpstreamTimeoutError } from './errors'\nimport { filterResponseHeaders, MAX_FRAME_BYTES } from './protocol'\nimport type { TunnelMeta } from '../types'\n\n/** Default idle limit on the operator's upstream socket. */\nexport const DEFAULT_UPSTREAM_TIMEOUT_MS = 30_000\n\nexport type ProxyTunnelRequestOptions = {\n /** Fail with `UpstreamTimeoutError` once the upstream socket is idle this long. 0 disables. */\n timeoutMs?: number\n /** Abort the upstream request, e.g. when the tunnel stream closes. */\n signal?: AbortSignal\n}\n\n/** Headers that describe one hop and must not be forwarded (RFC 9110 section 7.6.1). */\nconst HOP_BY_HOP_HEADERS = new Set([\n 'connection',\n 'keep-alive',\n 'proxy-connection',\n 'te',\n 'trailer',\n 'transfer-encoding',\n 'upgrade',\n])\n\n/**\n * Drop hop-by-hop headers and the client's `host`, which names the app server rather than\n * the upstream; it is passed on as `x-forwarded-host`. `content-length` is dropped because\n * Node sets it from the buffered body.\n */\nexport function upstreamRequestHeaders(headers: Record<string, string>): Record<string, string> {\n const named = new Set(\n (Object.entries(headers).find(([key]) => key.toLowerCase() === 'connection')?.[1] ?? '')\n .split(',')\n .map((token) => token.trim().toLowerCase())\n .filter(Boolean),\n )\n const out: Record<string, string> = {}\n let host: string | undefined\n for (const [key, value] of Object.entries(headers)) {\n const lower = key.toLowerCase()\n if (lower === 'host') {\n host = value\n continue\n }\n if (lower === 'content-length' || HOP_BY_HOP_HEADERS.has(lower) || named.has(lower)) continue\n out[key] = value\n }\n if (host && !Object.keys(out).some((key) => key.toLowerCase() === 'x-forwarded-host')) {\n out['x-forwarded-host'] = host\n }\n return out\n}\n\nexport async function proxyTunnelRequest(\n upstreamBase: string,\n meta: TunnelMeta,\n body: Buffer,\n options: ProxyTunnelRequestOptions = {},\n): Promise<{ status: number; headers: Record<string, string>; body: Buffer }> {\n const base = upstreamBase.replace(/\\/$/, '')\n const targetUrl = new URL(meta.path, `${base}/`)\n const timeoutMs = options.timeoutMs ?? DEFAULT_UPSTREAM_TIMEOUT_MS\n\n return new Promise((resolve, reject) => {\n const req = http.request(\n targetUrl,\n {\n method: meta.method,\n headers: upstreamRequestHeaders(meta.headers),\n signal: options.signal,\n },\n (res) => {\n const chunks: Buffer[] = []\n let received = 0\n res.on('data', (chunk: Buffer) => {\n received += chunk.length\n if (received > MAX_FRAME_BYTES) {\n req.destroy(\n new Error(`Upstream response exceeds ${MAX_FRAME_BYTES} bytes, the tunnel's limit`),\n )\n return\n }\n chunks.push(chunk)\n })\n res.on('end', () => {\n resolve({\n status: res.statusCode ?? 502,\n headers: filterResponseHeaders(res.headers as Record<string, string | string[] | undefined>),\n body: Buffer.concat(chunks),\n })\n })\n res.on('error', reject)\n },\n )\n if (timeoutMs > 0) {\n req.setTimeout(timeoutMs, () => req.destroy(new UpstreamTimeoutError(timeoutMs)))\n }\n req.on('error', reject)\n if (body.length > 0) {\n req.end(body)\n } else {\n req.end()\n }\n })\n}\n","import type { Duplex } from 'node:stream'\nimport HyperDHT from 'hyperdht'\nimport { readTunnelRequest, writeTunnelResponse } from './protocol'\nimport { UpstreamTimeoutError } from './errors'\nimport { proxyTunnelRequest } from './proxy'\nimport { loadOrCreateOperatorKeypair } from '../keys'\nimport type { ServeTunnelOptions, ServeTunnelResult } from '../types'\n\nexport type TunnelConnectionOptions = {\n /** Idle limit on each upstream request. Default 30 000; 0 disables. */\n upstreamTimeoutMs?: number\n}\n\nfunction errorResponse(\n status: number,\n message: string,\n): { status: number; headers: Record<string, string>; body: Buffer } {\n return {\n status,\n headers: { 'content-type': 'text/plain; charset=utf-8' },\n body: Buffer.from(message, 'utf8'),\n }\n}\n\n/**\n * Answer framed requests on one tunnel stream, in order, until it closes. Upstream timeouts\n * become 504 and other upstream failures 502, so the stream stays usable; only a broken\n * stream ends the loop. The stream ending or closing aborts the upstream request in flight.\n */\nexport async function serveTunnelConnection(\n socket: Duplex,\n upstream: string,\n options: TunnelConnectionOptions = {},\n): Promise<void> {\n // Clients never half-close, so `end` means the peer is gone, same as `close` or `error`.\n const closed = new AbortController()\n const onGone = () => closed.abort()\n socket.once('end', onGone)\n socket.once('close', onGone)\n socket.on('error', onGone)\n // Attach framed readers synchronously so HyperDHT early bytes are not lost.\n let pendingRequest = readTunnelRequest(socket)\n try {\n while (true) {\n const { meta, body } = await pendingRequest\n let result: { status: number; headers: Record<string, string>; body: Buffer }\n try {\n result = await proxyTunnelRequest(upstream, meta, body, {\n timeoutMs: options.upstreamTimeoutMs,\n signal: closed.signal,\n })\n } catch (err) {\n if (closed.signal.aborted) return\n const message = err instanceof Error ? err.message : String(err)\n result =\n err instanceof UpstreamTimeoutError\n ? errorResponse(504, `Gateway Hyper upstream timeout: ${message}`)\n : errorResponse(502, `Gateway Hyper upstream error: ${message}`)\n }\n await writeTunnelResponse(\n socket,\n { status: result.status, headers: result.headers },\n result.body,\n )\n pendingRequest = readTunnelRequest(socket)\n }\n } catch {\n socket.destroy()\n }\n}\n\n/**\n * Operator: accept Hyperswarm/DHT connections and proxy framed HTTP to upstream Traefik.\n */\nexport async function serveTunnel(options: ServeTunnelOptions): Promise<ServeTunnelResult> {\n const upstream = options.upstream.replace(/\\/$/, '')\n const keyFile = options.keyFile ?? '.seed/gateway-tunnel/operator.key.json'\n const keypair = loadOrCreateOperatorKeypair(keyFile)\n\n const dht = new HyperDHT()\n const server = dht.createServer((socket) => {\n void serveTunnelConnection(socket as Duplex, upstream, {\n upstreamTimeoutMs: options.upstreamTimeoutMs,\n })\n })\n\n await server.listen(keypair)\n\n return {\n key: keypair.z32,\n upstream,\n close: async () => {\n await server.close()\n await dht.destroy()\n },\n }\n}\n","/**\n * Strip a mount path prefix from an incoming request URL path (including query string).\n * If the path is already unmounted (framework stripped it), returns it unchanged (with leading `/`).\n */\nexport function stripMountPath(urlPath: string, mountPath: string): string {\n const raw = urlPath || '/'\n const qIndex = raw.indexOf('?')\n const pathname = qIndex === -1 ? raw : raw.slice(0, qIndex)\n const query = qIndex === -1 ? '' : raw.slice(qIndex)\n\n const mount = (mountPath || '').replace(/\\/$/, '')\n if (!mount || mount === '/') {\n const path = pathname.startsWith('/') ? pathname : `/${pathname}`\n return `${path}${query}` || '/'\n }\n\n if (pathname === mount || pathname.startsWith(`${mount}/`)) {\n const rest = pathname.slice(mount.length)\n const path = rest.startsWith('/') ? rest : rest ? `/${rest}` : '/'\n return `${path}${query}`\n }\n\n // Already stripped by the framework (e.g. Express mount)\n const path = pathname.startsWith('/') ? pathname : `/${pathname}`\n return `${path}${query}`\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http'\nimport {\n filterResponseHeaders,\n flattenRequestHeaders,\n} from './protocol'\nimport { stripMountPath } from './mountPath'\nimport { TunnelTimeoutError } from './errors'\nimport type { TunnelSession } from './session'\nimport type { TunnelMeta, TunnelResponseMeta } from '../types'\n\nasync function readNodeBody(req: IncomingMessage): Promise<Buffer> {\n const chunks: Buffer[] = []\n for await (const chunk of req) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk))\n }\n return Buffer.concat(chunks)\n}\n\n/** 504 when the tunnel timed out, 502 for any other tunnel failure. */\nfunction tunnelErrorStatus(err: unknown): number {\n return err instanceof TunnelTimeoutError ? 504 : 502\n}\n\nfunction tunnelErrorMessage(err: unknown): string {\n const message = err instanceof Error ? err.message : String(err)\n return `Gateway Hyper tunnel error: ${message}`\n}\n\nexport async function forwardNodeRequest(\n session: TunnelSession,\n req: IncomingMessage,\n res: ServerResponse,\n mountPath: string,\n): Promise<void> {\n // The caller hanging up abandons the request instead of leaving it on the tunnel.\n const controller = new AbortController()\n const onClose = () => {\n if (!res.writableEnded) controller.abort()\n }\n res.once('close', onClose)\n try {\n const body = await readNodeBody(req)\n const path = stripMountPath(req.url ?? '/', mountPath)\n const meta: TunnelMeta = {\n method: req.method ?? 'GET',\n path,\n headers: flattenRequestHeaders(req.headers as Record<string, string | string[] | undefined>),\n }\n const { meta: responseMeta, body: responseBody } = await session.forwardHttp(meta, body, {\n signal: controller.signal,\n })\n writeNodeResponse(res, responseMeta, responseBody)\n } catch (err) {\n if (controller.signal.aborted) return\n if (!res.headersSent) {\n res.writeHead(tunnelErrorStatus(err), { 'Content-Type': 'text/plain; charset=utf-8' })\n }\n res.end(tunnelErrorMessage(err))\n } finally {\n res.off('close', onClose)\n }\n}\n\nfunction writeNodeResponse(\n res: ServerResponse,\n meta: TunnelResponseMeta,\n body: Buffer,\n): void {\n res.writeHead(meta.status, filterResponseHeaders(meta.headers))\n res.end(body)\n}\n\nexport async function forwardFetchRequest(\n session: TunnelSession,\n request: Request,\n mountPath: string,\n): Promise<Response> {\n try {\n const url = new URL(request.url)\n const path = stripMountPath(`${url.pathname}${url.search}`, mountPath)\n const bodyBuf = Buffer.from(await request.arrayBuffer())\n const headerRecord: Record<string, string> = {}\n request.headers.forEach((value, key) => {\n headerRecord[key] = value\n })\n const meta: TunnelMeta = {\n method: request.method || 'GET',\n path,\n headers: flattenRequestHeaders(headerRecord),\n }\n const { meta: responseMeta, body: responseBody } = await session.forwardHttp(meta, bodyBuf, {\n signal: request.signal,\n })\n return new Response(responseBody, {\n status: responseMeta.status,\n headers: filterResponseHeaders(responseMeta.headers),\n })\n } catch (err) {\n return new Response(tunnelErrorMessage(err), {\n status: tunnelErrorStatus(err),\n headers: { 'Content-Type': 'text/plain; charset=utf-8' },\n })\n }\n}\n","import type { Duplex } from 'node:stream'\nimport HyperDHT from 'hyperdht'\nimport { createEphemeralClientKeypair, decodePublicKey } from '../keys'\nimport type { TunnelMeta, TunnelResponseMeta } from '../types'\nimport { TunnelConnectTimeoutError, TunnelTimeoutError } from './errors'\nimport { readTunnelResponse, writeTunnelRequest } from './protocol'\n\n/** Default idle limit for one request on the tunnel stream. */\nexport const DEFAULT_REQUEST_TIMEOUT_MS = 60_000\n\n/** Default limit for opening the HyperDHT connection. */\nexport const DEFAULT_CONNECT_TIMEOUT_MS = 30_000\n\n/**\n * Default number of streams a session opens to the operator. Streams open only when every\n * open one is busy, and each costs a DHT lookup and handshake plus an upstream request on\n * the operator, so a small pool keeps that cost down. Four leaves room for a page's burst of\n * gateway reads after one or two requests hang until their timeout.\n */\nexport const DEFAULT_MAX_STREAMS = 4\n\nexport type TunnelSessionOptions = {\n /** Operator public key (z32 or hex) */\n key: string\n /** Optional store path for DHT client state */\n storePath?: string\n /**\n * Abandon a request once the stream has sent and received nothing for this long, then\n * reconnect for the next request. Counts from when the request gets a stream.\n * Default 60 000; 0 disables.\n */\n requestTimeoutMs?: number\n /** Give up opening the HyperDHT connection after this long. Default 30 000; 0 disables. */\n connectTimeoutMs?: number\n /**\n * Most HyperDHT streams open to the operator at once; each carries one request at a time.\n * Default 4.\n */\n maxStreams?: number\n}\n\nexport type TunnelRequestOptions = {\n /** Aborting rejects the request; if it is already on the stream, the stream is destroyed. */\n signal?: AbortSignal\n /** Overrides the session's `requestTimeoutMs` for this request. */\n timeoutMs?: number\n}\n\nexport type TunnelSession = {\n key: string\n runOnTunnel: <T>(\n fn: (socket: Duplex) => Promise<T>,\n options?: TunnelRequestOptions,\n ) => Promise<T>\n forwardHttp: (\n meta: TunnelMeta,\n body: Buffer,\n options?: TunnelRequestOptions,\n ) => Promise<{ meta: TunnelResponseMeta; body: Buffer }>\n close: () => Promise<void>\n}\n\nfunction abortError(signal: AbortSignal): Error {\n const reason: unknown = signal.reason\n if (reason instanceof Error) return reason\n const err = new Error('The request was aborted')\n err.name = 'AbortError'\n return err\n}\n\n/** Reject as soon as `signal` aborts, even while `promise` is still queued. */\nfunction raceAbort<T>(promise: Promise<T>, signal: AbortSignal): Promise<T> {\n if (signal.aborted) return Promise.reject(abortError(signal))\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => reject(abortError(signal))\n signal.addEventListener('abort', onAbort, { once: true })\n promise.then(\n (value) => {\n signal.removeEventListener('abort', onAbort)\n resolve(value)\n },\n (err: unknown) => {\n signal.removeEventListener('abort', onAbort)\n reject(err)\n },\n )\n })\n}\n\n/**\n * Serialize transactions on the socket `getSocket` returns. Each runs under an idle timeout\n * and an optional abort signal; one that is abandoned or fails destroys the socket, so\n * `getSocket` must open a new one once the current one is destroyed.\n */\nexport function createTunnelQueue(\n getSocket: () => Promise<Duplex>,\n requestTimeoutMs: number = DEFAULT_REQUEST_TIMEOUT_MS,\n): TunnelSession['runOnTunnel'] {\n const runGuarded = async <T>(\n fn: (socket: Duplex) => Promise<T>,\n opts: TunnelRequestOptions,\n ): Promise<T> => {\n const { signal } = opts\n const timeoutMs = opts.timeoutMs ?? requestTimeoutMs\n if (signal?.aborted) throw abortError(signal)\n const socket = await getSocket()\n if (signal?.aborted) throw abortError(signal)\n\n return new Promise<T>((resolve, reject) => {\n let settled = false\n let timer: ReturnType<typeof setTimeout> | null = null\n const armTimer = () => {\n if (timeoutMs <= 0) return\n if (timer) clearTimeout(timer)\n timer = setTimeout(() => abandon(new TunnelTimeoutError(timeoutMs)), timeoutMs)\n }\n const cleanup = () => {\n if (timer) clearTimeout(timer)\n socket.off('data', armTimer)\n socket.off('drain', armTimer)\n signal?.removeEventListener('abort', onAbort)\n }\n // A late response would be read as the next request's reply, so the stream goes too.\n const abandon = (err: unknown) => {\n if (settled) return\n settled = true\n cleanup()\n socket.destroy()\n reject(err)\n }\n const onAbort = () => abandon(abortError(signal as AbortSignal))\n\n armTimer()\n // Bytes moving either way keep the request alive, so large bodies are not cut off.\n socket.on('data', armTimer)\n socket.on('drain', armTimer)\n signal?.addEventListener('abort', onAbort, { once: true })\n\n fn(socket).then((value) => {\n if (settled) return\n settled = true\n cleanup()\n resolve(value)\n }, abandon)\n })\n }\n\n let tunnelQueue: Promise<unknown> = Promise.resolve()\n return <T>(\n fn: (socket: Duplex) => Promise<T>,\n opts: TunnelRequestOptions = {},\n ): Promise<T> => {\n const run = tunnelQueue.then(() => runGuarded(fn, opts))\n tunnelQueue = run.catch(() => {})\n return opts.signal ? raceAbort(run, opts.signal) : run\n }\n}\n\ntype PoolSlot = {\n run: TunnelSession['runOnTunnel']\n socket: Duplex | null\n busy: boolean\n}\n\ntype PoolWaiter = {\n resolve: (slot: PoolSlot) => void\n reject: (err: Error) => void\n}\n\nexport type TunnelPoolOptions = {\n /** Most streams open at once. Default `DEFAULT_MAX_STREAMS`. */\n maxStreams?: number\n /** Idle limit for each request, as in `createTunnelQueue`. */\n requestTimeoutMs?: number\n}\n\nexport type TunnelPool = {\n runOnTunnel: TunnelSession['runOnTunnel']\n /** Reject queued requests and destroy every stream. */\n close: () => void\n}\n\nfunction closedError(): Error {\n return new Error('Tunnel session is closed')\n}\n\n/**\n * Run each transaction alone on one of up to `maxStreams` sockets from `openStream`. A request\n * takes an idle open stream if there is one, else opens a new stream while fewer than\n * `maxStreams` exist, else waits for the first stream to come free. Each stream is a\n * `createTunnelQueue`, so a request that is abandoned destroys only its own stream, and that\n * stream reopens for the next request it takes.\n */\nexport function createTunnelPool(\n openStream: () => Promise<Duplex>,\n options: TunnelPoolOptions = {},\n): TunnelPool {\n const maxStreams = Math.max(1, Math.floor(options.maxStreams ?? DEFAULT_MAX_STREAMS))\n const requestTimeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS\n const slots: PoolSlot[] = []\n const waiting: PoolWaiter[] = []\n let closed = false\n\n const addSlot = (): PoolSlot => {\n const slot: PoolSlot = { run: null as never, socket: null, busy: false }\n // The slot runs one request at a time, so there is never a second open in progress.\n slot.run = createTunnelQueue(async () => {\n if (closed) throw closedError()\n if (slot.socket && !slot.socket.destroyed) return slot.socket\n const socket = await openStream()\n if (closed) {\n socket.destroy()\n throw closedError()\n }\n slot.socket = socket\n return socket\n }, requestTimeoutMs)\n slots.push(slot)\n return slot\n }\n\n const takeSlot = (): PoolSlot | null => {\n const idle = slots.filter((slot) => !slot.busy)\n // An idle slot whose stream died reopens it, same as a new slot would.\n const slot =\n idle.find((s) => s.socket !== null && !s.socket.destroyed) ??\n idle[0] ??\n (slots.length < maxStreams ? addSlot() : undefined)\n if (!slot) return null\n slot.busy = true\n return slot\n }\n\n const release = (slot: PoolSlot) => {\n const next = waiting.shift()\n if (next) next.resolve(slot)\n else slot.busy = false\n }\n\n const acquire = (signal: AbortSignal | undefined): Promise<PoolSlot> => {\n const slot = takeSlot()\n if (slot) return Promise.resolve(slot)\n return new Promise<PoolSlot>((resolve, reject) => {\n const onAbort = () => {\n const index = waiting.indexOf(waiter)\n if (index >= 0) waiting.splice(index, 1)\n reject(abortError(signal as AbortSignal))\n }\n const waiter: PoolWaiter = {\n resolve: (s) => {\n signal?.removeEventListener('abort', onAbort)\n resolve(s)\n },\n reject: (err) => {\n signal?.removeEventListener('abort', onAbort)\n reject(err)\n },\n }\n waiting.push(waiter)\n signal?.addEventListener('abort', onAbort, { once: true })\n })\n }\n\n const runOnTunnel = async <T>(\n fn: (socket: Duplex) => Promise<T>,\n opts: TunnelRequestOptions = {},\n ): Promise<T> => {\n if (opts.signal?.aborted) throw abortError(opts.signal)\n if (closed) throw closedError()\n const slot = await acquire(opts.signal)\n try {\n return await slot.run(fn, opts)\n } finally {\n release(slot)\n }\n }\n\n return {\n runOnTunnel,\n close: () => {\n closed = true\n for (const waiter of waiting.splice(0)) waiter.reject(closedError())\n for (const slot of slots) slot.socket?.destroy()\n },\n }\n}\n\n/**\n * Dial the operator HyperDHT key and expose a request/response forwarder.\n *\n * Requests run on a pool of up to `maxStreams` streams to the operator, one request per\n * stream at a time (see `createTunnelPool`). The framing has no request ids, so a request\n * that is abandoned mid-flight (timeout, abort, or error) destroys its stream; the next\n * request on that stream opens a new one.\n */\nexport async function createTunnelSession(options: TunnelSessionOptions): Promise<TunnelSession> {\n const remotePublicKey = decodePublicKey(options.key)\n const clientKey = createEphemeralClientKeypair()\n const connectTimeoutMs = options.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS\n\n const dht = new HyperDHT()\n\n // Without a `pool` option, each connect is its own handshake and encrypted stream.\n const openStream = () =>\n new Promise<Duplex>((resolve, reject) => {\n const socket = dht.connect(remotePublicKey, {\n keyPair: { publicKey: clientKey.publicKey, secretKey: clientKey.secretKey },\n }) as Duplex\n let settled = false\n const timer =\n connectTimeoutMs > 0\n ? setTimeout(() => fail(new TunnelConnectTimeoutError(connectTimeoutMs)), connectTimeoutMs)\n : null\n const fail = (err: Error) => {\n if (settled) return\n settled = true\n if (timer) clearTimeout(timer)\n socket.destroy()\n reject(err)\n }\n const onReady = () => {\n if (settled) return\n settled = true\n if (timer) clearTimeout(timer)\n resolve(socket)\n }\n // Keep a listener for the socket's whole life so a late error never goes unhandled;\n // the frame reader sees errors through its own listener.\n socket.on('error', (err: Error) => fail(err))\n socket.once('close', () => fail(new Error('Tunnel connection closed before it opened')))\n socket.once('open', onReady)\n socket.once('connect', onReady)\n })\n\n const pool = createTunnelPool(openStream, {\n maxStreams: options.maxStreams,\n requestTimeoutMs: options.requestTimeoutMs,\n })\n const { runOnTunnel } = pool\n\n const forwardHttp = async (\n meta: TunnelMeta,\n body: Buffer,\n opts?: TunnelRequestOptions,\n ): Promise<{ meta: TunnelResponseMeta; body: Buffer }> => {\n return runOnTunnel(async (socket) => {\n await writeTunnelRequest(socket, meta, body)\n return readTunnelResponse(socket)\n }, opts)\n }\n\n return {\n key: options.key,\n runOnTunnel,\n forwardHttp,\n close: async () => {\n pool.close()\n await dht.destroy()\n },\n }\n}\n","import http from 'node:http'\nimport { forwardNodeRequest } from './forward'\nimport { createTunnelSession } from './session'\nimport type { ConnectTunnelOptions, ConnectTunnelResult } from '../types'\n\n/**\n * Client: dial operator key and expose a localhost HTTP server that forwards through the tunnel.\n */\nexport async function connectTunnel(options: ConnectTunnelOptions): Promise<ConnectTunnelResult> {\n const host = options.host ?? '127.0.0.1'\n const port = options.port ?? 1984\n\n const session = await createTunnelSession({\n key: options.key,\n storePath: options.storePath,\n requestTimeoutMs: options.requestTimeoutMs,\n connectTimeoutMs: options.connectTimeoutMs,\n maxStreams: options.maxStreams,\n })\n\n const server = http.createServer((req, res) => {\n void forwardNodeRequest(session, req, res, '')\n })\n\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject)\n server.listen(port, host, () => resolve())\n })\n\n const address = server.address()\n const boundPort =\n address && typeof address === 'object' ? address.port : port\n\n const baseUrl = `http://${host}:${boundPort}`\n\n return {\n key: options.key,\n host,\n port: boundPort,\n baseUrl,\n close: async () => {\n await new Promise<void>((resolve) => server.close(() => resolve()))\n await session.close()\n },\n }\n}\n\nexport function localGatewayUrl(baseUrl: string, path = ''): string {\n const base = baseUrl.replace(/\\/$/, '')\n if (!path) return base\n return path.startsWith('/') ? `${base}${path}` : `${base}/${path}`\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http'\nimport { createTunnelSession, type TunnelSession } from './session'\nimport { forwardFetchRequest, forwardNodeRequest } from './forward'\nimport type { CreateGatewayProxyOptions, GatewayProxy } from '../types'\n\nfunction resolveProxyKey(options: CreateGatewayProxyOptions): string {\n const key =\n options.key?.trim() ||\n (typeof process !== 'undefined' ? process.env.SEED_GATEWAY_HYPER_KEY?.trim() : '') ||\n ''\n if (!key) {\n throw new Error(\n 'createGatewayProxy requires options.key or SEED_GATEWAY_HYPER_KEY environment variable',\n )\n }\n return key\n}\n\n/**\n * App-server Hyper gateway proxy for hosted web apps (Path B).\n *\n * Mount on a Node route (Next.js Node runtime, Express, etc.). Keep the operator\n * Hyper key on the server only — browsers talk HTTP to `proxyBaseUrl`.\n *\n * Prefer Node.js over Bun for Holepunch natives.\n */\nexport function createGatewayProxy(options: CreateGatewayProxyOptions = {}): GatewayProxy {\n const mountPath = options.mountPath?.trim() || '/api/seed-gateway'\n const key = resolveProxyKey(options)\n\n let session: TunnelSession | null = null\n let starting: Promise<TunnelSession> | null = null\n\n const ensureSession = async (): Promise<TunnelSession> => {\n if (session) return session\n if (starting) return starting\n starting = createTunnelSession({\n key,\n storePath: options.storePath,\n requestTimeoutMs: options.requestTimeoutMs,\n connectTimeoutMs: options.connectTimeoutMs,\n maxStreams: options.maxStreams,\n }).then((s) => {\n session = s\n starting = null\n return s\n })\n try {\n return await starting\n } catch (err) {\n starting = null\n throw err\n }\n }\n\n const proxy: GatewayProxy = {\n mountPath,\n start: async () => {\n await ensureSession()\n },\n close: async () => {\n if (starting) {\n try {\n await starting\n } catch {\n /* ignore start failure during close */\n }\n }\n if (session) {\n await session.close()\n session = null\n }\n },\n handleNode: (req: IncomingMessage, res: ServerResponse) => {\n void (async () => {\n try {\n const s = await ensureSession()\n await forwardNodeRequest(s, req, res, mountPath)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n if (!res.headersSent) {\n res.writeHead(502, { 'Content-Type': 'text/plain; charset=utf-8' })\n }\n res.end(`Gateway Hyper tunnel error: ${message}`)\n }\n })()\n },\n handleFetch: async (request: Request): Promise<Response> => {\n try {\n const s = await ensureSession()\n return await forwardFetchRequest(s, request, mountPath)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n return new Response(`Gateway Hyper tunnel error: ${message}`, {\n status: 502,\n headers: { 'Content-Type': 'text/plain; charset=utf-8' },\n })\n }\n },\n }\n\n if (options.eager) {\n void proxy.start().catch(() => {\n /* first request will surface the error */\n })\n }\n\n return proxy\n}\n","/**\n * Official Seed Protocol gateway Hyper tunnel operator key (z32).\n * Empty until ops generate and back up the first operator keypair.\n * Also defined in packages/arweave/src/constants.ts; keep both equal (gateway-hyper __tests__/constants.test.ts checks).\n */\nexport const DEFAULT_SEED_GATEWAY_HYPER_KEY = ''\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../../src/tunnel/connect.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AA0CzE;;GAEG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAgC/F;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,SAAK,GAAG,MAAM,CAIlE"}
1
+ {"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../../src/tunnel/connect.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAEzE;;GAEG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAqC/F;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,SAAK,GAAG,MAAM,CAIlE"}
@@ -0,0 +1,19 @@
1
+ /** Client side: the tunnel stream was idle longer than `requestTimeoutMs`, so the request was abandoned. */
2
+ export declare class TunnelTimeoutError extends Error {
3
+ readonly timeoutMs: number;
4
+ readonly code = "TUNNEL_TIMEOUT";
5
+ constructor(timeoutMs: number);
6
+ }
7
+ /** Client side: the HyperDHT connection to the operator did not open within `connectTimeoutMs`. */
8
+ export declare class TunnelConnectTimeoutError extends Error {
9
+ readonly timeoutMs: number;
10
+ readonly code = "TUNNEL_CONNECT_TIMEOUT";
11
+ constructor(timeoutMs: number);
12
+ }
13
+ /** Operator side: the upstream socket was idle longer than `upstreamTimeoutMs`. */
14
+ export declare class UpstreamTimeoutError extends Error {
15
+ readonly timeoutMs: number;
16
+ readonly code = "UPSTREAM_TIMEOUT";
17
+ constructor(timeoutMs: number);
18
+ }
19
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/tunnel/errors.ts"],"names":[],"mappings":"AAAA,4GAA4G;AAC5G,qBAAa,kBAAmB,SAAQ,KAAK;IAG/B,QAAQ,CAAC,SAAS,EAAE,MAAM;IAFtC,QAAQ,CAAC,IAAI,oBAAmB;gBAEX,SAAS,EAAE,MAAM;CAIvC;AAED,mGAAmG;AACnG,qBAAa,yBAA0B,SAAQ,KAAK;IAGtC,QAAQ,CAAC,SAAS,EAAE,MAAM;IAFtC,QAAQ,CAAC,IAAI,4BAA2B;gBAEnB,SAAS,EAAE,MAAM;CAIvC;AAED,mFAAmF;AACnF,qBAAa,oBAAqB,SAAQ,KAAK;IAGjC,QAAQ,CAAC,SAAS,EAAE,MAAM;IAFtC,QAAQ,CAAC,IAAI,sBAAqB;gBAEb,SAAS,EAAE,MAAM;CAIvC"}
@@ -1 +1 @@
1
- {"version":3,"file":"forward.d.ts","sourceRoot":"","sources":["../../src/tunnel/forward.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAMhE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAW9C,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,aAAa,EACtB,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAkBf;AAWD,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,QAAQ,CAAC,CA0BnB"}
1
+ {"version":3,"file":"forward.d.ts","sourceRoot":"","sources":["../../src/tunnel/forward.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAOhE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAqB9C,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,aAAa,EACtB,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CA4Bf;AAWD,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,QAAQ,CAAC,CA2BnB"}
@@ -2,6 +2,8 @@ import type { Readable, Writable } from 'node:stream';
2
2
  import type { TunnelMeta, TunnelResponseMeta } from '../types';
3
3
  /** Maximum single frame payload (64 MiB). */
4
4
  export declare const MAX_FRAME_BYTES: number;
5
+ /** Largest single stream write. Secret-stream's limit is 16 MiB - 1. */
6
+ export declare const WRITE_CHUNK_BYTES: number;
5
7
  export declare function writeFrame(stream: Writable, payload: Buffer): Promise<void>;
6
8
  export declare function readFrame(stream: Readable): Promise<Buffer>;
7
9
  export declare function writeTunnelRequest(stream: Writable, meta: TunnelMeta, body: Buffer): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/tunnel/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAE9D,6CAA6C;AAC7C,eAAO,MAAM,eAAe,QAAmB,CAAA;AAyH/C,wBAAsB,UAAU,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQjF;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAUjE;AAED,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,QAAQ,EAChB,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAIf;AAED,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,QAAQ,GACf,OAAO,CAAC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAS7C;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,QAAQ,EAChB,IAAI,EAAE,kBAAkB,EACxB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAIf;AAED,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,QAAQ,GACf,OAAO,CAAC;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CASrD;AAED,+DAA+D;AAC/D,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GACrD,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAOxB;AAED,sEAAsE;AACtE,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GACrD,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAcxB"}
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/tunnel/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAE9D,6CAA6C;AAC7C,eAAO,MAAM,eAAe,QAAmB,CAAA;AAE/C,wEAAwE;AACxE,eAAO,MAAM,iBAAiB,QAAc,CAAA;AAqI5C,wBAAsB,UAAU,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWjF;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAQjE;AAED,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,QAAQ,EAChB,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAMf;AAED,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,QAAQ,GACf,OAAO,CAAC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAS7C;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,QAAQ,EAChB,IAAI,EAAE,kBAAkB,EACxB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAMf;AAED,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,QAAQ,GACf,OAAO,CAAC;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CASrD;AAED,+DAA+D;AAC/D,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GACrD,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAOxB;AAED,sEAAsE;AACtE,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GACrD,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAcxB"}
@@ -1,5 +1,19 @@
1
1
  import type { TunnelMeta } from '../types';
2
- export declare function proxyTunnelRequest(upstreamBase: string, meta: TunnelMeta, body: Buffer): Promise<{
2
+ /** Default idle limit on the operator's upstream socket. */
3
+ export declare const DEFAULT_UPSTREAM_TIMEOUT_MS = 30000;
4
+ export type ProxyTunnelRequestOptions = {
5
+ /** Fail with `UpstreamTimeoutError` once the upstream socket is idle this long. 0 disables. */
6
+ timeoutMs?: number;
7
+ /** Abort the upstream request, e.g. when the tunnel stream closes. */
8
+ signal?: AbortSignal;
9
+ };
10
+ /**
11
+ * Drop hop-by-hop headers and the client's `host`, which names the app server rather than
12
+ * the upstream; it is passed on as `x-forwarded-host`. `content-length` is dropped because
13
+ * Node sets it from the buffered body.
14
+ */
15
+ export declare function upstreamRequestHeaders(headers: Record<string, string>): Record<string, string>;
16
+ export declare function proxyTunnelRequest(upstreamBase: string, meta: TunnelMeta, body: Buffer, options?: ProxyTunnelRequestOptions): Promise<{
3
17
  status: number;
4
18
  headers: Record<string, string>;
5
19
  body: Buffer;
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/tunnel/proxy.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAE1C,wBAAsB,kBAAkB,CACtC,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CA8B5E"}
1
+ {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/tunnel/proxy.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAE1C,4DAA4D;AAC5D,eAAO,MAAM,2BAA2B,QAAS,CAAA;AAEjD,MAAM,MAAM,yBAAyB,GAAG;IACtC,+FAA+F;IAC/F,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sEAAsE;IACtE,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,CAAA;AAaD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAsB9F;AAED,wBAAsB,kBAAkB,CACtC,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CA8C5E"}
@@ -1 +1 @@
1
- {"version":3,"file":"proxyApp.d.ts","sourceRoot":"","sources":["../../src/tunnel/proxyApp.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,yBAAyB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAevE;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,yBAA8B,GAAG,YAAY,CA4ExF"}
1
+ {"version":3,"file":"proxyApp.d.ts","sourceRoot":"","sources":["../../src/tunnel/proxyApp.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,yBAAyB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAevE;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,yBAA8B,GAAG,YAAY,CAkFxF"}
@@ -1,4 +1,15 @@
1
+ import type { Duplex } from 'node:stream';
1
2
  import type { ServeTunnelOptions, ServeTunnelResult } from '../types';
3
+ export type TunnelConnectionOptions = {
4
+ /** Idle limit on each upstream request. Default 30 000; 0 disables. */
5
+ upstreamTimeoutMs?: number;
6
+ };
7
+ /**
8
+ * Answer framed requests on one tunnel stream, in order, until it closes. Upstream timeouts
9
+ * become 504 and other upstream failures 502, so the stream stays usable; only a broken
10
+ * stream ends the loop. The stream ending or closing aborts the upstream request in flight.
11
+ */
12
+ export declare function serveTunnelConnection(socket: Duplex, upstream: string, options?: TunnelConnectionOptions): Promise<void>;
2
13
  /**
3
14
  * Operator: accept Hyperswarm/DHT connections and proxy framed HTTP to upstream Traefik.
4
15
  */
@@ -1 +1 @@
1
- {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/tunnel/serve.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AA0BrE;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAoBzF"}
1
+ {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/tunnel/serve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAMzC,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAErE,MAAM,MAAM,uBAAuB,GAAG;IACpC,uEAAuE;IACvE,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B,CAAA;AAaD;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,IAAI,CAAC,CAoCf;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAsBzF"}
@@ -1,22 +1,82 @@
1
1
  import type { Duplex } from 'node:stream';
2
2
  import type { TunnelMeta, TunnelResponseMeta } from '../types';
3
+ /** Default idle limit for one request on the tunnel stream. */
4
+ export declare const DEFAULT_REQUEST_TIMEOUT_MS = 60000;
5
+ /** Default limit for opening the HyperDHT connection. */
6
+ export declare const DEFAULT_CONNECT_TIMEOUT_MS = 30000;
7
+ /**
8
+ * Default number of streams a session opens to the operator. Streams open only when every
9
+ * open one is busy, and each costs a DHT lookup and handshake plus an upstream request on
10
+ * the operator, so a small pool keeps that cost down. Four leaves room for a page's burst of
11
+ * gateway reads after one or two requests hang until their timeout.
12
+ */
13
+ export declare const DEFAULT_MAX_STREAMS = 4;
3
14
  export type TunnelSessionOptions = {
4
15
  /** Operator public key (z32 or hex) */
5
16
  key: string;
6
17
  /** Optional store path for DHT client state */
7
18
  storePath?: string;
19
+ /**
20
+ * Abandon a request once the stream has sent and received nothing for this long, then
21
+ * reconnect for the next request. Counts from when the request gets a stream.
22
+ * Default 60 000; 0 disables.
23
+ */
24
+ requestTimeoutMs?: number;
25
+ /** Give up opening the HyperDHT connection after this long. Default 30 000; 0 disables. */
26
+ connectTimeoutMs?: number;
27
+ /**
28
+ * Most HyperDHT streams open to the operator at once; each carries one request at a time.
29
+ * Default 4.
30
+ */
31
+ maxStreams?: number;
32
+ };
33
+ export type TunnelRequestOptions = {
34
+ /** Aborting rejects the request; if it is already on the stream, the stream is destroyed. */
35
+ signal?: AbortSignal;
36
+ /** Overrides the session's `requestTimeoutMs` for this request. */
37
+ timeoutMs?: number;
8
38
  };
9
39
  export type TunnelSession = {
10
40
  key: string;
11
- runOnTunnel: <T>(fn: (socket: Duplex) => Promise<T>) => Promise<T>;
12
- forwardHttp: (meta: TunnelMeta, body: Buffer) => Promise<{
41
+ runOnTunnel: <T>(fn: (socket: Duplex) => Promise<T>, options?: TunnelRequestOptions) => Promise<T>;
42
+ forwardHttp: (meta: TunnelMeta, body: Buffer, options?: TunnelRequestOptions) => Promise<{
13
43
  meta: TunnelResponseMeta;
14
44
  body: Buffer;
15
45
  }>;
16
46
  close: () => Promise<void>;
17
47
  };
18
48
  /**
19
- * Dial the operator HyperDHT key and expose a serialized request/response forwarder.
49
+ * Serialize transactions on the socket `getSocket` returns. Each runs under an idle timeout
50
+ * and an optional abort signal; one that is abandoned or fails destroys the socket, so
51
+ * `getSocket` must open a new one once the current one is destroyed.
52
+ */
53
+ export declare function createTunnelQueue(getSocket: () => Promise<Duplex>, requestTimeoutMs?: number): TunnelSession['runOnTunnel'];
54
+ export type TunnelPoolOptions = {
55
+ /** Most streams open at once. Default `DEFAULT_MAX_STREAMS`. */
56
+ maxStreams?: number;
57
+ /** Idle limit for each request, as in `createTunnelQueue`. */
58
+ requestTimeoutMs?: number;
59
+ };
60
+ export type TunnelPool = {
61
+ runOnTunnel: TunnelSession['runOnTunnel'];
62
+ /** Reject queued requests and destroy every stream. */
63
+ close: () => void;
64
+ };
65
+ /**
66
+ * Run each transaction alone on one of up to `maxStreams` sockets from `openStream`. A request
67
+ * takes an idle open stream if there is one, else opens a new stream while fewer than
68
+ * `maxStreams` exist, else waits for the first stream to come free. Each stream is a
69
+ * `createTunnelQueue`, so a request that is abandoned destroys only its own stream, and that
70
+ * stream reopens for the next request it takes.
71
+ */
72
+ export declare function createTunnelPool(openStream: () => Promise<Duplex>, options?: TunnelPoolOptions): TunnelPool;
73
+ /**
74
+ * Dial the operator HyperDHT key and expose a request/response forwarder.
75
+ *
76
+ * Requests run on a pool of up to `maxStreams` streams to the operator, one request per
77
+ * stream at a time (see `createTunnelPool`). The framing has no request ids, so a request
78
+ * that is abandoned mid-flight (timeout, abort, or error) destroys its stream; the next
79
+ * request on that stream opens a new one.
20
80
  */
21
81
  export declare function createTunnelSession(options: TunnelSessionOptions): Promise<TunnelSession>;
22
82
  //# sourceMappingURL=session.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/tunnel/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGzC,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAG9D,MAAM,MAAM,oBAAoB,GAAG;IACjC,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAA;IACX,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,EAAE,MAAM,CAAA;IACX,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAA;IAClE,WAAW,EAAE,CACX,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,MAAM,KACT,OAAO,CAAC;QAAE,IAAI,EAAE,kBAAkB,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACxD,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3B,CAAA;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,aAAa,CAAC,CA+D/F"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/tunnel/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGzC,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAI9D,+DAA+D;AAC/D,eAAO,MAAM,0BAA0B,QAAS,CAAA;AAEhD,yDAAyD;AACzD,eAAO,MAAM,0BAA0B,QAAS,CAAA;AAEhD;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,IAAI,CAAA;AAEpC,MAAM,MAAM,oBAAoB,GAAG;IACjC,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAA;IACX,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,2FAA2F;IAC3F,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,6FAA6F;IAC7F,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,EAAE,MAAM,CAAA;IACX,WAAW,EAAE,CAAC,CAAC,EACb,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,EAClC,OAAO,CAAC,EAAE,oBAAoB,KAC3B,OAAO,CAAC,CAAC,CAAC,CAAA;IACf,WAAW,EAAE,CACX,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,oBAAoB,KAC3B,OAAO,CAAC;QAAE,IAAI,EAAE,kBAAkB,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACxD,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3B,CAAA;AA6BD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,EAChC,gBAAgB,GAAE,MAAmC,GACpD,aAAa,CAAC,aAAa,CAAC,CA2D9B;AAaD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,gEAAgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,8DAA8D;IAC9D,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,WAAW,EAAE,aAAa,CAAC,aAAa,CAAC,CAAA;IACzC,uDAAuD;IACvD,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB,CAAA;AAMD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,EACjC,OAAO,GAAE,iBAAsB,GAC9B,UAAU,CAyFZ;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,aAAa,CAAC,CAiE/F"}
package/dist/types.d.ts CHANGED
@@ -14,6 +14,11 @@ export type ServeTunnelOptions = {
14
14
  keyFile?: string;
15
15
  /** Directory for DHT state (optional, in-memory if unset) */
16
16
  storePath?: string;
17
+ /**
18
+ * Answer 504 once the upstream socket has been idle this long, waiting for headers or
19
+ * body. Default 30 000; 0 disables.
20
+ */
21
+ upstreamTimeoutMs?: number;
17
22
  };
18
23
  export type ServeTunnelResult = {
19
24
  /** Operator public key (z32) */
@@ -30,6 +35,19 @@ export type ConnectTunnelOptions = {
30
35
  port?: number;
31
36
  /** Optional store path for DHT client state */
32
37
  storePath?: string;
38
+ /**
39
+ * Abandon a request once the tunnel stream has sent and received nothing for this long,
40
+ * answer 504, and reconnect for the next request. Keep it above the operator's
41
+ * `upstreamTimeoutMs` so the operator's own 504 arrives first. Default 60 000; 0 disables.
42
+ */
43
+ requestTimeoutMs?: number;
44
+ /** Give up opening the HyperDHT connection after this long. Default 30 000; 0 disables. */
45
+ connectTimeoutMs?: number;
46
+ /**
47
+ * Most HyperDHT streams open to the operator at once. Each carries one request at a time,
48
+ * so a slow request holds up only its own stream. Default 4.
49
+ */
50
+ maxStreams?: number;
33
51
  };
34
52
  export type ConnectTunnelResult = {
35
53
  key: string;
@@ -58,6 +76,19 @@ export type CreateGatewayProxyOptions = {
58
76
  storePath?: string;
59
77
  /** Start the Hyper session immediately (default: lazy on first request) */
60
78
  eager?: boolean;
79
+ /**
80
+ * Abandon a request once the tunnel stream has sent and received nothing for this long,
81
+ * answer 504, and reconnect for the next request. Keep it above the operator's
82
+ * `upstreamTimeoutMs` so the operator's own 504 arrives first. Default 60 000; 0 disables.
83
+ */
84
+ requestTimeoutMs?: number;
85
+ /** Give up opening the HyperDHT connection after this long. Default 30 000; 0 disables. */
86
+ connectTimeoutMs?: number;
87
+ /**
88
+ * Most HyperDHT streams open to the operator at once. Each carries one request at a time,
89
+ * so a slow request holds up only its own stream. Default 4.
90
+ */
91
+ maxStreams?: number;
61
92
  };
62
93
  export type GatewayProxy = {
63
94
  mountPath: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAChC,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAChC,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAA;IAChB,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,6DAA6D;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,gCAAgC;IAChC,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAA;IACX,2BAA2B;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,2BAA2B;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,GAAG,EAAE,MAAM,CAAA;CACZ,CAAA;AAED,MAAM,MAAM,yBAAyB,GAAG;IACtC;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,2EAA2E;IAC3E,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,mDAAmD;IACnD,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1B,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1B,0CAA0C;IAC1C,UAAU,EAAE,CAAC,GAAG,EAAE,OAAO,WAAW,EAAE,eAAe,EAAE,GAAG,EAAE,OAAO,WAAW,EAAE,cAAc,KAAK,IAAI,CAAA;IACvG;;;OAGG;IACH,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;CACrD,CAAA"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAChC,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAChC,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAA;IAChB,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,6DAA6D;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,gCAAgC;IAChC,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAA;IACX,2BAA2B;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,2BAA2B;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,2FAA2F;IAC3F,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,GAAG,EAAE,MAAM,CAAA;CACZ,CAAA;AAED,MAAM,MAAM,yBAAyB,GAAG;IACtC;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,2EAA2E;IAC3E,KAAK,CAAC,EAAE,OAAO,CAAA;IACf;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,2FAA2F;IAC3F,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,mDAAmD;IACnD,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1B,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1B,0CAA0C;IAC1C,UAAU,EAAE,CAAC,GAAG,EAAE,OAAO,WAAW,EAAE,eAAe,EAAE,GAAG,EAAE,OAAO,WAAW,EAAE,cAAc,KAAK,IAAI,CAAA;IACvG;;;OAGG;IACH,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;CACrD,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seedprotocol/gateway-hyper",
3
- "version": "0.7.5",
3
+ "version": "0.7.6-next.957.g6bb7768",
4
4
  "description": "HyperDHT HTTP tunnel that exposes a Seed Protocol gateway and upload API through a local sidecar or app-server proxy",
5
5
  "keywords": [
6
6
  "seed-protocol",