import { Logger } from "./logger"; import { UserAgent } from "./util"; export interface InitializeHandlerArguments { /** * User input to a command. Reflects the userland representation of the * union of data types the command can effectively handle. */ input: Input; } export interface InitializeHandlerOutput extends DeserializeHandlerOutput { output: Output; } export interface SerializeHandlerArguments extends InitializeHandlerArguments { /** * The user input serialized as a request object. The request object is unknown, * so you cannot modify it directly. When work with request, you need to guard its * type to e.g. HttpRequest with 'instanceof' operand * * During the build phase of the execution of a middleware stack, a built * request may or may not be available. */ request?: unknown; } export interface SerializeHandlerOutput extends InitializeHandlerOutput {} export interface BuildHandlerArguments extends FinalizeHandlerArguments {} export interface BuildHandlerOutput extends InitializeHandlerOutput {} export interface FinalizeHandlerArguments extends SerializeHandlerArguments { /** * The user input serialized as a request. */ request: unknown; } export interface FinalizeHandlerOutput extends InitializeHandlerOutput {} export interface DeserializeHandlerArguments extends FinalizeHandlerArguments {} export interface DeserializeHandlerOutput { /** * The raw response object from runtime is deserialized to structured output object. * The response object is unknown so you cannot modify it directly. When work with * response, you need to guard its type to e.g. HttpResponse with 'instanceof' operand. * * During the deserialize phase of the execution of a middleware stack, a deserialized * response may or may not be available */ response: unknown; output?: Output; } export interface InitializeHandler { /** * Asynchronously converts an input object into an output object. * * @param args An object containing a input to the command as well as any * associated or previously generated execution artifacts. */ (args: InitializeHandlerArguments): Promise>; } export type Handler = InitializeHandler; export interface SerializeHandler { /** * Asynchronously converts an input object into an output object. * * @param args An object containing a input to the command as well as any * associated or previously generated execution artifacts. */ (args: SerializeHandlerArguments): Promise>; } export interface FinalizeHandler { /** * Asynchronously converts an input object into an output object. * * @param args An object containing a input to the command as well as any * associated or previously generated execution artifacts. */ (args: FinalizeHandlerArguments): Promise>; } export interface BuildHandler { (args: BuildHandlerArguments): Promise>; } export interface DeserializeHandler { (args: DeserializeHandlerArguments): Promise>; } /** * A factory function that creates functions implementing the {Handler} * interface. */ export interface InitializeMiddleware { /** * @param next The handler to invoke after this middleware has operated on * the user input and before this middleware operates on the output. * * @param context Invariant data and functions for use by the handler. */ (next: InitializeHandler, context: HandlerExecutionContext): InitializeHandler; } /** * A factory function that creates functions implementing the {BuildHandler} * interface. */ export interface SerializeMiddleware { /** * @param next The handler to invoke after this middleware has operated on * the user input and before this middleware operates on the output. * * @param context Invariant data and functions for use by the handler. */ (next: SerializeHandler, context: HandlerExecutionContext): SerializeHandler; } /** * A factory function that creates functions implementing the {FinalizeHandler} * interface. */ export interface FinalizeRequestMiddleware { /** * @param next The handler to invoke after this middleware has operated on * the user input and before this middleware operates on the output. * * @param context Invariant data and functions for use by the handler. */ (next: FinalizeHandler, context: HandlerExecutionContext): FinalizeHandler; } export interface BuildMiddleware { (next: BuildHandler, context: HandlerExecutionContext): BuildHandler; } export interface DeserializeMiddleware { (next: DeserializeHandler, context: HandlerExecutionContext): DeserializeHandler; } export type MiddlewareType = | InitializeMiddleware | SerializeMiddleware | BuildMiddleware | FinalizeRequestMiddleware | DeserializeMiddleware; /** * A factory function that creates the terminal handler atop which a middleware * stack sits. */ export interface Terminalware { (context: HandlerExecutionContext): DeserializeHandler; } export type Step = "initialize" | "serialize" | "build" | "finalizeRequest" | "deserialize"; export type Priority = "high" | "normal" | "low"; export interface HandlerOptions { /** * Handlers are ordered using a "step" that describes the stage of command * execution at which the handler will be executed. The available steps are: * * - initialize: The input is being prepared. Examples of typical * initialization tasks include injecting default options computing * derived parameters. * - serialize: The input is complete and ready to be serialized. Examples * of typical serialization tasks include input validation and building * an HTTP request from user input. * - build: The input has been serialized into an HTTP request, but that * request may require further modification. Any request alterations * will be applied to all retries. Examples of typical build tasks * include injecting HTTP headers that describe a stable aspect of the * request, such as `Content-Length` or a body checksum. * - finalizeRequest: The request is being prepared to be sent over the wire. The * request in this stage should already be semantically complete and * should therefore only be altered as match the recipient's * expectations. Examples of typical finalization tasks include request * signing and injecting hop-by-hop headers. * - deserialize: The response has arrived, the middleware here will deserialize * the raw response object to structured response * * Unlike initialization and build handlers, which are executed once * per operation execution, finalization and deserialize handlers will be * executed foreach HTTP request sent. * * @default 'initialize' */ step?: Step; /** * A list of strings to any that identify the general purpose or important * characteristics of a given handler. */ tags?: Array; /** * A unique name to refer to a middleware */ name?: string; /** * A flag to override the existing middleware with the same name. Without * setting it, adding middleware with duplicated name will throw an exception. * @internal */ override?: boolean; } export interface AbsoluteLocation { /** * By default middleware will be added to individual step in un-guaranteed order. * In the case that * * @default 'normal' */ priority?: Priority; } export type Relation = "before" | "after"; export interface RelativeLocation { /** * Specify the relation to be before or after a know middleware. */ relation: Relation; /** * A known middleware name to indicate inserting middleware's location. */ toMiddleware: string; } export type RelativeMiddlewareOptions = RelativeLocation & Omit; export interface InitializeHandlerOptions extends HandlerOptions { step?: "initialize"; } export interface SerializeHandlerOptions extends HandlerOptions { step: "serialize"; } export interface BuildHandlerOptions extends HandlerOptions { step: "build"; } export interface FinalizeRequestHandlerOptions extends HandlerOptions { step: "finalizeRequest"; } export interface DeserializeHandlerOptions extends HandlerOptions { step: "deserialize"; } /** * A stack storing middleware. It can be resolved into a handler. It supports 2 * approaches for adding middleware: * 1. Adding middleware to specific step with `add()`. The order of middleware * added into same step is determined by order of adding them. If one middleware * needs to be executed at the front of the step or at the end of step, set * `priority` options to `high` or `low`. * 2. Adding middleware to location relative to known middleware with `addRelativeTo()`. * This is useful when given middleware must be executed before or after specific * middleware(`toMiddleware`). You can add a middleware relatively to another * middleware which also added relatively. But eventually, this relative middleware * chain **must** be 'anchored' by a middleware that added using `add()` API * with absolute `step` and `priority`. This mothod will throw if specified * `toMiddleware` is not found. */ export interface MiddlewareStack extends Pluggable { /** * Add middleware to the stack to be executed during the "initialize" step, * optionally specifying a priority, tags and name */ add(middleware: InitializeMiddleware, options?: InitializeHandlerOptions & AbsoluteLocation): void; /** * Add middleware to the stack to be executed during the "serialize" step, * optionally specifying a priority, tags and name */ add(middleware: SerializeMiddleware, options: SerializeHandlerOptions & AbsoluteLocation): void; /** * Add middleware to the stack to be executed during the "build" step, * optionally specifying a priority, tags and name */ add(middleware: BuildMiddleware, options: BuildHandlerOptions & AbsoluteLocation): void; /** * Add middleware to the stack to be executed during the "finalizeRequest" step, * optionally specifying a priority, tags and name */ add( middleware: FinalizeRequestMiddleware, options: FinalizeRequestHandlerOptions & AbsoluteLocation ): void; /** * Add middleware to the stack to be executed during the "deserialize" step, * optionally specifying a priority, tags and name */ add(middleware: DeserializeMiddleware, options: DeserializeHandlerOptions & AbsoluteLocation): void; /** * Add middleware to a stack position before or after a known middleware,optionally * specifying name and tags. */ addRelativeTo(middleware: MiddlewareType, options: RelativeMiddlewareOptions): void; /** * Apply a customization function to mutate the middleware stack, often * used for customizations that requires mutating multiple middleware. */ use(pluggable: Pluggable): void; /** * Create a shallow clone of this stack. Step bindings and handler priorities * and tags are preserved in the copy. */ clone(): MiddlewareStack; /** * Removes middleware from the stack. * * If a string is provided, it will be treated as middleware name. If a middleware * is inserted with the given name, it will be removed. * * If a middleware class is provided, all usages thereof will be removed. */ remove(toRemove: MiddlewareType | string): boolean; /** * Removes middleware that contains given tag * * Multiple middleware will potentially be removed */ removeByTag(toRemove: string): boolean; /** * Create a stack containing the middlewares in this stack as well as the * middlewares in the `from` stack. Neither source is modified, and step * bindings and handler priorities and tags are preserved in the copy. */ concat( from: MiddlewareStack ): MiddlewareStack; /** * Builds a single handler function from zero or more middleware classes and * a core handler. The core handler is meant to send command objects to AWS * services and return promises that will resolve with the operation result * or be rejected with an error. * * When a composed handler is invoked, the arguments will pass through all * middleware in a defined order, and the return from the innermost handler * will pass through all middleware in the reverse of that order. */ resolve( handler: DeserializeHandler, context: HandlerExecutionContext ): InitializeHandler; } /** * Data and helper objects that are not expected to change from one execution of * a composed handler to another. */ export interface HandlerExecutionContext { /** * A logger that may be invoked by any handler during execution of an * operation. */ logger?: Logger; /** * Additional user agent that inferred by middleware. It can be used to save * the internal user agent sections without overriding the `customUserAgent` * config in clients. */ userAgent?: UserAgent; [key: string]: any; } export interface Pluggable { /** * A function that mutate the passed in middleware stack. Functions implementing * this interface can add, remove, modify existing middleware stack from clients * or commands */ applyToStack: (stack: MiddlewareStack) => void; }