Skip to content

Commit 60a4215

Browse files
JordonPhillipsadamthom-amzngosar
authored
chore: merge ssdk branch into main (#2279)
* chore: serialize rest json error code header (#2166) * chore: short-circuit ssdk-incompatible integrations (#2167) * chore: disable idempotency autofill import when not generating a client (#2181) * Support generating non-AWS client (#2222) * feat(config-resolver): make region optional for non-AWS client * feat(codegen): skip integrations that are not relevant for non-AWS services This is an initial version to get a working version of generated code that compiles without manual edits in smithy-typescript-ssdk-demo. I expect to make updates to this logic. * chore(codegen): address code comments The minor ones from adamthom-amzn#1 * fix(codegen): use SigV4Trait check instead of ServiceTrait AddAwsRuntimeConfigTest is checking for some behaviors from AddAwsAuthPlugin too, which was failing with missing aws.auth#sigv4 trait after my change. Added the trait for now to the test, but unit tests will need to be added/refactored for all these changes. * chore(codegen): move isAwsService check to utils class * chore(codegen): code style formatting * chore(codegen): check SigV4 trait for including region * chore(codegen,config-resolver): refactor how endpoint is resolved for non-AWS client (#2287) * chore(config-resolver): refactor EndpointsConfig for non AWS services This reverts an earlier change to EndpointsConfig.ts and instead provides the new functionality in separate CustomEndpointsConfig.ts. This will be used as a separate plugin for endpoint resolution in non AWS clients. * feat(codegen): Use separate CustomEndpointsConfig for non-AWS clients This depends on newly added CustomEndpointsConfig in @aws-sdk/config-resolver package. * test(config-resolver): add test for CustomEndpointsConfig (#2305) Co-authored-by: Adam Thomas <[email protected]> Co-authored-by: Jaykumar Gosar <[email protected]>
1 parent 9ac1f40 commit 60a4215

File tree

14 files changed

+282
-46
lines changed

14 files changed

+282
-46
lines changed

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

+14-7
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
package software.amazon.smithy.aws.typescript.codegen;
1717

18+
import static software.amazon.smithy.aws.typescript.codegen.AwsTraitsUtils.isSigV4Service;
1819
import static software.amazon.smithy.typescript.codegen.integration.RuntimeClientPlugin.Convention.HAS_CONFIG;
1920
import static software.amazon.smithy.typescript.codegen.integration.RuntimeClientPlugin.Convention.HAS_MIDDLEWARE;
2021

@@ -46,6 +47,7 @@
4647
/**
4748
* Configure clients with AWS auth configurations and plugin.
4849
*/
50+
// TODO: Think about AWS Auth supported for only some operations and not all, when not AWS service, with say @auth([])
4951
public final class AddAwsAuthPlugin implements TypeScriptIntegration {
5052
static final String STS_CLIENT_PREFIX = "sts-client-";
5153
static final String ROLE_ASSUMERS_FILE = "defaultRoleAssumers";
@@ -59,6 +61,9 @@ public void addConfigInterfaceFields(
5961
TypeScriptWriter writer
6062
) {
6163
ServiceShape service = settings.getService(model);
64+
if (!isSigV4Service(service)) {
65+
return;
66+
}
6267
if (!areAllOptionalAuthOperations(model, service)) {
6368
writer.addImport("Credentials", "__Credentials", TypeScriptDependency.AWS_SDK_TYPES.packageName);
6469
writer.writeDocs("Default credentials provider; Not available in browser runtime.")
@@ -71,7 +76,9 @@ public List<RuntimeClientPlugin> getClientPlugins() {
7176
return ListUtils.of(
7277
RuntimeClientPlugin.builder()
7378
.withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "AwsAuth", HAS_CONFIG)
74-
.servicePredicate((m, s) -> !areAllOptionalAuthOperations(m, s) && !testServiceId(s, "STS"))
79+
.servicePredicate((m, s) -> isSigV4Service(s)
80+
&& !areAllOptionalAuthOperations(m, s)
81+
&& !testServiceId(s, "STS"))
7582
.build(),
7683
RuntimeClientPlugin.builder()
7784
.withConventions(AwsDependency.STS_MIDDLEWARE.dependency,
@@ -83,7 +90,7 @@ public List<RuntimeClientPlugin> getClientPlugins() {
8390
.withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "AwsAuth", HAS_MIDDLEWARE)
8491
// See operationUsesAwsAuth() below for AwsAuth Middleware customizations.
8592
.servicePredicate(
86-
(m, s) -> !testServiceId(s, "STS") && !hasOptionalAuthOperation(m, s)
93+
(m, s) -> !testServiceId(s, "STS") && isSigV4Service(s) && !hasOptionalAuthOperation(m, s)
8794
).build(),
8895
RuntimeClientPlugin.builder()
8996
.withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "AwsAuth", HAS_MIDDLEWARE)
@@ -100,7 +107,7 @@ public Map<String, Consumer<TypeScriptWriter>> getRuntimeConfigWriters(
100107
LanguageTarget target
101108
) {
102109
ServiceShape service = settings.getService(model);
103-
if (areAllOptionalAuthOperations(model, service)) {
110+
if (!isSigV4Service(service) || areAllOptionalAuthOperations(model, service)) {
104111
return Collections.emptyMap();
105112
}
106113
switch (target) {
@@ -187,8 +194,8 @@ private static boolean operationUsesAwsAuth(Model model, ServiceShape service, O
187194
}
188195

189196
// optionalAuth trait doesn't require authentication.
190-
if (hasOptionalAuthOperation(model, service)) {
191-
return !operation.getTrait(OptionalAuthTrait.class).isPresent();
197+
if (isSigV4Service(service) && hasOptionalAuthOperation(model, service)) {
198+
return !operation.hasTrait(OptionalAuthTrait.class);
192199
}
193200
return false;
194201
}
@@ -197,7 +204,7 @@ private static boolean hasOptionalAuthOperation(Model model, ServiceShape servic
197204
TopDownIndex topDownIndex = TopDownIndex.of(model);
198205
Set<OperationShape> operations = topDownIndex.getContainedOperations(service);
199206
for (OperationShape operation : operations) {
200-
if (operation.getTrait(OptionalAuthTrait.class).isPresent()) {
207+
if (operation.hasTrait(OptionalAuthTrait.class)) {
201208
return true;
202209
}
203210
}
@@ -208,7 +215,7 @@ private static boolean areAllOptionalAuthOperations(Model model, ServiceShape se
208215
TopDownIndex topDownIndex = TopDownIndex.of(model);
209216
Set<OperationShape> operations = topDownIndex.getContainedOperations(service);
210217
for (OperationShape operation : operations) {
211-
if (!operation.getTrait(OptionalAuthTrait.class).isPresent()) {
218+
if (!operation.hasTrait(OptionalAuthTrait.class)) {
212219
return false;
213220
}
214221
}

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

+60-38
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515

1616
package software.amazon.smithy.aws.typescript.codegen;
1717

18+
import static software.amazon.smithy.aws.typescript.codegen.AwsTraitsUtils.isAwsService;
19+
import static software.amazon.smithy.aws.typescript.codegen.AwsTraitsUtils.isSigV4Service;
20+
1821
import java.util.Collections;
1922
import java.util.HashMap;
2023
import java.util.Map;
@@ -31,6 +34,9 @@
3134
import software.amazon.smithy.typescript.codegen.integration.TypeScriptIntegration;
3235
import software.amazon.smithy.utils.MapUtils;
3336

37+
// TODO: This javadoc is specific to needs of AWS client. However it has elements that would be needed by non-AWS
38+
// clients too, like logger, region for SigV4. We should refactor these into different Integration or rename this
39+
// class to be generic.
3440
/**
3541
* AWS clients need to know the service name for collecting metrics, the
3642
* region name used to resolve endpoints, the max attempt to retry a request
@@ -82,10 +88,14 @@ public void addConfigInterfaceFields(
8288
writer.addImport("Provider", "__Provider", TypeScriptDependency.AWS_SDK_TYPES.packageName);
8389
writer.addImport("Logger", "__Logger", TypeScriptDependency.AWS_SDK_TYPES.packageName);
8490

85-
writer.writeDocs("Unique service identifier.\n@internal")
86-
.write("serviceId?: string;\n");
87-
writer.writeDocs("The AWS region to which this client will send requests")
88-
.write("region?: string | __Provider<string>;\n");
91+
if (isAwsService(settings, model)) {
92+
writer.writeDocs("Unique service identifier.\n@internal")
93+
.write("serviceId?: string;\n");
94+
}
95+
if (isSigV4Service(settings, model)) {
96+
writer.writeDocs("The AWS region to which this client will send requests or use as signingRegion")
97+
.write("region?: string | __Provider<string>;\n");
98+
}
8999
writer.writeDocs("Value for how many times a request will be made at most in case of retry.")
90100
.write("maxAttempts?: number | __Provider<number>;\n");
91101
writer.writeDocs("Optional logger for logging debug/info/warn/error.")
@@ -114,11 +124,17 @@ public Map<String, Consumer<TypeScriptWriter>> getRuntimeConfigWriters(
114124
+ "trait was found on " + service.getId());
115125
}
116126
}
117-
runtimeConfigs.putAll(getDefaultConfig(target));
127+
runtimeConfigs.putAll(getDefaultConfig(target, settings, model));
118128
return runtimeConfigs;
119129
}
120130

121-
private Map<String, Consumer<TypeScriptWriter>> getDefaultConfig(LanguageTarget target) {
131+
private Map<String, Consumer<TypeScriptWriter>> getDefaultConfig(
132+
LanguageTarget target,
133+
TypeScriptSettings settings,
134+
Model model
135+
) {
136+
Map<String, Consumer<TypeScriptWriter>> defaultConfigs = new HashMap();
137+
boolean isSigV4Service = isSigV4Service(settings, model);
122138
switch (target) {
123139
case SHARED:
124140
return MapUtils.of(
@@ -128,40 +144,46 @@ private Map<String, Consumer<TypeScriptWriter>> getDefaultConfig(LanguageTarget
128144
}
129145
);
130146
case BROWSER:
131-
return MapUtils.of(
132-
"region", writer -> {
133-
writer.addDependency(TypeScriptDependency.INVALID_DEPENDENCY);
134-
writer.addImport("invalidProvider", "invalidProvider",
135-
TypeScriptDependency.INVALID_DEPENDENCY.packageName);
136-
writer.write("region: invalidProvider(\"Region is missing\"),");
137-
},
138-
"maxAttempts", writer -> {
139-
writer.addDependency(TypeScriptDependency.MIDDLEWARE_RETRY);
140-
writer.addImport("DEFAULT_MAX_ATTEMPTS", "DEFAULT_MAX_ATTEMPTS",
141-
TypeScriptDependency.MIDDLEWARE_RETRY.packageName);
142-
writer.write("maxAttempts: DEFAULT_MAX_ATTEMPTS,");
143-
}
144-
);
147+
if (isSigV4Service) {
148+
defaultConfigs.put("region", writer -> {
149+
writer.addDependency(TypeScriptDependency.INVALID_DEPENDENCY);
150+
writer.addImport("invalidProvider", "invalidProvider",
151+
TypeScriptDependency.INVALID_DEPENDENCY.packageName);
152+
writer.write("region: invalidProvider(\"Region is missing\"),");
153+
});
154+
}
155+
defaultConfigs.put("maxAttempts", writer -> {
156+
writer.addDependency(TypeScriptDependency.MIDDLEWARE_RETRY);
157+
writer.addImport("DEFAULT_MAX_ATTEMPTS", "DEFAULT_MAX_ATTEMPTS",
158+
TypeScriptDependency.MIDDLEWARE_RETRY.packageName);
159+
writer.write("maxAttempts: DEFAULT_MAX_ATTEMPTS,");
160+
});
161+
return defaultConfigs;
145162
case NODE:
146-
return MapUtils.of(
147-
"region", writer -> {
148-
writer.addDependency(AwsDependency.NODE_CONFIG_PROVIDER);
149-
writer.addImport("loadConfig", "loadNodeConfig",
150-
AwsDependency.NODE_CONFIG_PROVIDER.packageName);
151-
writer.addDependency(TypeScriptDependency.CONFIG_RESOLVER);
152-
writer.addImport("NODE_REGION_CONFIG_OPTIONS", "NODE_REGION_CONFIG_OPTIONS",
153-
TypeScriptDependency.CONFIG_RESOLVER.packageName);
154-
writer.addImport("NODE_REGION_CONFIG_FILE_OPTIONS", "NODE_REGION_CONFIG_FILE_OPTIONS",
155-
TypeScriptDependency.CONFIG_RESOLVER.packageName);
156-
writer.write(
163+
if (isSigV4Service) {
164+
// TODO: For non-AWS service, figure out how the region should be configured.
165+
defaultConfigs.put("region", writer -> {
166+
writer.addDependency(AwsDependency.NODE_CONFIG_PROVIDER);
167+
writer.addImport("loadConfig", "loadNodeConfig",
168+
AwsDependency.NODE_CONFIG_PROVIDER.packageName);
169+
writer.addDependency(TypeScriptDependency.CONFIG_RESOLVER);
170+
writer.addImport("NODE_REGION_CONFIG_OPTIONS", "NODE_REGION_CONFIG_OPTIONS",
171+
TypeScriptDependency.CONFIG_RESOLVER.packageName);
172+
writer.addImport("NODE_REGION_CONFIG_FILE_OPTIONS", "NODE_REGION_CONFIG_FILE_OPTIONS",
173+
TypeScriptDependency.CONFIG_RESOLVER.packageName);
174+
writer.write(
157175
"region: loadNodeConfig(NODE_REGION_CONFIG_OPTIONS, NODE_REGION_CONFIG_FILE_OPTIONS),");
158-
},
159-
"maxAttempts", writer -> {
160-
writer.addImport("NODE_MAX_ATTEMPT_CONFIG_OPTIONS", "NODE_MAX_ATTEMPT_CONFIG_OPTIONS",
161-
TypeScriptDependency.MIDDLEWARE_RETRY.packageName);
162-
writer.write("maxAttempts: loadNodeConfig(NODE_MAX_ATTEMPT_CONFIG_OPTIONS),");
163-
}
164-
);
176+
});
177+
}
178+
defaultConfigs.put("maxAttempts", writer -> {
179+
writer.addDependency(AwsDependency.NODE_CONFIG_PROVIDER);
180+
writer.addImport("loadConfig", "loadNodeConfig",
181+
AwsDependency.NODE_CONFIG_PROVIDER.packageName);
182+
writer.addImport("NODE_MAX_ATTEMPT_CONFIG_OPTIONS", "NODE_MAX_ATTEMPT_CONFIG_OPTIONS",
183+
TypeScriptDependency.MIDDLEWARE_RETRY.packageName);
184+
writer.write("maxAttempts: loadNodeConfig(NODE_MAX_ATTEMPT_CONFIG_OPTIONS),");
185+
});
186+
return defaultConfigs;
165187
default:
166188
return Collections.emptyMap();
167189
}

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

+8
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
package software.amazon.smithy.aws.typescript.codegen;
1717

18+
import static software.amazon.smithy.aws.typescript.codegen.AwsTraitsUtils.isAwsService;
1819
import static software.amazon.smithy.typescript.codegen.integration.RuntimeClientPlugin.Convention.HAS_CONFIG;
1920
import static software.amazon.smithy.typescript.codegen.integration.RuntimeClientPlugin.Convention.HAS_MIDDLEWARE;
2021

@@ -44,9 +45,16 @@ public List<RuntimeClientPlugin> getClientPlugins() {
4445
return ListUtils.of(
4546
RuntimeClientPlugin.builder()
4647
.withConventions(TypeScriptDependency.CONFIG_RESOLVER.dependency, "Region", HAS_CONFIG)
48+
.servicePredicate((m, s) -> isAwsService(s))
4749
.build(),
50+
// Only one of Endpoints or CustomEndpoints should be used
4851
RuntimeClientPlugin.builder()
4952
.withConventions(TypeScriptDependency.CONFIG_RESOLVER.dependency, "Endpoints", HAS_CONFIG)
53+
.servicePredicate((m, s) -> isAwsService(s))
54+
.build(),
55+
RuntimeClientPlugin.builder()
56+
.withConventions(TypeScriptDependency.CONFIG_RESOLVER.dependency, "CustomEndpoints", HAS_CONFIG)
57+
.servicePredicate((m, s) -> !isAwsService(s))
5058
.build(),
5159
RuntimeClientPlugin.builder()
5260
.withConventions(TypeScriptDependency.MIDDLEWARE_RETRY.dependency, "Retry")

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

+12-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
package software.amazon.smithy.aws.typescript.codegen;
1717

18+
import static software.amazon.smithy.aws.typescript.codegen.AwsTraitsUtils.isAwsService;
19+
1820
import java.util.Collections;
1921
import java.util.List;
2022
import java.util.Map;
@@ -33,12 +35,15 @@
3335
/**
3436
* Add client plubins and configs to support injecting user agent.
3537
*/
38+
// TODO: Looks to add this back for non-AWS service clients, by fixing the dependency on ClientSharedValues.serviceId
3639
public class AddUserAgentDependency implements TypeScriptIntegration {
3740
@Override
3841
public List<RuntimeClientPlugin> getClientPlugins() {
3942
return ListUtils.of(
4043
RuntimeClientPlugin.builder()
41-
.withConventions(AwsDependency.MIDDLEWARE_USER_AGENT.dependency, "UserAgent").build());
44+
.withConventions(AwsDependency.MIDDLEWARE_USER_AGENT.dependency, "UserAgent")
45+
.servicePredicate((m, s) -> isAwsService(s))
46+
.build());
4247
}
4348

4449
@Override
@@ -48,6 +53,9 @@ public void addConfigInterfaceFields(
4853
SymbolProvider symbolProvider,
4954
TypeScriptWriter writer
5055
) {
56+
if (!isAwsService(settings, model)) {
57+
return;
58+
}
5159
writer.addImport("Provider", "Provider", TypeScriptDependency.AWS_SDK_TYPES.packageName);
5260
writer.addImport("UserAgent", "__UserAgent", TypeScriptDependency.AWS_SDK_TYPES.packageName);
5361
writer.writeDocs("The provider populating default tracking information to be sent with `user-agent`, "
@@ -62,6 +70,9 @@ public Map<String, Consumer<TypeScriptWriter>> getRuntimeConfigWriters(
6270
SymbolProvider symbolProvider,
6371
LanguageTarget target
6472
) {
73+
if (!isAwsService(settings, model)) {
74+
return Collections.emptyMap();
75+
}
6576
switch (target) {
6677
case NODE:
6778
return MapUtils.of(

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

+14
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
package software.amazon.smithy.aws.typescript.codegen;
1717

18+
import static software.amazon.smithy.aws.typescript.codegen.AwsTraitsUtils.isAwsService;
19+
1820
import java.util.Collections;
1921
import java.util.Map;
2022
import java.util.function.BiConsumer;
@@ -39,6 +41,10 @@ public void writeAdditionalFiles(
3941
SymbolProvider symbolProvider,
4042
BiConsumer<String, Consumer<TypeScriptWriter>> writerFactory
4143
) {
44+
if (!settings.generateClient() || !isAwsService(settings, model)) {
45+
return;
46+
}
47+
4248
writerFactory.accept("endpoints.ts", writer -> {
4349
new EndpointGenerator(settings.getService(model), writer).run();
4450
});
@@ -51,6 +57,10 @@ public void addConfigInterfaceFields(
5157
SymbolProvider symbolProvider,
5258
TypeScriptWriter writer
5359
) {
60+
if (!settings.generateClient() || !isAwsService(settings, model)) {
61+
return;
62+
}
63+
5464
writer.addImport("RegionInfoProvider", "RegionInfoProvider", TypeScriptDependency.AWS_SDK_TYPES.packageName);
5565
writer.writeDocs("Fetch related hostname, signing name or signing region with given region.");
5666
writer.write("regionInfoProvider?: RegionInfoProvider;\n");
@@ -63,6 +73,10 @@ public Map<String, Consumer<TypeScriptWriter>> getRuntimeConfigWriters(
6373
SymbolProvider symbolProvider,
6474
LanguageTarget target
6575
) {
76+
if (!settings.generateClient() || !isAwsService(settings, model)) {
77+
return Collections.emptyMap();
78+
}
79+
6680
switch (target) {
6781
case SHARED:
6882
return MapUtils.of("regionInfoProvider", writer -> {

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

+8
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
package software.amazon.smithy.aws.typescript.codegen;
1717

18+
import static software.amazon.smithy.aws.typescript.codegen.AwsTraitsUtils.isAwsService;
19+
1820
import java.util.Arrays;
1921
import java.util.Calendar;
2022
import java.util.function.BiConsumer;
@@ -55,6 +57,12 @@ public void writeAdditionalFiles(
5557
resource = resource.replace("${year}", Integer.toString(Calendar.getInstance().get(Calendar.YEAR)));
5658
writer.write(resource);
5759
});
60+
61+
// TODO: May need to generate a different/modified README.md for these cases
62+
if (!settings.generateClient() || !isAwsService(settings, model)) {
63+
return;
64+
}
65+
5866
writerFactory.accept("README.md", writer -> {
5967
ServiceShape service = settings.getService(model);
6068
String resource = IoUtils.readUtf8Resource(getClass(), "README.md.template");

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

+4
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,10 @@ static boolean writeXmlNamespace(GenerationContext context, Shape shape, String
221221
* @param context The generation context.
222222
*/
223223
static void addItempotencyAutofillImport(GenerationContext context) {
224+
// servers do not autogenerate idempotency tokens during deserialization
225+
if (!context.getSettings().generateClient()) {
226+
return;
227+
}
224228
context.getModel().shapes(MemberShape.class)
225229
.filter(memberShape -> memberShape.hasTrait(IdempotencyTokenTrait.class))
226230
.findFirst()

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

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public SymbolProvider decorateSymbolProvider(
4444
return symbol;
4545
}
4646

47+
// TODO: Should this WARNING be avoided somehow if client is not for an AWS service?
4748
// If the SDK service ID trait is present, use that, otherwise fall back to
4849
// the default naming strategy for the service.
4950
return shape.getTrait(ServiceTrait.class)

0 commit comments

Comments
 (0)