From a9ab1abb07c2009eda5210ff9e2157314149af89 Mon Sep 17 00:00:00 2001 From: George Fu Date: Mon, 23 Jun 2025 10:20:59 -0400 Subject: [PATCH] fix: add EndpointRequired config resolver to replace CustomEndpoint --- .changeset/wicked-squids-pretend.md | 5 ++ packages/middleware-endpoint/src/index.ts | 1 + .../src/resolveEndpointRequiredConfig.spec.ts | 13 +++++ .../src/resolveEndpointRequiredConfig.ts | 47 +++++++++++++++++++ .../src/RpcV2ProtocolClient.ts | 18 +++++-- .../src/RpcV2ProtocolClient.ts | 18 +++++-- .../AddDefaultEndpointRuleSet.java | 25 ++++++++-- 7 files changed, 115 insertions(+), 12 deletions(-) create mode 100644 .changeset/wicked-squids-pretend.md create mode 100644 packages/middleware-endpoint/src/resolveEndpointRequiredConfig.spec.ts create mode 100644 packages/middleware-endpoint/src/resolveEndpointRequiredConfig.ts diff --git a/.changeset/wicked-squids-pretend.md b/.changeset/wicked-squids-pretend.md new file mode 100644 index 00000000000..24fa0792afe --- /dev/null +++ b/.changeset/wicked-squids-pretend.md @@ -0,0 +1,5 @@ +--- +"@smithy/middleware-endpoint": patch +--- + +add resolveEndpointRequiredConfig resolver diff --git a/packages/middleware-endpoint/src/index.ts b/packages/middleware-endpoint/src/index.ts index bea06cfd784..3cff7511a03 100644 --- a/packages/middleware-endpoint/src/index.ts +++ b/packages/middleware-endpoint/src/index.ts @@ -11,6 +11,7 @@ export * from "./endpointMiddleware"; */ export * from "./getEndpointPlugin"; export * from "./resolveEndpointConfig"; +export * from "./resolveEndpointRequiredConfig"; /** * @internal */ diff --git a/packages/middleware-endpoint/src/resolveEndpointRequiredConfig.spec.ts b/packages/middleware-endpoint/src/resolveEndpointRequiredConfig.spec.ts new file mode 100644 index 00000000000..5ba74c08c88 --- /dev/null +++ b/packages/middleware-endpoint/src/resolveEndpointRequiredConfig.spec.ts @@ -0,0 +1,13 @@ +import { describe, expect, test as it } from "vitest"; + +import { resolveEndpointRequiredConfig } from "./resolveEndpointRequiredConfig"; + +describe(resolveEndpointRequiredConfig.name, () => { + it("creates a default endpoint resolver function", async () => { + const config = resolveEndpointRequiredConfig({ + endpoint: undefined as any, + }); + + expect(() => config.endpoint()).rejects.toThrow(); + }); +}); diff --git a/packages/middleware-endpoint/src/resolveEndpointRequiredConfig.ts b/packages/middleware-endpoint/src/resolveEndpointRequiredConfig.ts new file mode 100644 index 00000000000..cdc95aa5b60 --- /dev/null +++ b/packages/middleware-endpoint/src/resolveEndpointRequiredConfig.ts @@ -0,0 +1,47 @@ +import { Endpoint, EndpointV2, Provider } from "@smithy/types"; + +/** + * This is an additional config resolver layer for clients using the default + * endpoints ruleset. It modifies the input and output config types to make + * the endpoint configuration property required. + * + * It must be placed after the `resolveEndpointConfig` + * resolver. This replaces the "CustomEndpoints" config resolver, which was used + * prior to default endpoint rulesets. + * + * @public + */ +export interface EndpointRequiredInputConfig { + endpoint: string | Endpoint | Provider | EndpointV2 | Provider; +} + +/** + * @internal + */ +interface PreviouslyResolved { + endpoint?: Provider; +} + +/** + * @internal + */ +export interface EndpointRequiredResolvedConfig { + endpoint: Provider; +} + +/** + * @internal + */ +export const resolveEndpointRequiredConfig = ( + input: T & EndpointRequiredInputConfig & PreviouslyResolved +): T & EndpointRequiredResolvedConfig => { + const { endpoint } = input; + if (endpoint === undefined) { + input.endpoint = async () => { + throw new Error( + "@smithy/middleware-endpoint: (default endpointRuleSet) endpoint is not set - you must configure an endpoint." + ); + }; + } + return input as T & EndpointRequiredResolvedConfig; +}; diff --git a/private/smithy-rpcv2-cbor-schema/src/RpcV2ProtocolClient.ts b/private/smithy-rpcv2-cbor-schema/src/RpcV2ProtocolClient.ts index e6b848ab2db..b00d5438653 100644 --- a/private/smithy-rpcv2-cbor-schema/src/RpcV2ProtocolClient.ts +++ b/private/smithy-rpcv2-cbor-schema/src/RpcV2ProtocolClient.ts @@ -48,7 +48,14 @@ import { } from "@smithy/core"; import { getSchemaSerdePlugin } from "@smithy/core/schema"; import { getContentLengthPlugin } from "@smithy/middleware-content-length"; -import { EndpointInputConfig, EndpointResolvedConfig, resolveEndpointConfig } from "@smithy/middleware-endpoint"; +import { + EndpointInputConfig, + EndpointRequiredInputConfig, + EndpointRequiredResolvedConfig, + EndpointResolvedConfig, + resolveEndpointConfig, + resolveEndpointRequiredConfig, +} from "@smithy/middleware-endpoint"; import { RetryInputConfig, RetryResolvedConfig, getRetryPlugin, resolveRetryConfig } from "@smithy/middleware-retry"; import { HttpHandlerUserInput as __HttpHandlerUserInput } from "@smithy/protocol-http"; import { @@ -227,6 +234,7 @@ export type RpcV2ProtocolClientConfigType = Partial<__SmithyConfiguration<__Http ClientDefaults & RetryInputConfig & EndpointInputConfig & + EndpointRequiredInputConfig & HttpAuthSchemeInputConfig & ClientInputEndpointParameters; /** @@ -244,6 +252,7 @@ export type RpcV2ProtocolClientResolvedConfigType = __SmithyResolvedConfiguratio RuntimeExtensionsConfig & RetryResolvedConfig & EndpointResolvedConfig & + EndpointRequiredResolvedConfig & HttpAuthSchemeResolvedConfig & ClientResolvedEndpointParameters; /** @@ -274,9 +283,10 @@ export class RpcV2ProtocolClient extends __Client< let _config_1 = resolveClientEndpointParameters(_config_0); let _config_2 = resolveRetryConfig(_config_1); let _config_3 = resolveEndpointConfig(_config_2); - let _config_4 = resolveHttpAuthSchemeConfig(_config_3); - let _config_5 = resolveRuntimeExtensions(_config_4, configuration?.extensions || []); - this.config = _config_5; + let _config_4 = resolveEndpointRequiredConfig(_config_3); + let _config_5 = resolveHttpAuthSchemeConfig(_config_4); + let _config_6 = resolveRuntimeExtensions(_config_5, configuration?.extensions || []); + this.config = _config_6; this.middlewareStack.use(getSchemaSerdePlugin(this.config)); this.middlewareStack.use(getRetryPlugin(this.config)); this.middlewareStack.use(getContentLengthPlugin(this.config)); diff --git a/private/smithy-rpcv2-cbor/src/RpcV2ProtocolClient.ts b/private/smithy-rpcv2-cbor/src/RpcV2ProtocolClient.ts index bb39b2df6ea..2f1cddca96e 100644 --- a/private/smithy-rpcv2-cbor/src/RpcV2ProtocolClient.ts +++ b/private/smithy-rpcv2-cbor/src/RpcV2ProtocolClient.ts @@ -47,7 +47,14 @@ import { getHttpSigningPlugin, } from "@smithy/core"; import { getContentLengthPlugin } from "@smithy/middleware-content-length"; -import { EndpointInputConfig, EndpointResolvedConfig, resolveEndpointConfig } from "@smithy/middleware-endpoint"; +import { + EndpointInputConfig, + EndpointRequiredInputConfig, + EndpointRequiredResolvedConfig, + EndpointResolvedConfig, + resolveEndpointConfig, + resolveEndpointRequiredConfig, +} from "@smithy/middleware-endpoint"; import { RetryInputConfig, RetryResolvedConfig, getRetryPlugin, resolveRetryConfig } from "@smithy/middleware-retry"; import { HttpHandlerUserInput as __HttpHandlerUserInput } from "@smithy/protocol-http"; import { @@ -213,6 +220,7 @@ export type RpcV2ProtocolClientConfigType = Partial<__SmithyConfiguration<__Http ClientDefaults & RetryInputConfig & EndpointInputConfig & + EndpointRequiredInputConfig & HttpAuthSchemeInputConfig & ClientInputEndpointParameters; /** @@ -230,6 +238,7 @@ export type RpcV2ProtocolClientResolvedConfigType = __SmithyResolvedConfiguratio RuntimeExtensionsConfig & RetryResolvedConfig & EndpointResolvedConfig & + EndpointRequiredResolvedConfig & HttpAuthSchemeResolvedConfig & ClientResolvedEndpointParameters; /** @@ -260,9 +269,10 @@ export class RpcV2ProtocolClient extends __Client< let _config_1 = resolveClientEndpointParameters(_config_0); let _config_2 = resolveRetryConfig(_config_1); let _config_3 = resolveEndpointConfig(_config_2); - let _config_4 = resolveHttpAuthSchemeConfig(_config_3); - let _config_5 = resolveRuntimeExtensions(_config_4, configuration?.extensions || []); - this.config = _config_5; + let _config_4 = resolveEndpointRequiredConfig(_config_3); + let _config_5 = resolveHttpAuthSchemeConfig(_config_4); + let _config_6 = resolveRuntimeExtensions(_config_5, configuration?.extensions || []); + this.config = _config_6; this.middlewareStack.use(getRetryPlugin(this.config)); this.middlewareStack.use(getContentLengthPlugin(this.config)); this.middlewareStack.use( diff --git a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/endpointsV2/AddDefaultEndpointRuleSet.java b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/endpointsV2/AddDefaultEndpointRuleSet.java index 1d72a15fa75..8a4575e3d44 100644 --- a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/endpointsV2/AddDefaultEndpointRuleSet.java +++ b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/endpointsV2/AddDefaultEndpointRuleSet.java @@ -74,6 +74,8 @@ public class AddDefaultEndpointRuleSet implements TypeScriptIntegration { """)) .build(); + private boolean usesDefaultEndpointRuleset = false; + @Override public List runAfter() { return List.of(AddBuiltinPlugins.class.getCanonicalName()); @@ -81,11 +83,25 @@ public List runAfter() { @Override public List getClientPlugins() { + RuntimeClientPlugin endpointConfigResolver = RuntimeClientPlugin.builder() + .withConventions( + TypeScriptDependency.MIDDLEWARE_ENDPOINTS_V2.dependency, "Endpoint", HAS_CONFIG) + .build(); + + if (usesDefaultEndpointRuleset) { + return List.of( + endpointConfigResolver, + RuntimeClientPlugin.builder() + .withConventions( + TypeScriptDependency.MIDDLEWARE_ENDPOINTS_V2.dependency, + "EndpointRequired", + HAS_CONFIG + ) + .build() + ); + } return List.of( - RuntimeClientPlugin.builder() - .withConventions( - TypeScriptDependency.MIDDLEWARE_ENDPOINTS_V2.dependency, "Endpoint", HAS_CONFIG) - .build() + endpointConfigResolver ); } @@ -95,6 +111,7 @@ public Model preprocessModel(Model model, TypeScriptSettings settings) { model.getServiceShapes().forEach(serviceShape -> { if (!serviceShape.hasTrait(EndpointRuleSetTrait.class)) { + usesDefaultEndpointRuleset = true; modelBuilder.removeShape(serviceShape.toShapeId()); modelBuilder.addShape(serviceShape.toBuilder() .addTrait(DEFAULT_RULESET)