diff --git a/.changeset/hot-items-sing.md b/.changeset/hot-items-sing.md new file mode 100644 index 00000000000..e4262b33462 --- /dev/null +++ b/.changeset/hot-items-sing.md @@ -0,0 +1,5 @@ +--- +"@smithy/middleware-endpoint": patch +--- + +resolve service-specific endpoint once per client diff --git a/packages/middleware-endpoint/src/adaptors/getEndpointFromConfig.ts b/packages/middleware-endpoint/src/adaptors/getEndpointFromConfig.ts index 903f66fbb21..01329aac590 100644 --- a/packages/middleware-endpoint/src/adaptors/getEndpointFromConfig.ts +++ b/packages/middleware-endpoint/src/adaptors/getEndpointFromConfig.ts @@ -2,4 +2,7 @@ import { loadConfig } from "@smithy/node-config-provider"; import { getEndpointUrlConfig } from "./getEndpointUrlConfig"; -export const getEndpointFromConfig = async (serviceId: string) => loadConfig(getEndpointUrlConfig(serviceId))(); +/** + * @internal + */ +export const getEndpointFromConfig = async (serviceId?: string) => loadConfig(getEndpointUrlConfig(serviceId ?? ""))(); diff --git a/packages/middleware-endpoint/src/adaptors/getEndpointFromInstructions.ts b/packages/middleware-endpoint/src/adaptors/getEndpointFromInstructions.ts index 4e841c9a486..e1a862c70c7 100644 --- a/packages/middleware-endpoint/src/adaptors/getEndpointFromInstructions.ts +++ b/packages/middleware-endpoint/src/adaptors/getEndpointFromInstructions.ts @@ -39,9 +39,19 @@ export const getEndpointFromInstructions = async < context?: HandlerExecutionContext ): Promise => { if (!clientConfig.endpoint) { - const endpointFromConfig = await getEndpointFromConfig(clientConfig.serviceId || ""); + let endpointFromConfig: string | undefined; + + // This field is guaranteed by the type indicated by the config resolver, but is new + // and some existing standalone calls to this function may not provide the function, so + // this check should remain here. + if (clientConfig.serviceConfiguredEndpoint) { + endpointFromConfig = await clientConfig.serviceConfiguredEndpoint(); + } else { + endpointFromConfig = await getEndpointFromConfig(clientConfig.serviceId); + } + if (endpointFromConfig) { - clientConfig.endpoint = () => Promise.resolve(toEndpointV1(endpointFromConfig)); + clientConfig.endpoint = () => Promise.resolve(toEndpointV1(endpointFromConfig!)); } } diff --git a/packages/middleware-endpoint/src/resolveEndpointConfig.ts b/packages/middleware-endpoint/src/resolveEndpointConfig.ts index 3bbd3368527..168ed0a9a30 100644 --- a/packages/middleware-endpoint/src/resolveEndpointConfig.ts +++ b/packages/middleware-endpoint/src/resolveEndpointConfig.ts @@ -1,6 +1,7 @@ import { Endpoint, EndpointParameters, EndpointV2, Logger, Provider, UrlParser } from "@smithy/types"; import { normalizeProvider } from "@smithy/util-middleware"; +import { getEndpointFromConfig } from "./adaptors/getEndpointFromConfig"; import { toEndpointV1 } from "./adaptors/toEndpointV1"; /** @@ -42,6 +43,12 @@ export interface EndpointInputConfig; + + /** + * @internal + * This field is used internally so you should not fill any value to this field. + */ + serviceConfiguredEndpoint?: never; } interface PreviouslyResolved { @@ -49,6 +56,7 @@ interface PreviouslyResolved region: Provider; endpointProvider: (params: T, context?: { logger?: Logger }) => EndpointV2; logger?: Logger; + serviceId?: string; } /** @@ -95,6 +103,12 @@ export interface EndpointResolvedConfig; } /** @@ -111,7 +125,7 @@ export const resolveEndpointConfig = ; + + let configuredEndpointPromise: undefined | Promise = undefined; + resolvedConfig.serviceConfiguredEndpoint = async () => { + if (input.serviceId && !configuredEndpointPromise) { + configuredEndpointPromise = getEndpointFromConfig(input.serviceId); + } + return configuredEndpointPromise; + }; + + return resolvedConfig; };