Skip to content

Commit 11e7af2

Browse files
committed
fix: add fallback resolution
1 parent 3a3edc9 commit 11e7af2

File tree

5 files changed

+87
-26
lines changed

5 files changed

+87
-26
lines changed

packages/middleware-endpoint/src/adaptors/createConfigValueProvider.spec.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,31 @@ describe(createConfigValueProvider.name, () => {
5858
expect(await createConfigValueProvider("v1", "endpoint", config)()).toEqual(sampleUrl);
5959
expect(await createConfigValueProvider("v2", "endpoint", config)()).toEqual(sampleUrl);
6060
});
61+
62+
it("should prioritize clientContextParams over direct properties", async () => {
63+
const config = {
64+
apiKey: "direct-api-key",
65+
clientContextParams: {
66+
apiKey: "nested-api-key",
67+
},
68+
};
69+
expect(await createConfigValueProvider("apiKey", "apiKey", config)()).toEqual("nested-api-key");
70+
});
71+
72+
it("should fall back to direct property when clientContextParams is not provided", async () => {
73+
const config = {
74+
customParam: "direct-value",
75+
};
76+
expect(await createConfigValueProvider("customParam", "customParam", config)()).toEqual("direct-value");
77+
});
78+
79+
it("should fall back to direct property when clientContextParams exists but param is not in it", async () => {
80+
const config = {
81+
customParam: "direct-value",
82+
clientContextParams: {
83+
otherParam: "other-value",
84+
},
85+
};
86+
expect(await createConfigValueProvider("customParam", "customParam", config)()).toEqual("direct-value");
87+
});
6188
});

packages/middleware-endpoint/src/adaptors/createConfigValueProvider.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,13 @@ export const createConfigValueProvider = <Config extends Record<string, unknown>
1818
config: Config
1919
) => {
2020
const configProvider = async () => {
21-
const configValue: unknown = config[configKey] ?? config[canonicalEndpointParamKey];
21+
// Check clientContextParams first for client context parameters
22+
const clientContextParams = config.clientContextParams as Record<string, unknown> | undefined;
23+
const nestedValue: unknown = clientContextParams?.[configKey] ?? clientContextParams?.[canonicalEndpointParamKey];
24+
25+
// Fall back to direct config properties
26+
const configValue: unknown = nestedValue ?? config[configKey] ?? config[canonicalEndpointParamKey];
27+
2228
if (typeof configValue === "function") {
2329
return configValue();
2430
}

packages/middleware-endpoint/src/adaptors/getEndpointFromInstructions.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,13 @@ export const resolveParams = async <
7878
instructionsSupplier: EndpointParameterInstructionsSupplier,
7979
clientConfig: Partial<EndpointResolvedConfig<T>> & Config
8080
) => {
81+
// Initialize clientContextParams to empty object if undefined
82+
// when accessing nested properties during parameter resolution
83+
const config = clientConfig as typeof clientConfig & { clientContextParams?: Record<string, unknown> };
84+
if (config.clientContextParams === undefined) {
85+
config.clientContextParams = {};
86+
}
87+
8188
const endpointParams: EndpointParameters = {};
8289
const instructions: EndpointParameterInstructions = instructionsSupplier?.getEndpointParameterInstructions?.() || {};
8390

smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/endpointsV2/EndpointsV2Generator.java

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -111,29 +111,29 @@ private void generateEndpointParameters() {
111111
this.delegator.useFileWriter(
112112
Paths.get(CodegenUtils.SOURCE_FOLDER, ENDPOINT_FOLDER, ENDPOINT_PARAMETERS_FILE).toString(),
113113
writer -> {
114-
writer.addTypeImport("EndpointParameters", "__EndpointParameters", TypeScriptDependency.SMITHY_TYPES);
115-
writer.addTypeImport("Provider", null, TypeScriptDependency.SMITHY_TYPES);
114+
writer.addImport("EndpointParameters", "__EndpointParameters", TypeScriptDependency.SMITHY_TYPES);
115+
writer.addImport("Provider", null, TypeScriptDependency.SMITHY_TYPES);
116+
Map<String, String> clientContextParams =
117+
ruleSetParameterFinder.getClientContextParams();
118+
Map<String, String> builtInParams = ruleSetParameterFinder.getBuiltInParams();
119+
builtInParams.keySet().removeIf(OmitEndpointParams::isOmitted);
120+
Set<String> knownConfigKeys = Set.of(
121+
"apiKey", "retryStrategy", "requestHandler");
122+
// Generate clientContextParams with all params excluding built-ins
123+
Map<String, String> customerContextParams = new HashMap<>();
124+
for (Map.Entry<String, String> entry : clientContextParams.entrySet()) {
125+
if (!builtInParams.containsKey(entry.getKey())) {
126+
customerContextParams.put(entry.getKey(), entry.getValue());
127+
}
128+
}
116129

117130
writer.writeDocs("@public");
118131
writer.openBlock(
119132
"export interface ClientInputEndpointParameters {",
120133
"}",
121134
() -> {
122-
Map<String, String> clientContextParams =
123-
ruleSetParameterFinder.getClientContextParams();
124-
Map<String, String> builtInParams = ruleSetParameterFinder.getBuiltInParams();
125-
builtInParams.keySet().removeIf(OmitEndpointParams::isOmitted);
126-
Set<String> knownConfigKeys = Set.of(
127-
"apiKey", "retryStrategy", "requestHandler");
128-
// Generate clientContextParams with all params excluding built-ins
129-
Map<String, String> customerContextParams = new HashMap<>();
130-
for (Map.Entry<String, String> entry : clientContextParams.entrySet()) {
131-
if (!builtInParams.containsKey(entry.getKey())) {
132-
customerContextParams.put(entry.getKey(), entry.getValue());
133-
}
134-
}
135135
if (!customerContextParams.isEmpty()) {
136-
writer.write("clientContextParams: {");
136+
writer.write("clientContextParams?: {");
137137
writer.indent();
138138
ObjectNode ruleSet = endpointRuleSetTrait.getRuleSet().expectObjectNode();
139139
ruleSet.getObjectMember("parameters").ifPresent(parameters -> {
@@ -168,14 +168,6 @@ private void generateEndpointParameters() {
168168
};"""
169169
);
170170
// Generate clientContextParamDefaults only if there are customer context params
171-
Map<String, String> clientContextParams = ruleSetParameterFinder.getClientContextParams();
172-
Map<String, String> builtInParams = ruleSetParameterFinder.getBuiltInParams();
173-
Map<String, String> customerContextParams = new HashMap<>();
174-
for (Map.Entry<String, String> entry : clientContextParams.entrySet()) {
175-
if (!builtInParams.containsKey(entry.getKey())) {
176-
customerContextParams.put(entry.getKey(), entry.getValue());
177-
}
178-
}
179171
if (!customerContextParams.isEmpty()) {
180172
// Check if any parameters have default values
181173
boolean hasDefaults = false;
@@ -234,6 +226,34 @@ private void generateEndpointParameters() {
234226
"defaultSigningName: \"$L\",",
235227
settings.getDefaultSigningName()
236228
);
229+
// Only generate clientContextParams if there are customer context params
230+
if (!customerContextParams.isEmpty()) {
231+
// Initialize clientContextParams if undefined to satisfy type requirements
232+
// Check if we have defaults to merge
233+
boolean hasDefaultsForResolve = false;
234+
if (ruleSet.getObjectMember("parameters").isPresent()) {
235+
ObjectNode parameters = ruleSet.getObjectMember("parameters")
236+
.get().expectObjectNode();
237+
for (Map.Entry<String, String> entry : customerContextParams.entrySet()) {
238+
String paramName = entry.getKey();
239+
ObjectNode paramNode = parameters.getObjectMember(paramName).orElse(null);
240+
if (paramNode != null && paramNode.containsMember("default")) {
241+
hasDefaultsForResolve = true;
242+
break;
243+
}
244+
}
245+
}
246+
if (hasDefaultsForResolve) {
247+
writer.write(
248+
"clientContextParams: Object.assign(clientContextParamDefaults, "
249+
+ "options.clientContextParams ?? {}),"
250+
);
251+
} else {
252+
writer.write(
253+
"clientContextParams: options.clientContextParams ?? {},"
254+
);
255+
}
256+
}
237257
});
238258
}
239259
);

smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/endpointsV2/EndpointsV2GeneratorTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,13 @@ public void containsExtraContextParameter() {
154154
return Object.assign(options, {
155155
stage: options.stage ?? "production",
156156
defaultSigningName: "",
157+
clientContextParams: Object.assign(clientContextParamDefaults, options.clientContextParams ?? {}),
157158
});
158159
"""));
159160
assertThat(endpointParameters, containsString(
160161
"""
161162
export interface ClientInputEndpointParameters {
162-
clientContextParams: {
163+
clientContextParams?: {
163164
region?: string | undefined | Provider<string | undefined>;
164165
stage?: string | undefined | Provider<string | undefined>;
165166
};

0 commit comments

Comments
 (0)