UNPKG

@lodestar/api

Version:

A Typescript REST client for the Ethereum Consensus API

146 lines 5.36 kB
import { toBase64 } from "@lodestar/utils"; export { HttpHeader }; var HttpHeader; (function (HttpHeader) { HttpHeader["ContentType"] = "content-type"; HttpHeader["Accept"] = "accept"; HttpHeader["Authorization"] = "authorization"; /** * Used to indicate which response headers should be made available to * scripts running in the browser, in response to a cross-origin request. * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers */ HttpHeader["ExposeHeaders"] = "access-control-expose-headers"; })(HttpHeader || (HttpHeader = {})); export { MediaType }; var MediaType; (function (MediaType) { MediaType["json"] = "application/json"; MediaType["ssz"] = "application/octet-stream"; })(MediaType || (MediaType = {})); export const SUPPORTED_MEDIA_TYPES = Object.values(MediaType); function isSupportedMediaType(mediaType, supported) { return mediaType !== null && supported.includes(mediaType); } export function parseContentTypeHeader(contentType) { if (!contentType) { return null; } const mediaType = contentType.split(";", 1)[0].trim().toLowerCase(); return isSupportedMediaType(mediaType, SUPPORTED_MEDIA_TYPES) ? mediaType : null; } export function parseAcceptHeader(accept, supported = SUPPORTED_MEDIA_TYPES) { if (!accept) { return null; } // Respect Quality Values per RFC-9110 // Acceptable mime-types are comma separated with optional whitespace return accept .toLowerCase() .split(",") .map((x) => x.trim()) .reduce((best, current) => { // An optional `;` delimiter is used to separate the mime-type from the weight // Normalize here, using 1 as the default qvalue const quality = current.includes(";") ? current.split(";") : [current, "q=1"]; let mediaType = quality[0].trim(); if (mediaType === "*/*") { // Default to json if all media types are accepted mediaType = MediaType.json; } // If the mime type isn't acceptable, move on to the next entry if (!isSupportedMediaType(mediaType, supported)) { return best; } // Otherwise, the portion after the semicolon has optional whitespace and the constant prefix "q=" const weight = quality[1].trim(); if (!weight.startsWith("q=")) { // If the format is invalid simply move on to the next entry return best; } const qvalue = +weight.replace("q=", ""); if (Number.isNaN(qvalue) || qvalue > 1 || qvalue <= 0) { // If we can't convert the qvalue to a valid number, move on return best; } if (qvalue < best[0]) { // This mime type is not preferred return best; } // This mime type is preferred return [qvalue, mediaType]; }, [0, null])[1]; } export function setAuthorizationHeader(url, headers, { bearerToken }) { if (bearerToken && !headers.has(HttpHeader.Authorization)) { headers.set(HttpHeader.Authorization, `Bearer ${bearerToken}`); } if (url.username || url.password) { if (!headers.has(HttpHeader.Authorization)) { headers.set(HttpHeader.Authorization, `Basic ${toBase64(decodeURIComponent(`${url.username}:${url.password}`))}`); } // Remove the username and password from the URL url.username = ""; url.password = ""; } } export function mergeHeaders(...headersList) { const mergedHeaders = new Headers(); for (const headers of headersList) { if (!headers) { continue; } if (Array.isArray(headers)) { for (const [key, value] of headers) { mergedHeaders.set(key, value); } } else if (headers instanceof Headers) { for (const [key, value] of headers) { mergedHeaders.set(key, value); } } else { for (const [key, value] of Object.entries(headers)) { mergedHeaders.set(key, value); } } } return mergedHeaders; } /** * Get header from request headers, by default an error will be thrown if the header * is not present. The header can be marked as optional in which case the return value * might be `undefined` but no error will be thrown if header is missing. */ export function fromHeaders(headers, name, required = true) { // Fastify converts all headers to lower case const header = headers[name.toLowerCase()]; if (header === undefined && required) { throw Error(`${name} header is required`); } return header; } /** * Extension of Headers object returned by Fetch API */ export class HeadersExtra extends Headers { /** * Get required header from response headers */ getRequired(name) { const header = this.get(name); if (header === null) { throw Error(`${name} header is required in response`); } return header; } /** * Get optional header from response headers. * Return default value if it does not exist */ getOrDefault(name, defaultValue) { return this.get(name) ?? defaultValue; } } //# sourceMappingURL=headers.js.map