Skip to content

Commit cc6bab0

Browse files
committed
fix(codegen): add default aws regional endpoint provider
1 parent 8bcaf94 commit cc6bab0

File tree

3 files changed

+121
-1
lines changed

3 files changed

+121
-1
lines changed

codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddDefaultAwsEndpointRuleSet.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
package software.amazon.smithy.aws.typescript.codegen;
77

8+
import java.util.Collections;
89
import java.util.List;
910
import software.amazon.smithy.aws.traits.ServiceTrait;
1011
import software.amazon.smithy.model.Model;
@@ -13,13 +14,18 @@
1314
import software.amazon.smithy.rulesengine.traits.EndpointRuleSetTrait;
1415
import software.amazon.smithy.typescript.codegen.TypeScriptSettings;
1516
import software.amazon.smithy.typescript.codegen.endpointsV2.AddDefaultEndpointRuleSet;
17+
import software.amazon.smithy.typescript.codegen.integration.RuntimeClientPlugin;
1618
import software.amazon.smithy.typescript.codegen.integration.TypeScriptIntegration;
1719

20+
import static software.amazon.smithy.typescript.codegen.integration.RuntimeClientPlugin.Convention.HAS_CONFIG;
21+
1822

1923
/**
2024
* This replaces behavior from {@link EndpointGenerator}.
2125
*/
2226
public class AddDefaultAwsEndpointRuleSet implements TypeScriptIntegration {
27+
private boolean usesDefaultAwsRegionalEndpoints = false;
28+
2329
/**
2430
* Running before the smithy-typescript default endpoint integration
2531
* will prevent it from applying its non-AWS default ruleset and
@@ -31,6 +37,27 @@ public List<String> runBefore() {
3137
return List.of(AddDefaultEndpointRuleSet.class.getCanonicalName());
3238
}
3339

40+
@Override
41+
public List<RuntimeClientPlugin> getClientPlugins() {
42+
if (usesDefaultAwsRegionalEndpoints) {
43+
/*
44+
This resolver supports the behavior of endpoints.json-based endpoint provider
45+
for default regional services: it makes client.config.endpoint optional on the input side,
46+
but guaranteed on the resolved side.
47+
*/
48+
return List.of(
49+
RuntimeClientPlugin.builder()
50+
.withConventions(
51+
AwsDependency.UTIL_ENDPOINTS.dependency,
52+
"DefaultAwsRegionalEndpoints",
53+
HAS_CONFIG
54+
)
55+
.build()
56+
);
57+
}
58+
return Collections.emptyList();
59+
}
60+
3461
@Override
3562
public Model preprocessModel(Model model, TypeScriptSettings settings) {
3663
Model.Builder modelBuilder = model.toBuilder();
@@ -40,7 +67,7 @@ public Model preprocessModel(Model model, TypeScriptSettings settings) {
4067
&& AwsTraitsUtils.isAwsService(serviceShape)) {
4168
// this branch is for models that identify as AWS services
4269
// but do not include an endpoint ruleset.
43-
70+
usesDefaultAwsRegionalEndpoints = true;
4471
modelBuilder.removeShape(serviceShape.toShapeId());
4572
modelBuilder.addShape(
4673
serviceShape.toBuilder()
@@ -49,6 +76,8 @@ public Model preprocessModel(Model model, TypeScriptSettings settings) {
4976
))
5077
.build()
5178
);
79+
} else {
80+
usesDefaultAwsRegionalEndpoints = false;
5281
}
5382

5483
return modelBuilder.build();

packages/util-endpoints/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"dependencies": {
2727
"@aws-sdk/types": "*",
2828
"@smithy/types": "^4.3.1",
29+
"@smithy/url-parser": "^4.0.4",
2930
"@smithy/util-endpoints": "^3.0.6",
3031
"tslib": "^2.6.2"
3132
},
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import type { Endpoint, EndpointParameters, EndpointV2, Logger, Provider } from "@smithy/types";
2+
import { parseUrl } from "@smithy/url-parser";
3+
4+
/**
5+
* This is an additional config resolver layer for clients using the default
6+
* AWS regional endpoints ruleset. It makes the *resolved* config guarantee the presence of an
7+
* endpoint provider function. This differs from the base behavior of the Endpoint
8+
* config resolver, which only normalizes config.endpoint IFF one is provided by the caller.
9+
*
10+
* This is not used by AWS SDK clients, but rather
11+
* generated clients that have the aws.api#service trait. This includes protocol tests
12+
* and other customers.
13+
*
14+
* This resolver is MUTUALLY EXCLUSIVE with the EndpointRequired config resolver from
15+
* |@smithy/middleware-endpoint.
16+
*
17+
* It must be placed after the `resolveEndpointConfig`
18+
* resolver. This replaces the endpoints.json-based default endpoint provider.
19+
*
20+
* @public
21+
*/
22+
export type DefaultAwsRegionalEndpointsInputConfig = {
23+
endpoint?: unknown;
24+
endpointProvider: (
25+
endpointParams: EndpointParameters | DefaultRegionalEndpointParameters,
26+
context?: { logger?: Logger }
27+
) => EndpointV2;
28+
};
29+
30+
type PreviouslyResolved = {
31+
logger?: Logger;
32+
region?: undefined | string | Provider<string | undefined>;
33+
useFipsEndpoint?: undefined | boolean | Provider<string | boolean>;
34+
useDualstackEndpoint?: undefined | boolean | Provider<string | boolean>;
35+
};
36+
37+
/**
38+
* @internal
39+
*/
40+
type DefaultRegionalEndpointParameters = {
41+
Region?: string | undefined;
42+
UseDualStack?: boolean | undefined;
43+
UseFIPS?: boolean | undefined;
44+
};
45+
46+
/**
47+
* @internal
48+
*/
49+
export interface DefaultAwsRegionalEndpointsResolvedConfig {
50+
endpoint: Provider<Endpoint>;
51+
}
52+
53+
/**
54+
* MUST resolve after `\@smithy/middleware-endpoint`::`resolveEndpointConfig`.
55+
*
56+
* @internal
57+
*/
58+
export const resolveDefaultAwsRegionalEndpointsConfig = <T>(
59+
input: T & DefaultAwsRegionalEndpointsInputConfig & PreviouslyResolved
60+
): T & DefaultAwsRegionalEndpointsResolvedConfig => {
61+
if (typeof input.endpointProvider !== "function") {
62+
throw new Error("@aws-sdk/util-endpoint - endpointProvider and endpoint missing in config for this client.");
63+
}
64+
65+
const { endpoint } = input;
66+
if (endpoint === undefined) {
67+
input.endpoint = async () => {
68+
return toEndpointV1(
69+
input.endpointProvider(
70+
{
71+
Region: typeof input.region === "function" ? await input.region() : input.region,
72+
UseDualStack:
73+
typeof input.useDualstackEndpoint === "function"
74+
? await input.useDualstackEndpoint()
75+
: input.useDualstackEndpoint,
76+
UseFIPS:
77+
typeof input.useFipsEndpoint === "function" ? await input.useFipsEndpoint() : input.useFipsEndpoint,
78+
},
79+
{ logger: input.logger }
80+
)
81+
);
82+
};
83+
}
84+
return input as T & DefaultEndpointResolvedConfig;
85+
};
86+
87+
/**
88+
* @internal
89+
*/
90+
export const toEndpointV1 = (endpoint: EndpointV2): Endpoint => parseUrl(endpoint.url);

0 commit comments

Comments
 (0)