Skip to content

Commit de8d4a6

Browse files
authored
chore: release accountId-endpoints config and codegen changes (#6313)
This reverts commit 08aa23f.
1 parent d5011a5 commit de8d4a6

15 files changed

+394
-5
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package software.amazon.smithy.aws.typescript.codegen;
7+
8+
import static software.amazon.smithy.aws.typescript.codegen.AwsTraitsUtils.isAwsService;
9+
import static software.amazon.smithy.aws.typescript.codegen.AwsTraitsUtils.isSigV4Service;
10+
11+
import java.util.HashMap;
12+
import java.util.Map;
13+
import java.util.Optional;
14+
import java.util.function.Consumer;
15+
import java.util.logging.Logger;
16+
import software.amazon.smithy.codegen.core.SymbolProvider;
17+
import software.amazon.smithy.model.Model;
18+
import software.amazon.smithy.model.shapes.ServiceShape;
19+
import software.amazon.smithy.rulesengine.traits.EndpointRuleSetTrait;
20+
import software.amazon.smithy.typescript.codegen.LanguageTarget;
21+
import software.amazon.smithy.typescript.codegen.TypeScriptDependency;
22+
import software.amazon.smithy.typescript.codegen.TypeScriptSettings;
23+
import software.amazon.smithy.typescript.codegen.TypeScriptWriter;
24+
import software.amazon.smithy.typescript.codegen.endpointsV2.RuleSetParameterFinder;
25+
import software.amazon.smithy.typescript.codegen.integration.TypeScriptIntegration;
26+
import software.amazon.smithy.utils.SmithyInternalApi;
27+
28+
/**
29+
* Generates accountIdEndpointMode configuration field for service clients
30+
* that have the AccountIdEndpointMode built-in param in the ruleset.
31+
*/
32+
@SmithyInternalApi
33+
public final class AddAccountIdEndpointModeRuntimeConfig implements TypeScriptIntegration {
34+
35+
private static final Logger LOGGER = Logger.getLogger(AddAccountIdEndpointModeRuntimeConfig.class.getName());
36+
37+
@Override
38+
public void addConfigInterfaceFields(
39+
TypeScriptSettings settings,
40+
Model model,
41+
SymbolProvider symbolProvider,
42+
TypeScriptWriter writer
43+
) {
44+
if (isAwsService(settings, model)) {
45+
ServiceShape service = settings.getService(model);
46+
Optional<EndpointRuleSetTrait> endpointRuleSetTrait = service.getTrait(EndpointRuleSetTrait.class);
47+
if (endpointRuleSetTrait.isPresent()) {
48+
RuleSetParameterFinder ruleSetParameterFinder = new RuleSetParameterFinder(service);
49+
if (ruleSetParameterFinder.getBuiltInParams().containsKey("AccountIdEndpointMode")) {
50+
writer.addDependency(AwsDependency.AWS_SDK_CORE);
51+
// TODO: change to addImportSubmodule when available; smithy-ts, #pull-1280
52+
writer.addImport("AccountIdEndpointMode", "AccountIdEndpointMode",
53+
"@aws-sdk/core/account-id-endpoint");
54+
writer.writeDocs("Defines if the AWS AccountId will be used for endpoint routing.");
55+
writer.write("accountIdEndpointMode?: AccountIdEndpointMode | "
56+
+ "__Provider<AccountIdEndpointMode>;\n");
57+
}
58+
}
59+
}
60+
}
61+
62+
@Override
63+
public Map<String, Consumer<TypeScriptWriter>> getRuntimeConfigWriters(
64+
TypeScriptSettings settings,
65+
Model model,
66+
SymbolProvider symbolProvider,
67+
LanguageTarget target
68+
) {
69+
ServiceShape service = settings.getService(model);
70+
Map<String, Consumer<TypeScriptWriter>> runtimeConfigs = new HashMap<>();
71+
if (isAwsService(settings, model) || isSigV4Service(settings, model)) {
72+
Optional<EndpointRuleSetTrait> endpointRuleSetTrait = service.getTrait(EndpointRuleSetTrait.class);
73+
if (endpointRuleSetTrait.isPresent()) {
74+
RuleSetParameterFinder ruleSetParameterFinder = new RuleSetParameterFinder(service);
75+
if (ruleSetParameterFinder.getBuiltInParams().containsKey("AccountIdEndpointMode")) {
76+
switch (target) {
77+
case BROWSER:
78+
runtimeConfigs.put("accountIdEndpointMode", writer -> {
79+
writer.addDependency(AwsDependency.AWS_SDK_CORE);
80+
// TODO: change to addImportSubmodule when available
81+
writer.addImport("DEFAULT_ACCOUNT_ID_ENDPOINT_MODE", "DEFAULT_ACCOUNT_ID_ENDPOINT_MODE",
82+
"@aws-sdk/core/account-id-endpoint");
83+
writer.write("(() => Promise.resolve(DEFAULT_ACCOUNT_ID_ENDPOINT_MODE))");
84+
});
85+
break;
86+
case NODE:
87+
runtimeConfigs.put("accountIdEndpointMode", writer -> {
88+
writer.addDependency(TypeScriptDependency.NODE_CONFIG_PROVIDER);
89+
writer.addImport("loadConfig", "loadNodeConfig",
90+
TypeScriptDependency.NODE_CONFIG_PROVIDER);
91+
writer.addDependency(AwsDependency.AWS_SDK_CORE);
92+
// TODO: change to addImportSubmodule when available
93+
writer.addImport("NODE_ACCOUNT_ID_ENDPOINT_MODE_CONFIG_OPTIONS",
94+
"NODE_ACCOUNT_ID_ENDPOINT_MODE_CONFIG_OPTIONS",
95+
"@aws-sdk/core/account-id-endpoint");
96+
writer.write(
97+
"loadNodeConfig(NODE_ACCOUNT_ID_ENDPOINT_MODE_CONFIG_OPTIONS)");
98+
});
99+
break;
100+
default:
101+
LOGGER.warning("AccountIdEndpointMode config not supported for target: " + target);
102+
break;
103+
}
104+
}
105+
}
106+
}
107+
return runtimeConfigs;
108+
}
109+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package software.amazon.smithy.aws.typescript.codegen;
7+
8+
import software.amazon.smithy.typescript.codegen.TypeScriptCodegenContext;
9+
import software.amazon.smithy.typescript.codegen.endpointsV2.OmitEndpointParams;
10+
import software.amazon.smithy.typescript.codegen.integration.TypeScriptIntegration;
11+
import software.amazon.smithy.utils.SetUtils;
12+
import software.amazon.smithy.utils.SmithyInternalApi;
13+
14+
@SmithyInternalApi
15+
public class AddOmittedEndpointParams implements TypeScriptIntegration {
16+
17+
@Override
18+
public void customize(TypeScriptCodegenContext codegenContext) {
19+
setParamForOmission();
20+
}
21+
22+
private void setParamForOmission() {
23+
OmitEndpointParams.addOmittedParams(SetUtils.of("AccountId"));
24+
}
25+
}

codegen/smithy-aws-typescript-codegen/src/main/resources/META-INF/services/software.amazon.smithy.typescript.codegen.integration.TypeScriptIntegration

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
software.amazon.smithy.aws.typescript.codegen.AddEndpointsV2ParameterNameMap
22
software.amazon.smithy.aws.typescript.codegen.AddAwsRuntimeConfig
3+
software.amazon.smithy.aws.typescript.codegen.AddAccountIdEndpointModeRuntimeConfig
34
software.amazon.smithy.aws.typescript.codegen.AddBuiltinPlugins
45
software.amazon.smithy.aws.typescript.codegen.AddAwsAuthPlugin
56
software.amazon.smithy.aws.typescript.codegen.AddTokenAuthPlugin

packages/core/account-id-endpoint.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
/**
3+
* Do not edit:
4+
* This is a compatibility redirect for contexts that do not understand package.json exports field.
5+
*/
6+
module.exports = require("./dist-cjs/submodules/account-id-endpoint/index.js");

packages/core/package.json

+12-2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@
4646
"require": "./dist-cjs/submodules/httpAuthSchemes/index.js",
4747
"types": "./dist-types/submodules/httpAuthSchemes/index.d.ts"
4848
},
49+
"./account-id-endpoint": {
50+
"module": "./dist-es/submodules/account-id-endpoint/index.js",
51+
"node": "./dist-cjs/submodules/account-id-endpoint/index.js",
52+
"import": "./dist-es/submodules/account-id-endpoint/index.js",
53+
"require": "./dist-cjs/submodules/account-id-endpoint/index.js",
54+
"types": "./dist-types/submodules/account-id-endpoint/index.d.ts"
55+
},
4956
"./protocols": {
5057
"module": "./dist-es/submodules/protocols/index.js",
5158
"node": "./dist-cjs/submodules/protocols/index.js",
@@ -58,7 +65,8 @@
5865
"dist-*/**",
5966
"./client.js",
6067
"./httpAuthSchemes.js",
61-
"./protocols.js"
68+
"./protocols.js",
69+
"./account-id-endpoint.js"
6270
],
6371
"sideEffects": false,
6472
"author": {
@@ -73,7 +81,9 @@
7381
"@smithy/smithy-client": "^3.1.10",
7482
"@smithy/types": "^3.3.0",
7583
"fast-xml-parser": "4.2.5",
76-
"tslib": "^2.6.2"
84+
"tslib": "^2.6.2",
85+
"@smithy/node-config-provider": "^3.1.4",
86+
"@smithy/util-middleware": "^3.0.3"
7787
},
7888
"devDependencies": {
7989
"@tsconfig/recommended": "1.0.1",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { Provider } from "@smithy/types";
2+
import { normalizeProvider } from "@smithy/util-middleware";
3+
4+
import {
5+
AccountIdEndpointMode,
6+
DEFAULT_ACCOUNT_ID_ENDPOINT_MODE,
7+
validateAccountIdEndpointMode,
8+
} from "./AccountIdEndpointModeConstants";
9+
10+
/**
11+
* @public
12+
*/
13+
export interface AccountIdEndpointModeInputConfig {
14+
/**
15+
* The account ID endpoint mode to use.
16+
*/
17+
accountIdEndpointMode?: AccountIdEndpointMode | Provider<AccountIdEndpointMode>;
18+
}
19+
20+
/**
21+
* @internal
22+
*/
23+
interface PreviouslyResolved {}
24+
25+
/**
26+
* @internal
27+
*/
28+
export interface AccountIdEndpointModeResolvedConfig {
29+
/**
30+
* Resolved value for input config {config.accountIdEndpointMode}
31+
*/
32+
accountIdEndpointMode: Provider<AccountIdEndpointMode>;
33+
}
34+
35+
/**
36+
* @internal
37+
*/
38+
export const resolveAccountIdEndpointModeConfig = <T>(
39+
input: T & AccountIdEndpointModeInputConfig & PreviouslyResolved
40+
): T & AccountIdEndpointModeResolvedConfig => {
41+
return {
42+
...input,
43+
accountIdEndpointMode: async () => {
44+
const accountIdEndpointModeProvider = normalizeProvider(
45+
input.accountIdEndpointMode ?? DEFAULT_ACCOUNT_ID_ENDPOINT_MODE
46+
);
47+
const accIdMode = await accountIdEndpointModeProvider();
48+
if (!validateAccountIdEndpointMode(accIdMode)) {
49+
throw new Error(
50+
`Invalid value for accountIdEndpointMode: ${accIdMode}. Valid values are: "required", "preferred", "disabled".`
51+
);
52+
}
53+
return accIdMode;
54+
},
55+
};
56+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { validateAccountIdEndpointMode } from "./AccountIdEndpointModeConstants";
2+
3+
describe("validateAccountIdEndpointMode", () => {
4+
it('should return true for "disabled"', () => {
5+
const result = validateAccountIdEndpointMode("disabled");
6+
expect(result).toBe(true);
7+
});
8+
9+
it('should return true for "preferred"', () => {
10+
const result = validateAccountIdEndpointMode("preferred");
11+
expect(result).toBe(true);
12+
});
13+
14+
it('should return true for "required"', () => {
15+
const result = validateAccountIdEndpointMode("required");
16+
expect(result).toBe(true);
17+
});
18+
19+
it("should return false for an invalid value", () => {
20+
const result = validateAccountIdEndpointMode("invalidValue");
21+
expect(result).toBe(false);
22+
});
23+
24+
it("should return false for an empty string", () => {
25+
const result = validateAccountIdEndpointMode("");
26+
expect(result).toBe(false);
27+
});
28+
29+
it("should return false for a number", () => {
30+
const result = validateAccountIdEndpointMode(123);
31+
expect(result).toBe(false);
32+
});
33+
34+
it("should return false for null", () => {
35+
const result = validateAccountIdEndpointMode(null);
36+
expect(result).toBe(false);
37+
});
38+
39+
it("should return false for undefined", () => {
40+
const result = validateAccountIdEndpointMode(undefined);
41+
expect(result).toBe(false);
42+
});
43+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export type AccountIdEndpointMode = "disabled" | "preferred" | "required";
2+
3+
export const DEFAULT_ACCOUNT_ID_ENDPOINT_MODE = "preferred";
4+
5+
export const ACCOUNT_ID_ENDPOINT_MODE_VALUES: AccountIdEndpointMode[] = ["disabled", "preferred", "required"];
6+
7+
/**
8+
* @internal
9+
*/
10+
export function validateAccountIdEndpointMode(value: any): value is AccountIdEndpointMode {
11+
return ACCOUNT_ID_ENDPOINT_MODE_VALUES.includes(value);
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { DEFAULT_ACCOUNT_ID_ENDPOINT_MODE } from "./AccountIdEndpointModeConstants";
2+
import {
3+
CONFIG_ACCOUNT_ID_ENDPOINT_MODE,
4+
ENV_ACCOUNT_ID_ENDPOINT_MODE,
5+
NODE_ACCOUNT_ID_ENDPOINT_MODE_CONFIG_OPTIONS,
6+
} from "./NodeAccountIdEndpointModeConfigOptions";
7+
8+
describe("NODE_ACCOUNT_ID_ENDPOINT_MODE_CONFIG_OPTIONS", () => {
9+
const originalEnv = process.env;
10+
11+
beforeEach(() => {
12+
jest.resetModules();
13+
process.env = { ...originalEnv };
14+
});
15+
16+
afterEach(() => {
17+
process.env = originalEnv;
18+
});
19+
20+
describe("environmentVariableSelector", () => {
21+
it("should return the value set in environment variables", () => {
22+
const testValue = "preferred";
23+
process.env[ENV_ACCOUNT_ID_ENDPOINT_MODE] = testValue;
24+
const selector = NODE_ACCOUNT_ID_ENDPOINT_MODE_CONFIG_OPTIONS.environmentVariableSelector;
25+
expect(selector(process.env)).toEqual(testValue);
26+
});
27+
28+
it("should throw an error if the environment variable is set to an invalid value", () => {
29+
process.env[ENV_ACCOUNT_ID_ENDPOINT_MODE] = "InvalidValue";
30+
const selector = NODE_ACCOUNT_ID_ENDPOINT_MODE_CONFIG_OPTIONS.environmentVariableSelector;
31+
expect(() => selector(process.env)).toThrow("Invalid AccountIdEndpointMode value");
32+
});
33+
34+
it("should not throw an error if the environment variable is not set", () => {
35+
delete process.env[ENV_ACCOUNT_ID_ENDPOINT_MODE];
36+
const selector = NODE_ACCOUNT_ID_ENDPOINT_MODE_CONFIG_OPTIONS.environmentVariableSelector;
37+
expect(() => selector(process.env)).not.toThrow();
38+
});
39+
});
40+
41+
describe("configFileSelector", () => {
42+
it("should return the value set in the configuration file", () => {
43+
const testValue = "required";
44+
const profile = { [CONFIG_ACCOUNT_ID_ENDPOINT_MODE]: testValue };
45+
const selector = NODE_ACCOUNT_ID_ENDPOINT_MODE_CONFIG_OPTIONS.configFileSelector;
46+
expect(selector(profile)).toEqual(testValue);
47+
});
48+
49+
it("should throw an error if the configuration file contains an invalid value", () => {
50+
const profile = { [CONFIG_ACCOUNT_ID_ENDPOINT_MODE]: "InvalidValue" };
51+
const selector = NODE_ACCOUNT_ID_ENDPOINT_MODE_CONFIG_OPTIONS.configFileSelector;
52+
expect(() => selector(profile)).toThrow("Invalid AccountIdEndpointMode value");
53+
});
54+
55+
it("should not throw an error if the configuration file does not contain the setting", () => {
56+
const profile = {};
57+
const selector = NODE_ACCOUNT_ID_ENDPOINT_MODE_CONFIG_OPTIONS.configFileSelector;
58+
expect(() => selector(profile)).not.toThrow();
59+
});
60+
});
61+
62+
describe("default", () => {
63+
it("should return the default value", () => {
64+
const defaultValue = NODE_ACCOUNT_ID_ENDPOINT_MODE_CONFIG_OPTIONS.default;
65+
expect(defaultValue).toEqual(DEFAULT_ACCOUNT_ID_ENDPOINT_MODE);
66+
});
67+
});
68+
});

0 commit comments

Comments
 (0)