diff --git a/clients/node/client-rds-data-node/RDSDataClient.ts b/clients/node/client-rds-data-node/RDSDataClient.ts index de4814a34d6dd..17b0e79a5bf37 100644 --- a/clients/node/client-rds-data-node/RDSDataClient.ts +++ b/clients/node/client-rds-data-node/RDSDataClient.ts @@ -1,153 +1,47 @@ -import * as __aws_sdk_config_resolver from "@aws-sdk/config-resolver"; -import * as __aws_sdk_middleware_content_length from "@aws-sdk/middleware-content-length"; -import * as __aws_sdk_middleware_header_default from "@aws-sdk/middleware-header-default"; -import * as __aws_sdk_middleware_stack from "@aws-sdk/middleware-stack"; -import * as __aws_sdk_retry_middleware from "@aws-sdk/retry-middleware"; -import * as __aws_sdk_signing_middleware from "@aws-sdk/signing-middleware"; -import * as __aws_sdk_types from "@aws-sdk/types"; -import * as __aws_sdk_util_user_agent_node from "@aws-sdk/util-user-agent-node"; +import { contentLengthPlugin } from "@aws-sdk/middleware-content-length"; +import { UserAgentPlugin, UserAgentConfig } from "@aws-sdk/middleware-user-agent"; +import { retryPlugin, RetryConfig } from "@aws-sdk/retry-middleware"; +import { signingPlugin, AwsAuthConfiguration } from "@aws-sdk/signing-middleware"; import { RDSDataConfiguration, RDSDataResolvedConfiguration, - configurationProperties + RDSRuntimeConfiguration } from "./RDSDataConfiguration"; -import {version as clientVersion} from './package.json' -import {HttpOptions} from '@aws-sdk/types' - -/** - * To remove this when move to Smithy model - */ -const ServiceMetadata = { - endpointPrefix: "rds-data", - serviceId: "RDS Data" -}; +import { RegionConfiguration, EndpointsConfig, ProtocolConfig } from '@aws-sdk/config-resolver'; +import { HttpOptions, MetadataBearer } from '@aws-sdk/types'; +import { Client as SmithyClient } from "@aws-sdk/smithy-client"; type InputTypesUnion = any; -type OutputTypesUnion = any; +type OutputTypesUnion = MetadataBearer; -export class RDSDataClient { +export class RDSDataClient extends SmithyClient { readonly config: RDSDataResolvedConfiguration; - readonly middlewareStack = new __aws_sdk_middleware_stack.MiddlewareStack< - InputTypesUnion, - OutputTypesUnion - >(); - constructor(configuration: RDSDataConfiguration) { - this.config = __aws_sdk_config_resolver.resolveConfiguration( - configuration, - configurationProperties, - this.middlewareStack - ); - this.middlewareStack.add( - __aws_sdk_middleware_content_length.contentLengthMiddleware( - this.config.bodyLengthChecker - ), - { - step: "build", - priority: -80, - tags: { SET_CONTENT_LENGTH: true } - } - ); + const intermediaConfig_0 = ProtocolConfig.resolve({ + ...RDSRuntimeConfiguration, + ...configuration + }); + super(intermediaConfig_0); + let intermediaConfig_1 = RegionConfiguration.resolve(intermediaConfig_0); + let intermediaConfig_2 = AwsAuthConfiguration.resolve(intermediaConfig_1); + let intermediaConfig_3 = EndpointsConfig.resolve(intermediaConfig_2); + let intermediaConfig_4 = RetryConfig.resolve(intermediaConfig_3); + let intermediaConfig_5 = UserAgentConfig.resolve(intermediaConfig_4); + this.config = intermediaConfig_5; + super.use(contentLengthPlugin(this.config)); if (this.config.maxRetries > 0) { - this.middlewareStack.add( - __aws_sdk_retry_middleware.retryMiddleware( - this.config.maxRetries, - this.config.retryDecider, - this.config.delayDecider - ), - { - step: "finalize", - priority: Infinity, - tags: { RETRY: true } - } - ); + super.use(retryPlugin(this.config)); } - this.middlewareStack.add( - __aws_sdk_signing_middleware.signingMiddleware< - InputTypesUnion, - OutputTypesUnion - >(this.config.signer), - { - step: "finalize", - priority: 0, - tags: { SIGNATURE: true } - } - ); - this.middlewareStack.add( - __aws_sdk_middleware_header_default.headerDefault({ - "User-Agent": __aws_sdk_util_user_agent_node.defaultUserAgent( - ServiceMetadata.serviceId || ServiceMetadata.endpointPrefix, - clientVersion - ) - }), - { - step: "build", - priority: 0, - tags: { SET_USER_AGENT: true } - } - ); + super.use(signingPlugin(this.config)); + super.use(UserAgentPlugin(this.config)); } destroy(): void { if ( - !this.config._user_injected_http_handler && typeof this.config.httpHandler.destroy === 'function' ) { this.config.httpHandler.destroy(); } } - - /** - * This will need to be revised when the command interface lands. - */ - send( - command: __aws_sdk_types.Command< - InputTypesUnion, - InputType, - OutputTypesUnion, - OutputType, - RDSDataResolvedConfiguration - >, - options?: HttpOptions - ): Promise; - send( - command: __aws_sdk_types.Command< - InputTypesUnion, - InputType, - OutputTypesUnion, - OutputType, - RDSDataResolvedConfiguration - >, - options: HttpOptions, - cb: (err: any, data?: OutputType) => void - ): void; - send( - command: __aws_sdk_types.Command< - InputTypesUnion, - InputType, - OutputTypesUnion, - OutputType, - RDSDataResolvedConfiguration - >, - options?: HttpOptions, - cb?: (err: any, data?: OutputType) => void - ): Promise | void { - const handler = command.resolveMiddleware( - this.middlewareStack, - this.config, - options - ); - if (cb) { - handler(command) - .then(result => cb(null, result.output), (err: any) => cb(err)) - .catch( - // prevent any errors thrown in the callback from triggering an - // unhandled promise rejection - () => {} - ); - } else { - return handler(command).then(result => result.output); - } - } } diff --git a/clients/node/client-rds-data-node/RDSDataConfiguration.ts b/clients/node/client-rds-data-node/RDSDataConfiguration.ts index aca32a36c6639..b61aacd157333 100644 --- a/clients/node/client-rds-data-node/RDSDataConfiguration.ts +++ b/clients/node/client-rds-data-node/RDSDataConfiguration.ts @@ -1,290 +1,60 @@ -import * as __aws_sdk_credential_provider_node from "@aws-sdk/credential-provider-node"; -import * as __aws_sdk_hash_node from "@aws-sdk/hash-node"; -import * as __aws_sdk_http_handler from "@aws-sdk/node-http-handler"; -import * as __aws_sdk_region_provider from "@aws-sdk/region-provider"; -import * as __aws_sdk_signature_v4 from "@aws-sdk/signature-v4"; -import * as __aws_sdk_types from "@aws-sdk/types"; -import * as __aws_sdk_url_parser_node from "@aws-sdk/url-parser-node"; -import * as __aws_sdk_util_body_length_node from "@aws-sdk/util-body-length-node"; -import { Protocol, TransferHandler } from "@aws-sdk/types"; -import { HttpRequest, HttpResponse, HttpHandler } from "@aws-sdk/protocol-http"; +import { defaultProvider as credentialDefaultProvider } from "@aws-sdk/credential-provider-node"; +import { Hash } from "@aws-sdk/hash-node"; +import { NodeHttpHandler } from "@aws-sdk/node-http-handler"; +import { defaultProvider as regionDefaultProvider } from "@aws-sdk/region-provider"; +import { parseUrl } from "@aws-sdk/url-parser-node"; +import { calculateBodyLength } from "@aws-sdk/util-body-length-node"; +import { streamCollector } from '@aws-sdk/stream-collector-node'; import { RestJsonProtocol } from "@aws-sdk/protocol-rest-json"; - -export interface RDSDataConfiguration { - /** - * The credentials used to sign requests. - * - * If no static credentials are supplied, the SDK will attempt to credentials from known environment variables, from shared configuration and credentials files, and from the EC2 Instance Metadata Service, in that order. - */ - credentials?: - | __aws_sdk_types.Credentials - | __aws_sdk_types.Provider<__aws_sdk_types.Credentials>; - - /** - * A function that determines how long (in milliseconds) the SDK should wait before retrying a request - */ - delayDecider?: __aws_sdk_types.DelayDecider; - - /** - * The fully qualified endpoint of the webservice. This is only required when using a custom endpoint (for example, when using a local version of S3). - */ - endpoint?: - | string - | __aws_sdk_types.HttpEndpoint - | __aws_sdk_types.Provider<__aws_sdk_types.HttpEndpoint>; - - /** - * The endpoint provider to call if no endpoint is provided - */ - endpointProvider?: any; - - /** - * The HTTP handler to use - */ - httpHandler?: HttpHandler; - - /** - * Whether sockets should be kept open even when there are no outstanding requests so that future requests can forgo having to reestablish a TCP or TLS connection. Defaults to true. - */ - keepAlive?: boolean; - - /** - * The maximum number of redirects to follow for a service request. Set to `0` to disable retries. - */ - maxRedirects?: number; - - /** - * The maximum number of times requests that encounter potentially transient failures should be retried - */ - maxRetries?: number; - - /** - * The configuration profile to use. - */ - profile?: string; - - /** - * The AWS region to which this client will send requests - */ - region?: string | __aws_sdk_types.Provider; - - /** - * A function that determines whether an error is retryable - */ - retryDecider?: __aws_sdk_types.RetryDecider; - - /** - * A constructor for a class implementing the @aws-sdk/types.Hash interface that computes the SHA-256 HMAC or checksum of a string or binary buffer - */ - sha256?: __aws_sdk_types.HashConstructor; - - /** - * The signer to use when signing requests. - */ - signer?: __aws_sdk_types.RequestSigner; - - /** - * The service name with which to sign requests. - */ - signingName?: string; - - /** - * Whether SSL is enabled for requests. - */ - sslEnabled?: boolean; - - /** - * The function that will be used to convert strings into HTTP endpoints - */ - urlParser?: __aws_sdk_types.UrlParser; - - /** - * - */ - protocol?: Protocol; -} - -export interface RDSDataResolvableConfiguration extends RDSDataConfiguration { - /** - * Whether the HTTP handler was injected by the user and should thus not be destroyed when this client is - */ - _user_injected_http_handler: any; - - /** - * A function that can calculate the length of a request body. - */ - bodyLengthChecker: (body: any) => number | undefined; +import { fromUtf8, toUtf8 } from '@aws-sdk/util-utf8-node'; +import { fromBase64, toBase64 } from '@aws-sdk/util-base64-node'; +import { defaultUserAgent } from '@aws-sdk/util-user-agent-node'; +import { AwsAuthConfiguration, AwsAuthConfigurationInput } from '@aws-sdk/signing-middleware'; +import { UserAgentConfig, UserAgentConfigInput } from '@aws-sdk/middleware-user-agent'; +import { RetryConfig, RetryConfigInput } from '@aws-sdk/retry-middleware'; +import { name, version } from './package.json'; +import { + RegionConfiguration, + RegionConfigurationInput, + EndpointsConfig, + EndpointsConfigInput, + ProtocolConfig, + ProtocolConfigInput, + AWSClientRuntimeConfiguration +} from '@aws-sdk/config-resolver'; + +export type AWSClientRuntimeResolvedConfiguration = Required; + +export const RDSRuntimeConfiguration: AWSClientRuntimeResolvedConfiguration = { + protocolDefaultProvider: (handler) => new RestJsonProtocol(handler), + signingName: "rds-data", + service: "rds-data", + httpHandler: new NodeHttpHandler(), + sha256: Hash.bind(null, "sha256"), + credentialDefaultProvider, + regionDefaultProvider, + urlParser: parseUrl, + bodyLengthChecker: calculateBodyLength, + streamCollector, + base64Decoder: fromBase64, + base64Encoder: toBase64, + utf8Decoder: fromUtf8, + utf8Encoder: toUtf8, + defaultUserAgent: defaultUserAgent(name, version) } -export interface RDSDataResolvedConfiguration - extends RDSDataConfiguration { - _user_injected_http_handler: boolean; - - bodyLengthChecker: (body: any) => number | undefined; - - credentials: __aws_sdk_types.Provider<__aws_sdk_types.Credentials>; - - endpoint: __aws_sdk_types.Provider<__aws_sdk_types.HttpEndpoint>; - - endpointProvider: any; - - httpHandler: HttpHandler; - - keepAlive: boolean; - - maxRedirects: number; - - maxRetries: number; - - region: __aws_sdk_types.Provider; - - sha256: __aws_sdk_types.HashConstructor; - - signer: __aws_sdk_types.RequestSigner; - - signingName: string; - - sslEnabled: boolean; - - urlParser: __aws_sdk_types.UrlParser; - - protocol: Protocol; -} - -export const configurationProperties: __aws_sdk_types.ConfigurationDefinition< - RDSDataResolvableConfiguration, - RDSDataResolvedConfiguration -> = { - profile: {}, - maxRedirects: { - defaultValue: 10 - }, - maxRetries: { - defaultValue: 3 - }, - region: { - defaultProvider: __aws_sdk_region_provider.defaultProvider, - normalize: ( - value: string | __aws_sdk_types.Provider | undefined - ) => { - if (typeof value === "string") { - const promisified = Promise.resolve(value); - return () => promisified; - } - - return value!; - } - }, - sslEnabled: { - defaultValue: true - }, - urlParser: { - defaultValue: __aws_sdk_url_parser_node.parseUrl - }, - endpointProvider: { - defaultValue: (sslEnabled: boolean, region: string) => ({ - protocol: sslEnabled ? "https:" : "http:", - path: "/", - hostname: `rds-data.${region}.amazonaws.com` - }) - }, - endpoint: { - defaultProvider: (configuration: { - sslEnabled: boolean; - endpointProvider: any; - region: __aws_sdk_types.Provider; - }) => { - const promisified = configuration - .region() - .then(region => - configuration.endpointProvider(configuration.sslEnabled, region) - ); - return () => promisified; - }, - normalize: ( - value: - | string - | __aws_sdk_types.HttpEndpoint - | __aws_sdk_types.Provider<__aws_sdk_types.HttpEndpoint> - | undefined, - configuration: { - urlParser?: __aws_sdk_types.UrlParser; - } - ): __aws_sdk_types.Provider<__aws_sdk_types.HttpEndpoint> => { - if (typeof value === "string") { - const promisified = Promise.resolve(configuration.urlParser!(value)); - return () => promisified; - } else if (typeof value === "object") { - const promisified = Promise.resolve(value); - return () => promisified; - } - - // Users are not required to supply an endpoint, so `value` - // could be undefined. This function, however, will only be - // invoked if `value` is defined, so the return will never - // be undefined. - return value!; - } - }, - keepAlive: { - defaultValue: true - }, - _user_injected_http_handler: { - defaultProvider: (configuration: { httpHandler?: any }) => - !configuration.httpHandler - }, - httpHandler: { - defaultProvider: (configuration: { keepAlive: boolean }) => - new __aws_sdk_http_handler.NodeHttpHandler(configuration) - }, - bodyLengthChecker: { - defaultValue: __aws_sdk_util_body_length_node.calculateBodyLength - }, - retryDecider: {}, - delayDecider: {}, - credentials: { - defaultProvider: __aws_sdk_credential_provider_node.defaultProvider, - normalize: ( - value: - | __aws_sdk_types.Credentials - | __aws_sdk_types.Provider<__aws_sdk_types.Credentials> - | undefined - ) => { - if (typeof value === "object") { - const promisified = Promise.resolve(value); - return () => promisified; - } - - return value!; - } - }, - sha256: { - defaultValue: __aws_sdk_hash_node.Hash.bind(null, "sha256") - }, - signingName: { - defaultValue: "rds-data" - }, - signer: { - defaultProvider: (configuration: { - credentials: __aws_sdk_types.Provider<__aws_sdk_types.Credentials>; - region: __aws_sdk_types.Provider; - sha256: __aws_sdk_types.HashConstructor; - signingName: string; - }) => - new __aws_sdk_signature_v4.SignatureV4({ - credentials: configuration.credentials, - region: configuration.region, - service: configuration.signingName, - sha256: configuration.sha256, - uriEscapePath: true - }) - }, - protocol: { - defaultProvider: (configuration: { - httpHandler: TransferHandler< - HttpRequest, - HttpResponse - >; - }) => new RestJsonProtocol(configuration.httpHandler) - } -}; +export type RDSDataConfiguration = AWSClientRuntimeConfiguration & + AwsAuthConfigurationInput & + RegionConfigurationInput & + RetryConfigInput & + EndpointsConfigInput & + ProtocolConfigInput & + UserAgentConfigInput + +export type RDSDataResolvedConfiguration = AWSClientRuntimeResolvedConfiguration & + AwsAuthConfiguration.Resolved & + RegionConfiguration.Resolved & + RetryConfig.Resolved & + EndpointsConfig.Resolved & + ProtocolConfig.Resolved & + UserAgentConfig.Resolved \ No newline at end of file diff --git a/clients/node/client-rds-data-node/commands/ExecuteStatementCommand.ts b/clients/node/client-rds-data-node/commands/ExecuteStatementCommand.ts index 47940da0c07be..5a77f1d40815f 100644 --- a/clients/node/client-rds-data-node/commands/ExecuteStatementCommand.ts +++ b/clients/node/client-rds-data-node/commands/ExecuteStatementCommand.ts @@ -1,11 +1,11 @@ -import * as __aws_sdk_middleware_stack from "@aws-sdk/middleware-stack"; -import { serializerMiddleware } from "@aws-sdk/middleware-serializer"; -import { deserializerMiddleware } from "@aws-sdk/middleware-deserializer"; +import { Command } from '@aws-sdk/smithy-client'; +import { serializerPlugin } from "@aws-sdk/middleware-serializer"; +import { deserializerPlugin } from "@aws-sdk/middleware-deserializer"; import * as __aws_sdk_types from "@aws-sdk/types"; import { RDSDataResolvedConfiguration } from "../RDSDataConfiguration"; import { HttpRequest } from '@aws-sdk/protocol-http'; import { executeStatementSerializer, executeStatementDeserializer } from '../protocol/ExecuteStatement' -import { FinalizeHandlerArguments } from '@aws-sdk/types'; +import { FinalizeHandlerArguments, MiddlewareStack } from '@aws-sdk/types'; /** * To remove this when move to Smithy model @@ -15,16 +15,14 @@ type ExecuteStatementOutput = any; type InputTypesUnion = any; type OutputTypesUnion = any; -export class ExecuteStatementCommand { - readonly middlewareStack = new __aws_sdk_middleware_stack.MiddlewareStack< - ExecuteStatementInput, - ExecuteStatementOutput - >(); +export class ExecuteStatementCommand extends Command { - constructor(readonly input: ExecuteStatementInput) {} + constructor(readonly input: ExecuteStatementInput) { + super(); + } resolveMiddleware( - clientStack: __aws_sdk_middleware_stack.MiddlewareStack< + clientStack: MiddlewareStack< InputTypesUnion, OutputTypesUnion >, @@ -33,28 +31,8 @@ export class ExecuteStatementCommand { ): __aws_sdk_types.Handler { const { httpHandler } = configuration; - this.middlewareStack.add( - serializerMiddleware( - configuration.protocol, - executeStatementSerializer - ), - { - step: "serialize", - priority: 90, - tags: { SERIALIZER: true } - } - ); - this.middlewareStack.add( - deserializerMiddleware( - configuration.protocol, - executeStatementDeserializer - ) as any, - { - step: "deserialize", - priority: Infinity, - tags: { DESERIALIZER: true } - } - ); + this.use(serializerPlugin(configuration, executeStatementSerializer)); + this.use(deserializerPlugin(configuration, executeStatementDeserializer)); const stack = clientStack.concat(this.middlewareStack); @@ -63,7 +41,7 @@ export class ExecuteStatementCommand { }; return stack.resolve( - (request: FinalizeHandlerArguments) => {return httpHandler.handle(request.request as HttpRequest, options || {})}, + (request: FinalizeHandlerArguments) => httpHandler.handle(request.request as HttpRequest, options || {}), handlerExecutionContext ); } diff --git a/clients/node/client-rds-data-node/models/rdsdataservice/index.ts b/clients/node/client-rds-data-node/models/rdsdataservice/index.ts index 7342548d75cf1..4f25ad55bf9cd 100644 --- a/clients/node/client-rds-data-node/models/rdsdataservice/index.ts +++ b/clients/node/client-rds-data-node/models/rdsdataservice/index.ts @@ -1,4 +1,5 @@ import * as _smithy from "../../lib/smithy"; +import { MetadataBearer as $MetadataBearer } from "@aws-sdk/types"; export type ArrayValue = | ArrayValue.ArrayValuesMember @@ -135,7 +136,7 @@ export namespace BatchExecuteStatementRequest { } } -export interface BatchExecuteStatementResponse { +export interface BatchExecuteStatementResponse extends $MetadataBearer { __type?: "com.amazon.rdsdataservice#BatchExecuteStatementResponse"; updateResults?: Array; } @@ -162,7 +163,7 @@ export namespace BeginTransactionRequest { } } -export interface BeginTransactionResponse { +export interface BeginTransactionResponse extends $MetadataBearer { __type?: "com.amazon.rdsdataservice#BeginTransactionResponse"; transactionId?: string; } @@ -213,7 +214,7 @@ export namespace CommitTransactionRequest { } } -export interface CommitTransactionResponse { +export interface CommitTransactionResponse extends $MetadataBearer { __type?: "com.amazon.rdsdataservice#CommitTransactionResponse"; transactionStatus?: string; } @@ -246,7 +247,7 @@ export namespace ExecuteSqlRequest { } } -export interface ExecuteSqlResponse { +export interface ExecuteSqlResponse extends $MetadataBearer { __type?: "com.amazon.rdsdataservice#ExecuteSqlResponse"; sqlStatementResults?: Array; } @@ -279,7 +280,7 @@ export namespace ExecuteStatementRequest { } } -export interface ExecuteStatementResponse { +export interface ExecuteStatementResponse extends $MetadataBearer { __type?: "com.amazon.rdsdataservice#ExecuteStatementResponse"; numberOfRecordsUpdated?: number; records?: Array>; @@ -545,7 +546,7 @@ export namespace RollbackTransactionRequest { } } -export interface RollbackTransactionResponse { +export interface RollbackTransactionResponse extends $MetadataBearer { __type?: "com.amazon.rdsdataservice#RollbackTransactionResponse"; transactionStatus?: string; } diff --git a/clients/node/client-rds-data-node/package.json b/clients/node/client-rds-data-node/package.json index 8c50b00ca9dec..a309248f27850 100644 --- a/clients/node/client-rds-data-node/package.json +++ b/clients/node/client-rds-data-node/package.json @@ -28,6 +28,7 @@ "sideEffects": false, "license": "Apache-2.0", "dependencies": { + "@aws-sdk/smithy-client": "^0.1.0-preview.1", "@aws-sdk/protocol-http": "^0.1.0-preview.1", "@aws-crypto/sha256-browser": "^0.1.0-preview.1", "@aws-sdk/config-resolver": "^0.1.0-preview.5", @@ -37,7 +38,7 @@ "@aws-sdk/invalid-dependency": "^0.1.0-preview.1", "@aws-sdk/middleware-content-length": "^0.1.0-preview.5", "@aws-sdk/middleware-deserializer": "^0.1.0-preview.1", - "@aws-sdk/middleware-header-default": "^0.1.0-preview.5", + "@aws-sdk/middleware-user-agent": "^0.1.0-preview.1", "@aws-sdk/middleware-serializer": "^0.1.0-preview.5", "@aws-sdk/middleware-stack": "^0.1.0-preview.6", "@aws-sdk/node-http-handler": "^0.1.0-preview.6", diff --git a/clients/node/client-rds-data-node/protocol/AwsRestJson1_1.ts b/clients/node/client-rds-data-node/protocol/AwsRestJson1_1.ts index 38262e995cfe7..2d8b4347c7c49 100644 --- a/clients/node/client-rds-data-node/protocol/AwsRestJson1_1.ts +++ b/clients/node/client-rds-data-node/protocol/AwsRestJson1_1.ts @@ -11,11 +11,16 @@ import { ServiceUnavailableError } from "../models/rdsdataservice"; import { HttpRequest, HttpResponse } from "@aws-sdk/protocol-http"; +import { SerializerUtils, DeserializerUtils } from "@aws-sdk/types"; import * as __aws_sdk_stream_collector_node from "@aws-sdk/stream-collector-node"; import * as __aws_sdk_util_utf8_node from "@aws-sdk/util-utf8-node"; +import { ResponseMetadata } from "@aws-sdk/types"; + +type Utils = { [key: string]: any }; export function executeStatementAwsRestJson1_1Serialize( - input: ExecuteStatementRequest + input: ExecuteStatementRequest, + utils?: Utils ): HttpRequest { let body: any = {}; if (input.resourceArn !== undefined) { @@ -56,7 +61,7 @@ export function executeStatementAwsRestJson1_1Serialize( return new HttpRequest({ body: JSON.stringify(body), - path: "/execute", + path: "/Execute", method: "POST", protocol: "https:", headers: { @@ -66,13 +71,15 @@ export function executeStatementAwsRestJson1_1Serialize( } export async function executeStatementAwsRestJson1_1Deserialize( - output: HttpResponse + output: HttpResponse, + utils?: Utils ): Promise { if (output.statusCode !== 200) { return executeStatementAwsRestJson1_1DeserializeError(output); } - let data: any = await parseBody(output.body); + let data: any = await parseBody(output.body, utils); return Promise.resolve({ + $metadata: deserializeMetadata(output), __type: "com.amazon.rdsdataservice#ExecuteStatementResponse", records: recordsAwsRestJson1_1Deserialize(data.records), columnMetadata: columnMetadataListAwsRestJson1_1Deserialize( @@ -88,62 +95,73 @@ export async function executeStatementAwsRestJson1_1Deserialize( async function executeStatementAwsRestJson1_1DeserializeError( output: HttpResponse ): Promise { - const data: any = await parseBody(output); - - let response: any; - switch (output.headers["x-amzn-ErrorType"]) { - case "BadRequestException": - case "com.amazon.rdsdataservice#BadRequestException": - response = badRequestExceptionDeserialize(data); - break; - case "StatementTimeoutException": - case "com.amazon.rdsdataservice#StatementTimeoutException": - response = statementTimeoutExceptionDeserialize(data); - break; - case "ForbiddenException": - case "com.amazon.rdsdataservice#ForbiddenException": - response = forbiddenExceptionDeserialize(data); - break; - case "InternalServerErrorException": - case "com.amazon.rdsdataservice#InternalServerErrorException": - response = internalServerErrorExceptionDeserialize(data); - break; - case "ServiceUnavailableError": - case "com.amazon.rdsdataservice#ServiceUnavailableError": - response = serviceUnavailableErrorDeserialize(data); - break; - default: - response = { - __type: "com.amazon.rdsdataservice#UnknownException", - $name: "UnknownException", - $fault: "server" - }; + let data = await parseBody(output); + if (output.statusCode === 400 && data.dbConnectionId !== undefined) { + return Promise.reject({ + __type: "com.amazon.rdsdataservice#StatementTimeoutException", + $name: "StatementTimeoutException", + $fault: "client", + message: data.message, + dbConnectionId: data.dbConnectionId + }); } - return Promise.reject(response); -} + if (output.statusCode === 400) { + return Promise.reject({ + __type: "com.amazon.rdsdataservice#BadRequestException", + $name: "BadRequestException", + $fault: "client", + message: data.message + }); + } -function sqlParameterListAwsRestJson1_1Serialize( - input: Array -): Array { - let list: Array = []; - for (let SqlParameter of input) { - list.push(sqlParameterAwsRestJson1_1Serialize(SqlParameter)); + if (output.statusCode === 403) { + return Promise.reject({ + __type: "com.amazon.rdsdataservice#ForbiddenException", + $name: "ForbiddenException", + $fault: "client", + message: data.message + }); + } + + if (output.statusCode === 500) { + return Promise.reject({ + __type: "com.amazon.rdsdataservice#InternalServerErrorException", + $name: "InternalServerErrorException", + $fault: "server" + }); } - return list; -} -function sqlParameterAwsRestJson1_1Serialize(input: SqlParameter): any { - if (input.value !== undefined) { - return { - name: input.name, - value: fieldAwsRestJson1_1Serialize(input.value) - }; + if (output.statusCode === 503) { + return Promise.reject({ + __type: "com.amazon.rdsdataservice#ServiceUnavailableError", + $name: "ServiceUnavailableError", + $fault: "server" + }); } + + return Promise.reject({ + __type: "com.amazon.rdsdataservice#UnknownException", + $name: "UnknownException", + $fault: "server" + }); } -function fieldAwsRestJson1_1Serialize(input: Field): any { - return Field.visit(input, { +const sqlParameterListAwsRestJson1_1Serialize = ( + input: Array +): Array => + input && + input.map(sqlParameter => sqlParameterAwsRestJson1_1Serialize(sqlParameter)); + +const sqlParameterAwsRestJson1_1Serialize = (input: SqlParameter): any => + input.name && + input.value && { + name: input.name, + value: fieldAwsRestJson1_1Serialize(input.value) + }; + +const fieldAwsRestJson1_1Serialize = (input: Field): any => + Field.visit(input, { blobValue: value => { value; }, @@ -172,7 +190,6 @@ function fieldAwsRestJson1_1Serialize(input: Field): any { value; } }); -} export function columnMetadataAwsRestJson1_1Deserialize( input: any @@ -240,96 +257,74 @@ export function columnMetadataAwsRestJson1_1Deserialize( return columnMetadata; } -function columnMetadataListAwsRestJson1_1Deserialize( +const columnMetadataListAwsRestJson1_1Deserialize = ( input: any -): Array { - let list: Array = []; - for (let ColumnMetadata of input) { - list.push(columnMetadataAwsRestJson1_1Deserialize(ColumnMetadata)); - } - return list; -} - -function fieldAwsRestJson1_1Deserialize(input: any): Field { - return input.visit(input, {}); -} - -function generatedFieldsAwsRestJson1_1Deserialize(input: any): Array { - let list: Array = []; - for (let Field of input) { - list.push(fieldAwsRestJson1_1Deserialize(Field)); - } - return list; -} - -function recordsAwsRestJson1_1Deserialize(input: any): Array> { - let list: Array> = []; - for (let recordsList of input) { - list.push(recordsListAwsRestJson1_1Deserialize(input)); - } - return list; -} - -function recordsListAwsRestJson1_1Deserialize(input: any): Array { - let list: Array = []; - for (let Field of input) { - list.push(fieldAwsRestJson1_1Serialize(input)); - } - return list; -} - -function badRequestExceptionDeserialize(input: any): BadRequestException { - return { - __type: "com.amazon.rdsdataservice#BadRequestException", - $name: "BadRequestException", - $fault: "client", - message: input.message - }; -} - -function statementTimeoutExceptionDeserialize( - input: any -): StatementTimeoutException { - return { - __type: "com.amazon.rdsdataservice#StatementTimeoutException", - $name: "StatementTimeoutException", - $fault: "client", - message: input.message, - dbConnectionId: input.dbConnectionId - }; -} - -function forbiddenExceptionDeserialize(input: any): ForbiddenException { - return { - __type: "com.amazon.rdsdataservice#ForbiddenException", - $name: "ForbiddenException", - $fault: "client", - message: input.message - }; -} - -function internalServerErrorExceptionDeserialize( - input: any -): InternalServerErrorException { - return { - __type: "com.amazon.rdsdataservice#InternalServerErrorException", - $name: "InternalServerErrorException", - $fault: "server" - }; -} - -function serviceUnavailableErrorDeserialize( - input: any -): ServiceUnavailableError { - return { - __type: "com.amazon.rdsdataservice#ServiceUnavailableError", - $name: "ServiceUnavailableError", - $fault: "server" - }; -} +): Array => + input && + input.map((columnMetadata: any) => + columnMetadataAwsRestJson1_1Deserialize(columnMetadata) + ); + +const fieldAwsRestJson1_1Deserialize = (input: any): any => + Field.visit(input, { + blobValue: value => { + value; + }, + booleanValue: value => { + return value; + }, + arrayValue: value => { + return value; + }, + structValue: value => { + return value; + }, + longValue: value => { + return value; + }, + isNull: value => { + return value; + }, + doubleValue: value => { + return value; + }, + stringValue: value => { + return value; + }, + _: value => { + return value; + } + }); -function parseBody(streamBody: any): any { - __aws_sdk_stream_collector_node.streamCollector(streamBody).then(body => { - return JSON.parse(__aws_sdk_util_utf8_node.toUtf8(body)); +const generatedFieldsAwsRestJson1_1Deserialize = (input: any): Array => + input && input.map((field: any) => fieldAwsRestJson1_1Deserialize(field)); + +const recordsAwsRestJson1_1Deserialize = (input: any): Array> => + input && + input.map((recordsList: any) => + recordsListAwsRestJson1_1Deserialize(recordsList) + ); + +const recordsListAwsRestJson1_1Deserialize = (input: any): Array => + input && input.map((field: any) => fieldAwsRestJson1_1Deserialize(field)); + +const deserializeMetadata = (output: HttpResponse): ResponseMetadata => ({ + httpStatusCode: output.statusCode, + httpHeaders: output.headers, + requestId: output.headers["x-amzn-requestid"] +}); + +const parseBody = (streamBody: any, utils?: Utils): any => { + const streamCollector = + utils && utils["streamCollector"] + ? (utils)["streamCollector"] + : __aws_sdk_stream_collector_node.streamCollector; + const toUtf8 = + utils && utils["streamCollector"] + ? (utils)["utf8Encoder"] + : __aws_sdk_util_utf8_node.toUtf8; + + return streamCollector(streamBody).then(body => { + return JSON.parse(toUtf8(body)); }); -} +}; diff --git a/clients/node/client-rds-data-node/protocol/ExecuteStatement.ts b/clients/node/client-rds-data-node/protocol/ExecuteStatement.ts index b8bdeca5e8ae5..53bc195c5a0a4 100644 --- a/clients/node/client-rds-data-node/protocol/ExecuteStatement.ts +++ b/clients/node/client-rds-data-node/protocol/ExecuteStatement.ts @@ -8,13 +8,16 @@ import { executeStatementAwsRestJson1_1Deserialize } from "./AwsRestJson1_1"; +type Utils = { [key: string]: any }; + export function executeStatementSerializer( input: ExecuteStatementRequest, - protocol: string + protocol: string, + utils?: Utils ): HttpRequest { switch (protocol) { case "aws.rest-json-1.1": - return executeStatementAwsRestJson1_1Serialize(input); + return executeStatementAwsRestJson1_1Serialize(input, utils); default: throw new Error("Unknown protocol, use aws.rest-json-1.1"); } @@ -22,11 +25,12 @@ export function executeStatementSerializer( export async function executeStatementDeserializer( output: HttpResponse, - protocol: string + protocol: string, + utils?: Utils ): Promise { switch (protocol) { case "aws.rest-json-1.1": - return executeStatementAwsRestJson1_1Deserialize(output); + return executeStatementAwsRestJson1_1Deserialize(output, utils); default: throw new Error("Unknown protocol, use aws.rest-json-1.1"); } diff --git a/packages/config-resolver/package.json b/packages/config-resolver/package.json index e42c1fd730673..c1accf0871354 100644 --- a/packages/config-resolver/package.json +++ b/packages/config-resolver/package.json @@ -21,6 +21,8 @@ }, "dependencies": { "@aws-sdk/types": "^0.1.0-preview.5", + "@aws-sdk/signature-v4": "^0.1.0-preview.7", + "@aws-sdk/protocol-http": "^0.1.0-preview.1", "tslib": "^1.8.0" } } diff --git a/packages/config-resolver/src/components.ts b/packages/config-resolver/src/components.ts new file mode 100644 index 0000000000000..97052e2b54b8d --- /dev/null +++ b/packages/config-resolver/src/components.ts @@ -0,0 +1,222 @@ +import { + Credentials, + Provider, + HashConstructor, + UrlParser, + Protocol, + HttpOptions, + StreamCollector, + Decoder, + Encoder +} from "@aws-sdk/types"; +import { + HttpEndpoint, + HttpHandler, + HttpRequest, + HttpResponse +} from "@aws-sdk/protocol-http"; + +export interface RuntimeDependencies { + /** + * The HTTP handler to use. Fetch in browser and Https in Nodejs + */ + httpHandler?: HttpHandler; + + /** + * A constructor for a class implementing the @aws-sdk/types.Hash interface that computes the SHA-256 HMAC or checksum of a string or binary buffer + */ + sha256?: HashConstructor; + + /** + * Default credentials provider; Not available in browser runtime + */ + credentialDefaultProvider?: (input: any) => Provider; + + /** + * Provider function that return promise of a region string + */ + regionDefaultProvider?: (input: any) => Provider; + + /** + * The function that will be used to convert strings into HTTP endpoints + */ + urlParser?: UrlParser; + + /** + * A function that can calculate the length of a request body. + */ + bodyLengthChecker?: (body: any) => number | undefined; + + /** + * A function that converts a stream into an array of bytes. + */ + streamCollector?: StreamCollector; + + /** + * The function that will be used to convert a base64-encoded string to a byte array + */ + base64Decoder?: Decoder; + + /** + * The function that will be used to convert binary data to a base64-encoded string + */ + base64Encoder?: Encoder; + + /** + * The function that will be used to convert a UTF8-encoded string to a byte array + */ + utf8Decoder?: Decoder; + + /** + * The function that will be used to convert binary data to a UTF-8 encoded string + */ + utf8Encoder?: Encoder; + + /** + * The function that will be used to populate default value in 'User-Agent' header + */ + defaultUserAgent?: string; +} + +export interface AWSClientRuntimeConfiguration extends RuntimeDependencies { + /** + * The function that will be used to populate serializing protocol + */ + protocolDefaultProvider?: ( + handler: HttpHandler + ) => Protocol; + + /** + * The service name with which to sign requests. + */ + signingName?: string; + + /** + * The service name with which to construct endpoints. + */ + service?: string; +} + +export function normalizeProvider(input: T | Provider): Provider { + if (typeof input === "object") { + const promisified = Promise.resolve(input); + return () => promisified; + } + return input as Provider; +} + +export function normalizeEndpoint( + endpoint?: string | HttpEndpoint | Provider, + urlParser?: UrlParser +): Provider { + if (typeof endpoint === "string") { + const promisified = Promise.resolve(urlParser!(endpoint)); + return () => promisified; + } else if (typeof endpoint === "object") { + const promisified = Promise.resolve(endpoint); + return () => promisified; + } + return endpoint!; +} + +export namespace RegionConfiguration { + export interface Input { + /** + * The AWS region to which this client will send requests + */ + region?: string | Provider; + } + interface PreviouslyResolved { + regionDefaultProvider: (input: any) => Provider; + } + export interface Resolved { + region: Provider; + } + export function resolve( + input: T & Input & PreviouslyResolved + ): T & Resolved { + let region = input.region || input.regionDefaultProvider(input as any); + return { + ...input, + region: normalizeProvider(region) + }; + } +} +//export separately for showing comment block in Intellisense +export type RegionConfigurationInput = RegionConfiguration.Input; + +export namespace EndpointsConfig { + export interface Input { + /** + * The fully qualified endpoint of the webservice. This is only required when using a custom endpoint (for example, when using a local version of S3). + */ + endpoint?: string | HttpEndpoint | Provider; + + /** + * The endpoint provider to call if no endpoint is provided + */ + endpointProvider?: any; + + /** + * Whether TLS is enabled for requests. + */ + tls?: boolean; + } + interface PreviouslyResolved { + urlParser: UrlParser; + region: Provider; + service: string; + } + export interface Resolved extends Required { + endpoint: Provider; + } + export function resolve( + input: T & Input & PreviouslyResolved + ): T & Resolved { + const tls = input.tls || true; + const defaultProvider = (tls: boolean, region: string) => ({ + protocol: tls ? "https:" : "http:", + path: "/", + hostname: `${input.service}.${region}.amazonaws.com` + }); + const endpointProvider = input.endpointProvider || defaultProvider; + let endpoint: Provider = input.endpoint + ? normalizeEndpoint(input.endpoint, input.urlParser) + : () => input.region().then(region => endpointProvider(tls, region)); + return { + ...input, + endpointProvider, + endpoint, + tls + }; + } +} +//export separately for showing comment block in Intellisense +export type EndpointsConfigInput = EndpointsConfig.Input; + +export namespace ProtocolConfig { + export interface Input { + /** + * The serializing protocol to used in request + */ + protocol?: Protocol; + } + interface PreviouslyResolved { + httpHandler: HttpHandler; + protocolDefaultProvider: ( + handler: HttpHandler + ) => Protocol; + } + export type Resolved = Required; + export function resolve( + input: T & Input & PreviouslyResolved + ): T & Resolved { + return { + ...input, + protocol: + input.protocol || input.protocolDefaultProvider(input.httpHandler) + }; + } +} +//export separately for showing comment block in Intellisense +export type ProtocolConfigInput = ProtocolConfig.Input; diff --git a/packages/config-resolver/src/index.spec.ts b/packages/config-resolver/src/index.spec.ts deleted file mode 100644 index b89e734db4656..0000000000000 --- a/packages/config-resolver/src/index.spec.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { resolveConfiguration } from "./index"; -import { ConfigurationDefinition } from "@aws-sdk/types"; - -describe("resolveConfiguration", () => { - it("should throw if a required property is not supplied", () => { - const definition: ConfigurationDefinition< - { region: string }, - { region: string } - > = { - region: { - required: true - } - }; - const config = {}; - - expect(() => resolveConfiguration(config, definition, {} as any)).toThrow(); - }); - - it("should inject a default value if a property is not supplied", () => { - const definition: ConfigurationDefinition< - { region?: string }, - { region: string } - > = { - region: { - required: false, - defaultValue: "us-west-2" - } - }; - - expect(resolveConfiguration({}, definition, {} as any)).toEqual({ - region: "us-west-2" - }); - }); - - it("should not inject a default value if a property is supplied", () => { - const definition: ConfigurationDefinition< - { region?: string }, - { region: string } - > = { - region: { - required: false, - defaultValue: "us-west-2" - } - }; - - expect( - resolveConfiguration({ region: "eu-central-1" }, definition, {} as any) - ).toEqual({ region: "eu-central-1" }); - }); - - it("should call a default provider and inject its return value if a property is not supplied", () => { - const defaultProvider = jest.fn().mockReturnValue("us-west-2"); - const definition: ConfigurationDefinition< - { region?: string }, - { region: string } - > = { - region: { - required: false, - defaultProvider - } - }; - const config = {}; - - expect(resolveConfiguration(config, definition, {} as any)).toEqual({ - region: "us-west-2" - }); - expect(defaultProvider.mock.calls.length).toBe(1); - }); - - it("should not call a default provider if a property is supplied", () => { - const defaultProvider = jest.fn().mockReturnValue("us-west-2"); - const definition: ConfigurationDefinition< - { region?: string }, - { region: string } - > = { - region: { - required: false, - defaultProvider - } - }; - - expect( - resolveConfiguration({ region: "eu-central-1" }, definition, {} as any) - ).toEqual({ region: "eu-central-1" }); - expect(defaultProvider.mock.calls.length).toBe(0); - }); - - it("should always call a normalizer function if one is provided", () => { - const normalize = jest.fn().mockReturnValue("normalized!"); - const middlewareStack = {} as any; - const definition: ConfigurationDefinition< - { region: string }, - { region: string } - > = { - region: { - required: true, - normalize - } - }; - expect( - resolveConfiguration( - { region: "eu-central-1" }, - definition, - middlewareStack - ) - ).toEqual({ region: "normalized!" }); - expect(normalize.mock.calls.length).toBe(1); - expect(normalize.mock.calls[0][0]).toEqual("eu-central-1"); - }); - - it("should always call an apply function if one is provided", () => { - const apply = jest.fn(); - const middlewareStack = {} as any; - const definition: ConfigurationDefinition< - { region: string }, - { region: string } - > = { - region: { - required: true, - apply - } - }; - - expect( - resolveConfiguration( - { region: "eu-central-1" }, - definition, - middlewareStack - ) - ).toEqual({ region: "eu-central-1" }); - - expect(apply.mock.calls.length).toBe(1); - expect(apply.mock.calls[0]).toEqual([ - { region: "eu-central-1" }, - middlewareStack - ]); - }); -}); diff --git a/packages/config-resolver/src/index.ts b/packages/config-resolver/src/index.ts index a19aa2fd8eebb..40b494c5f8737 100644 --- a/packages/config-resolver/src/index.ts +++ b/packages/config-resolver/src/index.ts @@ -1,58 +1 @@ -import { - ConfigApplicator, - ConfigurationDefinition, - MiddlewareStack -} from "@aws-sdk/types"; - -export type IndexedObject = { [key: string]: any }; - -export function resolveConfiguration< - T extends IndexedObject, - R extends T, - Input extends object, - Output extends object ->( - providedConfiguration: T, - configurationDefinition: ConfigurationDefinition, - middlewareStack: MiddlewareStack -): R { - const out: Partial = {}; - const applicators: Array> = []; - - // Iterate over the definitions own keys, using getOwnPropertyNames to - // guarantee insertion order is preserved. - // @see https://www.ecma-international.org/ecma-262/6.0/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys - for (const property of Object.getOwnPropertyNames(configurationDefinition)) { - const { - required, - defaultValue, - defaultProvider, - normalize, - apply - } = configurationDefinition[property]; - let input = providedConfiguration[property]; - - if (input === undefined) { - if (defaultValue !== undefined) { - input = defaultValue; - } else if (defaultProvider) { - input = defaultProvider(out as R); - } else if (required) { - throw new Error( - `No input provided for required configuration parameter: ${property}` - ); - } - } else if (normalize) { - input = normalize(input, out); - } - //@ts-ignore - out[property] = input; - - if (apply) { - applicators.push(apply); - } - } - - applicators.forEach(func => func(out as R, middlewareStack)); - return out as R; -} +export * from "./components"; diff --git a/packages/middleware-content-length/src/index.ts b/packages/middleware-content-length/src/index.ts index abcff8f903a6d..16f97c7867548 100644 --- a/packages/middleware-content-length/src/index.ts +++ b/packages/middleware-content-length/src/index.ts @@ -4,12 +4,13 @@ import { BuildMiddleware, BodyLengthCalculator, MetadataBearer, - BuildHandlerOutput + BuildHandlerOutput, + InjectableMiddleware } from "@aws-sdk/types"; import { HttpRequest } from "@aws-sdk/protocol-http"; export function contentLengthMiddleware( - bodyLengthCalculator: BodyLengthCalculator + bodyLengthChecker: BodyLengthCalculator ): BuildMiddleware { return ( next: BuildHandler @@ -26,7 +27,7 @@ export function contentLengthMiddleware( .map(str => str.toLowerCase()) .indexOf("content-length") === -1 ) { - const length = bodyLengthCalculator(body); + const length = bodyLengthChecker(body); if (length !== undefined) { request.headers = { ...request.headers, @@ -42,3 +43,13 @@ export function contentLengthMiddleware( }); }; } + +export function contentLengthPlugin(options: { + bodyLengthChecker: BodyLengthCalculator; +}): InjectableMiddleware { + return { + middleware: contentLengthMiddleware(options.bodyLengthChecker), + step: "build", + tags: { SET_CONTENT_LENGTH: true } + }; +} diff --git a/packages/middleware-deserializer/src/index.ts b/packages/middleware-deserializer/src/index.ts index e9e1d6e7e989c..deb07eed2e87e 100644 --- a/packages/middleware-deserializer/src/index.ts +++ b/packages/middleware-deserializer/src/index.ts @@ -4,14 +4,16 @@ import { DeserializeHandlerArguments, DeserializeMiddleware, DeserializeHandlerOutput, - Protocol + Protocol, + DeserializerUtils, + InjectableMiddleware } from "@aws-sdk/types"; export function deserializerMiddleware< Input extends object, Output extends object >( - protocol: Protocol, + options: DeserializerMiddlewareConfig, deserializer: ResponseDeserializer ): DeserializeMiddleware { return ( @@ -20,10 +22,29 @@ export function deserializerMiddleware< args: DeserializeHandlerArguments ): Promise> => { const { response } = await next(args); - const parsed = await protocol.parse(deserializer, response); + const parsed = await options.protocol.deserialize( + deserializer, + response, + options + ); return { response, output: parsed as Output }; }; } + +export interface DeserializerMiddlewareConfig extends DeserializerUtils { + protocol: Protocol; +} + +export function deserializerPlugin( + config: DeserializerMiddlewareConfig, + serializer: ResponseDeserializer +): InjectableMiddleware { + return { + middleware: deserializerMiddleware(config, serializer), + step: "deserialize", + tags: { DESERIALIZER: true } + }; +} diff --git a/packages/middleware-serializer/src/index.ts b/packages/middleware-serializer/src/index.ts index 0be73abe3d492..b8361cc7baa1e 100644 --- a/packages/middleware-serializer/src/index.ts +++ b/packages/middleware-serializer/src/index.ts @@ -4,14 +4,16 @@ import { SerializeHandlerArguments, SerializeMiddleware, SerializeHandlerOutput, - Protocol + Protocol, + SerializerUtils, + InjectableMiddleware } from "@aws-sdk/types"; export function serializerMiddleware< Input extends object, Output extends object >( - protocol: Protocol, + options: SerializerMiddlewareConfig, serializer: RequestSerializer ): SerializeMiddleware { return ( @@ -19,10 +21,25 @@ export function serializerMiddleware< ): SerializeHandler => async ( args: SerializeHandlerArguments ): Promise> => { - const request = protocol.serialize(serializer, args.input); + const request = options.protocol.serialize(serializer, args.input, options); return next({ ...args, request }); }; } + +export interface SerializerMiddlewareConfig extends SerializerUtils { + protocol: Protocol; +} + +export function serializerPlugin( + config: SerializerMiddlewareConfig, + serializer: RequestSerializer +): InjectableMiddleware { + return { + middleware: serializerMiddleware(config, serializer), + step: "serialize", + tags: { SERIALIZER: true } + }; +} diff --git a/packages/middleware-stack/src/index.spec.ts b/packages/middleware-stack/src/index.spec.ts index 36ae48c754a38..d56f436133e59 100644 --- a/packages/middleware-stack/src/index.spec.ts +++ b/packages/middleware-stack/src/index.spec.ts @@ -5,7 +5,7 @@ import { FinalizeHandlerArguments, Middleware, HandlerExecutionContext, - FinalizeMiddleware, + FinalizeRequestMiddleware, FinalizeHandler, BuildMiddleware, HandlerOutput, @@ -19,7 +19,7 @@ type output = object; //return tagged union to make compiler happy function getConcatMiddleware( message: string -): Middleware | FinalizeMiddleware { +): Middleware | FinalizeRequestMiddleware { return (next: Handler): Handler => { return (args: HandlerArguments): Promise> => next({ @@ -47,8 +47,8 @@ describe("MiddlewareStack", () => { [getConcatMiddleware("first"), { priority: 10 }], [getConcatMiddleware("fourth"), { step: "build" }], [getConcatMiddleware("third"), { step: "build", priority: 1 }], - [getConcatMiddleware("fifth"), { step: "finalize" }], - [getConcatMiddleware("sixth"), { step: "finalize", priority: -1 }], + [getConcatMiddleware("fifth"), { step: "finalizeRequest" }], + [getConcatMiddleware("sixth"), { step: "finalizeRequest", priority: -1 }], [getConcatMiddleware("seven"), { step: "deserialize" }] ]); @@ -93,11 +93,11 @@ describe("MiddlewareStack", () => { const secondStack = new MiddlewareStack(); secondStack.add( - getConcatMiddleware("fourth") as FinalizeMiddleware, + getConcatMiddleware("fourth") as FinalizeRequestMiddleware, { step: "build" } ); secondStack.add( - getConcatMiddleware("third") as FinalizeMiddleware, + getConcatMiddleware("third") as FinalizeRequestMiddleware, { step: "build", priority: 100 } ); @@ -187,9 +187,9 @@ describe("MiddlewareStack", () => { step: "build" }); stack.add( - getConcatMiddleware("sixth") as FinalizeMiddleware, + getConcatMiddleware("sixth") as FinalizeRequestMiddleware, { - step: "finalize" + step: "finalizeRequest" } ); const filteredStack = stack.filter(middlewareStats => { diff --git a/packages/middleware-stack/src/index.ts b/packages/middleware-stack/src/index.ts index 7d6196088a2d9..d165cd763a65f 100644 --- a/packages/middleware-stack/src/index.ts +++ b/packages/middleware-stack/src/index.ts @@ -1,9 +1,9 @@ import { BuildHandlerOptions, FinalizeHandler, - FinalizeHandlerOptions, + FinalizeRequestHandlerOptions, SerializeMiddleware, - FinalizeMiddleware, + FinalizeRequestMiddleware, BuildMiddleware, Handler, HandlerExecutionContext, @@ -42,13 +42,13 @@ export class MiddlewareStack { ): void; add( - middleware: FinalizeMiddleware, + middleware: FinalizeRequestMiddleware, options: BuildHandlerOptions ): void; add( - middleware: FinalizeMiddleware, - options: FinalizeHandlerOptions + middleware: FinalizeRequestMiddleware, + options: FinalizeRequestHandlerOptions ): void; add( @@ -165,6 +165,6 @@ const stepWeights = { initialize: 5, serialize: 4, build: 3, - finalize: 2, + finalizeRequest: 2, deserialize: 1 }; diff --git a/packages/middleware-user-agent/.gitignore b/packages/middleware-user-agent/.gitignore new file mode 100644 index 0000000000000..3d1714c9806ef --- /dev/null +++ b/packages/middleware-user-agent/.gitignore @@ -0,0 +1,8 @@ +/node_modules/ +/build/ +/coverage/ +/docs/ +*.tsbuildinfo +*.tgz +*.log +package-lock.json diff --git a/packages/middleware-user-agent/.npmignore b/packages/middleware-user-agent/.npmignore new file mode 100644 index 0000000000000..4b9fe3abf33a6 --- /dev/null +++ b/packages/middleware-user-agent/.npmignore @@ -0,0 +1,13 @@ +/src/ +/coverage/ +/docs/ +tsconfig.test.json +*.tsbuildinfo + +*.spec.js +*.spec.d.ts +*.spec.js.map + +*.fixture.js +*.fixture.d.ts +*.fixture.js.map diff --git a/packages/middleware-user-agent/LICENSE b/packages/middleware-user-agent/LICENSE new file mode 100644 index 0000000000000..e907b58668da3 --- /dev/null +++ b/packages/middleware-user-agent/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/middleware-user-agent/README.md b/packages/middleware-user-agent/README.md new file mode 100644 index 0000000000000..3f0928c20d26c --- /dev/null +++ b/packages/middleware-user-agent/README.md @@ -0,0 +1,4 @@ +# @aws-sdk/@aws-sdk/middleware-user-agent + +[![NPM version](https://img.shields.io/npm/v/@aws-sdk/@aws-sdk/middleware-user-agent/preview.svg)](https://www.npmjs.com/package/@aws-sdk/@aws-sdk/middleware-user-agent) +[![NPM downloads](https://img.shields.io/npm/dm/@aws-sdk/@aws-sdk/middleware-user-agent.svg)](https://www.npmjs.com/package/@aws-sdk/@aws-sdk/middleware-user-agent) diff --git a/packages/middleware-user-agent/package.json b/packages/middleware-user-agent/package.json new file mode 100644 index 0000000000000..40d9018741942 --- /dev/null +++ b/packages/middleware-user-agent/package.json @@ -0,0 +1,26 @@ +{ + "name": "@aws-sdk/middleware-user-agent", + "version": "0.1.0-preview.1", + "scripts": { + "prepublishOnly": "tsc", + "pretest": "tsc -p tsconfig.test.json", + "test": "jest" + }, + "main": "./build/index.js", + "types": "./build/index.d.ts", + "author": { + "name": "AWS SDK for JavaScript Team", + "url": "https://aws.amazon.com/javascript/" + }, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^0.1.0-preview.5", + "@aws-sdk/protocol-http": "^0.1.0-preview.1", + "tslib": "^1.8.0" + }, + "devDependencies": { + "@types/jest": "^24.0.12", + "typescript": "~3.4.0", + "jest": "^24.7.1" + } +} diff --git a/packages/middleware-user-agent/src/configurations.ts b/packages/middleware-user-agent/src/configurations.ts new file mode 100644 index 0000000000000..a7c53b7482e59 --- /dev/null +++ b/packages/middleware-user-agent/src/configurations.ts @@ -0,0 +1,22 @@ +export namespace UserAgentConfig { + export interface Input { + /** + * The custom user agent header that would be appended to default one + */ + customUserAgent?: string; + } + export interface PreviouslyResolved { + defaultUserAgent: string; + } + export interface Resolved { + defaultUserAgent: string; + customUserAgent?: string; + } + export function resolve( + input: T & PreviouslyResolved & Input + ): T & Resolved { + return input; + } +} + +export type UserAgentConfigInput = UserAgentConfig.Input; diff --git a/packages/middleware-user-agent/src/index.ts b/packages/middleware-user-agent/src/index.ts new file mode 100644 index 0000000000000..ef4de14542fed --- /dev/null +++ b/packages/middleware-user-agent/src/index.ts @@ -0,0 +1,2 @@ +export * from "./configurations"; +export * from "./middleware"; diff --git a/packages/middleware-user-agent/src/middleware.ts b/packages/middleware-user-agent/src/middleware.ts new file mode 100644 index 0000000000000..1a6cd787403b3 --- /dev/null +++ b/packages/middleware-user-agent/src/middleware.ts @@ -0,0 +1,46 @@ +import { + BuildMiddleware, + BuildHandlerArguments, + BuildHandler, + MetadataBearer, + BuildHandlerOutput, + InjectableMiddleware +} from "@aws-sdk/types"; +import { HttpRequest } from "@aws-sdk/protocol-http"; +import { UserAgentConfig } from "./configurations"; + +const userAgentHeader = "User-Agent"; + +export function UserAgentMiddleware(options: UserAgentConfig.Resolved) { + return ( + next: BuildHandler + ): BuildHandler => ( + args: BuildHandlerArguments + ): Promise> => { + let { request } = args; + if (!HttpRequest.isInstance(request)) return next(args); + const { headers } = request; + if (!headers[userAgentHeader]) { + headers[userAgentHeader] = `${options.defaultUserAgent}`; + } else { + headers[userAgentHeader] += ` ${options.defaultUserAgent}`; + } + if (options.customUserAgent) { + headers[userAgentHeader] += ` ${options.customUserAgent}`; + } + return next({ + ...args, + request + }); + }; +} + +export function UserAgentPlugin( + options: UserAgentConfig.Resolved +): InjectableMiddleware { + return { + middleware: UserAgentMiddleware(options), + step: "build", + tags: { SET_USER_AGENT: true } + }; +} diff --git a/packages/middleware-user-agent/tsconfig.json b/packages/middleware-user-agent/tsconfig.json new file mode 100644 index 0000000000000..38b94cda274ec --- /dev/null +++ b/packages/middleware-user-agent/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "declaration": true, + "strict": true, + "sourceMap": true, + "downlevelIteration": true, + "importHelpers": true, + "noEmitHelpers": true, + "lib": [ + "es5", + "es2015.promise", + "es2015.collection", + "es2015.iterable", + "es2015.symbol.wellknown" + ], + "rootDir": "./src", + "outDir": "./build", + "incremental": true + } +} diff --git a/packages/middleware-user-agent/tsconfig.test.json b/packages/middleware-user-agent/tsconfig.test.json new file mode 100644 index 0000000000000..17d0f1b7321fb --- /dev/null +++ b/packages/middleware-user-agent/tsconfig.test.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "sourceMap": false, + "inlineSourceMap": true, + "inlineSources": true, + "rootDir": "./src", + "outDir": "./build", + "incremental": true + } +} diff --git a/packages/node-http-handler/src/node-http-handler.ts b/packages/node-http-handler/src/node-http-handler.ts index 64688423b694a..9177a628087a1 100644 --- a/packages/node-http-handler/src/node-http-handler.ts +++ b/packages/node-http-handler/src/node-http-handler.ts @@ -13,7 +13,7 @@ export class NodeHttpHandler implements HttpHandler { private readonly httpsAgent: https.Agent; constructor(private readonly httpOptions: NodeHttpOptions = {}) { - const { keepAlive } = httpOptions; + const { keepAlive = true } = httpOptions; this.httpAgent = new http.Agent({ keepAlive }); this.httpsAgent = new https.Agent({ keepAlive }); } diff --git a/packages/protocol-rest-json/src/index.ts b/packages/protocol-rest-json/src/index.ts index 0cec703af24f8..721a61dace048 100644 --- a/packages/protocol-rest-json/src/index.ts +++ b/packages/protocol-rest-json/src/index.ts @@ -3,7 +3,9 @@ import { ResponseDeserializer, Protocol, TransferHandler, - HttpOptions + HttpOptions, + SerializerUtils, + DeserializerUtils } from "@aws-sdk/types"; import { HttpRequest, HttpResponse } from "@aws-sdk/protocol-http"; @@ -17,10 +19,18 @@ export class RestJsonProtocol extends Protocol< ) { super(handler); } - serialize(serializer: RequestSerializer, input: any) { + serialize( + serializer: RequestSerializer, + input: any, + utils?: SerializerUtils + ) { return serializer(input, "aws.rest-json-1.1"); } - parse(parser: ResponseDeserializer, output: HttpResponse) { + deserialize( + parser: ResponseDeserializer, + output: HttpResponse, + utils?: DeserializerUtils + ) { return parser(output, "aws.rest-json-1.1") as any; } } diff --git a/packages/retry-middleware/package.json b/packages/retry-middleware/package.json index 09406d1630501..cd8acef83917a 100644 --- a/packages/retry-middleware/package.json +++ b/packages/retry-middleware/package.json @@ -20,6 +20,7 @@ }, "devDependencies": { "@types/jest": "^24.0.12", + "@aws-sdk/protocol-http": "^0.1.0-preview.1", "jest": "^24.7.1", "typescript": "~3.4.0" } diff --git a/packages/retry-middleware/src/configurations.ts b/packages/retry-middleware/src/configurations.ts new file mode 100644 index 0000000000000..1a944fd5a6f79 --- /dev/null +++ b/packages/retry-middleware/src/configurations.ts @@ -0,0 +1,31 @@ +import { RetryStrategy } from "@aws-sdk/types"; +import { ExponentialBackOffStrategy } from "./defaultStrategy"; + +export namespace RetryConfig { + export interface Input { + /** + * The maximum number of times requests that encounter potentially transient failures should be retried + */ + maxRetries?: number; + /** + * The strategy to retry the request. Using built-in exponential backoff strategy by default. + */ + retryStrategy?: RetryStrategy; + } + export interface Resolved { + maxRetries: number; + retryStrategy: RetryStrategy; + } + export function resolve(input: T & Input): T & Resolved { + const maxRetries = input.maxRetries === undefined ? 3 : input.maxRetries; + return { + ...input, + maxRetries, + retryStrategy: + input.retryStrategy || new ExponentialBackOffStrategy(maxRetries) + }; + } +} + +//export separately for showing comment block in Intellisense +export type RetryConfigInput = RetryConfig.Input; diff --git a/packages/retry-middleware/src/defaultStrategy.ts b/packages/retry-middleware/src/defaultStrategy.ts new file mode 100644 index 0000000000000..3deb619e6621f --- /dev/null +++ b/packages/retry-middleware/src/defaultStrategy.ts @@ -0,0 +1,23 @@ +import { + DEFAULT_RETRY_DELAY_BASE, + THROTTLING_RETRY_DELAY_BASE +} from "./constants"; +import { defaultDelayDecider } from "./delayDecider"; +import { defaultRetryDecider } from "./retryDecider"; +import { isThrottlingError } from "@aws-sdk/service-error-classification"; +import { RetryStrategy, SdkError } from "@aws-sdk/types"; + +export class ExponentialBackOffStrategy implements RetryStrategy { + constructor(public readonly maxRetries: number) {} + shouldRetry(error: SdkError, retryAttempted: number) { + return retryAttempted < this.maxRetries && defaultRetryDecider(error); + } + computeDelayBeforeNextRetry(error: SdkError, retryAttempted: number): number { + return defaultDelayDecider( + isThrottlingError(error) + ? THROTTLING_RETRY_DELAY_BASE + : DEFAULT_RETRY_DELAY_BASE, + retryAttempted + ); + } +} diff --git a/packages/retry-middleware/src/index.ts b/packages/retry-middleware/src/index.ts index d10a01177cac3..c541e7fed3cfb 100644 --- a/packages/retry-middleware/src/index.ts +++ b/packages/retry-middleware/src/index.ts @@ -1,3 +1,3 @@ -export * from "./delayDecider"; -export * from "./retryDecider"; export * from "./retryMiddleware"; +export * from "./defaultStrategy"; +export * from "./configurations"; diff --git a/packages/retry-middleware/src/retryDecider.spec.ts b/packages/retry-middleware/src/retryDecider.spec.ts index 12c1e77524c49..91c86c55265c4 100644 --- a/packages/retry-middleware/src/retryDecider.spec.ts +++ b/packages/retry-middleware/src/retryDecider.spec.ts @@ -1,49 +1,37 @@ import { defaultRetryDecider } from "./retryDecider"; describe("defaultRetryDecider", () => { - const decider = defaultRetryDecider(); - it("should return false when the provided error is falsy", () => { - expect(decider(null as any)).toBe(false); + expect(defaultRetryDecider(null as any)).toBe(false); }); it("should return true if the error was tagged as a connection error", () => { const err: Error & { connectionError?: boolean } = new Error(); err.connectionError = true; - expect(decider(err)).toBe(true); + expect(defaultRetryDecider(err)).toBe(true); }); for (const httpStatusCode of [429, 500, 502, 503, 504, 509]) { it(`should return true if the error represents a service response with an HTTP status code of ${httpStatusCode}`, () => { const err: any = new Error(); err.$metadata = { httpStatusCode }; - expect(decider(err)).toBe(true); + expect(defaultRetryDecider(err)).toBe(true); }); } it('should return true if the response represents a "still processing" error', () => { const err = new Error(); err.name = "PriorRequestNotComplete"; - expect(decider(err)).toBe(true); + expect(defaultRetryDecider(err)).toBe(true); }); it("should return true if the response represents a throttling error", () => { const err = new Error(); err.name = "TooManyRequestsException"; - expect(decider(err)).toBe(true); + expect(defaultRetryDecider(err)).toBe(true); }); it("should return false for other errors", () => { - expect(decider(new Error())).toBe(false); - }); - - describe("clock skew retries enabled", () => { - const decider = defaultRetryDecider(true); - - it("should return true if the response represents a clock skew error", () => { - const err = new Error(); - err.name = "RequestTimeTooSkewed"; - expect(decider(err)).toBe(true); - }); + expect(defaultRetryDecider(new Error())).toBe(false); }); }); diff --git a/packages/retry-middleware/src/retryDecider.ts b/packages/retry-middleware/src/retryDecider.ts index 9563fb3d46d12..542ed3fca41ac 100644 --- a/packages/retry-middleware/src/retryDecider.ts +++ b/packages/retry-middleware/src/retryDecider.ts @@ -4,35 +4,31 @@ import { isStillProcessingError, isThrottlingError } from "@aws-sdk/service-error-classification"; -import { MetadataBearer, SdkError, RetryDecider } from "@aws-sdk/types"; +import { MetadataBearer, SdkError } from "@aws-sdk/types"; -export function defaultRetryDecider( - retryClockSkewErrors = false -): RetryDecider { - return (error: SdkError) => { - if (!error) { - return false; - } +export const defaultRetryDecider = (error: SdkError) => { + if (!error) { + return false; + } - if (error.connectionError) { - return true; - } + if (error.connectionError) { + return true; + } - if ( - hasMetadata(error) && - error.$metadata.httpStatusCode && - RETRYABLE_STATUS_CODES.has(error.$metadata.httpStatusCode) - ) { - return true; - } + if ( + hasMetadata(error) && + error.$metadata.httpStatusCode && + RETRYABLE_STATUS_CODES.has(error.$metadata.httpStatusCode) + ) { + return true; + } - return ( - isStillProcessingError(error) || - isThrottlingError(error) || - (retryClockSkewErrors && isClockSkewError(error)) - ); - }; -} + return ( + isStillProcessingError(error) || + isThrottlingError(error) || + isClockSkewError(error) + ); +}; function hasMetadata(error: any): error is MetadataBearer { return error && error.$metadata; diff --git a/packages/retry-middleware/src/retryMiddleware.spec.ts b/packages/retry-middleware/src/retryMiddleware.spec.ts index 13313a8f53282..5247297ee5c87 100644 --- a/packages/retry-middleware/src/retryMiddleware.spec.ts +++ b/packages/retry-middleware/src/retryMiddleware.spec.ts @@ -3,15 +3,21 @@ import { THROTTLING_RETRY_DELAY_BASE } from "./constants"; import { retryMiddleware } from "./retryMiddleware"; +import { RetryConfig } from "./configurations"; +import * as delayDeciderModule from "./delayDecider"; +import { ExponentialBackOffStrategy } from "./defaultStrategy"; +import { HttpRequest } from "@aws-sdk/protocol-http"; describe("retryMiddleware", () => { it("should not retry when the handler completes successfully", async () => { const next = jest.fn().mockResolvedValue({ output: { $metadata: {} } }); - const retryHandler = retryMiddleware(0)(next); + const retryHandler = retryMiddleware( + RetryConfig.resolve({ maxRetries: 0 }) + )(next); const { output: { $metadata } - } = await retryHandler({ input: {}, request: {} as any }); + } = await retryHandler({ input: {}, request: new HttpRequest({}) }); expect($metadata.retries).toBe(0); expect($metadata.totalRetryDelay).toBe(0); @@ -23,10 +29,12 @@ describe("retryMiddleware", () => { const error = new Error(); error.name = "ProvisionedThroughputExceededException"; const next = jest.fn().mockRejectedValue(error); - const retryHandler = retryMiddleware(maxRetries)(next); + const retryHandler = retryMiddleware(RetryConfig.resolve({ maxRetries }))( + next + ); await expect( - retryHandler({ input: {}, request: {} as any }) + retryHandler({ input: {}, request: new HttpRequest({}) }) ).rejects.toMatchObject(error); expect(next.mock.calls.length).toBe(maxRetries + 1); @@ -36,10 +44,12 @@ describe("retryMiddleware", () => { const error = new Error(); error.name = "ValidationException"; const next = jest.fn().mockRejectedValue(error); - const retryHandler = retryMiddleware(3)(next); + const retryHandler = retryMiddleware( + RetryConfig.resolve({ maxRetries: 3 }) + )(next); await expect( - retryHandler({ input: {}, request: {} as any }) + retryHandler({ input: {}, request: new HttpRequest({}) }) ).rejects.toMatchObject(error); expect(next.mock.calls.length).toBe(1); @@ -56,13 +66,24 @@ describe("retryMiddleware", () => { throttling.name = "RequestLimitExceeded"; next.mockImplementationOnce(args => Promise.reject(throttling)); - const delayDecider = jest.fn().mockReturnValue(0); - const retryHandler = retryMiddleware(3, () => true, delayDecider)(next); + jest.mock("./delayDecider"); - await retryHandler({ input: {}, request: {} as any }); + const maxRetries = 3; + const delayDeciderMock = jest.spyOn( + delayDeciderModule, + "defaultDelayDecider" + ); + const strategy = new ExponentialBackOffStrategy(maxRetries); + strategy.shouldRetry = () => true; + const retryHandler = retryMiddleware({ + maxRetries, + retryStrategy: strategy + })(next); + + await retryHandler({ input: {}, request: new HttpRequest({}) }); expect(next.mock.calls.length).toBe(3); - expect(delayDecider.mock.calls).toEqual([ + expect(delayDeciderMock.mock.calls).toEqual([ [DEFAULT_RETRY_DELAY_BASE, 0], [THROTTLING_RETRY_DELAY_BASE, 1] ]); diff --git a/packages/retry-middleware/src/retryMiddleware.ts b/packages/retry-middleware/src/retryMiddleware.ts index 6f8d955ecb6cb..ffcc9d33ae3a4 100644 --- a/packages/retry-middleware/src/retryMiddleware.ts +++ b/packages/retry-middleware/src/retryMiddleware.ts @@ -1,24 +1,14 @@ import { - DEFAULT_RETRY_DELAY_BASE, - THROTTLING_RETRY_DELAY_BASE -} from "./constants"; -import { defaultDelayDecider } from "./delayDecider"; -import { defaultRetryDecider } from "./retryDecider"; -import { isThrottlingError } from "@aws-sdk/service-error-classification"; -import { - DelayDecider, FinalizeHandler, FinalizeHandlerArguments, MetadataBearer, - RetryDecider, - FinalizeHandlerOutput + FinalizeHandlerOutput, + SdkError, + InjectableMiddleware } from "@aws-sdk/types"; +import { RetryConfig } from "./configurations"; -export function retryMiddleware( - maxRetries: number, - retryDecider: RetryDecider = defaultRetryDecider(), - delayDecider: DelayDecider = defaultDelayDecider -) { +export function retryMiddleware(options: RetryConfig.Resolved) { return ( next: FinalizeHandler ): FinalizeHandler => @@ -35,13 +25,12 @@ export function retryMiddleware( return { response, output }; } catch (err) { - if (retries < maxRetries && retryDecider(err)) { - const delay = delayDecider( - isThrottlingError(err) - ? THROTTLING_RETRY_DELAY_BASE - : DEFAULT_RETRY_DELAY_BASE, - retries++ + if (options.retryStrategy.shouldRetry(err as SdkError, retries)) { + const delay = options.retryStrategy.computeDelayBeforeNextRetry( + err, + retries ); + retries++; totalDelay += delay; await new Promise(resolve => setTimeout(resolve, delay)); @@ -59,3 +48,14 @@ export function retryMiddleware( } }; } + +export function retryPlugin< + Input extends object, + Output extends MetadataBearer +>(options: RetryConfig.Resolved): InjectableMiddleware { + return { + middleware: retryMiddleware(options), + step: "finalizeRequest", + tags: { RETRY: true } + }; +} diff --git a/packages/service-types-generator/src/internalImports.ts b/packages/service-types-generator/src/internalImports.ts index 10f164252a08c..2b2b822a82669 100644 --- a/packages/service-types-generator/src/internalImports.ts +++ b/packages/service-types-generator/src/internalImports.ts @@ -108,6 +108,10 @@ export const IMPORTS: { [key: string]: Import } = { package: "@aws-sdk/http-serialization", version: "^0.1.0-preview.5" }, + "invalid-dependency": { + package: "@aws-sdk/invalid-dependency", + version: "^0.1.0-preview.1" + }, "is-array-buffer": { package: "@aws-sdk/is-array-buffer", version: "^0.1.0-preview.3" @@ -156,6 +160,10 @@ export const IMPORTS: { [key: string]: Import } = { package: "@aws-sdk/middleware-content-length", version: "^0.1.0-preview.5" }, + "middleware-deserializer": { + package: "@aws-sdk/middleware-deserializer", + version: "^0.1.0-preview.1" + }, "middleware-ec2-copysnapshot": { package: "@aws-sdk/middleware-ec2-copysnapshot", version: "^0.1.0-preview.7" @@ -216,9 +224,9 @@ export const IMPORTS: { [key: string]: Import } = { package: "@aws-sdk/property-provider", version: "^0.1.0-preview.5" }, - "protocol-json-rpc": { - package: "@aws-sdk/protocol-json-rpc", - version: "^0.1.0-preview.6" + "protocol-http": { + package: "@aws-sdk/protocol-http", + version: "^0.1.0-preview.1" }, "protocol-query": { package: "@aws-sdk/protocol-query", @@ -228,6 +236,10 @@ export const IMPORTS: { [key: string]: Import } = { package: "@aws-sdk/protocol-rest", version: "^0.1.0-preview.7" }, + "protocol-rest-json": { + package: "@aws-sdk/protocol-rest-json", + version: "^0.1.0-preview.5" + }, "protocol-timestamp": { package: "@aws-sdk/protocol-timestamp", version: "^0.1.0-preview.5" @@ -436,1468 +448,8 @@ export const IMPORTS: { [key: string]: Import } = { package: "@aws-sdk/xml-builder", version: "^0.1.0-preview.3" }, - "client-acm-browser": { - package: "@aws-sdk/client-acm-browser", - version: "^0.1.0-preview.3" - }, - "client-acm-pca-browser": { - package: "@aws-sdk/client-acm-pca-browser", - version: "^0.1.0-preview.3" - }, - "client-alexa-for-business-browser": { - package: "@aws-sdk/client-alexa-for-business-browser", - version: "^0.1.0-preview.3" - }, - "client-amplify-browser": { - package: "@aws-sdk/client-amplify-browser", - version: "^0.1.0-preview.3" - }, - "client-api-gateway-browser": { - package: "@aws-sdk/client-api-gateway-browser", - version: "^0.1.0-preview.3" - }, - "client-apigatewaymanagementapi-browser": { - package: "@aws-sdk/client-apigatewaymanagementapi-browser", - version: "^0.1.0-preview.3" - }, - "client-apigatewayv2-browser": { - package: "@aws-sdk/client-apigatewayv2-browser", - version: "^0.1.0-preview.3" - }, - "client-app-mesh-browser": { - package: "@aws-sdk/client-app-mesh-browser", - version: "^0.1.0-preview.3" - }, - "client-application-auto-scaling-browser": { - package: "@aws-sdk/client-application-auto-scaling-browser", - version: "^0.1.0-preview.3" - }, - "client-application-discovery-service-browser": { - package: "@aws-sdk/client-application-discovery-service-browser", - version: "^0.1.0-preview.3" - }, - "client-application-insights-browser": { - package: "@aws-sdk/client-application-insights-browser", - version: "^0.1.0-preview.3" - }, - "client-appstream-browser": { - package: "@aws-sdk/client-appstream-browser", - version: "^0.1.0-preview.3" - }, - "client-appsync-browser": { - package: "@aws-sdk/client-appsync-browser", - version: "^0.1.0-preview.3" - }, - "client-athena-browser": { - package: "@aws-sdk/client-athena-browser", - version: "^0.1.0-preview.3" - }, - "client-auto-scaling-browser": { - package: "@aws-sdk/client-auto-scaling-browser", - version: "^0.1.0-preview.3" - }, - "client-auto-scaling-plans-browser": { - package: "@aws-sdk/client-auto-scaling-plans-browser", - version: "^0.1.0-preview.3" - }, - "client-backup-browser": { - package: "@aws-sdk/client-backup-browser", - version: "^0.1.0-preview.3" - }, - "client-batch-browser": { - package: "@aws-sdk/client-batch-browser", - version: "^0.1.0-preview.3" - }, - "client-budgets-browser": { - package: "@aws-sdk/client-budgets-browser", - version: "^0.1.0-preview.3" - }, - "client-chime-browser": { - package: "@aws-sdk/client-chime-browser", - version: "^0.1.0-preview.3" - }, - "client-cloud9-browser": { - package: "@aws-sdk/client-cloud9-browser", - version: "^0.1.0-preview.3" - }, - "client-clouddirectory-browser": { - package: "@aws-sdk/client-clouddirectory-browser", - version: "^0.1.0-preview.3" - }, - "client-cloudformation-browser": { - package: "@aws-sdk/client-cloudformation-browser", - version: "^0.1.0-preview.3" - }, - "client-cloudfront-browser": { - package: "@aws-sdk/client-cloudfront-browser", - version: "^0.1.0-preview.3" - }, - "client-cloudhsm-browser": { - package: "@aws-sdk/client-cloudhsm-browser", - version: "^0.1.0-preview.3" - }, - "client-cloudhsm-v2-browser": { - package: "@aws-sdk/client-cloudhsm-v2-browser", - version: "^0.1.0-preview.3" - }, - "client-cloudsearch-browser": { - package: "@aws-sdk/client-cloudsearch-browser", - version: "^0.1.0-preview.3" - }, - "client-cloudsearch-domain-browser": { - package: "@aws-sdk/client-cloudsearch-domain-browser", - version: "^0.1.0-preview.3" - }, - "client-cloudtrail-browser": { - package: "@aws-sdk/client-cloudtrail-browser", - version: "^0.1.0-preview.3" - }, - "client-cloudwatch-browser": { - package: "@aws-sdk/client-cloudwatch-browser", - version: "^0.1.0-preview.3" - }, - "client-cloudwatch-events-browser": { - package: "@aws-sdk/client-cloudwatch-events-browser", - version: "^0.1.0-preview.3" - }, - "client-cloudwatch-logs-browser": { - package: "@aws-sdk/client-cloudwatch-logs-browser", - version: "^0.1.0-preview.3" - }, - "client-codebuild-browser": { - package: "@aws-sdk/client-codebuild-browser", - version: "^0.1.0-preview.3" - }, - "client-codecommit-browser": { - package: "@aws-sdk/client-codecommit-browser", - version: "^0.1.0-preview.3" - }, - "client-codedeploy-browser": { - package: "@aws-sdk/client-codedeploy-browser", - version: "^0.1.0-preview.3" - }, - "client-codepipeline-browser": { - package: "@aws-sdk/client-codepipeline-browser", - version: "^0.1.0-preview.3" - }, - "client-codestar-browser": { - package: "@aws-sdk/client-codestar-browser", - version: "^0.1.0-preview.3" - }, - "client-cognito-identity-browser": { - package: "@aws-sdk/client-cognito-identity-browser", - version: "^0.1.0-preview.7" - }, - "client-cognito-identity-provider-browser": { - package: "@aws-sdk/client-cognito-identity-provider-browser", - version: "^0.1.0-preview.3" - }, - "client-cognito-sync-browser": { - package: "@aws-sdk/client-cognito-sync-browser", - version: "^0.1.0-preview.3" - }, - "client-comprehend-browser": { - package: "@aws-sdk/client-comprehend-browser", - version: "^0.1.0-preview.3" - }, - "client-comprehendmedical-browser": { - package: "@aws-sdk/client-comprehendmedical-browser", - version: "^0.1.0-preview.3" - }, - "client-config-service-browser": { - package: "@aws-sdk/client-config-service-browser", - version: "^0.1.0-preview.3" - }, - "client-connect-browser": { - package: "@aws-sdk/client-connect-browser", - version: "^0.1.0-preview.3" - }, - "client-cost-and-usage-report-service-browser": { - package: "@aws-sdk/client-cost-and-usage-report-service-browser", - version: "^0.1.0-preview.3" - }, - "client-cost-explorer-browser": { - package: "@aws-sdk/client-cost-explorer-browser", - version: "^0.1.0-preview.3" - }, - "client-data-pipeline-browser": { - package: "@aws-sdk/client-data-pipeline-browser", - version: "^0.1.0-preview.3" - }, - "client-database-migration-service-browser": { - package: "@aws-sdk/client-database-migration-service-browser", - version: "^0.1.0-preview.3" - }, - "client-datasync-browser": { - package: "@aws-sdk/client-datasync-browser", - version: "^0.1.0-preview.3" - }, - "client-dax-browser": { - package: "@aws-sdk/client-dax-browser", - version: "^0.1.0-preview.3" - }, - "client-device-farm-browser": { - package: "@aws-sdk/client-device-farm-browser", - version: "^0.1.0-preview.3" - }, - "client-direct-connect-browser": { - package: "@aws-sdk/client-direct-connect-browser", - version: "^0.1.0-preview.3" - }, - "client-directory-service-browser": { - package: "@aws-sdk/client-directory-service-browser", - version: "^0.1.0-preview.3" - }, - "client-dlm-browser": { - package: "@aws-sdk/client-dlm-browser", - version: "^0.1.0-preview.3" - }, - "client-docdb-browser": { - package: "@aws-sdk/client-docdb-browser", - version: "^0.1.0-preview.3" - }, - "client-dynamodb-browser": { - package: "@aws-sdk/client-dynamodb-browser", - version: "^0.1.0-preview.6" - }, - "client-dynamodb-streams-browser": { - package: "@aws-sdk/client-dynamodb-streams-browser", - version: "^0.1.0-preview.3" - }, - "client-ec2-browser": { - package: "@aws-sdk/client-ec2-browser", - version: "^0.1.0-preview.3" - }, - "client-ec2-instance-connect-browser": { - package: "@aws-sdk/client-ec2-instance-connect-browser", - version: "^0.1.0-preview.3" - }, - "client-ecr-browser": { - package: "@aws-sdk/client-ecr-browser", - version: "^0.1.0-preview.3" - }, - "client-ecs-browser": { - package: "@aws-sdk/client-ecs-browser", - version: "^0.1.0-preview.3" - }, - "client-efs-browser": { - package: "@aws-sdk/client-efs-browser", - version: "^0.1.0-preview.3" - }, - "client-eks-browser": { - package: "@aws-sdk/client-eks-browser", - version: "^0.1.0-preview.3" - }, - "client-elastic-beanstalk-browser": { - package: "@aws-sdk/client-elastic-beanstalk-browser", - version: "^0.1.0-preview.3" - }, - "client-elastic-load-balancing-browser": { - package: "@aws-sdk/client-elastic-load-balancing-browser", - version: "^0.1.0-preview.3" - }, - "client-elastic-load-balancing-v2-browser": { - package: "@aws-sdk/client-elastic-load-balancing-v2-browser", - version: "^0.1.0-preview.3" - }, - "client-elastic-transcoder-browser": { - package: "@aws-sdk/client-elastic-transcoder-browser", - version: "^0.1.0-preview.3" - }, - "client-elasticache-browser": { - package: "@aws-sdk/client-elasticache-browser", - version: "^0.1.0-preview.3" - }, - "client-elasticsearch-service-browser": { - package: "@aws-sdk/client-elasticsearch-service-browser", - version: "^0.1.0-preview.3" - }, - "client-emr-browser": { - package: "@aws-sdk/client-emr-browser", - version: "^0.1.0-preview.3" - }, - "client-eventbridge-browser": { - package: "@aws-sdk/client-eventbridge-browser", - version: "^0.1.0-preview.3" - }, - "client-firehose-browser": { - package: "@aws-sdk/client-firehose-browser", - version: "^0.1.0-preview.3" - }, - "client-fms-browser": { - package: "@aws-sdk/client-fms-browser", - version: "^0.1.0-preview.3" - }, - "client-fsx-browser": { - package: "@aws-sdk/client-fsx-browser", - version: "^0.1.0-preview.3" - }, - "client-gamelift-browser": { - package: "@aws-sdk/client-gamelift-browser", - version: "^0.1.0-preview.3" - }, - "client-glacier-browser": { - package: "@aws-sdk/client-glacier-browser", - version: "^0.1.0-preview.3" - }, - "client-global-accelerator-browser": { - package: "@aws-sdk/client-global-accelerator-browser", - version: "^0.1.0-preview.3" - }, - "client-glue-browser": { - package: "@aws-sdk/client-glue-browser", - version: "^0.1.0-preview.3" - }, - "client-greengrass-browser": { - package: "@aws-sdk/client-greengrass-browser", - version: "^0.1.0-preview.3" - }, - "client-groundstation-browser": { - package: "@aws-sdk/client-groundstation-browser", - version: "^0.1.0-preview.3" - }, - "client-guardduty-browser": { - package: "@aws-sdk/client-guardduty-browser", - version: "^0.1.0-preview.3" - }, - "client-health-browser": { - package: "@aws-sdk/client-health-browser", - version: "^0.1.0-preview.3" - }, - "client-iam-browser": { - package: "@aws-sdk/client-iam-browser", - version: "^0.1.0-preview.3" - }, - "client-inspector-browser": { - package: "@aws-sdk/client-inspector-browser", - version: "^0.1.0-preview.3" - }, - "client-iot-1click-devices-service-browser": { - package: "@aws-sdk/client-iot-1click-devices-service-browser", - version: "^0.1.0-preview.3" - }, - "client-iot-1click-projects-browser": { - package: "@aws-sdk/client-iot-1click-projects-browser", - version: "^0.1.0-preview.3" - }, - "client-iot-browser": { - package: "@aws-sdk/client-iot-browser", - version: "^0.1.0-preview.3" - }, - "client-iot-data-plane-browser": { - package: "@aws-sdk/client-iot-data-plane-browser", - version: "^0.1.0-preview.3" - }, - "client-iot-events-browser": { - package: "@aws-sdk/client-iot-events-browser", - version: "^0.1.0-preview.3" - }, - "client-iot-events-data-browser": { - package: "@aws-sdk/client-iot-events-data-browser", - version: "^0.1.0-preview.3" - }, - "client-iot-jobs-data-plane-browser": { - package: "@aws-sdk/client-iot-jobs-data-plane-browser", - version: "^0.1.0-preview.3" - }, - "client-iotanalytics-browser": { - package: "@aws-sdk/client-iotanalytics-browser", - version: "^0.1.0-preview.3" - }, - "client-iotthingsgraph-browser": { - package: "@aws-sdk/client-iotthingsgraph-browser", - version: "^0.1.0-preview.3" - }, - "client-kafka-browser": { - package: "@aws-sdk/client-kafka-browser", - version: "^0.1.0-preview.3" - }, - "client-kinesis-analytics-browser": { - package: "@aws-sdk/client-kinesis-analytics-browser", - version: "^0.1.0-preview.3" - }, - "client-kinesis-analytics-v2-browser": { - package: "@aws-sdk/client-kinesis-analytics-v2-browser", - version: "^0.1.0-preview.3" - }, - "client-kinesis-browser": { - package: "@aws-sdk/client-kinesis-browser", - version: "^0.1.0-preview.7" - }, - "client-kinesis-video-archived-media-browser": { - package: "@aws-sdk/client-kinesis-video-archived-media-browser", - version: "^0.1.0-preview.3" - }, - "client-kinesis-video-browser": { - package: "@aws-sdk/client-kinesis-video-browser", - version: "^0.1.0-preview.3" - }, - "client-kinesis-video-media-browser": { - package: "@aws-sdk/client-kinesis-video-media-browser", - version: "^0.1.0-preview.3" - }, - "client-kms-browser": { - package: "@aws-sdk/client-kms-browser", - version: "^0.1.0-preview.6" - }, - "client-lambda-browser": { - package: "@aws-sdk/client-lambda-browser", - version: "^0.1.0-preview.3" - }, - "client-lex-model-building-service-browser": { - package: "@aws-sdk/client-lex-model-building-service-browser", - version: "^0.1.0-preview.3" - }, - "client-lex-runtime-service-browser": { - package: "@aws-sdk/client-lex-runtime-service-browser", - version: "^0.1.0-preview.3" - }, - "client-license-manager-browser": { - package: "@aws-sdk/client-license-manager-browser", - version: "^0.1.0-preview.3" - }, - "client-lightsail-browser": { - package: "@aws-sdk/client-lightsail-browser", - version: "^0.1.0-preview.3" - }, - "client-machine-learning-browser": { - package: "@aws-sdk/client-machine-learning-browser", - version: "^0.1.0-preview.3" - }, - "client-macie-browser": { - package: "@aws-sdk/client-macie-browser", - version: "^0.1.0-preview.3" - }, - "client-managedblockchain-browser": { - package: "@aws-sdk/client-managedblockchain-browser", - version: "^0.1.0-preview.3" - }, - "client-marketplace-commerce-analytics-browser": { - package: "@aws-sdk/client-marketplace-commerce-analytics-browser", - version: "^0.1.0-preview.3" - }, - "client-marketplace-entitlement-service-browser": { - package: "@aws-sdk/client-marketplace-entitlement-service-browser", - version: "^0.1.0-preview.3" - }, - "client-marketplace-metering-browser": { - package: "@aws-sdk/client-marketplace-metering-browser", - version: "^0.1.0-preview.3" - }, - "client-mediaconnect-browser": { - package: "@aws-sdk/client-mediaconnect-browser", - version: "^0.1.0-preview.3" - }, - "client-mediaconvert-browser": { - package: "@aws-sdk/client-mediaconvert-browser", - version: "^0.1.0-preview.3" - }, - "client-medialive-browser": { - package: "@aws-sdk/client-medialive-browser", - version: "^0.1.0-preview.3" - }, - "client-mediapackage-browser": { - package: "@aws-sdk/client-mediapackage-browser", - version: "^0.1.0-preview.3" - }, - "client-mediapackage-vod-browser": { - package: "@aws-sdk/client-mediapackage-vod-browser", - version: "^0.1.0-preview.3" - }, - "client-mediastore-browser": { - package: "@aws-sdk/client-mediastore-browser", - version: "^0.1.0-preview.3" - }, - "client-mediastore-data-browser": { - package: "@aws-sdk/client-mediastore-data-browser", - version: "^0.1.0-preview.3" - }, - "client-mediatailor-browser": { - package: "@aws-sdk/client-mediatailor-browser", - version: "^0.1.0-preview.3" - }, - "client-migration-hub-browser": { - package: "@aws-sdk/client-migration-hub-browser", - version: "^0.1.0-preview.3" - }, - "client-mobile-browser": { - package: "@aws-sdk/client-mobile-browser", - version: "^0.1.0-preview.3" - }, - "client-mq-browser": { - package: "@aws-sdk/client-mq-browser", - version: "^0.1.0-preview.3" - }, - "client-mturk-browser": { - package: "@aws-sdk/client-mturk-browser", - version: "^0.1.0-preview.3" - }, - "client-neptune-browser": { - package: "@aws-sdk/client-neptune-browser", + "client-rds-data-node": { + package: "@aws-sdk/client-rds-data-node", version: "^0.1.0-preview.3" - }, - "client-opsworks-browser": { - package: "@aws-sdk/client-opsworks-browser", - version: "^0.1.0-preview.3" - }, - "client-opsworkscm-browser": { - package: "@aws-sdk/client-opsworkscm-browser", - version: "^0.1.0-preview.3" - }, - "client-organizations-browser": { - package: "@aws-sdk/client-organizations-browser", - version: "^0.1.0-preview.3" - }, - "client-personalize-browser": { - package: "@aws-sdk/client-personalize-browser", - version: "^0.1.0-preview.3" - }, - "client-personalize-events-browser": { - package: "@aws-sdk/client-personalize-events-browser", - version: "^0.1.0-preview.3" - }, - "client-personalize-runtime-browser": { - package: "@aws-sdk/client-personalize-runtime-browser", - version: "^0.1.0-preview.3" - }, - "client-pi-browser": { - package: "@aws-sdk/client-pi-browser", - version: "^0.1.0-preview.3" - }, - "client-pinpoint-browser": { - package: "@aws-sdk/client-pinpoint-browser", - version: "^0.1.0-preview.7" - }, - "client-pinpoint-email-browser": { - package: "@aws-sdk/client-pinpoint-email-browser", - version: "^0.1.0-preview.3" - }, - "client-pinpoint-sms-voice-browser": { - package: "@aws-sdk/client-pinpoint-sms-voice-browser", - version: "^0.1.0-preview.3" - }, - "client-polly-browser": { - package: "@aws-sdk/client-polly-browser", - version: "^0.1.0-preview.3" - }, - "client-pricing-browser": { - package: "@aws-sdk/client-pricing-browser", - version: "^0.1.0-preview.3" - }, - "client-quicksight-browser": { - package: "@aws-sdk/client-quicksight-browser", - version: "^0.1.0-preview.3" - }, - "client-ram-browser": { - package: "@aws-sdk/client-ram-browser", - version: "^0.1.0-preview.3" - }, - "client-rds-browser": { - package: "@aws-sdk/client-rds-browser", - version: "^0.1.0-preview.3" - }, - "client-rds-data-browser": { - package: "@aws-sdk/client-rds-data-browser", - version: "^0.1.0-preview.3" - }, - "client-redshift-browser": { - package: "@aws-sdk/client-redshift-browser", - version: "^0.1.0-preview.3" - }, - "client-rekognition-browser": { - package: "@aws-sdk/client-rekognition-browser", - version: "^0.1.0-preview.3" - }, - "client-resource-groups-browser": { - package: "@aws-sdk/client-resource-groups-browser", - version: "^0.1.0-preview.3" - }, - "client-resource-groups-tagging-api-browser": { - package: "@aws-sdk/client-resource-groups-tagging-api-browser", - version: "^0.1.0-preview.3" - }, - "client-robomaker-browser": { - package: "@aws-sdk/client-robomaker-browser", - version: "^0.1.0-preview.3" - }, - "client-route-53-browser": { - package: "@aws-sdk/client-route-53-browser", - version: "^0.1.0-preview.3" - }, - "client-route-53-domains-browser": { - package: "@aws-sdk/client-route-53-domains-browser", - version: "^0.1.0-preview.3" - }, - "client-route53resolver-browser": { - package: "@aws-sdk/client-route53resolver-browser", - version: "^0.1.0-preview.3" - }, - "client-s3-browser": { - package: "@aws-sdk/client-s3-browser", - version: "^0.1.0-preview.4" - }, - "client-s3-control-browser": { - package: "@aws-sdk/client-s3-control-browser", - version: "^0.1.0-preview.3" - }, - "client-sagemaker-browser": { - package: "@aws-sdk/client-sagemaker-browser", - version: "^0.1.0-preview.3" - }, - "client-sagemaker-runtime-browser": { - package: "@aws-sdk/client-sagemaker-runtime-browser", - version: "^0.1.0-preview.3" - }, - "client-secrets-manager-browser": { - package: "@aws-sdk/client-secrets-manager-browser", - version: "^0.1.0-preview.3" - }, - "client-securityhub-browser": { - package: "@aws-sdk/client-securityhub-browser", - version: "^0.1.0-preview.3" - }, - "client-serverlessapplicationrepository-browser": { - package: "@aws-sdk/client-serverlessapplicationrepository-browser", - version: "^0.1.0-preview.3" - }, - "client-service-catalog-browser": { - package: "@aws-sdk/client-service-catalog-browser", - version: "^0.1.0-preview.3" - }, - "client-service-quotas-browser": { - package: "@aws-sdk/client-service-quotas-browser", - version: "^0.1.0-preview.3" - }, - "client-servicediscovery-browser": { - package: "@aws-sdk/client-servicediscovery-browser", - version: "^0.1.0-preview.3" - }, - "client-ses-browser": { - package: "@aws-sdk/client-ses-browser", - version: "^0.1.0-preview.3" - }, - "client-sfn-browser": { - package: "@aws-sdk/client-sfn-browser", - version: "^0.1.0-preview.3" - }, - "client-shield-browser": { - package: "@aws-sdk/client-shield-browser", - version: "^0.1.0-preview.3" - }, - "client-signer-browser": { - package: "@aws-sdk/client-signer-browser", - version: "^0.1.0-preview.3" - }, - "client-sms-browser": { - package: "@aws-sdk/client-sms-browser", - version: "^0.1.0-preview.3" - }, - "client-snowball-browser": { - package: "@aws-sdk/client-snowball-browser", - version: "^0.1.0-preview.3" - }, - "client-sns-browser": { - package: "@aws-sdk/client-sns-browser", - version: "^0.1.0-preview.3" - }, - "client-sqs-browser": { - package: "@aws-sdk/client-sqs-browser", - version: "^0.1.0-preview.3" - }, - "client-ssm-browser": { - package: "@aws-sdk/client-ssm-browser", - version: "^0.1.0-preview.3" - }, - "client-storage-gateway-browser": { - package: "@aws-sdk/client-storage-gateway-browser", - version: "^0.1.0-preview.3" - }, - "client-sts-browser": { - package: "@aws-sdk/client-sts-browser", - version: "^0.1.0-preview.3" - }, - "client-support-browser": { - package: "@aws-sdk/client-support-browser", - version: "^0.1.0-preview.3" - }, - "client-swf-browser": { - package: "@aws-sdk/client-swf-browser", - version: "^0.1.0-preview.3" - }, - "client-textract-browser": { - package: "@aws-sdk/client-textract-browser", - version: "^0.1.0-preview.3" - }, - "client-transcribe-browser": { - package: "@aws-sdk/client-transcribe-browser", - version: "^0.1.0-preview.3" - }, - "client-transfer-browser": { - package: "@aws-sdk/client-transfer-browser", - version: "^0.1.0-preview.3" - }, - "client-translate-browser": { - package: "@aws-sdk/client-translate-browser", - version: "^0.1.0-preview.3" - }, - "client-waf-browser": { - package: "@aws-sdk/client-waf-browser", - version: "^0.1.0-preview.3" - }, - "client-waf-regional-browser": { - package: "@aws-sdk/client-waf-regional-browser", - version: "^0.1.0-preview.3" - }, - "client-workdocs-browser": { - package: "@aws-sdk/client-workdocs-browser", - version: "^0.1.0-preview.3" - }, - "client-worklink-browser": { - package: "@aws-sdk/client-worklink-browser", - version: "^0.1.0-preview.3" - }, - "client-workmail-browser": { - package: "@aws-sdk/client-workmail-browser", - version: "^0.1.0-preview.3" - }, - "client-workspaces-browser": { - package: "@aws-sdk/client-workspaces-browser", - version: "^0.1.0-preview.3" - }, - "client-xray-browser": { - package: "@aws-sdk/client-xray-browser", - version: "^0.1.0-preview.3" - }, - "client-acm-node": { - package: "@aws-sdk/client-acm-node", - version: "^0.1.0-preview.3" - }, - "client-acm-pca-node": { - package: "@aws-sdk/client-acm-pca-node", - version: "^0.1.0-preview.3" - }, - "client-alexa-for-business-node": { - package: "@aws-sdk/client-alexa-for-business-node", - version: "^0.1.0-preview.3" - }, - "client-amplify-node": { - package: "@aws-sdk/client-amplify-node", - version: "^0.1.0-preview.3" - }, - "client-api-gateway-node": { - package: "@aws-sdk/client-api-gateway-node", - version: "^0.1.0-preview.3" - }, - "client-apigatewaymanagementapi-node": { - package: "@aws-sdk/client-apigatewaymanagementapi-node", - version: "^0.1.0-preview.3" - }, - "client-apigatewayv2-node": { - package: "@aws-sdk/client-apigatewayv2-node", - version: "^0.1.0-preview.3" - }, - "client-app-mesh-node": { - package: "@aws-sdk/client-app-mesh-node", - version: "^0.1.0-preview.3" - }, - "client-application-auto-scaling-node": { - package: "@aws-sdk/client-application-auto-scaling-node", - version: "^0.1.0-preview.3" - }, - "client-application-discovery-service-node": { - package: "@aws-sdk/client-application-discovery-service-node", - version: "^0.1.0-preview.3" - }, - "client-application-insights-node": { - package: "@aws-sdk/client-application-insights-node", - version: "^0.1.0-preview.3" - }, - "client-appstream-node": { - package: "@aws-sdk/client-appstream-node", - version: "^0.1.0-preview.3" - }, - "client-appsync-node": { - package: "@aws-sdk/client-appsync-node", - version: "^0.1.0-preview.3" - }, - "client-athena-node": { - package: "@aws-sdk/client-athena-node", - version: "^0.1.0-preview.3" - }, - "client-auto-scaling-node": { - package: "@aws-sdk/client-auto-scaling-node", - version: "^0.1.0-preview.3" - }, - "client-auto-scaling-plans-node": { - package: "@aws-sdk/client-auto-scaling-plans-node", - version: "^0.1.0-preview.3" - }, - "client-backup-node": { - package: "@aws-sdk/client-backup-node", - version: "^0.1.0-preview.3" - }, - "client-batch-node": { - package: "@aws-sdk/client-batch-node", - version: "^0.1.0-preview.3" - }, - "client-budgets-node": { - package: "@aws-sdk/client-budgets-node", - version: "^0.1.0-preview.3" - }, - "client-chime-node": { - package: "@aws-sdk/client-chime-node", - version: "^0.1.0-preview.3" - }, - "client-cloud9-node": { - package: "@aws-sdk/client-cloud9-node", - version: "^0.1.0-preview.3" - }, - "client-clouddirectory-node": { - package: "@aws-sdk/client-clouddirectory-node", - version: "^0.1.0-preview.3" - }, - "client-cloudformation-node": { - package: "@aws-sdk/client-cloudformation-node", - version: "^0.1.0-preview.3" - }, - "client-cloudfront-node": { - package: "@aws-sdk/client-cloudfront-node", - version: "^0.1.0-preview.3" - }, - "client-cloudhsm-node": { - package: "@aws-sdk/client-cloudhsm-node", - version: "^0.1.0-preview.3" - }, - "client-cloudhsm-v2-node": { - package: "@aws-sdk/client-cloudhsm-v2-node", - version: "^0.1.0-preview.3" - }, - "client-cloudsearch-domain-node": { - package: "@aws-sdk/client-cloudsearch-domain-node", - version: "^0.1.0-preview.3" - }, - "client-cloudsearch-node": { - package: "@aws-sdk/client-cloudsearch-node", - version: "^0.1.0-preview.3" - }, - "client-cloudtrail-node": { - package: "@aws-sdk/client-cloudtrail-node", - version: "^0.1.0-preview.3" - }, - "client-cloudwatch-events-node": { - package: "@aws-sdk/client-cloudwatch-events-node", - version: "^0.1.0-preview.3" - }, - "client-cloudwatch-logs-node": { - package: "@aws-sdk/client-cloudwatch-logs-node", - version: "^0.1.0-preview.3" - }, - "client-cloudwatch-node": { - package: "@aws-sdk/client-cloudwatch-node", - version: "^0.1.0-preview.3" - }, - "client-codebuild-node": { - package: "@aws-sdk/client-codebuild-node", - version: "^0.1.0-preview.3" - }, - "client-codecommit-node": { - package: "@aws-sdk/client-codecommit-node", - version: "^0.1.0-preview.7" - }, - "client-codedeploy-node": { - package: "@aws-sdk/client-codedeploy-node", - version: "^0.1.0-preview.3" - }, - "client-codepipeline-node": { - package: "@aws-sdk/client-codepipeline-node", - version: "^0.1.0-preview.3" - }, - "client-codestar-node": { - package: "@aws-sdk/client-codestar-node", - version: "^0.1.0-preview.3" - }, - "client-cognito-identity-node": { - package: "@aws-sdk/client-cognito-identity-node", - version: "^0.1.0-preview.3" - }, - "client-cognito-identity-provider-node": { - package: "@aws-sdk/client-cognito-identity-provider-node", - version: "^0.1.0-preview.3" - }, - "client-cognito-sync-node": { - package: "@aws-sdk/client-cognito-sync-node", - version: "^0.1.0-preview.3" - }, - "client-comprehend-node": { - package: "@aws-sdk/client-comprehend-node", - version: "^0.1.0-preview.3" - }, - "client-comprehendmedical-node": { - package: "@aws-sdk/client-comprehendmedical-node", - version: "^0.1.0-preview.3" - }, - "client-config-service-node": { - package: "@aws-sdk/client-config-service-node", - version: "^0.1.0-preview.3" - }, - "client-connect-node": { - package: "@aws-sdk/client-connect-node", - version: "^0.1.0-preview.3" - }, - "client-cost-and-usage-report-service-node": { - package: "@aws-sdk/client-cost-and-usage-report-service-node", - version: "^0.1.0-preview.3" - }, - "client-cost-explorer-node": { - package: "@aws-sdk/client-cost-explorer-node", - version: "^0.1.0-preview.3" - }, - "client-data-pipeline-node": { - package: "@aws-sdk/client-data-pipeline-node", - version: "^0.1.0-preview.3" - }, - "client-database-migration-service-node": { - package: "@aws-sdk/client-database-migration-service-node", - version: "^0.1.0-preview.3" - }, - "client-datasync-node": { - package: "@aws-sdk/client-datasync-node", - version: "^0.1.0-preview.3" - }, - "client-dax-node": { - package: "@aws-sdk/client-dax-node", - version: "^0.1.0-preview.3" - }, - "client-device-farm-node": { - package: "@aws-sdk/client-device-farm-node", - version: "^0.1.0-preview.3" - }, - "client-direct-connect-node": { - package: "@aws-sdk/client-direct-connect-node", - version: "^0.1.0-preview.3" - }, - "client-directory-service-node": { - package: "@aws-sdk/client-directory-service-node", - version: "^0.1.0-preview.3" - }, - "client-dlm-node": { - package: "@aws-sdk/client-dlm-node", - version: "^0.1.0-preview.3" - }, - "client-docdb-node": { - package: "@aws-sdk/client-docdb-node", - version: "^0.1.0-preview.3" - }, - "client-dynamodb-node": { - package: "@aws-sdk/client-dynamodb-node", - version: "^0.1.0-preview.6" - }, - "client-dynamodb-streams-node": { - package: "@aws-sdk/client-dynamodb-streams-node", - version: "^0.1.0-preview.3" - }, - "client-ec2-instance-connect-node": { - package: "@aws-sdk/client-ec2-instance-connect-node", - version: "^0.1.0-preview.3" - }, - "client-ec2-node": { - package: "@aws-sdk/client-ec2-node", - version: "^0.1.0-preview.3" - }, - "client-ecr-node": { - package: "@aws-sdk/client-ecr-node", - version: "^0.1.0-preview.3" - }, - "client-ecs-node": { - package: "@aws-sdk/client-ecs-node", - version: "^0.1.0-preview.3" - }, - "client-efs-node": { - package: "@aws-sdk/client-efs-node", - version: "^0.1.0-preview.3" - }, - "client-eks-node": { - package: "@aws-sdk/client-eks-node", - version: "^0.1.0-preview.3" - }, - "client-elastic-beanstalk-node": { - package: "@aws-sdk/client-elastic-beanstalk-node", - version: "^0.1.0-preview.3" - }, - "client-elastic-load-balancing-node": { - package: "@aws-sdk/client-elastic-load-balancing-node", - version: "^0.1.0-preview.3" - }, - "client-elastic-load-balancing-v2-node": { - package: "@aws-sdk/client-elastic-load-balancing-v2-node", - version: "^0.1.0-preview.3" - }, - "client-elastic-transcoder-node": { - package: "@aws-sdk/client-elastic-transcoder-node", - version: "^0.1.0-preview.3" - }, - "client-elasticache-node": { - package: "@aws-sdk/client-elasticache-node", - version: "^0.1.0-preview.3" - }, - "client-elasticsearch-service-node": { - package: "@aws-sdk/client-elasticsearch-service-node", - version: "^0.1.0-preview.3" - }, - "client-emr-node": { - package: "@aws-sdk/client-emr-node", - version: "^0.1.0-preview.3" - }, - "client-eventbridge-node": { - package: "@aws-sdk/client-eventbridge-node", - version: "^0.1.0-preview.3" - }, - "client-firehose-node": { - package: "@aws-sdk/client-firehose-node", - version: "^0.1.0-preview.3" - }, - "client-fms-node": { - package: "@aws-sdk/client-fms-node", - version: "^0.1.0-preview.3" - }, - "client-fsx-node": { - package: "@aws-sdk/client-fsx-node", - version: "^0.1.0-preview.3" - }, - "client-gamelift-node": { - package: "@aws-sdk/client-gamelift-node", - version: "^0.1.0-preview.3" - }, - "client-glacier-node": { - package: "@aws-sdk/client-glacier-node", - version: "^0.1.0-preview.8" - }, - "client-global-accelerator-node": { - package: "@aws-sdk/client-global-accelerator-node", - version: "^0.1.0-preview.3" - }, - "client-glue-node": { - package: "@aws-sdk/client-glue-node", - version: "^0.1.0-preview.3" - }, - "client-greengrass-node": { - package: "@aws-sdk/client-greengrass-node", - version: "^0.1.0-preview.3" - }, - "client-groundstation-node": { - package: "@aws-sdk/client-groundstation-node", - version: "^0.1.0-preview.3" - }, - "client-guardduty-node": { - package: "@aws-sdk/client-guardduty-node", - version: "^0.1.0-preview.3" - }, - "client-health-node": { - package: "@aws-sdk/client-health-node", - version: "^0.1.0-preview.3" - }, - "client-iam-node": { - package: "@aws-sdk/client-iam-node", - version: "^0.1.0-preview.3" - }, - "client-inspector-node": { - package: "@aws-sdk/client-inspector-node", - version: "^0.1.0-preview.3" - }, - "client-iot-1click-devices-service-node": { - package: "@aws-sdk/client-iot-1click-devices-service-node", - version: "^0.1.0-preview.3" - }, - "client-iot-1click-projects-node": { - package: "@aws-sdk/client-iot-1click-projects-node", - version: "^0.1.0-preview.3" - }, - "client-iot-data-plane-node": { - package: "@aws-sdk/client-iot-data-plane-node", - version: "^0.1.0-preview.3" - }, - "client-iot-events-data-node": { - package: "@aws-sdk/client-iot-events-data-node", - version: "^0.1.0-preview.3" - }, - "client-iot-events-node": { - package: "@aws-sdk/client-iot-events-node", - version: "^0.1.0-preview.3" - }, - "client-iot-jobs-data-plane-node": { - package: "@aws-sdk/client-iot-jobs-data-plane-node", - version: "^0.1.0-preview.3" - }, - "client-iot-node": { - package: "@aws-sdk/client-iot-node", - version: "^0.1.0-preview.3" - }, - "client-iotanalytics-node": { - package: "@aws-sdk/client-iotanalytics-node", - version: "^0.1.0-preview.3" - }, - "client-iotthingsgraph-node": { - package: "@aws-sdk/client-iotthingsgraph-node", - version: "^0.1.0-preview.3" - }, - "client-kafka-node": { - package: "@aws-sdk/client-kafka-node", - version: "^0.1.0-preview.3" - }, - "client-kinesis-analytics-node": { - package: "@aws-sdk/client-kinesis-analytics-node", - version: "^0.1.0-preview.3" - }, - "client-kinesis-analytics-v2-node": { - package: "@aws-sdk/client-kinesis-analytics-v2-node", - version: "^0.1.0-preview.3" - }, - "client-kinesis-node": { - package: "@aws-sdk/client-kinesis-node", - version: "^0.1.0-preview.3" - }, - "client-kinesis-video-archived-media-node": { - package: "@aws-sdk/client-kinesis-video-archived-media-node", - version: "^0.1.0-preview.3" - }, - "client-kinesis-video-media-node": { - package: "@aws-sdk/client-kinesis-video-media-node", - version: "^0.1.0-preview.3" - }, - "client-kinesis-video-node": { - package: "@aws-sdk/client-kinesis-video-node", - version: "^0.1.0-preview.3" - }, - "client-kms-node": { - package: "@aws-sdk/client-kms-node", - version: "^0.1.0-preview.6" - }, - "client-lambda-node": { - package: "@aws-sdk/client-lambda-node", - version: "^0.1.0-preview.8" - }, - "client-lex-model-building-service-node": { - package: "@aws-sdk/client-lex-model-building-service-node", - version: "^0.1.0-preview.3" - }, - "client-lex-runtime-service-node": { - package: "@aws-sdk/client-lex-runtime-service-node", - version: "^0.1.0-preview.3" - }, - "client-license-manager-node": { - package: "@aws-sdk/client-license-manager-node", - version: "^0.1.0-preview.3" - }, - "client-lightsail-node": { - package: "@aws-sdk/client-lightsail-node", - version: "^0.1.0-preview.3" - }, - "client-machine-learning-node": { - package: "@aws-sdk/client-machine-learning-node", - version: "^0.1.0-preview.3" - }, - "client-macie-node": { - package: "@aws-sdk/client-macie-node", - version: "^0.1.0-preview.3" - }, - "client-managedblockchain-node": { - package: "@aws-sdk/client-managedblockchain-node", - version: "^0.1.0-preview.3" - }, - "client-marketplace-commerce-analytics-node": { - package: "@aws-sdk/client-marketplace-commerce-analytics-node", - version: "^0.1.0-preview.3" - }, - "client-marketplace-entitlement-service-node": { - package: "@aws-sdk/client-marketplace-entitlement-service-node", - version: "^0.1.0-preview.3" - }, - "client-marketplace-metering-node": { - package: "@aws-sdk/client-marketplace-metering-node", - version: "^0.1.0-preview.3" - }, - "client-mediaconnect-node": { - package: "@aws-sdk/client-mediaconnect-node", - version: "^0.1.0-preview.3" - }, - "client-mediaconvert-node": { - package: "@aws-sdk/client-mediaconvert-node", - version: "^0.1.0-preview.3" - }, - "client-medialive-node": { - package: "@aws-sdk/client-medialive-node", - version: "^0.1.0-preview.3" - }, - "client-mediapackage-node": { - package: "@aws-sdk/client-mediapackage-node", - version: "^0.1.0-preview.3" - }, - "client-mediapackage-vod-node": { - package: "@aws-sdk/client-mediapackage-vod-node", - version: "^0.1.0-preview.3" - }, - "client-mediastore-data-node": { - package: "@aws-sdk/client-mediastore-data-node", - version: "^0.1.0-preview.3" - }, - "client-mediastore-node": { - package: "@aws-sdk/client-mediastore-node", - version: "^0.1.0-preview.3" - }, - "client-mediatailor-node": { - package: "@aws-sdk/client-mediatailor-node", - version: "^0.1.0-preview.3" - }, - "client-migration-hub-node": { - package: "@aws-sdk/client-migration-hub-node", - version: "^0.1.0-preview.3" - }, - "client-mobile-node": { - package: "@aws-sdk/client-mobile-node", - version: "^0.1.0-preview.3" - }, - "client-mq-node": { - package: "@aws-sdk/client-mq-node", - version: "^0.1.0-preview.3" - }, - "client-mturk-node": { - package: "@aws-sdk/client-mturk-node", - version: "^0.1.0-preview.3" - }, - "client-neptune-node": { - package: "@aws-sdk/client-neptune-node", - version: "^0.1.0-preview.3" - }, - "client-opsworks-node": { - package: "@aws-sdk/client-opsworks-node", - version: "^0.1.0-preview.3" - }, - "client-opsworkscm-node": { - package: "@aws-sdk/client-opsworkscm-node", - version: "^0.1.0-preview.3" - }, - "client-organizations-node": { - package: "@aws-sdk/client-organizations-node", - version: "^0.1.0-preview.3" - }, - "client-personalize-events-node": { - package: "@aws-sdk/client-personalize-events-node", - version: "^0.1.0-preview.3" - }, - "client-personalize-node": { - package: "@aws-sdk/client-personalize-node", - version: "^0.1.0-preview.3" - }, - "client-personalize-runtime-node": { - package: "@aws-sdk/client-personalize-runtime-node", - version: "^0.1.0-preview.3" - }, - "client-pi-node": { - package: "@aws-sdk/client-pi-node", - version: "^0.1.0-preview.3" - }, - "client-pinpoint-email-node": { - package: "@aws-sdk/client-pinpoint-email-node", - version: "^0.1.0-preview.3" - }, - "client-pinpoint-node": { - package: "@aws-sdk/client-pinpoint-node", - version: "^0.1.0-preview.3" - }, - "client-pinpoint-sms-voice-node": { - package: "@aws-sdk/client-pinpoint-sms-voice-node", - version: "^0.1.0-preview.3" - }, - "client-polly-node": { - package: "@aws-sdk/client-polly-node", - version: "^0.1.0-preview.3" - }, - "client-pricing-node": { - package: "@aws-sdk/client-pricing-node", - version: "^0.1.0-preview.3" - }, - "client-quicksight-node": { - package: "@aws-sdk/client-quicksight-node", - version: "^0.1.0-preview.3" - }, - "client-ram-node": { - package: "@aws-sdk/client-ram-node", - version: "^0.1.0-preview.3" - }, - "client-rds-data-node": { - package: "@aws-sdk/client-rds-data-node", - version: "^0.1.0-preview.3" - }, - "client-rds-node": { - package: "@aws-sdk/client-rds-node", - version: "^0.1.0-preview.3" - }, - "client-redshift-node": { - package: "@aws-sdk/client-redshift-node", - version: "^0.1.0-preview.3" - }, - "client-rekognition-node": { - package: "@aws-sdk/client-rekognition-node", - version: "^0.1.0-preview.3" - }, - "client-resource-groups-node": { - package: "@aws-sdk/client-resource-groups-node", - version: "^0.1.0-preview.3" - }, - "client-resource-groups-tagging-api-node": { - package: "@aws-sdk/client-resource-groups-tagging-api-node", - version: "^0.1.0-preview.3" - }, - "client-robomaker-node": { - package: "@aws-sdk/client-robomaker-node", - version: "^0.1.0-preview.3" - }, - "client-route-53-domains-node": { - package: "@aws-sdk/client-route-53-domains-node", - version: "^0.1.0-preview.3" - }, - "client-route-53-node": { - package: "@aws-sdk/client-route-53-node", - version: "^0.1.0-preview.3" - }, - "client-route53resolver-node": { - package: "@aws-sdk/client-route53resolver-node", - version: "^0.1.0-preview.3" - }, - "client-s3-control-node": { - package: "@aws-sdk/client-s3-control-node", - version: "^0.1.0-preview.3" - }, - "client-s3-node": { - package: "@aws-sdk/client-s3-node", - version: "^0.1.0-preview.4" - }, - "client-sagemaker-node": { - package: "@aws-sdk/client-sagemaker-node", - version: "^0.1.0-preview.3" - }, - "client-sagemaker-runtime-node": { - package: "@aws-sdk/client-sagemaker-runtime-node", - version: "^0.1.0-preview.3" - }, - "client-secrets-manager-node": { - package: "@aws-sdk/client-secrets-manager-node", - version: "^0.1.0-preview.3" - }, - "client-securityhub-node": { - package: "@aws-sdk/client-securityhub-node", - version: "^0.1.0-preview.3" - }, - "client-serverlessapplicationrepository-node": { - package: "@aws-sdk/client-serverlessapplicationrepository-node", - version: "^0.1.0-preview.3" - }, - "client-service-catalog-node": { - package: "@aws-sdk/client-service-catalog-node", - version: "^0.1.0-preview.3" - }, - "client-service-quotas-node": { - package: "@aws-sdk/client-service-quotas-node", - version: "^0.1.0-preview.3" - }, - "client-servicediscovery-node": { - package: "@aws-sdk/client-servicediscovery-node", - version: "^0.1.0-preview.3" - }, - "client-ses-node": { - package: "@aws-sdk/client-ses-node", - version: "^0.1.0-preview.3" - }, - "client-sfn-node": { - package: "@aws-sdk/client-sfn-node", - version: "^0.1.0-preview.3" - }, - "client-shield-node": { - package: "@aws-sdk/client-shield-node", - version: "^0.1.0-preview.3" - }, - "client-signer-node": { - package: "@aws-sdk/client-signer-node", - version: "^0.1.0-preview.3" - }, - "client-sms-node": { - package: "@aws-sdk/client-sms-node", - version: "^0.1.0-preview.3" - }, - "client-snowball-node": { - package: "@aws-sdk/client-snowball-node", - version: "^0.1.0-preview.3" - }, - "client-sns-node": { - package: "@aws-sdk/client-sns-node", - version: "^0.1.0-preview.3" - }, - "client-sqs-node": { - package: "@aws-sdk/client-sqs-node", - version: "^0.1.0-preview.8" - }, - "client-ssm-node": { - package: "@aws-sdk/client-ssm-node", - version: "^0.1.0-preview.3" - }, - "client-storage-gateway-node": { - package: "@aws-sdk/client-storage-gateway-node", - version: "^0.1.0-preview.3" - }, - "client-sts-node": { - package: "@aws-sdk/client-sts-node", - version: "^0.1.0-preview.3" - }, - "client-support-node": { - package: "@aws-sdk/client-support-node", - version: "^0.1.0-preview.3" - }, - "client-swf-node": { - package: "@aws-sdk/client-swf-node", - version: "^0.1.0-preview.3" - }, - "client-textract-node": { - package: "@aws-sdk/client-textract-node", - version: "^0.1.0-preview.3" - }, - "client-transcribe-node": { - package: "@aws-sdk/client-transcribe-node", - version: "^0.1.0-preview.3" - }, - "client-transfer-node": { - package: "@aws-sdk/client-transfer-node", - version: "^0.1.0-preview.3" - }, - "client-translate-node": { - package: "@aws-sdk/client-translate-node", - version: "^0.1.0-preview.3" - }, - "client-waf-node": { - package: "@aws-sdk/client-waf-node", - version: "^0.1.0-preview.3" - }, - "client-waf-regional-node": { - package: "@aws-sdk/client-waf-regional-node", - version: "^0.1.0-preview.3" - }, - "client-workdocs-node": { - package: "@aws-sdk/client-workdocs-node", - version: "^0.1.0-preview.3" - }, - "client-worklink-node": { - package: "@aws-sdk/client-worklink-node", - version: "^0.1.0-preview.3" - }, - "client-workmail-node": { - package: "@aws-sdk/client-workmail-node", - version: "^0.1.0-preview.3" - }, - "client-workspaces-node": { - package: "@aws-sdk/client-workspaces-node", - version: "^0.1.0-preview.3" - }, - "client-xray-node": { - package: "@aws-sdk/client-xray-node", - version: "^0.1.0-preview.8" } }; diff --git a/packages/signing-middleware/package.json b/packages/signing-middleware/package.json index 796b74e945c56..911a26e27eee6 100644 --- a/packages/signing-middleware/package.json +++ b/packages/signing-middleware/package.json @@ -21,6 +21,7 @@ "dependencies": { "@aws-sdk/signature-v4": "^0.1.0-preview.7", "@aws-sdk/types": "^0.1.0-preview.5", + "@aws-sdk/protocol-http": "^0.1.0-preview.1", "tslib": "^1.8.0" } } diff --git a/packages/signing-middleware/src/configurations.ts b/packages/signing-middleware/src/configurations.ts new file mode 100644 index 0000000000000..f95063d33c7df --- /dev/null +++ b/packages/signing-middleware/src/configurations.ts @@ -0,0 +1,68 @@ +import { + RequestSigner, + Credentials, + Provider, + HashConstructor +} from "@aws-sdk/types"; +import { SignatureV4 } from "@aws-sdk/signature-v4"; + +export namespace AwsAuthConfiguration { + export interface Input { + /** + * The credentials used to sign requests. + */ + credentials?: Credentials | Provider; + + /** + * The signer to use when signing requests. + */ + signer?: RequestSigner; + + /** + * Whether to escape request path when signing the request + */ + signingEscapePath?: boolean; + } + interface PreviouslyResolved { + credentialDefaultProvider: (input: any) => Provider; + region: string | Provider; + signingName: string; + sha256: HashConstructor; + } + export interface Resolved { + credentials: Provider; + signer: RequestSigner; + signingEscapePath: boolean; + } + export function resolve( + input: T & Input & PreviouslyResolved + ): T & Resolved { + let credentials = + input.credentials || input.credentialDefaultProvider(input as any); + const normalizedCreds = normalizeProvider(credentials); + const signingEscapePath = input.signingEscapePath || false; + return { + ...input, + signingEscapePath, + credentials: normalizedCreds, + signer: new SignatureV4({ + credentials: normalizedCreds, + region: input.region, + service: input.signingName, + sha256: input.sha256, + uriEscapePath: signingEscapePath + }) + }; + } +} + +//export separately for showing comment block in Intellisense +export type AwsAuthConfigurationInput = AwsAuthConfiguration.Input; + +function normalizeProvider(input: T | Provider): Provider { + if (typeof input === "object") { + const promisified = Promise.resolve(input); + return () => promisified; + } + return input as Provider; +} diff --git a/packages/signing-middleware/src/index.ts b/packages/signing-middleware/src/index.ts index 81d6d868a9b46..ef4de14542fed 100644 --- a/packages/signing-middleware/src/index.ts +++ b/packages/signing-middleware/src/index.ts @@ -1,23 +1,2 @@ -import { - FinalizeHandler, - FinalizeHandlerArguments, - FinalizeMiddleware, - RequestSigner, - FinalizeHandlerOutput, - HttpRequest -} from "@aws-sdk/types"; - -export function signingMiddleware( - signer: RequestSigner -): FinalizeMiddleware { - return ( - next: FinalizeHandler - ): FinalizeHandler => async ( - args: FinalizeHandlerArguments - ): Promise> => - //TODO: check if request is HttpRequest instance - next({ - ...args, - request: await signer.sign(args.request as HttpRequest) - }); -} +export * from "./configurations"; +export * from "./middleware"; diff --git a/packages/signing-middleware/src/index.spec.ts b/packages/signing-middleware/src/middleware.spec.ts similarity index 69% rename from packages/signing-middleware/src/index.spec.ts rename to packages/signing-middleware/src/middleware.spec.ts index f50cf2ad883bf..6f7fce67cd8b9 100644 --- a/packages/signing-middleware/src/index.spec.ts +++ b/packages/signing-middleware/src/middleware.spec.ts @@ -1,5 +1,6 @@ -import { signingMiddleware } from "./"; -import { Handler, RequestSigner, HttpRequest } from "@aws-sdk/types"; +import { signingMiddleware } from "./middleware"; +import { RequestSigner } from "@aws-sdk/types"; +import { HttpRequest } from '@aws-sdk/protocol-http'; describe("SigningHandler", () => { const noOpSigner: RequestSigner = { @@ -19,12 +20,12 @@ describe("SigningHandler", () => { }); it("should sign the request and pass it to the next handler", async () => { - const signingHandler = signingMiddleware(noOpSigner)(noOpNext, {} as any); + const signingHandler = signingMiddleware({ signer: noOpSigner } as any)(noOpNext, {} as any); await signingHandler({ input: {}, - request: { + request: new HttpRequest({ headers: {} - } as any + }) }); const { calls } = (noOpNext as any).mock; diff --git a/packages/signing-middleware/src/middleware.ts b/packages/signing-middleware/src/middleware.ts new file mode 100644 index 0000000000000..bbcd92ae58a04 --- /dev/null +++ b/packages/signing-middleware/src/middleware.ts @@ -0,0 +1,36 @@ +import { + FinalizeHandler, + FinalizeHandlerArguments, + FinalizeRequestMiddleware, + FinalizeHandlerOutput, + InjectableMiddleware +} from "@aws-sdk/types"; +import { AwsAuthConfiguration } from "./configurations"; +import { HttpRequest } from "@aws-sdk/protocol-http"; + +export function signingMiddleware( + options: AwsAuthConfiguration.Resolved +): FinalizeRequestMiddleware { + return ( + next: FinalizeHandler + ): FinalizeHandler => + async function( + args: FinalizeHandlerArguments + ): Promise> { + if (!HttpRequest.isInstance(args.request)) return next(args); + return next({ + ...args, + request: await options.signer.sign(args.request) + }); + }; +} + +export function signingPlugin( + options: AwsAuthConfiguration.Resolved +): InjectableMiddleware { + return { + middleware: signingMiddleware(options), + step: "finalizeRequest", + tags: { SIGNATURE: true } + }; +} diff --git a/packages/smithy-client/.gitignore b/packages/smithy-client/.gitignore new file mode 100644 index 0000000000000..3d1714c9806ef --- /dev/null +++ b/packages/smithy-client/.gitignore @@ -0,0 +1,8 @@ +/node_modules/ +/build/ +/coverage/ +/docs/ +*.tsbuildinfo +*.tgz +*.log +package-lock.json diff --git a/packages/smithy-client/.npmignore b/packages/smithy-client/.npmignore new file mode 100644 index 0000000000000..4b9fe3abf33a6 --- /dev/null +++ b/packages/smithy-client/.npmignore @@ -0,0 +1,13 @@ +/src/ +/coverage/ +/docs/ +tsconfig.test.json +*.tsbuildinfo + +*.spec.js +*.spec.d.ts +*.spec.js.map + +*.fixture.js +*.fixture.d.ts +*.fixture.js.map diff --git a/packages/smithy-client/LICENSE b/packages/smithy-client/LICENSE new file mode 100644 index 0000000000000..e907b58668da3 --- /dev/null +++ b/packages/smithy-client/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/smithy-client/README.md b/packages/smithy-client/README.md new file mode 100644 index 0000000000000..a0ef1a4d7005c --- /dev/null +++ b/packages/smithy-client/README.md @@ -0,0 +1,4 @@ +# @aws-sdk/@aws-sdk/smithy-client + +[![NPM version](https://img.shields.io/npm/v/@aws-sdk/@aws-sdk/smithy-client/preview.svg)](https://www.npmjs.com/package/@aws-sdk/@aws-sdk/smithy-client) +[![NPM downloads](https://img.shields.io/npm/dm/@aws-sdk/@aws-sdk/smithy-client.svg)](https://www.npmjs.com/package/@aws-sdk/@aws-sdk/smithy-client) diff --git a/packages/smithy-client/package.json b/packages/smithy-client/package.json new file mode 100644 index 0000000000000..6b191621f9794 --- /dev/null +++ b/packages/smithy-client/package.json @@ -0,0 +1,26 @@ +{ + "name": "@aws-sdk/smithy-client", + "version": "0.1.0-preview.1", + "scripts": { + "prepublishOnly": "tsc", + "pretest": "tsc -p tsconfig.test.json", + "test": "jest" + }, + "main": "./build/index.js", + "types": "./build/index.d.ts", + "author": { + "name": "AWS SDK for JavaScript Team", + "url": "https://aws.amazon.com/javascript/" + }, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^0.1.0-preview.5", + "@aws-sdk/middleware-stack": "^0.1.0-preview.6", + "tslib": "^1.8.0" + }, + "devDependencies": { + "@types/jest": "^24.0.12", + "typescript": "~3.4.0", + "jest": "^24.7.1" + } +} diff --git a/packages/smithy-client/src/client.ts b/packages/smithy-client/src/client.ts new file mode 100644 index 0000000000000..683b33c1ef6d5 --- /dev/null +++ b/packages/smithy-client/src/client.ts @@ -0,0 +1,92 @@ +import { MiddlewareStack } from "@aws-sdk/middleware-stack"; +import { + Protocol, + Command, + MetadataBearer, + InjectableMiddleware, + HandlerOptions as InjectOptions +} from "@aws-sdk/types"; + +export interface SmithyConfiguration { + protocol: Protocol; +} + +export type SmithyResolvedConfiguration = SmithyConfiguration< + HandlerOptions +>; + +export class Client< + HandlerOptions = any, + ClientInput extends object = any, + ClientOutput extends MetadataBearer = any +> { + public middlewareStack = new MiddlewareStack(); + readonly config: SmithyResolvedConfiguration; + constructor(config: SmithyConfiguration) { + this.config = config; + } + use( + injectable: InjectableMiddleware, + options: InjectOptions = {} + ) { + const { middleware, step, priority, tags } = injectable; + this.middlewareStack.add( + // @ts-ignore -- Middleware and option type matching safety is enforced by InjectableMiddleware types + middleware, + { + step: options.step || step, + priority: options.priority || priority, + tags: { ...tags, ...options.tags } + } + ); + } + send( + command: Command< + ClientInput, + InputType, + ClientOutput, + OutputType, + SmithyResolvedConfiguration + >, + options?: HandlerOptions + ): Promise; + send( + command: Command< + ClientInput, + InputType, + ClientOutput, + OutputType, + SmithyResolvedConfiguration + >, + options: HandlerOptions, + cb: (err: any, data?: OutputType) => void + ): void; + send( + command: Command< + ClientInput, + InputType, + ClientOutput, + OutputType, + SmithyResolvedConfiguration + >, + options?: HandlerOptions, + cb?: (err: any, data?: OutputType) => void + ): Promise | void { + const handler = command.resolveMiddleware( + this.middlewareStack as any, + this.config, + options + ); + if (cb) { + handler(command) + .then(result => cb(null, result.output), (err: any) => cb(err)) + .catch( + // prevent any errors thrown in the callback from triggering an + // unhandled promise rejection + () => {} + ); + } else { + return handler(command).then(result => result.output); + } + } +} diff --git a/packages/smithy-client/src/command.ts b/packages/smithy-client/src/command.ts new file mode 100644 index 0000000000000..2648c9eb0d74f --- /dev/null +++ b/packages/smithy-client/src/command.ts @@ -0,0 +1,24 @@ +import { MiddlewareStack } from "@aws-sdk/middleware-stack"; +import { + InjectableMiddleware, + HandlerOptions as InjectOptions +} from "@aws-sdk/types"; + +export class Command { + readonly middlewareStack = new MiddlewareStack(); + use( + injectable: InjectableMiddleware, + options: InjectOptions = {} + ) { + const { middleware, step, priority, tags } = injectable; + this.middlewareStack.add( + // @ts-ignore + middleware, + { + step: options.step || step, + priority: options.priority || priority, + tags: { ...tags, ...options.tags } + } + ); + } +} diff --git a/packages/smithy-client/src/index.ts b/packages/smithy-client/src/index.ts new file mode 100644 index 0000000000000..2b06c3db3fa7f --- /dev/null +++ b/packages/smithy-client/src/index.ts @@ -0,0 +1,2 @@ +export * from "./client"; +export * from "./command"; diff --git a/packages/smithy-client/tsconfig.json b/packages/smithy-client/tsconfig.json new file mode 100644 index 0000000000000..38b94cda274ec --- /dev/null +++ b/packages/smithy-client/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "declaration": true, + "strict": true, + "sourceMap": true, + "downlevelIteration": true, + "importHelpers": true, + "noEmitHelpers": true, + "lib": [ + "es5", + "es2015.promise", + "es2015.collection", + "es2015.iterable", + "es2015.symbol.wellknown" + ], + "rootDir": "./src", + "outDir": "./build", + "incremental": true + } +} diff --git a/packages/smithy-client/tsconfig.test.json b/packages/smithy-client/tsconfig.test.json new file mode 100644 index 0000000000000..17d0f1b7321fb --- /dev/null +++ b/packages/smithy-client/tsconfig.test.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "sourceMap": false, + "inlineSourceMap": true, + "inlineSources": true, + "rootDir": "./src", + "outDir": "./build", + "incremental": true + } +} diff --git a/packages/stream-collector-browser/src/index.ts b/packages/stream-collector-browser/src/index.ts index 6c64d92624a8e..690cd1643116b 100644 --- a/packages/stream-collector-browser/src/index.ts +++ b/packages/stream-collector-browser/src/index.ts @@ -1,13 +1,12 @@ import { StreamCollector } from "@aws-sdk/types"; -export const streamCollector: StreamCollector = function streamCollector( +export const streamCollector: StreamCollector = ( stream: Blob -): Promise { - return new Promise((resolve, reject) => { +): Promise => + new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => resolve(new Uint8Array(reader.result as ArrayBuffer)); reader.onabort = () => reject(new Error("Read aborted")); reader.onerror = () => reject(reader.error); reader.readAsArrayBuffer(stream); }); -}; diff --git a/packages/stream-collector-node/src/index.ts b/packages/stream-collector-node/src/index.ts index 41bfa4cdd951e..f21df2f75bc92 100644 --- a/packages/stream-collector-node/src/index.ts +++ b/packages/stream-collector-node/src/index.ts @@ -2,10 +2,10 @@ import { Readable } from "stream"; import { StreamCollector } from "@aws-sdk/types"; import { Collector } from "./collector"; -export const streamCollector: StreamCollector< - Readable -> = function streamCollector(stream): Promise { - return new Promise((resolve, reject) => { +export const streamCollector: StreamCollector = ( + stream: Readable +): Promise => + new Promise((resolve, reject) => { const collector = new Collector(); stream.pipe(collector); stream.on("error", err => { @@ -19,4 +19,3 @@ export const streamCollector: StreamCollector< resolve(bytes); }); }); -}; diff --git a/packages/types/src/client.ts b/packages/types/src/client.ts index e8f5f3798edd6..dbff770e57e43 100644 --- a/packages/types/src/client.ts +++ b/packages/types/src/client.ts @@ -2,7 +2,7 @@ import { MiddlewareStack, Terminalware } from "./middleware"; import { Structure } from "./protocol"; import { Provider, Decoder, Encoder, UrlParser } from "./util"; // import { StreamCollector, ResponseParser } from "./unmarshaller"; -import { RequestSerializer } from "./marshaller"; +import { RequestSerializer } from "./serializer"; import { HttpEndpoint } from "./http"; import { TransferHandler } from "./transfer"; import { Command } from "./command"; @@ -43,19 +43,6 @@ export interface ConfigurationPropertyDefinition< normalize?: { (value: InputType, config: Partial): ResolvedType; }; - - /** - * A function that finalizes the value supplied and/or alters the client - * configuration or middleware stack in reaction to it. - */ - apply?: ConfigApplicator; -} - -export interface ConfigApplicator { - ( - config: FullConfiguration, - clientMiddlewareStack: MiddlewareStack - ): void; } /** @@ -149,20 +136,7 @@ interface InvokeFunction< * A general interface for service clients, idempotent to browser or node clients */ export interface AWSClient { - readonly config: ClientResolvedConfigurationBase; + // readonly config: ClientResolvedConfigurationBase; middlewareStack: MiddlewareStack; send: InvokeFunction; } - -export interface Injectable { - injectTo: (client: AWSClient) => AWSClient; -} - -export interface ClientPlugin< - ConfigType extends object, - ResolvedConfig = Required -> extends Injectable { - clientConfig: ConfigType; - resolvedClientConfig: ResolvedConfig; - middleware: Middleware; -} diff --git a/packages/types/src/deserializer.ts b/packages/types/src/deserializer.ts new file mode 100644 index 0000000000000..bfd81f4404db5 --- /dev/null +++ b/packages/types/src/deserializer.ts @@ -0,0 +1,37 @@ +import { Decoder, Encoder } from "./util"; + +export interface StreamCollector { + /** + * A function that converts a stream into an array of bytes. + * + * @param stream The low-level native stream from browser or Nodejs runtime + */ + (stream: any): Promise; +} + +/** + * Response deserializer utils functions for AWS services + */ +export interface DeserializerUtils { + base64Decoder: Decoder; + utf8Encoder: Encoder; + streamCollector: StreamCollector; +} + +export interface ResponseDeserializer { + /** + * Converts the output of an operation into JavaScript types. + * + * @param operation The operation model describing the structure of the HTTP + * response received + * @param input The HTTP response received from the service + * + * @param utils The runtime-specific util functions. If provided will + * overwrite the provided ones + */ + ( + output: ResponseType, + protocolName: string, + utils?: { [key: string]: any } + ): Promise; +} diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 2b1e3614520f6..17c39145e0c26 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -6,11 +6,11 @@ export * from "./crypto"; export * from "./exception"; export * from "./http"; export * from "./logger"; -export * from "./marshaller"; +export * from "./serializer"; export * from "./middleware"; export * from "./protocol"; export * from "./response"; export * from "./signature"; -export * from "./unmarshaller"; +export * from "./deserializer"; export * from "./transfer"; export * from "./util"; diff --git a/packages/types/src/marshaller.ts b/packages/types/src/marshaller.ts deleted file mode 100644 index 8e009072428ce..0000000000000 --- a/packages/types/src/marshaller.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Member, OperationModel } from "./protocol"; -import { HttpRequest } from "./http"; - -// export interface BodySerializer { -// /** -// * Converts the provided `input` into the serialized format described in the -// * provided `shape`. -// * -// * @param options Modeled and user-provided operation input to serialize. -// * -// * @throws if a node in the input cannot be converted into the type -// * specified by the serialization model -// */ -// build(options: BodySerializerBuildOptions): SerializedType; -// } - -// export interface BodySerializerBuildOptions { -// /** -// * Whether the operation input contains a payload member. -// */ -// hasPayload?: boolean; -// /** -// * The value to convert. -// */ -// input: any; -// /** -// * The root input member of the operation used to serialize the body. -// * Should be either operation input or the input payload member. -// * Defaults to operation.input. -// */ -// member?: Member; -// /** -// * Location name for the member. -// */ -// memberName?: string; -// /** -// * The operation model to which the input should be converted. -// */ -// operation: OperationModel; -// } - -export interface RequestSerializer { - /** - * Converts the provided `input` into a request object - * - * @param transferProtocol The protocol as the request to be serialized - * to. Like `RestJson`, `RestXML` - * @param input The user input to serialize. - */ - (input: any, transferProtocol: string): Request; -} diff --git a/packages/types/src/middleware.ts b/packages/types/src/middleware.ts index e0c10f87f87c3..1b9292f68aed5 100644 --- a/packages/types/src/middleware.ts +++ b/packages/types/src/middleware.ts @@ -1,4 +1,5 @@ import { Logger } from "./logger"; +import { AWSClient } from "./client"; export interface HandlerArguments { /** @@ -149,7 +150,7 @@ export interface SerializeMiddleware< * A factory function that creates functions implementing the {FinalizeHandler} * interface. */ -export interface FinalizeMiddleware< +export interface FinalizeRequestMiddleware< Input extends object, Output extends object > { @@ -166,7 +167,7 @@ export interface FinalizeMiddleware< } export interface BuildMiddleware - extends FinalizeMiddleware {} + extends FinalizeRequestMiddleware {} export interface DeserializeMiddleware< Input extends object, @@ -189,7 +190,7 @@ export type Step = | "initialize" | "serialize" | "build" - | "finalize" + | "finalizeRequest" | "deserialize"; export interface HandlerOptions { @@ -208,7 +209,7 @@ export interface HandlerOptions { * 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. - * - finalize: The request is being prepared to be sent over the wire. The + * - 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 @@ -251,8 +252,8 @@ export interface BuildHandlerOptions extends HandlerOptions { step: "build"; } -export interface FinalizeHandlerOptions extends HandlerOptions { - step: "finalize"; +export interface FinalizeRequestHandlerOptions extends HandlerOptions { + step: "finalizeRequest"; } export interface DeserializeHandlerOptions extends HandlerOptions { @@ -282,17 +283,17 @@ export interface MiddlewareStack { * optionally specifying a priority and tags. */ add( - middleware: FinalizeMiddleware, + middleware: FinalizeRequestMiddleware, options: BuildHandlerOptions ): void; /** - * Add middleware to the list to be executed during the "finalize" phase, + * Add middleware to the list to be executed during the "finalizeRequest" phase, * optionally specifying a priority and tags. */ add( - middleware: FinalizeMiddleware, - options: FinalizeHandlerOptions + middleware: FinalizeRequestMiddleware, + options: FinalizeRequestHandlerOptions ): void; /** @@ -364,3 +365,38 @@ export interface HandlerExecutionContext { */ logger: Logger; } + +export type InjectableMiddleware< + Input extends object = any, + Output extends object = any +> = + | { + middleware: Middleware; + step: "initialize"; + priority?: number; + tags?: { [tag: string]: any }; + } + | { + middleware: SerializeMiddleware; + step: "serialize"; + priority?: number; + tags?: { [tag: string]: any }; + } + | { + middleware: FinalizeRequestMiddleware; + step: "build"; + priority?: number; + tags?: { [tag: string]: any }; + } + | { + middleware: FinalizeRequestMiddleware; + step: "finalizeRequest"; + priority?: number; + tags?: { [tag: string]: any }; + } + | { + middleware: DeserializeMiddleware; + step: "deserialize"; + priority?: number; + tags?: { [tag: string]: any }; + }; diff --git a/packages/types/src/serializer.ts b/packages/types/src/serializer.ts new file mode 100644 index 0000000000000..d12df2a98301f --- /dev/null +++ b/packages/types/src/serializer.ts @@ -0,0 +1,27 @@ +import { Decoder, Encoder } from "./util"; + +/** + * Response deserializer util functions for AWS services + */ +export interface SerializerUtils { + utf8Decoder: Decoder; + base64Encoder: Encoder; +} + +export interface RequestSerializer { + /** + * Converts the provided `input` into a request object + * + * @param transferProtocol The protocol as the request to be serialized + * to. Like `RestJson`, `RestXML` + * @param input The user input to serialize. + * + * @param config The runtime-specific util functions. If provided will + * overwrite the provided ones + */ + ( + input: any, + transferProtocol: string, + utils?: { [key: string]: any } + ): Request; +} diff --git a/packages/types/src/transfer.ts b/packages/types/src/transfer.ts index ba28093af6710..f5ed165541314 100644 --- a/packages/types/src/transfer.ts +++ b/packages/types/src/transfer.ts @@ -1,5 +1,5 @@ -import { RequestSerializer } from "./marshaller"; -import { ResponseDeserializer } from "./unmarshaller"; +import { RequestSerializer } from "./serializer"; +import { ResponseDeserializer } from "./deserializer"; export type TransferHandlerOutput = { response: ResponseType }; @@ -21,10 +21,12 @@ export abstract class Protocol { ) {} abstract serialize( serializer: RequestSerializer, - input: any + input: any, + utils?: { [key: string]: any } ): RequestType; - abstract parse>( + abstract deserialize>( parser: T, - input: ResponseType + input: ResponseType, + utils?: { [key: string]: any } ): ReturnType; } diff --git a/packages/types/src/unmarshaller.ts b/packages/types/src/unmarshaller.ts deleted file mode 100644 index e33b29439a679..0000000000000 --- a/packages/types/src/unmarshaller.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Member, OperationModel } from "./protocol"; -import { HttpResponse, ResolvedHttpResponse } from "./http"; -import { MetadataBearer } from "./response"; -import { ServiceException } from "./exception"; - -// export interface BodyParser { -// /** -// * Convert the provided input into the shape described in the supplied -// * serialization model. -// * -// * @param shape A serialization model describing the expected shape of the -// * value supplied as `input`. -// * @param input The value to parse -// */ -// parse(shape: Member, input: SerializedType): OutputType; -// } - -export interface ResponseDeserializer { - /** - * Converts the output of an operation into JavaScript types. - * - * @param operation The operation model describing the structure of the HTTP - * response received - * @param input The HTTP response received from the service - */ - (output: ResponseType, protocolName: string): Promise; -} - -/** - * A function that converts a stream into an array of bytes. - */ -export interface StreamCollector { - (stream: StreamType): Promise; -} - -// /** -// * A function that parses the http response when http status code > 299, -// * parse the error response according to response and throw the ServiceException -// */ -// export interface ServiceExceptionParser { -// ( -// operation: OperationModel, -// response: ResolvedHttpResponse, -// errorBodyParser: BodyParser -// ): ServiceException; -// } diff --git a/packages/types/src/util.ts b/packages/types/src/util.ts index 7fbe500d9278c..969a4485eec04 100644 --- a/packages/types/src/util.ts +++ b/packages/types/src/util.ts @@ -47,28 +47,15 @@ export interface BodyLengthCalculator { (body: any): number | undefined; } -/** - * Determines the number of milliseconds to wait before retrying an action. - * - * @param delayBase The base delay (in milliseconds). - * @param attempts The number of times the action has already been tried. - */ -export interface DelayDecider { - (delayBase: number, attempts: number): number; -} - // TODO Unify with the types created for the error parsers export type SdkError = Error & { connectionError?: boolean }; -/** - * Determines whether an error is retryable based on the number of retries - * already attempted, the HTTP status code, and the error received (if any). - * - * @param statusCode The HTTP status code received. - * @param error The error encountered. - */ -export interface RetryDecider { - (error: SdkError): boolean; +export interface RetryStrategy { + shouldRetry: (error: SdkError, retryAttempted: number) => boolean; + computeDelayBeforeNextRetry: ( + error: SdkError, + retryAttempted: number + ) => number; } /**