UNPKG

@nestia/fetcher

Version:

Fetcher library of Nestia SDK

177 lines (167 loc) 6.33 kB
import { AesPkcs5 } from "./AesPkcs5"; import { IConnection } from "./IConnection"; import { IEncryptionPassword } from "./IEncryptionPassword"; import { IFetchRoute } from "./IFetchRoute"; import { IPropagation } from "./IPropagation"; import { FetcherBase } from "./internal/FetcherBase"; /** * Utility class for `fetch` functions used in `@nestia/sdk` with encryption. * * `EncryptedFetcher` is a utility class designed for SDK functions generated by * [`@nestia/sdk`](https://nestia.io/docs/sdk/sdk), interacting with the remote * HTTP API encrypted by AES-PKCS algorithm. In other words, this is a * collection of dedicated `fetch()` functions for `@nestia/sdk` with * encryption. * * For reference, `EncryptedFetcher` class being used only when target * controller method is encrypting body data by `@EncryptedRoute` or * `@EncryptedBody` decorators. If those decorators are not used, * {@link PlainFetcher} class would be used instead. * * @author Jeongho Nam - https://github.com/samchon */ export namespace EncryptedFetcher { /** * Fetch function only for `HEAD` method. * * @param connection Connection information for the remote HTTP server * @param route Route information about the target API * @returns Nothing because of `HEAD` method */ export function fetch( connection: IConnection, route: IFetchRoute<"HEAD">, ): Promise<void>; /** * Fetch function only for `GET` method. * * @param connection Connection information for the remote HTTP server * @param route Route information about the target API * @returns Response body data from the remote API */ export function fetch<Output>( connection: IConnection, route: IFetchRoute<"GET">, ): Promise<Output>; /** * Fetch function for the `POST`, `PUT`, `PATCH` and `DELETE` methods. * * @param connection Connection information for the remote HTTP server * @param route Route information about the target API * @returns Response body data from the remote API */ export function fetch<Input, Output>( connection: IConnection, route: IFetchRoute<"POST" | "PUT" | "PATCH" | "DELETE">, input?: Input, stringify?: (input: Input) => string, ): Promise<Output>; export async function fetch<Input, Output>( connection: IConnection, route: IFetchRoute<"DELETE" | "GET" | "HEAD" | "PATCH" | "POST" | "PUT">, input?: Input, stringify?: (input: Input) => string, ): Promise<Output> { if ( (route.request?.encrypted === true || route.response?.encrypted) && connection.encryption === undefined ) throw new Error( "Error on EncryptedFetcher.fetch(): the encryption password has not been configured.", ); const closure = typeof connection.encryption === "function" ? (direction: "encode" | "decode") => ( headers: Record<string, IConnection.HeaderValue | undefined>, body: string, ) => (connection.encryption as IEncryptionPassword.Closure)({ headers, body, direction, }) : () => () => connection.encryption as IEncryptionPassword; return FetcherBase.request({ className: "EncryptedFetcher", encode: route.request?.encrypted === true ? (input, headers) => { const p: IEncryptionPassword = closure("encode")(headers, input); return AesPkcs5.encrypt( (stringify ?? JSON.stringify)(input), p.key, p.iv, ); } : (input) => input, decode: route.response?.encrypted === true ? (input, headers) => { const p: IEncryptionPassword = closure("decode")(headers, input); const s: string = AesPkcs5.decrypt(input, p.key, p.iv); return s.length ? JSON.parse(s) : s; } : (input) => input, })(connection, route, input, stringify); } export function propagate<Output extends IPropagation<any, any>>( connection: IConnection, route: IFetchRoute<"GET" | "HEAD">, ): Promise<Output>; export function propagate<Input, Output extends IPropagation<any, any>>( connection: IConnection, route: IFetchRoute<"DELETE" | "GET" | "HEAD" | "PATCH" | "POST" | "PUT">, input?: Input, stringify?: (input: Input) => string, ): Promise<Output>; export async function propagate<Input, Output extends IPropagation<any, any>>( connection: IConnection, route: IFetchRoute<"DELETE" | "GET" | "HEAD" | "PATCH" | "POST" | "PUT">, input?: Input, stringify?: (input: Input) => string, ): Promise<Output> { if ( (route.request?.encrypted === true || route.response?.encrypted) && connection.encryption === undefined ) throw new Error( "Error on EncryptedFetcher.propagate(): the encryption password has not been configured.", ); const closure = typeof connection.encryption === "function" ? (direction: "encode" | "decode") => ( headers: Record<string, IConnection.HeaderValue | undefined>, body: string, ) => (connection.encryption as IEncryptionPassword.Closure)({ headers, body, direction, }) : () => () => connection.encryption as IEncryptionPassword; return FetcherBase.propagate({ className: "EncryptedFetcher", encode: route.request?.encrypted === true ? (input, headers) => { const p: IEncryptionPassword = closure("encode")(headers, input); return AesPkcs5.encrypt( (stringify ?? JSON.stringify)(input), p.key, p.iv, ); } : (input) => input, decode: route.response?.encrypted === true ? (input, headers) => { const p: IEncryptionPassword = closure("decode")(headers, input); const s: string = AesPkcs5.decrypt(input, p.key, p.iv); return s.length ? JSON.parse(s) : s; } : (input) => input, })(connection, route, input, stringify) as Promise<Output>; } }