UNPKG

shelving

Version:

Toolkit for using data in JavaScript.

186 lines (185 loc) 10.3 kB
import { type Data } from "./data.js"; import type { ImmutableDictionary } from "./dictionary.js"; import type { AnyCaller, Arguments } from "./function.js"; import { type Nullish } from "./null.js"; import { type PossibleURIParams } from "./uri.js"; import { type PossibleURL } from "./url.js"; /** A handler function takes a `Request` and optional extra arguments and returns a `Response` (possibly asynchronously). */ export type RequestHandler<A extends Arguments = []> = (request: Request, ...args: A) => Response | Promise<Response>; /** An optional request handler that may return `undefined` to indicate no match. */ export type OptionalRequestHandler<A extends Arguments = []> = (request: Request, ...args: A) => Response | Promise<Response> | undefined; /** A list of optional request handlers. */ export type OptionalRequestHandlers<A extends Arguments = []> = Iterable<OptionalRequestHandler<A>>; /** * Parse the body content of an HTTP `Request` based on its content type, or throw `RequestError` if the content could not be parsed. * * @returns undefined If the request method is `GET` or `HEAD` (these request methods have no body). * @returns unknown If content type is `application/json` and has valid JSON (including `undefined` if the content is empty). * @returns unknown If content type is `multipart/form-data` then convert it to a simple `Data` object. * @returns string If content type is `text/plain` or anything else (including `""` empty string if it's empty). * * @throws RequestError if the content is not `text/plain`, or `application/json` with valid JSON. */ export declare function parseRequestBody(request: Request, caller?: AnyCaller): Promise<unknown>; /** * Parse JSON from an HTTP `Request`, or return `undefined` when the request has no body. * * @throws RequestError If the request body is not valid JSON. */ export declare function parseRequestJSON(request: Request, caller?: AnyCaller): Promise<unknown>; /** * Parse `FormData` from an HTTP `Request`, or return `undefined` when the request has no body. * * @throws RequestError If the request body is not valid multipart form-data. */ export declare function parseRequestFormData(request: Request, caller?: AnyCaller): Promise<FormData | undefined>; /** * Parse the body content of an HTTP `Response` based on its content type, or throw `ResponseError` if the content could not be parsed. * * @returns unknown If content type is `application/json` and has valid JSON (including `undefined` if the content is empty). * @returns unknown If content type is `multipart/form-data` then convert it to a simple `Data` object. * @returns string If content type is `text/plain` or anything else (including `""` empty string if it's empty). * * @throws ResponseError if the content is not `text/plain` or `application/json` with valid JSON. */ export declare function parseResponseBody(response: Response, caller?: AnyCaller): Promise<unknown>; /** * Parse JSON from an HTTP `Response`, or return `undefined` when the response has no body. * * @throws ResponseError If the response body is not valid JSON. */ export declare function parseResponseJSON(response: Response, caller?: AnyCaller): Promise<unknown>; /** * Parse `FormData` from an HTTP `Response`, or return `undefined` when the response has no body. * * @throws ResponseError If the response body is not valid multipart form-data. */ export declare function parseResponseFormData(response: Response, caller?: AnyCaller): Promise<FormData>; /** * Get an HTTP `Response` for an unknown value. * * @param value The value to convert to a `Response`. * @returns A `Response` with a 2xx status, and response body as JSON (if it was set), or no body if `value` is `undefined` */ export declare function getResponse(value: unknown): Response; /** * Get an HTTP `Response` for an unknown error value. * * Returns the correct `Response` based on the type of error thrown: * - If `reason` is a `Response` instance, return it directly. * - If `reason` is a string, return a 422 response with the string message, e.g. `"Invalid input"` * - If `reason` is an `RequestError` instance, return a response with the error's message and code (but only if `debug` is true so we don't leak error details to the client). * - If `reason` is an `Error` instance, return a 500 response with the error's message (but only if `debug` is true so we don't leak error details to the client). * - Anything else returns a 500 response. * * @param reason The error value to convert to a `Response`. * @param debug If `true` include the error message in the response (for debugging), or `false` to return generic error codes (for security). */ export declare function getErrorResponse(reason: unknown, debug?: boolean): Response; /** HTTP request methods that have no body. */ export type RequestHeadMethod = "HEAD" | "GET"; /** HTTP request methods that have a body. */ export type RequestBodyMethod = "POST" | "PUT" | "PATCH" | "DELETE"; /** HTTP request methods. */ export type RequestMethod = RequestHeadMethod | RequestBodyMethod; /** Check whether an HTTP Request method string is a supported request methods. */ export declare function isRequestMethod(method: string): method is RequestMethod; /** Check whether an HTTP Request method string is a supported request method that never sends a body. */ export declare function isRequestHeadMethod(method: string): method is RequestHeadMethod; /** Params in requests are a dictionary of strings. */ export type RequestParams = ImmutableDictionary<string>; /** Configurable options for endpoint requests. */ export type RequestOptions = Pick<RequestInit, "cache" | "credentials" | "headers" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal">; /** * Merge provider-level and call-level request options. * - Scalar options from `b` override `a`. * - Header dictionaries are merged so call-level headers override default headers by key. * - Abort signals are merged, so either abort signal will cancel the request. */ export declare function mergeRequestOptions({ headers: aHeaders, signal: aSignal, ...a }?: RequestOptions, { headers: bHeaders, signal: bSignal, ...b }?: RequestOptions): RequestOptions; /** * Create a body-less `Request`. * - `HEAD` and `GET` requests never send a body. * * @param method The HTTP method. * @param url The target URL. * @param params `?query` params to encode into the URL. * @param options Additional request options. * @returns A `Request` with no body content. * * @example createHeadRequest("POST", "https://api.example.com/items", { name: "abc" }) */ export declare function createHeadRequest(method: RequestHeadMethod, url: PossibleURL, params: Nullish<PossibleURIParams>, options?: RequestOptions, caller?: AnyCaller): Request; /** * Create a plain-text `Request`. * * - `HEAD` and `GET` requests never send a body. * * @param method The HTTP method. * @param url The target URL. * @param body The plain-text request body. * @param options Additional request options. * @returns A `Request` with `text/plain` content type. * * @example createTextRequest("POST", "https://api.example.com/items", "hello") */ export declare function createTextRequest(method: RequestMethod, url: PossibleURL, body: string, options?: RequestOptions, caller?: AnyCaller): Request; /** * Create a JSON `Request`. * - `HEAD` and `GET` requests never send a body. * - If the JSON body is a data object for `HEAD` or `GET`, it is appended as `?query` params instead. * * @param method The HTTP method. * @param url The target URL. * @param body The value to JSON-encode. * @param options Additional request options. * @returns A `Request` with `application/json` content type. * * @example createJSONRequest("POST", "https://api.example.com/items", { name: "abc" }) */ export declare function createJSONRequest(method: RequestBodyMethod, url: PossibleURL, body: unknown, options?: RequestOptions, caller?: AnyCaller): Request; /** * Create a multipart form-data `Request`. * - `HEAD` and `GET` requests never send a body. * * @param method The HTTP method. * @param url The target URL. * @param body The `FormData` payload. * @param options Additional request options. * @returns A `Request` with a multipart body. * * @example createFormDataRequest("POST", "https://api.example.com/upload", new FormData()) */ export declare function createFormDataRequest(method: RequestBodyMethod, url: PossibleURL, body: FormData, options?: RequestOptions, caller?: AnyCaller): Request; /** * Create an XML `Request`. * - `HEAD` and `GET` requests never send a body. * - For `HEAD` and `GET`, the data object is appended as `?query` params instead. * * @param method The HTTP method. * @param url The target URL. * @param data The data object to serialize as XML. * @param options Additional request options. * @returns A `Request` with `application/xml` content type. * * @throws {RequiredError} If the XML data contains invalid element names or values. * * @example createXMLRequest("POST", "https://api.example.com/items", { item: { name: "abc" } }) */ export declare function createXMLRequest(method: RequestBodyMethod, url: PossibleURL, data: Data, options?: RequestOptions, caller?: AnyCaller): Request; /** * Create a `Request` instance with a valid content type based on the body. * - `undefined` or `null` are sent with no body. * - `FormData` is sent with `multipart/formdata` * - `string` is sent with `text/plain` header. * - Anything else is sent as `application/json` * - Expects a fully valid URL (any `{placeholders}` in the URL are not considered). * - As per the HTTP spec, `GET` and `HEAD` requests cannot contain a body * * @returns Request object. * * @throws {RequiredError} if this is a `HEAD` or `GET` request but `body` is not a data object. */ export declare function createRequest(method: RequestMethod, url: PossibleURL, payload: unknown, options?: RequestOptions, caller?: AnyCaller): Request; /** Assert that the payload for a HEAD or GET method is a data object, null, or undefined. */ export declare function assertRequestHeadPayload(payload: unknown, method: RequestHeadMethod, caller?: AnyCaller): asserts payload is Nullish<Data>;