@opengeni/network 0.2.3 → 0.3.0-canary.1

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.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/json-base64.ts"],"sourcesContent":["// The explicit entrypoint avoids Bun's native `undici` compatibility shim,\n// which exposes an Agent-shaped object without Dispatcher methods.\nimport { Agent, fetch as undiciFetchImpl, request as undiciRequestImpl } from \"undici/index.js\";\nimport { lookup as nodeLookup } from \"node:dns/promises\";\nimport { isIP } from \"node:net\";\n\nexport * from \"./json-base64\";\n\nexport type FetchLike = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;\n\nexport type DnsAddress = {\n address: string;\n family: 4 | 6;\n};\n\nexport type DnsLookup = (hostname: string) => Promise<readonly DnsAddress[]>;\n\nexport type OutboundNetworkSettings = {\n environment: string;\n integrationsAllowPrivateNetworkTargets: boolean;\n};\n\nexport type PinnedDestination = {\n url: URL;\n hostname: string;\n addresses: readonly DnsAddress[];\n};\n\nexport type DispatcherLifecycle = {\n /** The raw dispatcher handed to fetch; omitted for test-only lifecycle fakes. */\n dispatcher?: unknown;\n close: () => Promise<void> | void;\n destroy: (error?: unknown) => Promise<void> | void;\n};\n\nexport type PinnedFetchOptions = {\n fetchImpl?: FetchLike;\n dnsLookup?: DnsLookup;\n agentFactory?: (addresses: readonly DnsAddress[]) => DispatcherLifecycle;\n label?: string;\n requireHttpsOutsideLocalTest?: boolean;\n};\n\nconst DISPATCHER_CLOSE_TIMEOUT_MS = 100;\n\nexport const OAUTH_MAX_RESPONSE_BYTES = 1024 * 1024;\n\nexport type HttpUrlValidationOptions = {\n allowLoopbackHttp?: boolean;\n label?: string;\n};\n\n/** Validate a protocol endpoint before it is persisted, returned, or opened. */\nexport function validateHttpUrl(rawUrl: string, options: HttpUrlValidationOptions = {}): string {\n const label = options.label ?? \"HTTP endpoint\";\n let url: URL;\n try {\n url = new URL(rawUrl);\n } catch {\n throw new DestinationPolicyError(\"invalid_url\", `${label} URL is invalid`);\n }\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n throw new DestinationPolicyError(\n \"unsupported_protocol\",\n `${label} only supports http and https URLs`,\n );\n }\n if (url.username || url.password) {\n throw new DestinationPolicyError(\"invalid_url\", `${label} URL may not contain credentials`);\n }\n if (url.hash) {\n throw new DestinationPolicyError(\"invalid_url\", `${label} URL may not contain a fragment`);\n }\n if (\n url.protocol === \"http:\" &&\n !(options.allowLoopbackHttp && isLoopbackHostname(url.hostname))\n ) {\n throw new DestinationPolicyError(\"https_required\", `${label} must use https`);\n }\n return url.toString();\n}\n\n/**\n * Raised when a response cannot be safely consumed within its caller's byte\n * budget. The error intentionally contains no response bytes or provider\n * message: these readers are used on credential-bearing paths.\n */\nexport class ResponseBodyLimitError extends Error {\n constructor(\n readonly label: string,\n readonly actualBytes: number,\n readonly maxBytes: number,\n readonly reason: \"declared_length\" | \"stream_overflow\" | \"invalid_content_length\",\n ) {\n super(`${label} exceeded its ${maxBytes}-byte response limit`);\n this.name = \"ResponseBodyLimitError\";\n }\n}\n\n/** Raised when a caller-supplied absolute request deadline expires. */\nexport class RequestDeadlineError extends Error {\n constructor(readonly label: string) {\n super(`${label} timed out`);\n this.name = \"RequestDeadlineError\";\n }\n}\n\nexport type BoundedResponseReadOptions = {\n signal?: AbortSignal;\n};\n\n/**\n * Read a response through its stream with a hard byte ceiling.\n *\n * A declared Content-Length above the ceiling is rejected before reading. A\n * body exactly at the ceiling is accepted; the first byte beyond it cancels\n * the stream and rejects. Cancellation is important because pinnedFetch owns a\n * per-response dispatcher which must be closed on every exit path.\n */\nexport async function readResponseBodyBounded(\n response: Response,\n maxBytes: number,\n label: string,\n options: BoundedResponseReadOptions = {},\n): Promise<Uint8Array> {\n if (!Number.isSafeInteger(maxBytes) || maxBytes < 0) {\n throw new RangeError(\"response body limit must be a non-negative safe integer\");\n }\n const declared = response.headers.get(\"content-length\");\n if (declared !== null) {\n const normalized = declared.trim();\n if (!/^\\d+$/.test(normalized)) {\n await cancelResponse(response);\n throw new ResponseBodyLimitError(label, 0, maxBytes, \"invalid_content_length\");\n }\n const declaredBytes = Number(normalized);\n if (!Number.isSafeInteger(declaredBytes) || declaredBytes > maxBytes) {\n await cancelResponse(response);\n throw new ResponseBodyLimitError(label, declaredBytes, maxBytes, \"declared_length\");\n }\n }\n if (!response.body) {\n return new Uint8Array();\n }\n\n const reader = response.body.getReader();\n const chunks: Uint8Array[] = [];\n let receivedBytes = 0;\n try {\n for (;;) {\n const result = await readStreamChunk(reader, options.signal, label);\n if (result.done) {\n break;\n }\n receivedBytes += result.value.byteLength;\n if (receivedBytes > maxBytes) {\n await reader.cancel().catch(() => undefined);\n throw new ResponseBodyLimitError(label, receivedBytes, maxBytes, \"stream_overflow\");\n }\n chunks.push(result.value);\n }\n } catch (error) {\n void reader.cancel(error).catch(() => undefined);\n throw error;\n } finally {\n try {\n reader.releaseLock();\n } catch {\n // An aborted read may still own the lock until the underlying transport\n // observes cancellation. The response is already being cancelled above.\n }\n }\n\n const body = new Uint8Array(receivedBytes);\n let offset = 0;\n for (const chunk of chunks) {\n body.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return body;\n}\n\nexport async function readResponseTextBounded(\n response: Response,\n maxBytes: number,\n label: string,\n options: BoundedResponseReadOptions = {},\n): Promise<string> {\n return new TextDecoder().decode(\n await readResponseBodyBounded(response, maxBytes, label, options),\n );\n}\n\nexport async function readResponseJsonBounded<T = unknown>(\n response: Response,\n maxBytes: number,\n label: string,\n options: BoundedResponseReadOptions = {},\n): Promise<T> {\n return JSON.parse(await readResponseTextBounded(response, maxBytes, label, options)) as T;\n}\n\ntype ResponseStreamReadResult = Awaited<\n ReturnType<ReadableStreamDefaultReader<Uint8Array>[\"read\"]>\n>;\n\nasync function readStreamChunk(\n reader: ReadableStreamDefaultReader<Uint8Array>,\n signal: AbortSignal | undefined,\n label: string,\n): Promise<ResponseStreamReadResult> {\n if (!signal) return await reader.read();\n if (signal.aborted) throw new RequestDeadlineError(label);\n return await new Promise<ResponseStreamReadResult>((resolve, reject) => {\n let settled = false;\n const finish = (callback: () => void) => {\n if (settled) return;\n settled = true;\n signal.removeEventListener(\"abort\", onAbort);\n callback();\n };\n const onAbort = () => {\n const error = new RequestDeadlineError(label);\n void reader.cancel(error).catch(() => undefined);\n finish(() => reject(error));\n };\n signal.addEventListener(\"abort\", onAbort, { once: true });\n void reader.read().then(\n (result) => finish(() => resolve(result)),\n (error) => finish(() => reject(error)),\n );\n });\n}\n\nexport type ResolvePinnedDestinationOptions = {\n dnsLookup?: DnsLookup;\n label?: string;\n requireHttpsOutsideLocalTest?: boolean;\n};\n\nexport type DestinationPolicyReason =\n | \"invalid_url\"\n | \"unsupported_protocol\"\n | \"https_required\"\n | \"dns_failed\"\n | \"dns_empty\"\n | \"invalid_dns_answer\"\n | \"private_or_special_use\";\n\nexport class DestinationPolicyError extends Error {\n constructor(\n readonly reason: DestinationPolicyReason,\n message: string,\n ) {\n super(message);\n this.name = \"DestinationPolicyError\";\n }\n}\n\nconst defaultDnsLookup: DnsLookup = async (hostname) => {\n const answers = await nodeLookup(hostname, { all: true });\n return answers.map((entry) => normalizeDnsAnswer(entry));\n};\n\nconst defaultFetch: FetchLike = (input, init) =>\n (undiciFetchImpl as unknown as FetchLike)(input, init);\n\nconst pinnedRequestFetch: FetchLike = async (input, init) => {\n const source = input instanceof Request ? input : null;\n const url = source?.url ?? input.toString();\n const method = init?.method ?? source?.method ?? \"GET\";\n const headers = new Headers(source?.headers);\n if (init?.headers) {\n new Headers(init.headers).forEach((value, name) => headers.set(name, value));\n }\n // Undici request() deliberately does not auto-decompress. Asking providers\n // for identity encoding keeps the returned web Response body truthful.\n if (!headers.has(\"accept-encoding\")) headers.set(\"accept-encoding\", \"identity\");\n const rawBody = init?.body ?? (method !== \"GET\" && method !== \"HEAD\" ? source?.body : undefined);\n const body = await normalizeUndiciRequestBody(rawBody, headers);\n const dispatcher = (init as (RequestInit & { dispatcher?: unknown }) | undefined)?.dispatcher;\n const result = await undiciRequestImpl(url, {\n method: method as never,\n headers,\n ...(body !== undefined && body !== null ? { body: body as never } : {}),\n ...(init?.signal ? { signal: init.signal } : source?.signal ? { signal: source.signal } : {}),\n ...(dispatcher ? { dispatcher: dispatcher as never } : {}),\n maxRedirections: 0,\n });\n const iterator = result.body[Symbol.asyncIterator]();\n const responseBody = new ReadableStream<Uint8Array>({\n async pull(controller) {\n try {\n const chunk = await iterator.next();\n if (chunk.done) {\n controller.close();\n return;\n }\n controller.enqueue(\n chunk.value instanceof Uint8Array ? chunk.value : new Uint8Array(chunk.value),\n );\n } catch (error) {\n controller.error(error);\n }\n },\n async cancel(reason) {\n result.body.destroy(reason instanceof Error ? reason : undefined);\n await iterator.return?.();\n },\n });\n const responseHeaders = new Headers();\n for (const [name, value] of Object.entries(result.headers)) {\n if (Array.isArray(value)) {\n for (const entry of value) appendWebCompatibleResponseHeader(responseHeaders, name, entry);\n } else if (value !== undefined) {\n appendWebCompatibleResponseHeader(responseHeaders, name, value, true);\n }\n }\n const response = new Response(responseBody, {\n status: result.statusCode,\n headers: responseHeaders,\n });\n Object.defineProperty(response, \"url\", { value: url });\n return response;\n};\n\n/**\n * Undici's low-level request API preserves response-header values that the\n * Fetch `Headers` implementation may reject (for example, UTF-8 object-store\n * lifecycle metadata). Such an unrelated extension header must not discard a\n * valid response body. Omit only the unrepresentable field; security and\n * framing headers remain subject to the same strict Fetch validation.\n */\nfunction appendWebCompatibleResponseHeader(\n headers: Headers,\n name: string,\n value: string,\n replace = false,\n): void {\n try {\n if (replace) headers.set(name, value);\n else headers.append(name, value);\n } catch (error) {\n if (!(error instanceof TypeError)) throw error;\n }\n}\n\n/**\n * Preserve Fetch BodyInit semantics for values that Undici request() does not\n * normalize itself. URLSearchParams is otherwise mistaken for an iterable of\n * body chunks and each [name, value] tuple reaches the socket as an Array.\n */\nasync function normalizeUndiciRequestBody(\n body: BodyInit | null | undefined,\n headers: Headers,\n): Promise<BodyInit | Uint8Array | null | undefined> {\n if (body instanceof URLSearchParams) {\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"application/x-www-form-urlencoded;charset=UTF-8\");\n }\n return body.toString();\n }\n if (body instanceof Blob) {\n if (body.type && !headers.has(\"content-type\")) headers.set(\"content-type\", body.type);\n return new Uint8Array(await body.arrayBuffer());\n }\n if (body instanceof ArrayBuffer) return new Uint8Array(body);\n if (ArrayBuffer.isView(body)) {\n return new Uint8Array(body.buffer, body.byteOffset, body.byteLength);\n }\n return body;\n}\n\n/** Undici fetch used by the pinned transport; Bun callers should prefer this over native fetch. */\nexport const undiciFetch: FetchLike = defaultFetch;\n\n/**\n * Resolve and policy-check one destination. The returned address set is the\n * complete DNS answer that the caller is allowed to use; the transport never\n * performs a second resolver call.\n */\nexport async function resolvePinnedDestination(\n rawUrl: string | URL,\n settings: OutboundNetworkSettings,\n options: ResolvePinnedDestinationOptions = {},\n): Promise<PinnedDestination> {\n const label = options.label ?? \"Outbound request\";\n let url: URL;\n try {\n url = new URL(rawUrl);\n } catch {\n throw new DestinationPolicyError(\"invalid_url\", `${label} URL is invalid`);\n }\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n throw new DestinationPolicyError(\n \"unsupported_protocol\",\n `${label} only supports http and https URLs`,\n );\n }\n const localTestEscape = isLocalTestEnvironment(settings.environment);\n if (options.requireHttpsOutsideLocalTest && !localTestEscape && url.protocol !== \"https:\") {\n throw new DestinationPolicyError(\n \"https_required\",\n `${label} must use https outside local/test`,\n );\n }\n\n const hostname = normalizeHostname(url.hostname);\n if (!hostname) {\n throw new DestinationPolicyError(\"invalid_url\", `${label} URL has no hostname`);\n }\n\n const literalFamily = isIP(hostname);\n let addresses: readonly DnsAddress[];\n try {\n addresses = literalFamily\n ? [{ address: hostname, family: literalFamily === 6 ? 6 : 4 }]\n : await (options.dnsLookup ?? defaultDnsLookup)(hostname);\n } catch (error) {\n if (error instanceof DestinationPolicyError && error.reason === \"invalid_dns_answer\") {\n throw error;\n }\n throw new DestinationPolicyError(\"dns_failed\", `${label} hostname could not be resolved`);\n }\n\n const normalizedAddresses = dedupeAddresses(addresses);\n if (normalizedAddresses.length === 0) {\n throw new DestinationPolicyError(\"dns_empty\", `${label} hostname has no addresses`);\n }\n if (normalizedAddresses.some((entry) => isInvalidAddress(entry.address))) {\n throw new DestinationPolicyError(\n \"invalid_dns_answer\",\n `${label} hostname returned an invalid address`,\n );\n }\n\n const privateEscape = localTestEscape || settings.integrationsAllowPrivateNetworkTargets === true;\n if (\n !privateEscape &&\n (isLocalHostname(hostname) ||\n normalizedAddresses.some((entry) => isNonPublicAddress(entry.address)))\n ) {\n throw new DestinationPolicyError(\n \"private_or_special_use\",\n `${label} may not target a private or special-use network address`,\n );\n }\n return { url, hostname, addresses: preferIpv4Addresses(normalizedAddresses) };\n}\n\n/**\n * Keep every vetted resolver answer pinned, but prefer IPv4 when both public\n * families are available. Docker hosts commonly advertise public IPv6 DNS\n * without an IPv6 egress route; selecting that answer first turns a healthy\n * dual-stack destination into a deterministic connection failure.\n */\nfunction preferIpv4Addresses(addresses: readonly DnsAddress[]): DnsAddress[] {\n return [\n ...addresses.filter((entry) => entry.family === 4),\n ...addresses.filter((entry) => entry.family === 6),\n ];\n}\n\n/**\n * Fetch through a dispatcher whose lookup is pinned to the result of exactly\n * one policy resolution. The response body owns the one-shot agent until\n * completion, cancellation, or stream failure.\n */\nexport async function pinnedFetch(\n input: string | URL | Request,\n init: RequestInit | undefined,\n settings: OutboundNetworkSettings,\n options: PinnedFetchOptions = {},\n): Promise<Response> {\n const rawUrl = input instanceof Request ? input.url : input;\n const destination = await resolvePinnedDestination(rawUrl, settings, options);\n const dispatcher =\n options.agentFactory?.(destination.addresses) ?? createPinnedAgent(destination.addresses);\n const fetchImpl = options.fetchImpl ?? pinnedRequestFetch;\n const fetchInit = {\n ...init,\n redirect: \"manual\" as const,\n dispatcher: dispatcher.dispatcher ?? dispatcher,\n } as RequestInit & { dispatcher: DispatcherLifecycle };\n let response: Response;\n try {\n response = await fetchImpl(input, fetchInit);\n } catch (error) {\n await destroyDispatcher(dispatcher, error);\n throw error;\n }\n if (!response.body) {\n await closeDispatcher(dispatcher, DISPATCHER_CLOSE_TIMEOUT_MS);\n return response;\n }\n return responseWithDispatcherLifecycle(response, dispatcher, DISPATCHER_CLOSE_TIMEOUT_MS);\n}\n\nexport function isLocalTestEnvironment(environment: string): boolean {\n return environment === \"local\" || environment === \"test\";\n}\n\n/** Return true for malformed, non-IPv4, and non-IPv6 address strings. */\nexport function isInvalidAddress(address: string): boolean {\n return isIP(stripAddressBrackets(address.trim())) === 0;\n}\n\n/**\n * Classify private, reserved, documentation, benchmark, multicast, and other\n * special-use answers. IPv4-mapped IPv6 addresses are classified through their\n * embedded IPv4 value.\n */\nexport function isNonPublicAddress(address: string): boolean {\n const normalized = stripAddressBrackets(address.trim().toLowerCase());\n const family = isIP(normalized);\n if (family === 0) {\n return true;\n }\n if (family === 4) {\n return isNonPublicIpv4(normalized);\n }\n const mappedText = ipv4FromMappedText(normalized);\n if (mappedText !== null) {\n return isNonPublicIpv4(mappedText);\n }\n const value = parseIpv6(normalized);\n if (value === null) {\n return true;\n }\n const mapped = ipv4FromMappedIpv6(value);\n if (mapped !== null) {\n return isNonPublicIpv4(mapped);\n }\n // Fail closed on unallocated/non-global IPv6 space. Current globally routed\n // unicast addresses live in 2000::/3; local, transition, multicast, and\n // future-use ranges must not become credential-bearing egress merely because\n // they were absent from a denylist.\n if (!hasIpv6Prefix(value, IPV6_GLOBAL_UNICAST_PREFIX, 3)) {\n return true;\n }\n return IPV6_SPECIAL_PREFIXES.some(([prefix, bits]) => hasIpv6Prefix(value, prefix, bits));\n}\n\n// Backwards-compatible name used by the database token-broker API.\nexport const isPrivateAddress = isNonPublicAddress;\n\nfunction createPinnedAgent(addresses: readonly DnsAddress[]): DispatcherLifecycle {\n const agent = new Agent({\n connect: {\n lookup: ((\n _hostname: string,\n options: { all?: boolean; family?: number },\n callback: (\n error: Error | null,\n address?: string | Array<{ address: string; family: number }>,\n family?: number,\n ) => void,\n ) => {\n const candidates =\n options.family === 4 || options.family === 6\n ? addresses.filter((entry) => entry.family === options.family)\n : addresses;\n if (candidates.length === 0) {\n callback(new Error(\"pinned DNS answer has no address for requested family\"));\n return;\n }\n if (options.all) {\n callback(\n null,\n candidates.map((entry) => ({\n address: entry.address,\n family: entry.family,\n })),\n );\n return;\n }\n const first = candidates[0]!;\n callback(null, first.address, first.family);\n }) as never,\n },\n });\n return {\n dispatcher: agent,\n close: async () => {\n await agent.close();\n },\n destroy: async (error) => {\n await agent.destroy(error instanceof Error ? error : null);\n },\n };\n}\n\nfunction responseWithDispatcherLifecycle(\n response: Response,\n dispatcher: DispatcherLifecycle,\n closeTimeoutMs: number,\n): Response {\n const reader = response.body!.getReader();\n let readerReleased = false;\n const releaseReader = () => {\n if (readerReleased) return;\n readerReleased = true;\n reader.releaseLock();\n };\n let disposed: Promise<void> | null = null;\n let cancelled = false;\n const finish = (destroy: boolean, error?: unknown): Promise<void> => {\n if (!disposed) {\n disposed = destroy\n ? destroyDispatcher(dispatcher, error)\n : closeDispatcher(dispatcher, closeTimeoutMs);\n }\n return disposed;\n };\n const body = new ReadableStream<Uint8Array>({\n async pull(controller) {\n try {\n const chunk = await reader.read();\n if (chunk.done) {\n // The dispatcher cannot finish gracefully while OpenGeni still owns\n // the provider response's reader lock. Release it before teardown;\n // otherwise Undici can wait forever after the complete body arrived.\n releaseReader();\n await finish(cancelled);\n controller.close();\n return;\n }\n controller.enqueue(chunk.value);\n } catch (error) {\n releaseReader();\n await finish(true, error);\n controller.error(error);\n }\n },\n async cancel(reason) {\n cancelled = true;\n try {\n await reader.cancel(reason);\n } finally {\n releaseReader();\n await finish(true, reason);\n }\n },\n });\n const wrapped = new Response(body, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n });\n Object.defineProperties(wrapped, {\n redirected: { value: response.redirected },\n type: { value: response.type },\n url: { value: response.url },\n });\n return wrapped;\n}\n\nasync function closeDispatcher(dispatcher: DispatcherLifecycle, timeoutMs: number): Promise<void> {\n let timeout: ReturnType<typeof setTimeout> | undefined;\n const outcome = await Promise.race([\n Promise.resolve()\n .then(() => dispatcher.close())\n .then(\n () => \"closed\" as const,\n () => \"failed\" as const,\n ),\n new Promise<\"timed_out\">((resolve) => {\n timeout = setTimeout(() => resolve(\"timed_out\"), timeoutMs);\n }),\n ]);\n if (timeout) clearTimeout(timeout);\n if (outcome !== \"closed\") {\n // Destruction starts immediately. Do not await a provider/dispatcher\n // shutdown promise after the bounded graceful-close deadline has elapsed.\n void destroyDispatcher(dispatcher);\n }\n}\n\nasync function destroyDispatcher(dispatcher: DispatcherLifecycle, error?: unknown): Promise<void> {\n try {\n await dispatcher.destroy(error);\n } catch {\n // Cleanup is best effort after the dispatcher has already failed.\n }\n}\n\nasync function cancelResponse(response: Response): Promise<void> {\n await response.body?.cancel().catch(() => undefined);\n}\n\nfunction normalizeHostname(hostname: string): string {\n return stripAddressBrackets(hostname.trim().toLowerCase()).replace(/\\.$/, \"\");\n}\n\nfunction stripAddressBrackets(address: string): string {\n return address.startsWith(\"[\") && address.endsWith(\"]\") ? address.slice(1, -1) : address;\n}\n\nfunction isLocalHostname(hostname: string): boolean {\n return hostname === \"localhost\" || hostname.endsWith(\".localhost\");\n}\n\nfunction isLoopbackHostname(hostname: string): boolean {\n const normalized = normalizeHostname(hostname);\n return (\n normalized === \"localhost\" ||\n normalized.endsWith(\".localhost\") ||\n normalized === \"::1\" ||\n isLoopbackIpv4(normalized)\n );\n}\n\nfunction isLoopbackIpv4(hostname: string): boolean {\n if (isIP(hostname) !== 4) return false;\n return hostname.split(\".\")[0] === \"127\";\n}\n\nfunction dedupeAddresses(addresses: readonly DnsAddress[]): DnsAddress[] {\n const out: DnsAddress[] = [];\n const seen = new Set<string>();\n if (!Array.isArray(addresses)) {\n throw invalidDnsAnswer();\n }\n for (const entry of addresses) {\n const normalized = normalizeDnsAnswer(entry);\n const key = `${normalized.family}:${normalized.address}`;\n if (!seen.has(key)) {\n seen.add(key);\n out.push(normalized);\n }\n }\n return out;\n}\n\n/**\n * Validate resolver metadata before it can influence either policy checks or\n * the pinned dispatcher. Never infer a family from the address while retaining\n * a conflicting resolver claim: an invalid answer is an invalid answer.\n */\nfunction normalizeDnsAnswer(entry: unknown): DnsAddress {\n if (!entry || typeof entry !== \"object\") {\n throw invalidDnsAnswer();\n }\n const candidate = entry as { address?: unknown; family?: unknown };\n if (typeof candidate.address !== \"string\") {\n throw invalidDnsAnswer();\n }\n const family = candidate.family;\n if (family !== 4 && family !== 6) {\n throw invalidDnsAnswer();\n }\n const address = stripAddressBrackets(candidate.address.trim().toLowerCase());\n const actualFamily = isIP(address);\n if (actualFamily !== family) {\n throw invalidDnsAnswer();\n }\n return { address, family };\n}\n\nfunction invalidDnsAnswer(): DestinationPolicyError {\n return new DestinationPolicyError(\n \"invalid_dns_answer\",\n \"hostname returned an invalid DNS answer\",\n );\n}\n\nfunction isNonPublicIpv4(address: string): boolean {\n const parts = address.split(\".\").map(Number);\n if (\n parts.length !== 4 ||\n parts.some((part) => !Number.isInteger(part) || part < 0 || part > 255)\n ) {\n return true;\n }\n const value = (parts[0]! << 24) | (parts[1]! << 16) | (parts[2]! << 8) | parts[3]!;\n const unsigned = value >>> 0;\n return (\n inIpv4Range(unsigned, 0x00000000, 0x00ffffff) ||\n inIpv4Range(unsigned, 0x0a000000, 0x0affffff) ||\n inIpv4Range(unsigned, 0x64400000, 0x647fffff) ||\n inIpv4Range(unsigned, 0x7f000000, 0x7fffffff) ||\n inIpv4Range(unsigned, 0xa9fe0000, 0xa9feffff) ||\n inIpv4Range(unsigned, 0xac100000, 0xac1fffff) ||\n inIpv4Range(unsigned, 0xc0000000, 0xc00000ff) ||\n inIpv4Range(unsigned, 0xc0000200, 0xc00002ff) ||\n inIpv4Range(unsigned, 0xc01fc400, 0xc01fc4ff) ||\n inIpv4Range(unsigned, 0xc034c100, 0xc034c1ff) ||\n inIpv4Range(unsigned, 0xc0586300, 0xc05863ff) ||\n inIpv4Range(unsigned, 0xc0a80000, 0xc0a8ffff) ||\n inIpv4Range(unsigned, 0xc0af3000, 0xc0af30ff) ||\n inIpv4Range(unsigned, 0xc6120000, 0xc613ffff) ||\n inIpv4Range(unsigned, 0xc6336400, 0xc63364ff) ||\n inIpv4Range(unsigned, 0xcb007100, 0xcb0071ff) ||\n inIpv4Range(unsigned, 0xe0000000, 0xffffffff)\n );\n}\n\nfunction inIpv4Range(value: number, start: number, end: number): boolean {\n return value >= start && value <= end;\n}\n\nconst IPV6_GLOBAL_UNICAST_PREFIX = ipv6Constant(\"2000::\");\n\nconst IPV6_SPECIAL_PREFIXES: readonly [bigint, number][] = [\n [ipv6Constant(\"::\"), 96],\n [ipv6Constant(\"64:ff9b::\"), 96],\n [ipv6Constant(\"64:ff9b:1::\"), 48],\n [ipv6Constant(\"100::\"), 64],\n // IETF protocol assignments contain globally reachable carve-outs, but they\n // are control-plane anycast/protocol addresses rather than integration\n // endpoints. Credential-bearing MCP/OAuth egress fails closed on the full\n // special-purpose block.\n [ipv6Constant(\"2001::\"), 23],\n [ipv6Constant(\"2001:db8::\"), 32],\n [ipv6Constant(\"2002::\"), 16],\n [ipv6Constant(\"2620:4f:8000::\"), 48],\n [ipv6Constant(\"3ffe::\"), 16],\n [ipv6Constant(\"3fff::\"), 20],\n [ipv6Constant(\"5f00::\"), 16],\n [ipv6Constant(\"fc00::\"), 7],\n [ipv6Constant(\"fe80::\"), 10],\n [ipv6Constant(\"fec0::\"), 10],\n [ipv6Constant(\"ff00::\"), 8],\n];\n\nfunction hasIpv6Prefix(value: bigint, prefix: bigint, bits: number): boolean {\n const shift = 128n - BigInt(bits);\n return value >> shift === prefix >> shift;\n}\n\nfunction ipv4FromMappedIpv6(value: bigint): string | null {\n if (value >> 32n !== 0xffffn) {\n return null;\n }\n const embedded = Number(value & 0xffffffffn);\n return `${embedded >>> 24}.${(embedded >>> 16) & 0xff}.${(embedded >>> 8) & 0xff}.${embedded & 0xff}`;\n}\n\nfunction ipv4FromMappedText(address: string): string | null {\n if (!address.startsWith(\"::ffff:\")) {\n return null;\n }\n const embedded = address.slice(\"::ffff:\".length);\n if (isIP(embedded) === 4) {\n return embedded;\n }\n const parts = embedded.split(\":\");\n if (parts.length !== 2 || parts.some((part) => !/^[0-9a-f]{1,4}$/.test(part))) {\n return null;\n }\n const high = Number.parseInt(parts[0]!, 16);\n const low = Number.parseInt(parts[1]!, 16);\n return `${(high >> 8) & 0xff}.${high & 0xff}.${(low >> 8) & 0xff}.${low & 0xff}`;\n}\n\nfunction parseIpv6(address: string): bigint | null {\n const percent = address.indexOf(\"%\");\n if (percent >= 0) {\n return null;\n }\n let value = address;\n if (value.includes(\".\")) {\n const lastColon = value.lastIndexOf(\":\");\n const dotted = value.slice(lastColon + 1);\n const parts = dotted.split(\".\").map(Number);\n if (\n parts.length !== 4 ||\n parts.some((part) => !Number.isInteger(part) || part < 0 || part > 255)\n ) {\n return null;\n }\n const hex =\n ((parts[0]! << 8) | parts[1]!).toString(16).padStart(4, \"0\") +\n ((parts[2]! << 8) | parts[3]!).toString(16).padStart(4, \"0\");\n value = `${value.slice(0, lastColon + 1)}${hex}`;\n }\n const halves = value.split(\"::\");\n if (halves.length > 2) {\n return null;\n }\n const left = halves[0] ? halves[0].split(\":\") : [];\n const right = halves.length === 2 && halves[1] ? halves[1].split(\":\") : [];\n if (left.concat(right).some((part) => !/^[0-9a-f]{1,4}$/i.test(part))) {\n return null;\n }\n const missing = halves.length === 2 ? 8 - left.length - right.length : 0;\n if (missing < 0 || (halves.length === 1 && missing !== 0)) {\n return null;\n }\n const groups = [...left, ...Array.from({ length: missing }, () => \"0\"), ...right];\n if (groups.length !== 8) {\n return null;\n }\n return groups.reduce((acc, group) => (acc << 16n) | BigInt(`0x${group}`), 0n);\n}\n\nfunction ipv6Constant(address: string): bigint {\n const value = parseIpv6(address);\n if (value === null) {\n throw new Error(`invalid IPv6 constant: ${address}`);\n }\n return value;\n}\n","export type JsonBase64FieldShape = \"string\" | \"first_array_string\";\n\nexport type ReadJsonBase64FieldOptions = {\n fieldName: string;\n shape: JsonBase64FieldShape;\n maxResponseBytes: number;\n maxDecodedBytes: number;\n label: string;\n signal?: AbortSignal;\n};\n\n/** A bounded provider response violated the expected JSON/base64 wire contract. */\nexport class JsonBase64ResponseError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"JsonBase64ResponseError\";\n }\n}\n\n/**\n * Decode one JSON base64 field directly from a response stream.\n *\n * This deliberately does not materialize the JSON envelope or encoded string.\n * It accepts only canonical base64 and returns after the first matching value,\n * cancelling the unread response tail. The caller still validates the decoded\n * media bytes; this function owns only the bounded wire representation.\n */\nexport async function readJsonBase64Field(\n response: Response,\n options: ReadJsonBase64FieldOptions,\n): Promise<Uint8Array> {\n assertOptions(options);\n declaredResponseLength(response, options.maxResponseBytes, options.label);\n if (!response.body) {\n throw new JsonBase64ResponseError(`${options.label} returned no response body`);\n }\n\n const reader = response.body.getReader();\n const writer = new BoundedByteWriter(\n options.maxDecodedBytes,\n Math.min(64 * 1024, options.maxDecodedBytes),\n options.label,\n );\n const key = new TextEncoder().encode(options.fieldName);\n const quartet = new Uint8Array(4);\n let quartetLength = 0;\n let received = 0;\n let inString = false;\n let escaped = false;\n let keyCouldMatch = false;\n let keyIndex = 0;\n let awaitingColon = false;\n let awaitingValue = false;\n let awaitingArrayItem = false;\n let readingBase64 = false;\n let base64Ended = false;\n\n try {\n for (;;) {\n const next = await readChunk(reader, options.signal, options.label);\n if (next.done) break;\n received += next.value.byteLength;\n if (received > options.maxResponseBytes) {\n throw new JsonBase64ResponseError(`${options.label} exceeded its response byte limit`);\n }\n\n for (const byte of next.value) {\n if (readingBase64) {\n if (byte === 0x22) {\n if (quartetLength !== 0 || writer.length === 0) {\n throw new JsonBase64ResponseError(`${options.label} returned malformed base64`);\n }\n await reader.cancel(\"requested base64 field decoded\").catch(() => undefined);\n return writer.value();\n }\n if (base64Ended || byte === 0x5c || !isBase64Byte(byte)) {\n throw new JsonBase64ResponseError(`${options.label} returned malformed base64`);\n }\n quartet[quartetLength++] = byte;\n if (quartetLength === 4) {\n base64Ended = decodeBase64Quartet(quartet, writer, options.label);\n quartetLength = 0;\n }\n continue;\n }\n\n if (inString) {\n if (escaped) {\n escaped = false;\n keyCouldMatch = false;\n continue;\n }\n if (byte === 0x5c) {\n escaped = true;\n keyCouldMatch = false;\n continue;\n }\n if (byte === 0x22) {\n inString = false;\n if (keyCouldMatch && keyIndex === key.length) awaitingColon = true;\n continue;\n }\n if (keyCouldMatch) {\n if (keyIndex < key.length && byte === key[keyIndex]) keyIndex += 1;\n else keyCouldMatch = false;\n }\n continue;\n }\n\n if (awaitingColon) {\n if (isJsonWhitespace(byte)) continue;\n awaitingColon = false;\n if (byte === 0x3a) {\n awaitingValue = true;\n continue;\n }\n }\n if (awaitingValue) {\n if (isJsonWhitespace(byte)) continue;\n awaitingValue = false;\n if (options.shape === \"first_array_string\") {\n if (byte !== 0x5b) {\n throw new JsonBase64ResponseError(\n `${options.label} returned an invalid base64 array`,\n );\n }\n awaitingArrayItem = true;\n continue;\n }\n if (byte !== 0x22) {\n throw new JsonBase64ResponseError(`${options.label} returned an invalid base64 field`);\n }\n readingBase64 = true;\n continue;\n }\n if (awaitingArrayItem) {\n if (isJsonWhitespace(byte)) continue;\n awaitingArrayItem = false;\n if (byte !== 0x22) {\n throw new JsonBase64ResponseError(`${options.label} returned no base64 array item`);\n }\n readingBase64 = true;\n continue;\n }\n if (byte === 0x22) {\n inString = true;\n escaped = false;\n keyCouldMatch = true;\n keyIndex = 0;\n }\n }\n }\n } catch (error) {\n await reader.cancel(error).catch(() => undefined);\n throw error;\n } finally {\n try {\n reader.releaseLock();\n } catch {\n // Cancellation can release the lock asynchronously in some fetch implementations.\n }\n }\n throw new JsonBase64ResponseError(`${options.label} returned no base64 image data`);\n}\n\nfunction assertOptions(options: ReadJsonBase64FieldOptions): void {\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(options.fieldName)) {\n throw new TypeError(\"JSON base64 field name must be a simple ASCII identifier\");\n }\n if (!Number.isSafeInteger(options.maxResponseBytes) || options.maxResponseBytes <= 0) {\n throw new RangeError(\"JSON response byte limit must be a positive safe integer\");\n }\n if (!Number.isSafeInteger(options.maxDecodedBytes) || options.maxDecodedBytes <= 0) {\n throw new RangeError(\"decoded base64 byte limit must be a positive safe integer\");\n }\n if (!options.label.trim()) throw new TypeError(\"JSON base64 response label is empty\");\n}\n\nfunction declaredResponseLength(\n response: Response,\n maxBytes: number,\n label: string,\n): number | null {\n const raw = response.headers.get(\"content-length\");\n if (raw === null) return null;\n if (!/^\\d+$/.test(raw)) {\n void response.body?.cancel(\"invalid content length\").catch(() => undefined);\n throw new JsonBase64ResponseError(`${label} returned an invalid content length`);\n }\n const length = Number(raw);\n if (!Number.isSafeInteger(length) || length > maxBytes) {\n void response.body?.cancel(\"response exceeds byte limit\").catch(() => undefined);\n throw new JsonBase64ResponseError(`${label} exceeded its response byte limit`);\n }\n return length;\n}\n\ntype StreamRead = Awaited<ReturnType<ReadableStreamDefaultReader<Uint8Array>[\"read\"]>>;\n\nasync function readChunk(\n reader: ReadableStreamDefaultReader<Uint8Array>,\n signal: AbortSignal | undefined,\n label: string,\n): Promise<StreamRead> {\n if (!signal) return await reader.read();\n if (signal.aborted) throw new DOMException(`${label} was aborted`, \"AbortError\");\n return await new Promise<StreamRead>((resolve, reject) => {\n let settled = false;\n const finish = (callback: () => void) => {\n if (settled) return;\n settled = true;\n signal.removeEventListener(\"abort\", onAbort);\n callback();\n };\n const onAbort = () =>\n finish(() => reject(new DOMException(`${label} was aborted`, \"AbortError\")));\n signal.addEventListener(\"abort\", onAbort, { once: true });\n void reader.read().then(\n (result) => finish(() => resolve(result)),\n (error: unknown) => finish(() => reject(error)),\n );\n });\n}\n\nclass BoundedByteWriter {\n private bytes: Uint8Array;\n length = 0;\n\n constructor(\n private readonly maxBytes: number,\n initialCapacity: number,\n private readonly label: string,\n ) {\n this.bytes = new Uint8Array(initialCapacity);\n }\n\n push(byte: number): void {\n if (this.length >= this.maxBytes) {\n throw new JsonBase64ResponseError(`${this.label} exceeded its decoded byte limit`);\n }\n if (this.length === this.bytes.byteLength) this.grow();\n this.bytes[this.length++] = byte;\n }\n\n value(): Uint8Array {\n if (this.length === this.bytes.byteLength) return this.bytes;\n return this.bytes.subarray(0, this.length);\n }\n\n private grow(): void {\n const capacity = Math.min(\n this.maxBytes,\n Math.max(this.bytes.byteLength + 1, this.bytes.byteLength * 2),\n );\n if (capacity <= this.bytes.byteLength) {\n throw new JsonBase64ResponseError(`${this.label} exceeded its decoded byte limit`);\n }\n const grown = new Uint8Array(capacity);\n grown.set(this.bytes);\n this.bytes = grown;\n }\n}\n\nfunction decodeBase64Quartet(\n quartet: Uint8Array,\n writer: BoundedByteWriter,\n label: string,\n): boolean {\n const a = base64Sextet(quartet[0]!);\n const b = base64Sextet(quartet[1]!);\n const thirdPadding = quartet[2] === 0x3d;\n const fourthPadding = quartet[3] === 0x3d;\n if (a < 0 || b < 0 || (thirdPadding && !fourthPadding)) {\n throw new JsonBase64ResponseError(`${label} returned malformed base64`);\n }\n writer.push((a << 2) | (b >> 4));\n if (thirdPadding) {\n if ((b & 0x0f) !== 0) {\n throw new JsonBase64ResponseError(`${label} returned non-canonical base64`);\n }\n return true;\n }\n const c = base64Sextet(quartet[2]!);\n if (c < 0) throw new JsonBase64ResponseError(`${label} returned malformed base64`);\n writer.push(((b & 0x0f) << 4) | (c >> 2));\n if (fourthPadding) {\n if ((c & 0x03) !== 0) {\n throw new JsonBase64ResponseError(`${label} returned non-canonical base64`);\n }\n return true;\n }\n const d = base64Sextet(quartet[3]!);\n if (d < 0) throw new JsonBase64ResponseError(`${label} returned malformed base64`);\n writer.push(((c & 0x03) << 6) | d);\n return false;\n}\n\nfunction base64Sextet(byte: number): number {\n if (byte >= 0x41 && byte <= 0x5a) return byte - 0x41;\n if (byte >= 0x61 && byte <= 0x7a) return byte - 0x61 + 26;\n if (byte >= 0x30 && byte <= 0x39) return byte - 0x30 + 52;\n if (byte === 0x2b) return 62;\n if (byte === 0x2f) return 63;\n return -1;\n}\n\nfunction isBase64Byte(byte: number): boolean {\n return base64Sextet(byte) >= 0 || byte === 0x3d;\n}\n\nfunction isJsonWhitespace(byte: number): boolean {\n return byte === 0x20 || byte === 0x09 || byte === 0x0a || byte === 0x0d;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/json-base64.ts","../src/mcp-oauth-discovery.ts"],"sourcesContent":["// The explicit entrypoint avoids Bun's native `undici` compatibility shim,\n// which exposes an Agent-shaped object without Dispatcher methods.\nimport { Agent, fetch as undiciFetchImpl, request as undiciRequestImpl } from \"undici/index.js\";\nimport { lookup as nodeLookup } from \"node:dns/promises\";\nimport { isIP } from \"node:net\";\n\nexport * from \"./json-base64\";\nexport * from \"./mcp-oauth-discovery\";\n\nexport type FetchLike = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;\n\nexport type DnsAddress = {\n address: string;\n family: 4 | 6;\n};\n\nexport type DnsLookup = (hostname: string) => Promise<readonly DnsAddress[]>;\n\nexport type OutboundNetworkSettings = {\n environment: string;\n integrationsAllowPrivateNetworkTargets: boolean;\n};\n\nexport type PinnedDestination = {\n url: URL;\n hostname: string;\n addresses: readonly DnsAddress[];\n};\n\nexport type DispatcherLifecycle = {\n /** The raw dispatcher handed to fetch; omitted for test-only lifecycle fakes. */\n dispatcher?: unknown;\n close: () => Promise<void> | void;\n destroy: (error?: unknown) => Promise<void> | void;\n};\n\nexport type PinnedFetchOptions = {\n fetchImpl?: FetchLike;\n dnsLookup?: DnsLookup;\n agentFactory?: (addresses: readonly DnsAddress[]) => DispatcherLifecycle;\n label?: string;\n requireHttpsOutsideLocalTest?: boolean;\n};\n\nconst DISPATCHER_CLOSE_TIMEOUT_MS = 100;\n\nexport const OAUTH_MAX_RESPONSE_BYTES = 1024 * 1024;\n\nexport type HttpUrlValidationOptions = {\n allowLoopbackHttp?: boolean;\n label?: string;\n};\n\n/** Validate a protocol endpoint before it is persisted, returned, or opened. */\nexport function validateHttpUrl(rawUrl: string, options: HttpUrlValidationOptions = {}): string {\n const label = options.label ?? \"HTTP endpoint\";\n let url: URL;\n try {\n url = new URL(rawUrl);\n } catch {\n throw new DestinationPolicyError(\"invalid_url\", `${label} URL is invalid`);\n }\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n throw new DestinationPolicyError(\n \"unsupported_protocol\",\n `${label} only supports http and https URLs`,\n );\n }\n if (url.username || url.password) {\n throw new DestinationPolicyError(\"invalid_url\", `${label} URL may not contain credentials`);\n }\n if (url.hash) {\n throw new DestinationPolicyError(\"invalid_url\", `${label} URL may not contain a fragment`);\n }\n if (\n url.protocol === \"http:\" &&\n !(options.allowLoopbackHttp && isLoopbackHostname(url.hostname))\n ) {\n throw new DestinationPolicyError(\"https_required\", `${label} must use https`);\n }\n return url.toString();\n}\n\n/**\n * Raised when a response cannot be safely consumed within its caller's byte\n * budget. The error intentionally contains no response bytes or provider\n * message: these readers are used on credential-bearing paths.\n */\nexport class ResponseBodyLimitError extends Error {\n constructor(\n readonly label: string,\n readonly actualBytes: number,\n readonly maxBytes: number,\n readonly reason: \"declared_length\" | \"stream_overflow\" | \"invalid_content_length\",\n ) {\n super(`${label} exceeded its ${maxBytes}-byte response limit`);\n this.name = \"ResponseBodyLimitError\";\n }\n}\n\n/** Raised when a caller-supplied absolute request deadline expires. */\nexport class RequestDeadlineError extends Error {\n constructor(readonly label: string) {\n super(`${label} timed out`);\n this.name = \"RequestDeadlineError\";\n }\n}\n\nexport type BoundedResponseReadOptions = {\n signal?: AbortSignal;\n};\n\n/**\n * Read a response through its stream with a hard byte ceiling.\n *\n * A declared Content-Length above the ceiling is rejected before reading. A\n * body exactly at the ceiling is accepted; the first byte beyond it cancels\n * the stream and rejects. Cancellation is important because pinnedFetch owns a\n * per-response dispatcher which must be closed on every exit path.\n */\nexport async function readResponseBodyBounded(\n response: Response,\n maxBytes: number,\n label: string,\n options: BoundedResponseReadOptions = {},\n): Promise<Uint8Array> {\n if (!Number.isSafeInteger(maxBytes) || maxBytes < 0) {\n throw new RangeError(\"response body limit must be a non-negative safe integer\");\n }\n const declared = response.headers.get(\"content-length\");\n if (declared !== null) {\n const normalized = declared.trim();\n if (!/^\\d+$/.test(normalized)) {\n await cancelResponse(response);\n throw new ResponseBodyLimitError(label, 0, maxBytes, \"invalid_content_length\");\n }\n const declaredBytes = Number(normalized);\n if (!Number.isSafeInteger(declaredBytes) || declaredBytes > maxBytes) {\n await cancelResponse(response);\n throw new ResponseBodyLimitError(label, declaredBytes, maxBytes, \"declared_length\");\n }\n }\n if (!response.body) {\n return new Uint8Array();\n }\n\n const reader = response.body.getReader();\n const chunks: Uint8Array[] = [];\n let receivedBytes = 0;\n try {\n for (;;) {\n const result = await readStreamChunk(reader, options.signal, label);\n if (result.done) {\n break;\n }\n receivedBytes += result.value.byteLength;\n if (receivedBytes > maxBytes) {\n await reader.cancel().catch(() => undefined);\n throw new ResponseBodyLimitError(label, receivedBytes, maxBytes, \"stream_overflow\");\n }\n chunks.push(result.value);\n }\n } catch (error) {\n void reader.cancel(error).catch(() => undefined);\n throw error;\n } finally {\n try {\n reader.releaseLock();\n } catch {\n // An aborted read may still own the lock until the underlying transport\n // observes cancellation. The response is already being cancelled above.\n }\n }\n\n const body = new Uint8Array(receivedBytes);\n let offset = 0;\n for (const chunk of chunks) {\n body.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return body;\n}\n\nexport async function readResponseTextBounded(\n response: Response,\n maxBytes: number,\n label: string,\n options: BoundedResponseReadOptions = {},\n): Promise<string> {\n return new TextDecoder().decode(\n await readResponseBodyBounded(response, maxBytes, label, options),\n );\n}\n\nexport async function readResponseJsonBounded<T = unknown>(\n response: Response,\n maxBytes: number,\n label: string,\n options: BoundedResponseReadOptions = {},\n): Promise<T> {\n return JSON.parse(await readResponseTextBounded(response, maxBytes, label, options)) as T;\n}\n\ntype ResponseStreamReadResult = Awaited<\n ReturnType<ReadableStreamDefaultReader<Uint8Array>[\"read\"]>\n>;\n\nasync function readStreamChunk(\n reader: ReadableStreamDefaultReader<Uint8Array>,\n signal: AbortSignal | undefined,\n label: string,\n): Promise<ResponseStreamReadResult> {\n if (!signal) return await reader.read();\n if (signal.aborted) throw new RequestDeadlineError(label);\n return await new Promise<ResponseStreamReadResult>((resolve, reject) => {\n let settled = false;\n const finish = (callback: () => void) => {\n if (settled) return;\n settled = true;\n signal.removeEventListener(\"abort\", onAbort);\n callback();\n };\n const onAbort = () => {\n const error = new RequestDeadlineError(label);\n void reader.cancel(error).catch(() => undefined);\n finish(() => reject(error));\n };\n signal.addEventListener(\"abort\", onAbort, { once: true });\n void reader.read().then(\n (result) => finish(() => resolve(result)),\n (error) => finish(() => reject(error)),\n );\n });\n}\n\nexport type ResolvePinnedDestinationOptions = {\n dnsLookup?: DnsLookup;\n label?: string;\n requireHttpsOutsideLocalTest?: boolean;\n};\n\nexport type DestinationPolicyReason =\n | \"invalid_url\"\n | \"unsupported_protocol\"\n | \"https_required\"\n | \"dns_failed\"\n | \"dns_empty\"\n | \"invalid_dns_answer\"\n | \"private_or_special_use\";\n\nexport class DestinationPolicyError extends Error {\n constructor(\n readonly reason: DestinationPolicyReason,\n message: string,\n ) {\n super(message);\n this.name = \"DestinationPolicyError\";\n }\n}\n\nconst defaultDnsLookup: DnsLookup = async (hostname) => {\n const answers = await nodeLookup(hostname, { all: true });\n return answers.map((entry) => normalizeDnsAnswer(entry));\n};\n\nconst defaultFetch: FetchLike = (input, init) =>\n (undiciFetchImpl as unknown as FetchLike)(input, init);\n\nconst pinnedRequestFetch: FetchLike = async (input, init) => {\n const source = input instanceof Request ? input : null;\n const url = source?.url ?? input.toString();\n const method = init?.method ?? source?.method ?? \"GET\";\n const headers = new Headers(source?.headers);\n if (init?.headers) {\n new Headers(init.headers).forEach((value, name) => headers.set(name, value));\n }\n // Undici request() deliberately does not auto-decompress. Asking providers\n // for identity encoding keeps the returned web Response body truthful.\n if (!headers.has(\"accept-encoding\")) headers.set(\"accept-encoding\", \"identity\");\n const rawBody = init?.body ?? (method !== \"GET\" && method !== \"HEAD\" ? source?.body : undefined);\n const body = await normalizeUndiciRequestBody(rawBody, headers);\n const dispatcher = (init as (RequestInit & { dispatcher?: unknown }) | undefined)?.dispatcher;\n const result = await undiciRequestImpl(url, {\n method: method as never,\n headers,\n ...(body !== undefined && body !== null ? { body: body as never } : {}),\n ...(init?.signal ? { signal: init.signal } : source?.signal ? { signal: source.signal } : {}),\n ...(dispatcher ? { dispatcher: dispatcher as never } : {}),\n maxRedirections: 0,\n });\n const iterator = result.body[Symbol.asyncIterator]();\n const responseBody = new ReadableStream<Uint8Array>({\n async pull(controller) {\n try {\n const chunk = await iterator.next();\n if (chunk.done) {\n controller.close();\n return;\n }\n controller.enqueue(\n chunk.value instanceof Uint8Array ? chunk.value : new Uint8Array(chunk.value),\n );\n } catch (error) {\n controller.error(error);\n }\n },\n async cancel(reason) {\n result.body.destroy(reason instanceof Error ? reason : undefined);\n await iterator.return?.();\n },\n });\n const responseHeaders = new Headers();\n for (const [name, value] of Object.entries(result.headers)) {\n if (Array.isArray(value)) {\n for (const entry of value) appendWebCompatibleResponseHeader(responseHeaders, name, entry);\n } else if (value !== undefined) {\n appendWebCompatibleResponseHeader(responseHeaders, name, value, true);\n }\n }\n const response = new Response(responseBody, {\n status: result.statusCode,\n headers: responseHeaders,\n });\n Object.defineProperty(response, \"url\", { value: url });\n return response;\n};\n\n/**\n * Undici's low-level request API preserves response-header values that the\n * Fetch `Headers` implementation may reject (for example, UTF-8 object-store\n * lifecycle metadata). Such an unrelated extension header must not discard a\n * valid response body. Omit only the unrepresentable field; security and\n * framing headers remain subject to the same strict Fetch validation.\n */\nfunction appendWebCompatibleResponseHeader(\n headers: Headers,\n name: string,\n value: string,\n replace = false,\n): void {\n try {\n if (replace) headers.set(name, value);\n else headers.append(name, value);\n } catch (error) {\n if (!(error instanceof TypeError)) throw error;\n }\n}\n\n/**\n * Preserve Fetch BodyInit semantics for values that Undici request() does not\n * normalize itself. URLSearchParams is otherwise mistaken for an iterable of\n * body chunks and each [name, value] tuple reaches the socket as an Array.\n */\nasync function normalizeUndiciRequestBody(\n body: BodyInit | null | undefined,\n headers: Headers,\n): Promise<BodyInit | Uint8Array | null | undefined> {\n if (body instanceof URLSearchParams) {\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"application/x-www-form-urlencoded;charset=UTF-8\");\n }\n return body.toString();\n }\n if (body instanceof Blob) {\n if (body.type && !headers.has(\"content-type\")) headers.set(\"content-type\", body.type);\n return new Uint8Array(await body.arrayBuffer());\n }\n if (body instanceof ArrayBuffer) return new Uint8Array(body);\n if (ArrayBuffer.isView(body)) {\n return new Uint8Array(body.buffer, body.byteOffset, body.byteLength);\n }\n return body;\n}\n\n/** Undici fetch used by the pinned transport; Bun callers should prefer this over native fetch. */\nexport const undiciFetch: FetchLike = defaultFetch;\n\n/**\n * Resolve and policy-check one destination. The returned address set is the\n * complete DNS answer that the caller is allowed to use; the transport never\n * performs a second resolver call.\n */\nexport async function resolvePinnedDestination(\n rawUrl: string | URL,\n settings: OutboundNetworkSettings,\n options: ResolvePinnedDestinationOptions = {},\n): Promise<PinnedDestination> {\n const label = options.label ?? \"Outbound request\";\n let url: URL;\n try {\n url = new URL(rawUrl);\n } catch {\n throw new DestinationPolicyError(\"invalid_url\", `${label} URL is invalid`);\n }\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n throw new DestinationPolicyError(\n \"unsupported_protocol\",\n `${label} only supports http and https URLs`,\n );\n }\n const localTestEscape = isLocalTestEnvironment(settings.environment);\n if (options.requireHttpsOutsideLocalTest && !localTestEscape && url.protocol !== \"https:\") {\n throw new DestinationPolicyError(\n \"https_required\",\n `${label} must use https outside local/test`,\n );\n }\n\n const hostname = normalizeHostname(url.hostname);\n if (!hostname) {\n throw new DestinationPolicyError(\"invalid_url\", `${label} URL has no hostname`);\n }\n\n const literalFamily = isIP(hostname);\n let addresses: readonly DnsAddress[];\n try {\n addresses = literalFamily\n ? [{ address: hostname, family: literalFamily === 6 ? 6 : 4 }]\n : await (options.dnsLookup ?? defaultDnsLookup)(hostname);\n } catch (error) {\n if (error instanceof DestinationPolicyError && error.reason === \"invalid_dns_answer\") {\n throw error;\n }\n throw new DestinationPolicyError(\"dns_failed\", `${label} hostname could not be resolved`);\n }\n\n const normalizedAddresses = dedupeAddresses(addresses);\n if (normalizedAddresses.length === 0) {\n throw new DestinationPolicyError(\"dns_empty\", `${label} hostname has no addresses`);\n }\n if (normalizedAddresses.some((entry) => isInvalidAddress(entry.address))) {\n throw new DestinationPolicyError(\n \"invalid_dns_answer\",\n `${label} hostname returned an invalid address`,\n );\n }\n\n const privateEscape = localTestEscape || settings.integrationsAllowPrivateNetworkTargets === true;\n if (\n !privateEscape &&\n (isLocalHostname(hostname) ||\n normalizedAddresses.some((entry) => isNonPublicAddress(entry.address)))\n ) {\n throw new DestinationPolicyError(\n \"private_or_special_use\",\n `${label} may not target a private or special-use network address`,\n );\n }\n return { url, hostname, addresses: preferIpv4Addresses(normalizedAddresses) };\n}\n\n/**\n * Keep every vetted resolver answer pinned, but prefer IPv4 when both public\n * families are available. Docker hosts commonly advertise public IPv6 DNS\n * without an IPv6 egress route; selecting that answer first turns a healthy\n * dual-stack destination into a deterministic connection failure.\n */\nfunction preferIpv4Addresses(addresses: readonly DnsAddress[]): DnsAddress[] {\n return [\n ...addresses.filter((entry) => entry.family === 4),\n ...addresses.filter((entry) => entry.family === 6),\n ];\n}\n\n/**\n * Fetch through a dispatcher whose lookup is pinned to the result of exactly\n * one policy resolution. The response body owns the one-shot agent until\n * completion, cancellation, or stream failure.\n */\nexport async function pinnedFetch(\n input: string | URL | Request,\n init: RequestInit | undefined,\n settings: OutboundNetworkSettings,\n options: PinnedFetchOptions = {},\n): Promise<Response> {\n const rawUrl = input instanceof Request ? input.url : input;\n const destination = await resolvePinnedDestination(rawUrl, settings, options);\n const dispatcher =\n options.agentFactory?.(destination.addresses) ?? createPinnedAgent(destination.addresses);\n const fetchImpl = options.fetchImpl ?? pinnedRequestFetch;\n const fetchInit = {\n ...init,\n redirect: \"manual\" as const,\n dispatcher: dispatcher.dispatcher ?? dispatcher,\n } as RequestInit & { dispatcher: DispatcherLifecycle };\n let response: Response;\n try {\n response = await fetchImpl(input, fetchInit);\n } catch (error) {\n await destroyDispatcher(dispatcher, error);\n throw error;\n }\n if (!response.body) {\n await closeDispatcher(dispatcher, DISPATCHER_CLOSE_TIMEOUT_MS);\n return response;\n }\n return responseWithDispatcherLifecycle(response, dispatcher, DISPATCHER_CLOSE_TIMEOUT_MS);\n}\n\nexport function isLocalTestEnvironment(environment: string): boolean {\n return environment === \"local\" || environment === \"test\";\n}\n\n/** Return true for malformed, non-IPv4, and non-IPv6 address strings. */\nexport function isInvalidAddress(address: string): boolean {\n return isIP(stripAddressBrackets(address.trim())) === 0;\n}\n\n/**\n * Classify private, reserved, documentation, benchmark, multicast, and other\n * special-use answers. IPv4-mapped IPv6 addresses are classified through their\n * embedded IPv4 value.\n */\nexport function isNonPublicAddress(address: string): boolean {\n const normalized = stripAddressBrackets(address.trim().toLowerCase());\n const family = isIP(normalized);\n if (family === 0) {\n return true;\n }\n if (family === 4) {\n return isNonPublicIpv4(normalized);\n }\n const mappedText = ipv4FromMappedText(normalized);\n if (mappedText !== null) {\n return isNonPublicIpv4(mappedText);\n }\n const value = parseIpv6(normalized);\n if (value === null) {\n return true;\n }\n const mapped = ipv4FromMappedIpv6(value);\n if (mapped !== null) {\n return isNonPublicIpv4(mapped);\n }\n // Fail closed on unallocated/non-global IPv6 space. Current globally routed\n // unicast addresses live in 2000::/3; local, transition, multicast, and\n // future-use ranges must not become credential-bearing egress merely because\n // they were absent from a denylist.\n if (!hasIpv6Prefix(value, IPV6_GLOBAL_UNICAST_PREFIX, 3)) {\n return true;\n }\n return IPV6_SPECIAL_PREFIXES.some(([prefix, bits]) => hasIpv6Prefix(value, prefix, bits));\n}\n\n// Backwards-compatible name used by the database token-broker API.\nexport const isPrivateAddress = isNonPublicAddress;\n\nfunction createPinnedAgent(addresses: readonly DnsAddress[]): DispatcherLifecycle {\n const agent = new Agent({\n connect: {\n lookup: ((\n _hostname: string,\n options: { all?: boolean; family?: number },\n callback: (\n error: Error | null,\n address?: string | Array<{ address: string; family: number }>,\n family?: number,\n ) => void,\n ) => {\n const candidates =\n options.family === 4 || options.family === 6\n ? addresses.filter((entry) => entry.family === options.family)\n : addresses;\n if (candidates.length === 0) {\n callback(new Error(\"pinned DNS answer has no address for requested family\"));\n return;\n }\n if (options.all) {\n callback(\n null,\n candidates.map((entry) => ({\n address: entry.address,\n family: entry.family,\n })),\n );\n return;\n }\n const first = candidates[0]!;\n callback(null, first.address, first.family);\n }) as never,\n },\n });\n return {\n dispatcher: agent,\n close: async () => {\n await agent.close();\n },\n destroy: async (error) => {\n await agent.destroy(error instanceof Error ? error : null);\n },\n };\n}\n\nfunction responseWithDispatcherLifecycle(\n response: Response,\n dispatcher: DispatcherLifecycle,\n closeTimeoutMs: number,\n): Response {\n const reader = response.body!.getReader();\n let readerReleased = false;\n const releaseReader = () => {\n if (readerReleased) return;\n readerReleased = true;\n reader.releaseLock();\n };\n let disposed: Promise<void> | null = null;\n let cancelled = false;\n const finish = (destroy: boolean, error?: unknown): Promise<void> => {\n if (!disposed) {\n disposed = destroy\n ? destroyDispatcher(dispatcher, error)\n : closeDispatcher(dispatcher, closeTimeoutMs);\n }\n return disposed;\n };\n const body = new ReadableStream<Uint8Array>({\n async pull(controller) {\n try {\n const chunk = await reader.read();\n if (chunk.done) {\n // The dispatcher cannot finish gracefully while OpenGeni still owns\n // the provider response's reader lock. Release it before teardown;\n // otherwise Undici can wait forever after the complete body arrived.\n releaseReader();\n await finish(cancelled);\n controller.close();\n return;\n }\n controller.enqueue(chunk.value);\n } catch (error) {\n releaseReader();\n await finish(true, error);\n controller.error(error);\n }\n },\n async cancel(reason) {\n cancelled = true;\n try {\n await reader.cancel(reason);\n } finally {\n releaseReader();\n await finish(true, reason);\n }\n },\n });\n const wrapped = new Response(body, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n });\n Object.defineProperties(wrapped, {\n redirected: { value: response.redirected },\n type: { value: response.type },\n url: { value: response.url },\n });\n return wrapped;\n}\n\nasync function closeDispatcher(dispatcher: DispatcherLifecycle, timeoutMs: number): Promise<void> {\n let timeout: ReturnType<typeof setTimeout> | undefined;\n const outcome = await Promise.race([\n Promise.resolve()\n .then(() => dispatcher.close())\n .then(\n () => \"closed\" as const,\n () => \"failed\" as const,\n ),\n new Promise<\"timed_out\">((resolve) => {\n timeout = setTimeout(() => resolve(\"timed_out\"), timeoutMs);\n }),\n ]);\n if (timeout) clearTimeout(timeout);\n if (outcome !== \"closed\") {\n // Destruction starts immediately. Do not await a provider/dispatcher\n // shutdown promise after the bounded graceful-close deadline has elapsed.\n void destroyDispatcher(dispatcher);\n }\n}\n\nasync function destroyDispatcher(dispatcher: DispatcherLifecycle, error?: unknown): Promise<void> {\n try {\n await dispatcher.destroy(error);\n } catch {\n // Cleanup is best effort after the dispatcher has already failed.\n }\n}\n\nasync function cancelResponse(response: Response): Promise<void> {\n await response.body?.cancel().catch(() => undefined);\n}\n\nfunction normalizeHostname(hostname: string): string {\n return stripAddressBrackets(hostname.trim().toLowerCase()).replace(/\\.$/, \"\");\n}\n\nfunction stripAddressBrackets(address: string): string {\n return address.startsWith(\"[\") && address.endsWith(\"]\") ? address.slice(1, -1) : address;\n}\n\nfunction isLocalHostname(hostname: string): boolean {\n return hostname === \"localhost\" || hostname.endsWith(\".localhost\");\n}\n\nfunction isLoopbackHostname(hostname: string): boolean {\n const normalized = normalizeHostname(hostname);\n return (\n normalized === \"localhost\" ||\n normalized.endsWith(\".localhost\") ||\n normalized === \"::1\" ||\n isLoopbackIpv4(normalized)\n );\n}\n\nfunction isLoopbackIpv4(hostname: string): boolean {\n if (isIP(hostname) !== 4) return false;\n return hostname.split(\".\")[0] === \"127\";\n}\n\nfunction dedupeAddresses(addresses: readonly DnsAddress[]): DnsAddress[] {\n const out: DnsAddress[] = [];\n const seen = new Set<string>();\n if (!Array.isArray(addresses)) {\n throw invalidDnsAnswer();\n }\n for (const entry of addresses) {\n const normalized = normalizeDnsAnswer(entry);\n const key = `${normalized.family}:${normalized.address}`;\n if (!seen.has(key)) {\n seen.add(key);\n out.push(normalized);\n }\n }\n return out;\n}\n\n/**\n * Validate resolver metadata before it can influence either policy checks or\n * the pinned dispatcher. Never infer a family from the address while retaining\n * a conflicting resolver claim: an invalid answer is an invalid answer.\n */\nfunction normalizeDnsAnswer(entry: unknown): DnsAddress {\n if (!entry || typeof entry !== \"object\") {\n throw invalidDnsAnswer();\n }\n const candidate = entry as { address?: unknown; family?: unknown };\n if (typeof candidate.address !== \"string\") {\n throw invalidDnsAnswer();\n }\n const family = candidate.family;\n if (family !== 4 && family !== 6) {\n throw invalidDnsAnswer();\n }\n const address = stripAddressBrackets(candidate.address.trim().toLowerCase());\n const actualFamily = isIP(address);\n if (actualFamily !== family) {\n throw invalidDnsAnswer();\n }\n return { address, family };\n}\n\nfunction invalidDnsAnswer(): DestinationPolicyError {\n return new DestinationPolicyError(\n \"invalid_dns_answer\",\n \"hostname returned an invalid DNS answer\",\n );\n}\n\nfunction isNonPublicIpv4(address: string): boolean {\n const parts = address.split(\".\").map(Number);\n if (\n parts.length !== 4 ||\n parts.some((part) => !Number.isInteger(part) || part < 0 || part > 255)\n ) {\n return true;\n }\n const value = (parts[0]! << 24) | (parts[1]! << 16) | (parts[2]! << 8) | parts[3]!;\n const unsigned = value >>> 0;\n return (\n inIpv4Range(unsigned, 0x00000000, 0x00ffffff) ||\n inIpv4Range(unsigned, 0x0a000000, 0x0affffff) ||\n inIpv4Range(unsigned, 0x64400000, 0x647fffff) ||\n inIpv4Range(unsigned, 0x7f000000, 0x7fffffff) ||\n inIpv4Range(unsigned, 0xa9fe0000, 0xa9feffff) ||\n inIpv4Range(unsigned, 0xac100000, 0xac1fffff) ||\n inIpv4Range(unsigned, 0xc0000000, 0xc00000ff) ||\n inIpv4Range(unsigned, 0xc0000200, 0xc00002ff) ||\n inIpv4Range(unsigned, 0xc01fc400, 0xc01fc4ff) ||\n inIpv4Range(unsigned, 0xc034c100, 0xc034c1ff) ||\n inIpv4Range(unsigned, 0xc0586300, 0xc05863ff) ||\n inIpv4Range(unsigned, 0xc0a80000, 0xc0a8ffff) ||\n inIpv4Range(unsigned, 0xc0af3000, 0xc0af30ff) ||\n inIpv4Range(unsigned, 0xc6120000, 0xc613ffff) ||\n inIpv4Range(unsigned, 0xc6336400, 0xc63364ff) ||\n inIpv4Range(unsigned, 0xcb007100, 0xcb0071ff) ||\n inIpv4Range(unsigned, 0xe0000000, 0xffffffff)\n );\n}\n\nfunction inIpv4Range(value: number, start: number, end: number): boolean {\n return value >= start && value <= end;\n}\n\nconst IPV6_GLOBAL_UNICAST_PREFIX = ipv6Constant(\"2000::\");\n\nconst IPV6_SPECIAL_PREFIXES: readonly [bigint, number][] = [\n [ipv6Constant(\"::\"), 96],\n [ipv6Constant(\"64:ff9b::\"), 96],\n [ipv6Constant(\"64:ff9b:1::\"), 48],\n [ipv6Constant(\"100::\"), 64],\n // IETF protocol assignments contain globally reachable carve-outs, but they\n // are control-plane anycast/protocol addresses rather than integration\n // endpoints. Credential-bearing MCP/OAuth egress fails closed on the full\n // special-purpose block.\n [ipv6Constant(\"2001::\"), 23],\n [ipv6Constant(\"2001:db8::\"), 32],\n [ipv6Constant(\"2002::\"), 16],\n [ipv6Constant(\"2620:4f:8000::\"), 48],\n [ipv6Constant(\"3ffe::\"), 16],\n [ipv6Constant(\"3fff::\"), 20],\n [ipv6Constant(\"5f00::\"), 16],\n [ipv6Constant(\"fc00::\"), 7],\n [ipv6Constant(\"fe80::\"), 10],\n [ipv6Constant(\"fec0::\"), 10],\n [ipv6Constant(\"ff00::\"), 8],\n];\n\nfunction hasIpv6Prefix(value: bigint, prefix: bigint, bits: number): boolean {\n const shift = 128n - BigInt(bits);\n return value >> shift === prefix >> shift;\n}\n\nfunction ipv4FromMappedIpv6(value: bigint): string | null {\n if (value >> 32n !== 0xffffn) {\n return null;\n }\n const embedded = Number(value & 0xffffffffn);\n return `${embedded >>> 24}.${(embedded >>> 16) & 0xff}.${(embedded >>> 8) & 0xff}.${embedded & 0xff}`;\n}\n\nfunction ipv4FromMappedText(address: string): string | null {\n if (!address.startsWith(\"::ffff:\")) {\n return null;\n }\n const embedded = address.slice(\"::ffff:\".length);\n if (isIP(embedded) === 4) {\n return embedded;\n }\n const parts = embedded.split(\":\");\n if (parts.length !== 2 || parts.some((part) => !/^[0-9a-f]{1,4}$/.test(part))) {\n return null;\n }\n const high = Number.parseInt(parts[0]!, 16);\n const low = Number.parseInt(parts[1]!, 16);\n return `${(high >> 8) & 0xff}.${high & 0xff}.${(low >> 8) & 0xff}.${low & 0xff}`;\n}\n\nfunction parseIpv6(address: string): bigint | null {\n const percent = address.indexOf(\"%\");\n if (percent >= 0) {\n return null;\n }\n let value = address;\n if (value.includes(\".\")) {\n const lastColon = value.lastIndexOf(\":\");\n const dotted = value.slice(lastColon + 1);\n const parts = dotted.split(\".\").map(Number);\n if (\n parts.length !== 4 ||\n parts.some((part) => !Number.isInteger(part) || part < 0 || part > 255)\n ) {\n return null;\n }\n const hex =\n ((parts[0]! << 8) | parts[1]!).toString(16).padStart(4, \"0\") +\n ((parts[2]! << 8) | parts[3]!).toString(16).padStart(4, \"0\");\n value = `${value.slice(0, lastColon + 1)}${hex}`;\n }\n const halves = value.split(\"::\");\n if (halves.length > 2) {\n return null;\n }\n const left = halves[0] ? halves[0].split(\":\") : [];\n const right = halves.length === 2 && halves[1] ? halves[1].split(\":\") : [];\n if (left.concat(right).some((part) => !/^[0-9a-f]{1,4}$/i.test(part))) {\n return null;\n }\n const missing = halves.length === 2 ? 8 - left.length - right.length : 0;\n if (missing < 0 || (halves.length === 1 && missing !== 0)) {\n return null;\n }\n const groups = [...left, ...Array.from({ length: missing }, () => \"0\"), ...right];\n if (groups.length !== 8) {\n return null;\n }\n return groups.reduce((acc, group) => (acc << 16n) | BigInt(`0x${group}`), 0n);\n}\n\nfunction ipv6Constant(address: string): bigint {\n const value = parseIpv6(address);\n if (value === null) {\n throw new Error(`invalid IPv6 constant: ${address}`);\n }\n return value;\n}\n","export type JsonBase64FieldShape = \"string\" | \"first_array_string\";\n\nexport type ReadJsonBase64FieldOptions = {\n fieldName: string;\n shape: JsonBase64FieldShape;\n maxResponseBytes: number;\n maxDecodedBytes: number;\n label: string;\n signal?: AbortSignal;\n};\n\n/** A bounded provider response violated the expected JSON/base64 wire contract. */\nexport class JsonBase64ResponseError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"JsonBase64ResponseError\";\n }\n}\n\n/**\n * Decode one JSON base64 field directly from a response stream.\n *\n * This deliberately does not materialize the JSON envelope or encoded string.\n * It accepts only canonical base64 and returns after the first matching value,\n * cancelling the unread response tail. The caller still validates the decoded\n * media bytes; this function owns only the bounded wire representation.\n */\nexport async function readJsonBase64Field(\n response: Response,\n options: ReadJsonBase64FieldOptions,\n): Promise<Uint8Array> {\n assertOptions(options);\n declaredResponseLength(response, options.maxResponseBytes, options.label);\n if (!response.body) {\n throw new JsonBase64ResponseError(`${options.label} returned no response body`);\n }\n\n const reader = response.body.getReader();\n const writer = new BoundedByteWriter(\n options.maxDecodedBytes,\n Math.min(64 * 1024, options.maxDecodedBytes),\n options.label,\n );\n const key = new TextEncoder().encode(options.fieldName);\n const quartet = new Uint8Array(4);\n let quartetLength = 0;\n let received = 0;\n let inString = false;\n let escaped = false;\n let keyCouldMatch = false;\n let keyIndex = 0;\n let awaitingColon = false;\n let awaitingValue = false;\n let awaitingArrayItem = false;\n let readingBase64 = false;\n let base64Ended = false;\n\n try {\n for (;;) {\n const next = await readChunk(reader, options.signal, options.label);\n if (next.done) break;\n received += next.value.byteLength;\n if (received > options.maxResponseBytes) {\n throw new JsonBase64ResponseError(`${options.label} exceeded its response byte limit`);\n }\n\n for (const byte of next.value) {\n if (readingBase64) {\n if (byte === 0x22) {\n if (quartetLength !== 0 || writer.length === 0) {\n throw new JsonBase64ResponseError(`${options.label} returned malformed base64`);\n }\n await reader.cancel(\"requested base64 field decoded\").catch(() => undefined);\n return writer.value();\n }\n if (base64Ended || byte === 0x5c || !isBase64Byte(byte)) {\n throw new JsonBase64ResponseError(`${options.label} returned malformed base64`);\n }\n quartet[quartetLength++] = byte;\n if (quartetLength === 4) {\n base64Ended = decodeBase64Quartet(quartet, writer, options.label);\n quartetLength = 0;\n }\n continue;\n }\n\n if (inString) {\n if (escaped) {\n escaped = false;\n keyCouldMatch = false;\n continue;\n }\n if (byte === 0x5c) {\n escaped = true;\n keyCouldMatch = false;\n continue;\n }\n if (byte === 0x22) {\n inString = false;\n if (keyCouldMatch && keyIndex === key.length) awaitingColon = true;\n continue;\n }\n if (keyCouldMatch) {\n if (keyIndex < key.length && byte === key[keyIndex]) keyIndex += 1;\n else keyCouldMatch = false;\n }\n continue;\n }\n\n if (awaitingColon) {\n if (isJsonWhitespace(byte)) continue;\n awaitingColon = false;\n if (byte === 0x3a) {\n awaitingValue = true;\n continue;\n }\n }\n if (awaitingValue) {\n if (isJsonWhitespace(byte)) continue;\n awaitingValue = false;\n if (options.shape === \"first_array_string\") {\n if (byte !== 0x5b) {\n throw new JsonBase64ResponseError(\n `${options.label} returned an invalid base64 array`,\n );\n }\n awaitingArrayItem = true;\n continue;\n }\n if (byte !== 0x22) {\n throw new JsonBase64ResponseError(`${options.label} returned an invalid base64 field`);\n }\n readingBase64 = true;\n continue;\n }\n if (awaitingArrayItem) {\n if (isJsonWhitespace(byte)) continue;\n awaitingArrayItem = false;\n if (byte !== 0x22) {\n throw new JsonBase64ResponseError(`${options.label} returned no base64 array item`);\n }\n readingBase64 = true;\n continue;\n }\n if (byte === 0x22) {\n inString = true;\n escaped = false;\n keyCouldMatch = true;\n keyIndex = 0;\n }\n }\n }\n } catch (error) {\n await reader.cancel(error).catch(() => undefined);\n throw error;\n } finally {\n try {\n reader.releaseLock();\n } catch {\n // Cancellation can release the lock asynchronously in some fetch implementations.\n }\n }\n throw new JsonBase64ResponseError(`${options.label} returned no base64 image data`);\n}\n\nfunction assertOptions(options: ReadJsonBase64FieldOptions): void {\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(options.fieldName)) {\n throw new TypeError(\"JSON base64 field name must be a simple ASCII identifier\");\n }\n if (!Number.isSafeInteger(options.maxResponseBytes) || options.maxResponseBytes <= 0) {\n throw new RangeError(\"JSON response byte limit must be a positive safe integer\");\n }\n if (!Number.isSafeInteger(options.maxDecodedBytes) || options.maxDecodedBytes <= 0) {\n throw new RangeError(\"decoded base64 byte limit must be a positive safe integer\");\n }\n if (!options.label.trim()) throw new TypeError(\"JSON base64 response label is empty\");\n}\n\nfunction declaredResponseLength(\n response: Response,\n maxBytes: number,\n label: string,\n): number | null {\n const raw = response.headers.get(\"content-length\");\n if (raw === null) return null;\n if (!/^\\d+$/.test(raw)) {\n void response.body?.cancel(\"invalid content length\").catch(() => undefined);\n throw new JsonBase64ResponseError(`${label} returned an invalid content length`);\n }\n const length = Number(raw);\n if (!Number.isSafeInteger(length) || length > maxBytes) {\n void response.body?.cancel(\"response exceeds byte limit\").catch(() => undefined);\n throw new JsonBase64ResponseError(`${label} exceeded its response byte limit`);\n }\n return length;\n}\n\ntype StreamRead = Awaited<ReturnType<ReadableStreamDefaultReader<Uint8Array>[\"read\"]>>;\n\nasync function readChunk(\n reader: ReadableStreamDefaultReader<Uint8Array>,\n signal: AbortSignal | undefined,\n label: string,\n): Promise<StreamRead> {\n if (!signal) return await reader.read();\n if (signal.aborted) throw new DOMException(`${label} was aborted`, \"AbortError\");\n return await new Promise<StreamRead>((resolve, reject) => {\n let settled = false;\n const finish = (callback: () => void) => {\n if (settled) return;\n settled = true;\n signal.removeEventListener(\"abort\", onAbort);\n callback();\n };\n const onAbort = () =>\n finish(() => reject(new DOMException(`${label} was aborted`, \"AbortError\")));\n signal.addEventListener(\"abort\", onAbort, { once: true });\n void reader.read().then(\n (result) => finish(() => resolve(result)),\n (error: unknown) => finish(() => reject(error)),\n );\n });\n}\n\nclass BoundedByteWriter {\n private bytes: Uint8Array;\n length = 0;\n\n constructor(\n private readonly maxBytes: number,\n initialCapacity: number,\n private readonly label: string,\n ) {\n this.bytes = new Uint8Array(initialCapacity);\n }\n\n push(byte: number): void {\n if (this.length >= this.maxBytes) {\n throw new JsonBase64ResponseError(`${this.label} exceeded its decoded byte limit`);\n }\n if (this.length === this.bytes.byteLength) this.grow();\n this.bytes[this.length++] = byte;\n }\n\n value(): Uint8Array {\n if (this.length === this.bytes.byteLength) return this.bytes;\n return this.bytes.subarray(0, this.length);\n }\n\n private grow(): void {\n const capacity = Math.min(\n this.maxBytes,\n Math.max(this.bytes.byteLength + 1, this.bytes.byteLength * 2),\n );\n if (capacity <= this.bytes.byteLength) {\n throw new JsonBase64ResponseError(`${this.label} exceeded its decoded byte limit`);\n }\n const grown = new Uint8Array(capacity);\n grown.set(this.bytes);\n this.bytes = grown;\n }\n}\n\nfunction decodeBase64Quartet(\n quartet: Uint8Array,\n writer: BoundedByteWriter,\n label: string,\n): boolean {\n const a = base64Sextet(quartet[0]!);\n const b = base64Sextet(quartet[1]!);\n const thirdPadding = quartet[2] === 0x3d;\n const fourthPadding = quartet[3] === 0x3d;\n if (a < 0 || b < 0 || (thirdPadding && !fourthPadding)) {\n throw new JsonBase64ResponseError(`${label} returned malformed base64`);\n }\n writer.push((a << 2) | (b >> 4));\n if (thirdPadding) {\n if ((b & 0x0f) !== 0) {\n throw new JsonBase64ResponseError(`${label} returned non-canonical base64`);\n }\n return true;\n }\n const c = base64Sextet(quartet[2]!);\n if (c < 0) throw new JsonBase64ResponseError(`${label} returned malformed base64`);\n writer.push(((b & 0x0f) << 4) | (c >> 2));\n if (fourthPadding) {\n if ((c & 0x03) !== 0) {\n throw new JsonBase64ResponseError(`${label} returned non-canonical base64`);\n }\n return true;\n }\n const d = base64Sextet(quartet[3]!);\n if (d < 0) throw new JsonBase64ResponseError(`${label} returned malformed base64`);\n writer.push(((c & 0x03) << 6) | d);\n return false;\n}\n\nfunction base64Sextet(byte: number): number {\n if (byte >= 0x41 && byte <= 0x5a) return byte - 0x41;\n if (byte >= 0x61 && byte <= 0x7a) return byte - 0x61 + 26;\n if (byte >= 0x30 && byte <= 0x39) return byte - 0x30 + 52;\n if (byte === 0x2b) return 62;\n if (byte === 0x2f) return 63;\n return -1;\n}\n\nfunction isBase64Byte(byte: number): boolean {\n return base64Sextet(byte) >= 0 || byte === 0x3d;\n}\n\nfunction isJsonWhitespace(byte: number): boolean {\n return byte === 0x20 || byte === 0x09 || byte === 0x0a || byte === 0x0d;\n}\n","import { createHash } from \"node:crypto\";\n\nexport type McpOAuthDiscoveryMode = \"rfc9728_protected_resource\" | \"legacy_2025_03_26_metadata\";\n\nexport type McpOAuthDiscoveryClassification =\n | \"oauth_rfc9728\"\n | \"oauth_legacy_same_origin_metadata\"\n | \"oauth_legacy_default_endpoints_unverified\"\n | \"oauth_requires_profile\"\n | \"oauth_discovery_broken\";\n\nexport type McpOAuthChallenge = {\n scheme: \"bearer\" | \"oauth\" | null;\n resourceMetadata?: string;\n scope: string[];\n error?: string;\n};\n\nexport type McpProtectedResourceMetadata = {\n resource?: string;\n authorizationServers: string[];\n scopesSupported: string[];\n raw: Record<string, unknown>;\n metadataUrl: string;\n};\n\nexport type McpAuthorizationServerMetadata = {\n issuer: string;\n authorizationServer: string;\n authorizationEndpoint: string;\n tokenEndpoint: string;\n registrationEndpoint?: string;\n clientIdMetadataDocumentSupported: boolean;\n tokenEndpointAuthMethodsSupported: string[];\n codeChallengeMethodsSupported: string[];\n raw: Record<string, unknown>;\n metadataUrl: string;\n};\n\nexport type McpOAuthMetadataKind = \"protected_resource\" | \"authorization_server\";\n\nexport type McpOAuthMetadataFetchResult =\n | {\n status: \"present\";\n url: string;\n document: Record<string, unknown>;\n }\n | {\n status: \"absent\";\n url: string;\n httpStatus: 404 | 410;\n };\n\nexport type McpOAuthDiscoveryResult = {\n mode: McpOAuthDiscoveryMode;\n classification: Extract<\n McpOAuthDiscoveryClassification,\n \"oauth_rfc9728\" | \"oauth_legacy_same_origin_metadata\"\n >;\n challenge: McpOAuthChallenge;\n resource: string;\n protectedResourceMetadata: McpProtectedResourceMetadata;\n authorizationServerMetadata: McpAuthorizationServerMetadata;\n provenance: {\n protectedResourceMetadataUrl: string | null;\n authorizationServerMetadataUrl: string;\n metadataSha256: string;\n };\n};\n\nexport class McpOAuthDiscoveryError extends Error {\n constructor(\n readonly stage: \"protected_resource_metadata\" | \"authorization_server_metadata\",\n readonly classification: Exclude<\n McpOAuthDiscoveryClassification,\n \"oauth_rfc9728\" | \"oauth_legacy_same_origin_metadata\"\n >,\n message: string,\n readonly cause?: unknown,\n ) {\n super(message);\n this.name = \"McpOAuthDiscoveryError\";\n }\n}\n\nexport type ResolveMcpOAuthDiscoveryInput = {\n resourceUrl: string;\n challenge: McpOAuthChallenge;\n fetchMetadata: (input: {\n kind: McpOAuthMetadataKind;\n url: string;\n }) => Promise<McpOAuthMetadataFetchResult>;\n validateEndpoint: (rawUrl: string, label: string) => string;\n canonicalizeResource: (rawResource: string) => string;\n};\n\n/**\n * Resolve modern MCP OAuth discovery first, with the 2025-03-26 same-origin\n * metadata profile as a narrowly bounded compatibility fallback.\n *\n * Only an explicit 404/410 result is absence. Callers must throw for network,\n * redirect, destination-policy, body, JSON, and other HTTP failures so none of\n * those failures can silently downgrade a server to the legacy profile.\n */\nexport async function resolveMcpOAuthDiscovery(\n input: ResolveMcpOAuthDiscoveryInput,\n): Promise<McpOAuthDiscoveryResult> {\n const prmCandidates = protectedResourceMetadataCandidates(\n input.resourceUrl,\n input.challenge.resourceMetadata,\n );\n let prmDocument: (McpOAuthMetadataFetchResult & { status: \"present\" }) | null = null;\n for (const candidate of prmCandidates) {\n const fetched = await input.fetchMetadata({ kind: \"protected_resource\", url: candidate });\n if (fetched.status === \"absent\") continue;\n prmDocument = fetched;\n break;\n }\n\n if (prmDocument) {\n const prm = parseProtectedResourceMetadata(prmDocument, input);\n const authorizationServer = prm.authorizationServers[0]!;\n const as = await discoverAuthorizationServerMetadata(authorizationServer, \"modern\", input);\n return discoveryResult({\n mode: \"rfc9728_protected_resource\",\n classification: \"oauth_rfc9728\",\n challenge: input.challenge,\n resource: prm.resource ?? input.canonicalizeResource(input.resourceUrl),\n prm,\n as,\n });\n }\n\n if (input.challenge.resourceMetadata !== undefined) {\n throw new McpOAuthDiscoveryError(\n \"protected_resource_metadata\",\n \"oauth_discovery_broken\",\n \"MCP advertised protected resource metadata, but no metadata document was found\",\n );\n }\n if (!input.challenge.scheme) {\n throw new McpOAuthDiscoveryError(\n \"protected_resource_metadata\",\n \"oauth_discovery_broken\",\n \"MCP protected resource metadata was absent and the server returned no Bearer/OAuth challenge\",\n );\n }\n\n const resource = input.canonicalizeResource(input.resourceUrl);\n const resourceOrigin = new URL(resource).origin;\n const as = await discoverAuthorizationServerMetadata(resourceOrigin, \"legacy\", input);\n if (new URL(as.issuer).origin !== resourceOrigin) {\n throw new McpOAuthDiscoveryError(\n \"authorization_server_metadata\",\n \"oauth_requires_profile\",\n \"legacy MCP OAuth discovery requires the authorization server issuer to share the MCP server origin\",\n );\n }\n const syntheticPrm: McpProtectedResourceMetadata = {\n resource,\n authorizationServers: [as.issuer],\n scopesSupported: [...input.challenge.scope],\n raw: {\n resource,\n authorization_servers: [as.issuer],\n scopes_supported: [...input.challenge.scope],\n },\n metadataUrl: \"\",\n };\n return discoveryResult({\n mode: \"legacy_2025_03_26_metadata\",\n classification: \"oauth_legacy_same_origin_metadata\",\n challenge: input.challenge,\n resource,\n prm: syntheticPrm,\n as,\n });\n}\n\nexport function parseMcpOAuthChallenge(header: string | null): McpOAuthChallenge {\n if (!header) return { scheme: null, scope: [] };\n const challenges = parseAuthenticateChallenges(header);\n if (!challenges) return { scheme: null, scope: [] };\n const oauthChallenges = challenges\n .filter((candidate) => {\n const scheme = candidate.scheme.toLowerCase();\n return scheme === \"bearer\" || scheme === \"oauth\";\n })\n .map(parseOAuthChallenge);\n return (\n oauthChallenges.find((challenge) => challenge.resourceMetadata !== undefined) ??\n oauthChallenges[0] ?? { scheme: null, scope: [] }\n );\n}\n\nfunction parseOAuthChallenge(challenge: {\n scheme: string;\n parameterParts: string[];\n}): McpOAuthChallenge {\n const scheme = challenge.scheme.toLowerCase() as \"bearer\" | \"oauth\";\n const resourceMetadataPresent = challenge.parameterParts.some((part) =>\n /^resource_metadata\\s*=/i.test(part.trim()),\n );\n const paramsText = challenge.parameterParts.join(\",\");\n const params: Record<string, string> = {};\n const re = /([a-zA-Z_][a-zA-Z0-9_-]*)\\s*=\\s*(\"(?:[^\"\\\\]|\\\\.)*\"|[^,\\s]+)/g;\n let match: RegExpExecArray | null;\n while ((match = re.exec(paramsText)) !== null) {\n const raw = match[2]!;\n params[match[1]!.toLowerCase()] = raw.startsWith('\"')\n ? raw.slice(1, -1).replace(/\\\\\"/g, '\"')\n : raw;\n }\n return {\n scheme,\n scope: params.scope ? params.scope.split(/\\s+/).filter(Boolean) : [],\n ...(resourceMetadataPresent ? { resourceMetadata: params.resource_metadata ?? \"\" } : {}),\n ...(params.error ? { error: params.error } : {}),\n };\n}\n\nconst MAX_EMPTY_AUTHENTICATE_LIST_ELEMENTS = 8;\n\nfunction parseAuthenticateChallenges(\n header: string,\n): Array<{ scheme: string; parameterParts: string[] }> | null {\n const segments = splitAuthenticateHeader(header);\n if (!segments) return null;\n const challenges: Array<{ scheme: string; parameterParts: string[] }> = [];\n let emptyElements = 0;\n for (const segment of segments) {\n const trimmed = segment.trim();\n if (!trimmed) {\n emptyElements += 1;\n if (emptyElements > MAX_EMPTY_AUTHENTICATE_LIST_ELEMENTS) return null;\n continue;\n }\n const token = /^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+/.exec(trimmed)?.[0];\n if (!token) return null;\n let cursor = token.length;\n while (/\\s/.test(trimmed[cursor] ?? \"\")) cursor += 1;\n if (trimmed[cursor] === \"=\") {\n const current = challenges.at(-1);\n if (!current) return null;\n current.parameterParts.push(trimmed);\n continue;\n }\n const remainder = trimmed.slice(token.length);\n if (remainder && !/^\\s/.test(remainder)) return null;\n challenges.push({\n scheme: token,\n parameterParts: remainder.trim() ? [remainder.trim()] : [],\n });\n }\n return challenges;\n}\n\nfunction splitAuthenticateHeader(header: string): string[] | null {\n const segments: string[] = [];\n let segmentStart = 0;\n let quoted = false;\n let escaped = false;\n for (let index = 0; index < header.length; index += 1) {\n const character = header[index]!;\n if (quoted) {\n if (escaped) {\n escaped = false;\n } else if (character === \"\\\\\") {\n escaped = true;\n } else if (character === '\"') {\n quoted = false;\n }\n continue;\n }\n if (character === '\"') {\n quoted = true;\n continue;\n }\n if (character === \",\") {\n segments.push(header.slice(segmentStart, index));\n segmentStart = index + 1;\n }\n }\n if (quoted) return null;\n segments.push(header.slice(segmentStart));\n return segments;\n}\n\nexport function protectedResourceMetadataCandidates(\n resourceUrl: string,\n advertisedUrl?: string,\n): string[] {\n return uniqueStrings([\n ...(advertisedUrl !== undefined ? [advertisedUrl] : []),\n ...oauthWellKnownCandidates(resourceUrl, \"oauth-protected-resource\"),\n ]);\n}\n\nexport function authorizationServerMetadataCandidates(authorizationServer: string): string[] {\n return uniqueStrings([\n ...oauthWellKnownCandidates(authorizationServer, \"oauth-authorization-server\"),\n ...oauthWellKnownCandidates(authorizationServer, \"openid-configuration\"),\n authorizationServer,\n ]);\n}\n\nexport function legacyAuthorizationServerMetadataCandidates(resourceUrl: string): string[] {\n const origin = new URL(resourceUrl).origin;\n return [`${origin}/.well-known/oauth-authorization-server`];\n}\n\nfunction oauthWellKnownCandidates(rawUrl: string, name: string): string[] {\n const url = new URL(rawUrl);\n const path = url.pathname.replace(/^\\/+|\\/+$/g, \"\");\n return uniqueStrings([\n `${url.origin}/.well-known/${name}${path ? `/${path}` : \"\"}`,\n `${url.origin}${path ? `/${path}` : \"\"}/.well-known/${name}`,\n `${url.origin}/.well-known/${name}`,\n ]);\n}\n\nfunction parseProtectedResourceMetadata(\n fetched: McpOAuthMetadataFetchResult & { status: \"present\" },\n input: ResolveMcpOAuthDiscoveryInput,\n): McpProtectedResourceMetadata {\n const authorizationServers = stringArray(fetched.document.authorization_servers).map((value) =>\n validateDiscoveryEndpoint(\n input,\n value,\n \"OAuth authorization server\",\n \"protected_resource_metadata\",\n ),\n );\n if (authorizationServers.length === 0) {\n throw new McpOAuthDiscoveryError(\n \"protected_resource_metadata\",\n \"oauth_discovery_broken\",\n \"MCP protected resource metadata did not advertise an authorization server\",\n );\n }\n const resourceValue = stringValue(fetched.document.resource);\n return {\n authorizationServers,\n scopesSupported: stringArray(fetched.document.scopes_supported),\n raw: fetched.document,\n metadataUrl: fetched.url,\n ...(resourceValue ? { resource: input.canonicalizeResource(resourceValue) } : {}),\n };\n}\n\nasync function discoverAuthorizationServerMetadata(\n authorizationServer: string,\n profile: \"modern\" | \"legacy\",\n input: ResolveMcpOAuthDiscoveryInput,\n): Promise<McpAuthorizationServerMetadata> {\n const safeAuthorizationServer = validateDiscoveryEndpoint(\n input,\n authorizationServer,\n \"OAuth authorization server\",\n \"authorization_server_metadata\",\n ).replace(/\\/+$/, \"\");\n const candidates =\n profile === \"legacy\"\n ? legacyAuthorizationServerMetadataCandidates(safeAuthorizationServer)\n : authorizationServerMetadataCandidates(safeAuthorizationServer);\n let fetched: (McpOAuthMetadataFetchResult & { status: \"present\" }) | null = null;\n for (const candidate of candidates) {\n const result = await input.fetchMetadata({ kind: \"authorization_server\", url: candidate });\n if (result.status === \"absent\") continue;\n fetched = result;\n break;\n }\n if (!fetched) {\n throw new McpOAuthDiscoveryError(\n \"authorization_server_metadata\",\n profile === \"legacy\" ? \"oauth_legacy_default_endpoints_unverified\" : \"oauth_discovery_broken\",\n profile === \"legacy\"\n ? \"legacy MCP OAuth metadata was absent; default authorization endpoints require explicit verification\"\n : \"could not discover OAuth authorization server metadata\",\n );\n }\n\n const authorizationEndpoint = requiredString(\n fetched.document.authorization_endpoint,\n \"authorization_endpoint\",\n \"authorization_server_metadata\",\n );\n const tokenEndpoint = requiredString(\n fetched.document.token_endpoint,\n \"token_endpoint\",\n \"authorization_server_metadata\",\n );\n const issuerValue = stringValue(fetched.document.issuer);\n if (profile === \"legacy\" && !issuerValue) {\n throw new McpOAuthDiscoveryError(\n \"authorization_server_metadata\",\n \"oauth_discovery_broken\",\n \"legacy MCP OAuth metadata did not include issuer\",\n );\n }\n const issuer = validateDiscoveryEndpoint(\n input,\n issuerValue ?? safeAuthorizationServer,\n \"OAuth issuer\",\n \"authorization_server_metadata\",\n );\n if (\n profile === \"legacy\" &&\n normalizedIssuerIdentifier(issuer) !== normalizedIssuerIdentifier(safeAuthorizationServer)\n ) {\n const crossOrigin = new URL(issuer).origin !== new URL(safeAuthorizationServer).origin;\n throw new McpOAuthDiscoveryError(\n \"authorization_server_metadata\",\n crossOrigin ? \"oauth_requires_profile\" : \"oauth_discovery_broken\",\n \"OAuth authorization server metadata issuer did not match the selected authorization server\",\n );\n }\n const registrationEndpoint = stringValue(fetched.document.registration_endpoint);\n const parsed: McpAuthorizationServerMetadata = {\n issuer,\n authorizationServer: safeAuthorizationServer,\n authorizationEndpoint: validateDiscoveryEndpoint(\n input,\n authorizationEndpoint,\n \"OAuth authorization endpoint\",\n \"authorization_server_metadata\",\n ),\n tokenEndpoint: validateDiscoveryEndpoint(\n input,\n tokenEndpoint,\n \"OAuth token endpoint\",\n \"authorization_server_metadata\",\n ),\n clientIdMetadataDocumentSupported:\n fetched.document.client_id_metadata_document_supported === true,\n tokenEndpointAuthMethodsSupported: stringArray(\n fetched.document.token_endpoint_auth_methods_supported,\n ),\n codeChallengeMethodsSupported: stringArray(fetched.document.code_challenge_methods_supported),\n raw: fetched.document,\n metadataUrl: fetched.url,\n ...(registrationEndpoint\n ? {\n registrationEndpoint: validateDiscoveryEndpoint(\n input,\n registrationEndpoint,\n \"OAuth registration endpoint\",\n \"authorization_server_metadata\",\n ),\n }\n : {}),\n };\n if (!parsed.codeChallengeMethodsSupported.includes(\"S256\")) {\n throw new McpOAuthDiscoveryError(\n \"authorization_server_metadata\",\n \"oauth_discovery_broken\",\n \"authorization server does not support required PKCE S256\",\n );\n }\n return parsed;\n}\n\nfunction discoveryResult(input: {\n mode: McpOAuthDiscoveryMode;\n classification: \"oauth_rfc9728\" | \"oauth_legacy_same_origin_metadata\";\n challenge: McpOAuthChallenge;\n resource: string;\n prm: McpProtectedResourceMetadata;\n as: McpAuthorizationServerMetadata;\n}): McpOAuthDiscoveryResult {\n const protectedResourceMetadataUrl = input.prm.metadataUrl || null;\n return {\n mode: input.mode,\n classification: input.classification,\n challenge: input.challenge,\n resource: input.resource,\n protectedResourceMetadata: input.prm,\n authorizationServerMetadata: input.as,\n provenance: {\n protectedResourceMetadataUrl,\n authorizationServerMetadataUrl: input.as.metadataUrl,\n metadataSha256: createHash(\"sha256\")\n .update(\n stableJson({\n mode: input.mode,\n resource: input.resource,\n challenge: input.challenge,\n protectedResourceMetadata: {\n url: protectedResourceMetadataUrl,\n document: input.prm.raw,\n },\n authorizationServerMetadata: {\n url: input.as.metadataUrl,\n document: input.as.raw,\n },\n }),\n )\n .digest(\"hex\"),\n },\n };\n}\n\nfunction validateDiscoveryEndpoint(\n input: ResolveMcpOAuthDiscoveryInput,\n rawUrl: string,\n label: string,\n stage: McpOAuthDiscoveryError[\"stage\"],\n): string {\n try {\n return input.validateEndpoint(rawUrl, label);\n } catch (error) {\n throw new McpOAuthDiscoveryError(\n stage,\n \"oauth_discovery_broken\",\n error instanceof Error ? error.message : `${label} was invalid`,\n error,\n );\n }\n}\n\nfunction normalizedIssuerIdentifier(value: string): string {\n return value.replace(/\\/+$/, \"\");\n}\n\nfunction stableJson(value: unknown): string {\n if (value === null || typeof value !== \"object\") return JSON.stringify(value);\n if (Array.isArray(value)) return `[${value.map(stableJson).join(\",\")}]`;\n const record = value as Record<string, unknown>;\n return `{${Object.keys(record)\n .sort()\n .map((key) => `${JSON.stringify(key)}:${stableJson(record[key])}`)\n .join(\",\")}}`;\n}\n\nfunction uniqueStrings(values: string[]): string[] {\n return [...new Set(values.map((value) => value.trim()).filter(Boolean))];\n}\n\nfunction stringArray(value: unknown): string[] {\n return Array.isArray(value)\n ? uniqueStrings(value.filter((entry): entry is string => typeof entry === \"string\"))\n : [];\n}\n\nfunction stringValue(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n}\n\nfunction requiredString(\n value: unknown,\n field: string,\n stage: McpOAuthDiscoveryError[\"stage\"],\n): string {\n const parsed = stringValue(value);\n if (!parsed) {\n throw new McpOAuthDiscoveryError(\n stage,\n \"oauth_discovery_broken\",\n `OAuth metadata did not include ${field}`,\n );\n }\n return parsed;\n}\n"],"mappings":"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","names":["as"]}
@@ -0,0 +1,79 @@
1
+ export type McpOAuthDiscoveryMode = "rfc9728_protected_resource" | "legacy_2025_03_26_metadata";
2
+ export type McpOAuthDiscoveryClassification = "oauth_rfc9728" | "oauth_legacy_same_origin_metadata" | "oauth_legacy_default_endpoints_unverified" | "oauth_requires_profile" | "oauth_discovery_broken";
3
+ export type McpOAuthChallenge = {
4
+ scheme: "bearer" | "oauth" | null;
5
+ resourceMetadata?: string;
6
+ scope: string[];
7
+ error?: string;
8
+ };
9
+ export type McpProtectedResourceMetadata = {
10
+ resource?: string;
11
+ authorizationServers: string[];
12
+ scopesSupported: string[];
13
+ raw: Record<string, unknown>;
14
+ metadataUrl: string;
15
+ };
16
+ export type McpAuthorizationServerMetadata = {
17
+ issuer: string;
18
+ authorizationServer: string;
19
+ authorizationEndpoint: string;
20
+ tokenEndpoint: string;
21
+ registrationEndpoint?: string;
22
+ clientIdMetadataDocumentSupported: boolean;
23
+ tokenEndpointAuthMethodsSupported: string[];
24
+ codeChallengeMethodsSupported: string[];
25
+ raw: Record<string, unknown>;
26
+ metadataUrl: string;
27
+ };
28
+ export type McpOAuthMetadataKind = "protected_resource" | "authorization_server";
29
+ export type McpOAuthMetadataFetchResult = {
30
+ status: "present";
31
+ url: string;
32
+ document: Record<string, unknown>;
33
+ } | {
34
+ status: "absent";
35
+ url: string;
36
+ httpStatus: 404 | 410;
37
+ };
38
+ export type McpOAuthDiscoveryResult = {
39
+ mode: McpOAuthDiscoveryMode;
40
+ classification: Extract<McpOAuthDiscoveryClassification, "oauth_rfc9728" | "oauth_legacy_same_origin_metadata">;
41
+ challenge: McpOAuthChallenge;
42
+ resource: string;
43
+ protectedResourceMetadata: McpProtectedResourceMetadata;
44
+ authorizationServerMetadata: McpAuthorizationServerMetadata;
45
+ provenance: {
46
+ protectedResourceMetadataUrl: string | null;
47
+ authorizationServerMetadataUrl: string;
48
+ metadataSha256: string;
49
+ };
50
+ };
51
+ export declare class McpOAuthDiscoveryError extends Error {
52
+ readonly stage: "protected_resource_metadata" | "authorization_server_metadata";
53
+ readonly classification: Exclude<McpOAuthDiscoveryClassification, "oauth_rfc9728" | "oauth_legacy_same_origin_metadata">;
54
+ readonly cause?: unknown;
55
+ constructor(stage: "protected_resource_metadata" | "authorization_server_metadata", classification: Exclude<McpOAuthDiscoveryClassification, "oauth_rfc9728" | "oauth_legacy_same_origin_metadata">, message: string, cause?: unknown);
56
+ }
57
+ export type ResolveMcpOAuthDiscoveryInput = {
58
+ resourceUrl: string;
59
+ challenge: McpOAuthChallenge;
60
+ fetchMetadata: (input: {
61
+ kind: McpOAuthMetadataKind;
62
+ url: string;
63
+ }) => Promise<McpOAuthMetadataFetchResult>;
64
+ validateEndpoint: (rawUrl: string, label: string) => string;
65
+ canonicalizeResource: (rawResource: string) => string;
66
+ };
67
+ /**
68
+ * Resolve modern MCP OAuth discovery first, with the 2025-03-26 same-origin
69
+ * metadata profile as a narrowly bounded compatibility fallback.
70
+ *
71
+ * Only an explicit 404/410 result is absence. Callers must throw for network,
72
+ * redirect, destination-policy, body, JSON, and other HTTP failures so none of
73
+ * those failures can silently downgrade a server to the legacy profile.
74
+ */
75
+ export declare function resolveMcpOAuthDiscovery(input: ResolveMcpOAuthDiscoveryInput): Promise<McpOAuthDiscoveryResult>;
76
+ export declare function parseMcpOAuthChallenge(header: string | null): McpOAuthChallenge;
77
+ export declare function protectedResourceMetadataCandidates(resourceUrl: string, advertisedUrl?: string): string[];
78
+ export declare function authorizationServerMetadataCandidates(authorizationServer: string): string[];
79
+ export declare function legacyAuthorizationServerMetadataCandidates(resourceUrl: string): string[];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@opengeni/network",
3
- "version": "0.2.3",
4
- "description": "DNS-pinned outbound HTTP transport for OpenGeni credential-bearing requests.",
3
+ "version": "0.3.0-canary.1",
4
+ "description": "DNS-pinned outbound HTTP transport and shared MCP OAuth discovery primitives.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
package/src/index.ts CHANGED
@@ -5,6 +5,7 @@ import { lookup as nodeLookup } from "node:dns/promises";
5
5
  import { isIP } from "node:net";
6
6
 
7
7
  export * from "./json-base64";
8
+ export * from "./mcp-oauth-discovery";
8
9
 
9
10
  export type FetchLike = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
10
11