Smithy code generators for TypeScript. (in development)
Installations
npm install @smithy/util-retry
Releases
@smithy/middleware-compression@3.1.4
Published on 21 Nov 2024
@smithy/util-defaults-mode-node@3.0.28
Published on 21 Nov 2024
@smithy/util-defaults-mode-browser@3.0.28
Published on 21 Nov 2024
@smithy/smithy-client@3.4.5
Published on 21 Nov 2024
@smithy/middleware-retry@3.0.28
Published on 21 Nov 2024
@smithy/middleware-endpoint@3.2.4
Published on 21 Nov 2024
Developer
awslabs
Developer Guide
Module System
CommonJS
Min. Node Version
>=16.0.0
Typescript Support
Yes
Node Version
18.20.4
NPM Version
10.7.0
Statistics
234 Stars
2,408 Commits
89 Forks
13 Watching
33 Branches
95 Contributors
Updated on 28 Nov 2024
Languages
TypeScript (54.07%)
Java (43.14%)
JavaScript (1.76%)
Smithy (0.99%)
Makefile (0.03%)
Shell (0.01%)
Total Downloads
Cumulative downloads
Total Downloads
856,145,928
Last day
-18.2%
3,901,455
Compared to previous day
Last week
0.8%
24,190,852
Compared to previous week
Last month
11.3%
101,593,350
Compared to previous month
Last year
466.5%
727,698,757
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
Dev Dependencies
5
Smithy TypeScript
WARNING: Smithy TypeScript is currently in Developer Preview. All interfaces and supported JavaScript platforms are subject to change.
smithy-typescript
includes the reference implementations of the Smithy code generators for TypeScript.
For Client SDK code generation, the typescript-client-codegen
plugin provides a framework for generating extensible TypeScript clients that can support multiple JavaScript platforms, including Node.js, Browser, and React-Native. See the section on generating a client to see how to get started, or the typescript-client-codegen
documentation.
Note: Node.js support includes versions >= 16, and is subject to change.
For Server SDK code generation, the typescript-server-codegen
plugin provides a framework for generating server scaffolding at a higher level of abstraction and with type safety. More documentation can be found at in the typescript-server-codegen
documentation, or smithy.io.
Generating a client
The Smithy TypeScript typescript-client-codegen
code generator in this repository generates TypeScript clients from Smithy models, and can be built with both the idiomatic Smithy CLI or through Gradle.
The Smithy CLI is a prerequisite for this section when using the
smithy init
commands. See the installation guide for how to install the Smithy CLI. If installing the Smithy CLI is not preferred, the templates used can be found in the Smithy Examples repository.
For additional configuration, see the typescript-client-codegen
documentation and the documentation for smithy-build.json
.
Using Smithy TypeScript with the Smithy CLI
Using the Smithy CLI, a new Smithy CLI project can be created using the default smithy init
template. In this example, the project will be called smithy-typescript-example-client
.
1smithy init -o smithy-typescript-example-client 2cd smithy-typescript-example-client/
This will create a project with the following directory structure:
1smithy-typescript-example-client/ 2├── README.md 3├── models 4│ └── weather.smithy 5└── smithy-build.json
To add a minimal typescript-client-codegen
plugin, add the following to smithy-build.json
:
1// smithy-build.json 2{ 3 "version": "1.0", 4 "sources": ["models"], 5 // Add the Smithy TypeScript code generator dependency 6 "maven": { 7 "dependencies": [ 8 "software.amazon.smithy.typescript:smithy-typescript-codegen:0.25.0" 9 ] 10 }, 11 "plugins": { 12 // Add the Smithy TypeScript client plugin 13 "typescript-client-codegen": { 14 // Minimal configuration: add package name and version 15 "package": "@smithy/typescript-example-client", 16 "packageVersion": "0.0.1" 17 } 18 } 19}
After smithy-build.json
has been configured, run smithy build
. This will code generate the TypeScript client under the source
projection, found in the build/smithy/source/typescript-client-codegen
directory.
Verify the client is able to compile by running the following:
1cd build/smithy/source/typescript-client-codegen 2# Yarn is used in this example, but equivalent commands using other package managers can be used, e.g. npm and pnpm 3yarn 4yarn build
Note that running the NPM scripts to verify the generated TypeScript client is NOT part of the code generation process, and needs to be explicitly executed after the client is generated.
Using Smithy TypeScript with Gradle
Using the Smithy CLI, a new Gradle project can be created using the quickstart-gradle
template. In this example, the project will be called smithy-typescript-example-client-gradle
.
1smithy init -t quickstart-gradle -o smithy-typescript-example-client-gradle 2cd smithy-typescript-example-client-gradle/
This will create a project with the following directory structure:
1smithy-typescript-example-client-gradle/ 2├── README.md 3├── build.gradle.kts 4├── gradle 5│ └── wrapper 6│ ├── gradle-wrapper.jar 7│ └── gradle-wrapper.properties 8├── gradle.properties 9├── gradlew 10├── gradlew.bat 11├── models 12│ └── weather.smithy 13├── settings.gradle.kts 14└── smithy-build.json
To add a minimal typescript-client-codegen
plugin, add the following to smithy-build.json
:
1// smithy-build.json 2{ 3 "version": "1.0", 4 "sources": ["models"], 5 "plugins": { 6 // Add the Smithy TypeScript client plugin 7 "typescript-client-codegen": { 8 // Minimal configuration: add package name and version 9 "package": "@smithy/typescript-example-client", 10 "packageVersion": "0.0.1" 11 } 12 } 13}
Note: Maven dependencies cannot be configured in
smithy-build.json
for Gradle projects.
Then, add the smithy-typescript-codegen
dependency in build.gradle.kts
:
1plugins { 2 id("java-library") 3 id("software.amazon.smithy.gradle.smithy-jar").version("0.10.1") 4} 5 6repositories { 7 mavenLocal() 8 mavenCentral() 9} 10 11dependencies { 12 val smithyVersion: String by project 13 14 smithyCli("software.amazon.smithy:smithy-cli:$smithyVersion") 15 16 // Add the Smithy TypeScript code generator dependency 17 implementation("software.amazon.smithy.typescript:smithy-typescript-codegen:0.25.0") 18 19 // Uncomment below to add various smithy dependencies (see full list of smithy dependencies in https://github.com/awslabs/smithy) 20 // implementation("software.amazon.smithy:smithy-model:$smithyVersion") 21 // implementation("software.amazon.smithy:smithy-linters:$smithyVersion") 22}
After smithy-build.json
and build.gradle.kts
have been configured, run ./gradlew clean build
. This will code generate the TypeScript client under the source
projection, found in the build/smithyprojections/quickstart-gradle/source/typescript-client-codegen
directory.
Verify the client is able to compile by running the following:
1cd build/smithyprojections/quickstart-gradle/source/typescript-client-codegen 2# Yarn is used in this example, but equivalent commands using other package managers can be used, e.g. npm and pnpm 3yarn 4yarn build
Note that running the NPM scripts to verify the generated TypeScript client is NOT part of the code generation process, and needs to be explicitly executed after the client is generated.
For another example of a Gradle project using Smithy Typescript, the smithy-typescript-codegen-test
package can be referenced as it builds different TypeScript artifacts through projections.
See the Smithy documentation for more information on build Smithy projects with Gradle.
Note: the Smithy Gradle Plugin is under heavy development and is subject to breaking changes.
TypeScript code generation
By default, the Smithy TypeScript code generators provide the code generation framework to generate TypeScript artifacts (e.g. types, interfaces, implementations) of specified Smithy models. However there are implementations for code generation and TypeScript that either need to be implemented or consumed from third-party packages:
- Protocols: Protocols define how operation shapes (for clients and servers, these are usually inputs and outputs) are serialized and deserialized on the wire. This behavior can be defined in Smithy through protocol traits with corresponding implementations of the
ProtocolGenerator
interface. For example, AWS SDK for JavaScript v3, a customer of Smithy TypeScript, implements the AWS protocols in thesoftware.amazon.smithy.typescript:smithy-aws-typescript-codegen
package. See the section on protocol generator implementations for more details. - Publishing: There is no idiomatic utility to publish generated artifacts since package distribution can vary depending on different technical requirements. For example, AWS SDK for JavaScript v3, a customer of Smithy TypeScript, has custom tooling to manage versioning, change logs, and publishing in a monorepo. See the section on publishing client packages for more details.
- Endpoint resolution (clients): Endpoint resolution is not implemented by default due to a variety of different implementations. In most cases, providing a default provider in the runtime config for the client config
endpoint
property should suffice. More complex use cases include the@smithy.rules#endpointRuleSet
trait which provides a complete DSL for endpoint resolution. See the section on handling endpoint resolution for more details. - Operation handler implementations (servers): The server code generator provides the scaffolding for operations. The operation handlers defining the business logic of the Smithy service need to be implemented manually.
Client SDK code generation: typescript-client-codegen
plugin
typescript-client-codegen
plugin configuration
Note: Although plugin configuration is maintained with backward compatibility in mind, breaking changes may still occur.
TypeScriptSettings
contains all of the settings enabled from smithy-build.json
and helper methods and types. The up-to-date list of top-level properties enabled for typescript-client-codegen
can be found in TypeScriptSettings.ArtifactType.CLIENT
.
Setting | Required | Description |
---|---|---|
package | Yes | Name of the package in package.json . |
packageVersion | Yes | Version of the package in package.json . |
packageDescription | No | Description of the package in package.json . The default value is ${package} client |
packageJson | No | Custom package.json properties that will be merged with the base package.json . The default value is an empty object. |
packageManager | No | Configured package manager for the package. The default value is yarn . |
service | No | The Shape ID of the service to generate a client for. If not provided, the code generator will attempt to infer the service Shape ID. If there is exactly 1 service found in the model, then the service is used as the inferred Shape ID. If no services are found, then code generation fails. If more than 1 service is found, then code generation fails. |
protocol | No | The Shape ID of the protocol used to generate serialization and deserialization. If not provided, the code generator will attempt to resolve the highest priority service protocol supported in code generation (registered through TypeScriptIntegration ). If no protocols are found, code generation will use serialization and deserialization error stubs. |
private | No | Whether the package is private in package.json . The default value is false . |
requiredMemberMode | No | NOT RECOMMENDED DUE TO BACKWARD COMPATIBILITY CONCERNS. Sets whether members marked with the @required trait are allowed to be undefined . See more details on the risks in TypeScriptSettings.RequiredMemberMode . The default value is nullable . |
createDefaultReadme | No | Whether to generate a default README.md for the package. The default value is false . |
useLegacyAuth | No | NOT RECOMMENDED, AVAILABLE ONLY FOR BACKWARD COMPATIBILITY CONCERNS. Flag that enables using legacy auth. When in doubt, use the default identity and auth behavior (not configuring useLegacyAuth ) as the golden path. |
serviceProtocolPriority | No | Map of service ShapeId strings to lists of protocol ShapeId strings. Used to override protocol selection behavior. |
defaultProtocolPriority | No | List of protocol ShapeId strings. Lower precedence than serviceProtocolPriority but applies to all services. |
typescript-client-codegen
plugin artifacts
Smithy TypeScript clients are extensible (see the AWS blog post on the middleware stack), robust, and support multiple JavaScript platforms. The main components of a client are the following ($SERVICE
is the name of a Smithy service, $OPERATION
is the name of a Smithy operation, $N
is a number starting from 0):
- Client classes: A standalone tree-shakeable client defined in
src/$SERVICEClient.ts
and an aggregated client defined insrc/$SERVICE.ts
. The client classes are the entry point to calling a service, defining the input configuration of the service and adding any service-level middleware.1import { 2 $SERVICEClient, 3 $SERVICE 4} from "..."; // example client package 5 6const individualClient = new $SERVICEClient({ 7 // Input configuration with type hints 8}); 9 10const aggregatedClient = new $SERVICE({ 11 // Input configuration with type hints 12});
- Command classes: Individual commands defined in
src/commands/$OPERATIONCommand.ts
. These classes include operation-level middleware and additional values to the client resolved configuration through the middleware context.1import { 2 $SERVICEClient, 3 $OPERATIONCommand, 4 $OPERATIONCommandOutput 5} from "..."; // example client package 6 7const individualClient = new $SERVICEClient({ 8 // Input configuration with type hints 9}); 10 11const response: Promise<$OPERATIONCommandOutput> = individualClient.send(new $OPERATIONCommand({ 12 // Operation input with type hints 13 // Operations can also be called callback style or with HandlerOptions 14}));
- Models: Types and interfaces exported from
models/index.ts
, found individually inmodels/model_$N.ts
, and errors including a base$SERVICEServicexception.ts
.1import { 2 $SERVICEClient, 3 $SERVICEServiceException, 4 $OPERATIONCommand, 5 $OPERATIONCommandOutput 6} from "..."; // example client package 7 8const individualClient = new $SERVICEClient({ 9 // Input configuration with type hints 10}); 11 12try { 13 // $OPERATIONCommandOutput generated from the Smithy model 14 const response: $OPERATIONCommandOutput = await individualClient.send(new $OPERATIONCommand({})); 15} catch (error) { 16 // If more errors are defined in the Smithy model, then more extensive checks can be made 17 if (error instanceof $SERVICEServiceException) { 18 console.error("Oh no, a service exception was thrown!"); 19 } 20 throw error; 21}
- Runtime Configurations: Populated default values for a client input configuration for different platforms, currently supporting Node.js, Browser, and React-Native. All of these have a shared runtime configuration that is overwritten with more specific platform values. Not every client input configuration needs a default value, but it is best practice to provide a reasonable default. For example, the
extensions
property defaults to an empty array when no runtime extensions are specified.1Least-specific 2 3┌──────────────────────────────────────────────────────────┐ 4│ Shared Runtime Configuration (`runtimeConfig.shared.ts`) │ 5└──────────────────────────────────────────────────────────┘ 6 │ │ 7┌──────────────────────────────┐ ┌─────────────────────────────────────-┐ 8│ Node.js (`runtimeConfig.ts`) │ │ Browser (`runtimeConfig.browser.ts`) │ 9└──────────────────────────────┘ └──────────────────────────────────────┘ 10 │ 11 ┌─────────────────────────────────────────-┐ 12 │ React-Native (`runtimeConfig.native.ts`) │ 13 └──────────────────────────────────────────┘ 14 15Most-specific (overrides values from parent)
- Runtime Extensions: Interfaces to implement extensions enabling alternative default values to the runtime configuration. See the section on customizing TypeScript Client Configuration for more details.
- Package Configuration files:
package.json
and TypeScript configuration files for different platforms.
Other directories could include code generated paginators, waiters, endpoint resolvers, etc., but are usually generated only when traits are present. If code-generating custom files for the SDK client, it is recommended to use a separate directory for separation of concerns.
Here is the directory structure of the generated artifacts from the example client in the getting started section.
build/smithy/source/typescript-client-codegen/
├── package.json
├── src
│ ├── Weather.ts
│ ├── WeatherClient.ts
│ ├── commands
│ ├── extensionConfiguration.ts
│ ├── index.ts
│ ├── models
│ ├── pagination
│ ├── runtimeConfig.browser.ts
│ ├── runtimeConfig.native.ts
│ ├── runtimeConfig.shared.ts
│ ├── runtimeConfig.ts
│ └── runtimeExtensions.ts
├── tsconfig.cjs.json
├── tsconfig.es.json
├── tsconfig.json
├── tsconfig.types.json
└── typedoc.json
Code generation implementations not included
Smithy TypeScript provides default code generation implementations for generating TypeScript clients, but also requires customers to either implement or consume certain implementations where there is no default.
For Smithy TypeScript clients, the main implementations not provided are protocol generators and handling endpoint resolution (see the TypeScript code generation section).
If there are items missing from this section, feel free to create an issue.
Protocol generator implementations
Protocols define how operation inputs and outputs are serialized and deserialized on the wire. This behavior can be defined in Smithy through protocol traits with corresponding implementations of the ProtocolGenerator
interface in Smithy TypeScript. Besides the ProtocolGenerator
interface, Smithy TypeScript has additional abstract classes that partially implement the ProtocolGenerator
interface and can be extended: HttpBindingProtocolGenerator
for HTTP binding protocols and HttpRpcProtocolGenerator
for HTTP RPC protocols.
Once a ProtocolGenerator
is implemented, the implementation can be registered through a TypeScriptIntegration
:
TypeScriptIntegration
withProtocolGenerator
implementation:1// src/main/java/typescript/example/client/gradle/ExampleClientProtocolGeneratorIntegration.java 2package typescript.example.client.gradle; 3 4// ... 5 6public class ExampleClientProtocolGeneratorIntegration implements TypeScriptIntegration { 7 // ProtocolGenerator implementation is inline for brevity, but should be in its 8 // own file 9 private static class ExampleClientProtocolGenerator implements ProtocolGenerator { 10 // Protocol generator for a @example.client#protocol protocol trait 11 @Override 12 public ShapeId getProtocol() { 13 return ShapeId.from("example.client#protocol"); 14 } 15 // Implement ProtocolGenerator methods ... 16 } 17 18 @Override 19 public List<ProtocolGenerator> getProtocolGenerators() { 20 return List.of(new ExampleClientProtocolGenerator()); 21 } 22}
- Registering the
TypeScriptIntegration
:1// src/main/resources/META-INF/services/software.amazon.smithy.typescript.codegen.integration.TypeScriptIntegration 2typescript.example.client.gradle.ExampleClientProtocolGeneratorIntegration
See the section on customizations via TypeScriptIntegration
for more details.
Note: AWS SDK for JavaScript v3, a customer of Smithy TypeScript, implements the AWS protocols and can be consumed by adding the
software.amazon.smithy.typescript:smithy-aws-typescript-codegen
package.
Handling endpoint resolution
Endpoint resolution is not implemented by default due to the inherent complexity. By default, if no endpoint resolution is provided, customers will not be able to pass in an endpoint to the client (TypeScript will fail to compile).
Smithy TypeScript has the CustomEndpoints
configuration which can be used to add the endpoint
property to the client configuration, and the TypeScriptIntegration::getRuntimeConfigWriters()
method can be used to provide a default endpoint:
TypeScriptIntegration
implementation:1// src/main/java/typescript/example/client/gradle/ExampleClientEndpointResolutionIntegration.java 2package typescript.example.client.gradle; 3 4// ... 5 6public class ExampleClientEndpointResolutionIntegration implements TypeScriptIntegration { 7 @Override 8 public List<RuntimeClientPlugin> getClientPlugins() { 9 return List.of( 10 RuntimeClientPlugin.builder() 11 .withConventions( 12 TypeScriptDependency.CONFIG_RESOLVER.dependency, 13 "CustomEndpoints", 14 Convention.HAS_CONFIG) 15 .build()); 16 } 17 18 @Override 19 public Map<String, Consumer<TypeScriptWriter>> getRuntimeConfigWriters( 20 TypeScriptSettings settings, 21 Model model, 22 SymbolProvider symbolProvider, 23 LanguageTarget target 24 ) { 25 // Runtime config value also be specified per platform by using the `target` 26 // argument, e.g. 27 // if (target.equals(LanguageTarget.NODE)) { ... } 28 if (target.equals(LanguageTarget.SHARED)) { 29 // This example provides an arbitrary endpoint on the shared runtime config 30 return Map.of("endpoint", w -> w.write("$S", "https://www.example.com")); 31 } 32 // No need to redefine endpoint for other targets since it's inherited from the 33 // shared target 34 return Collections.emptyMap(); 35 } 36}
- Registering the
TypeScriptIntegration
:1// src/main/resources/META-INF/services/software.amazon.smithy.typescript.codegen.integration.TypeScriptIntegration 2typescript.example.client.gradle.ExampleClientEndpointResolutionIntegration
Customers can then pass in an endpoint to the client configuration:
1import { 2 $SERVICEClient, 3} from "..."; // example client package 4 5// Without providing the endpoint, a "No valid endpoint provider available." error will be thrown 6const individualClient = new $SERVICEClient({ 7 // string 8 endpoint: "https://www.example.com", 9});
See the section on customizations via TypeScriptIntegration
for more details.
Publishing a Client SDK package
Note: There is no prescribed way to publish NPM packages since there are many ways to maintain SDKs. Some publishing tools include using
npm publish
oryarn publish
directly, or managing a monorepo with tools liketurbo
. This section provides tips for how a general publishing workflow could work.
A generated client is a package that is ready to be published. After running smithy build
, the generated client artifacts will be in the build directory under the projection and plugin name. For example, generated client artifacts for the source projection using the typescript-client-codegen
plugin in a Smithy CLI project would be in the build/smithy/source/typescript-client-codegen/
directory. A common practice is to copy the generated client artifacts into a source control repository. After the artifacts are staged, any modifications that are needed prior to publishing the generated client artifacts specific to the SDK should be run, e.g. adding a README.md
, editing changelog entries. Finally, with a chosen publishing tool for the SDK, publish the artifacts after running the prepack
script per client package.
Server SDK code generation: typescript-server-codegen
plugin
For documentation of typescript-server-codegen
artifacts and implementation, see the Smithy TypeScript Server SDK walkthrough and Developer Preview announcement blog post.
typescript-server-codegen
plugin configuration
Note: Although plugin configuration is maintained with backward compatibility in mind, breaking changes may still occur.
TypeScriptSettings
contains all of the settings enabled from smithy-build.json
and helper methods and types. The up-to-date list of top-level properties enabled for typescript-server-codegen
can be found in TypeScriptSettings.ArtifactType.SSDK
.
Setting | Required | Description |
---|---|---|
package | Yes | Name of the package in package.json . |
packageVersion | Yes | Version of the package in package.json . |
packageDescription | No | Description of the package in package.json . The default value is ${package} server . |
packageJson | No | Custom package.json properties that will be merged with the base package.json . The default value is an empty object. |
packageManager | No | Configured package manager for the package. The default value is yarn . |
service | No | The Shape ID of the service to generate a client for. If not provided, the code generator will attempt to infer the service Shape ID. If there is exactly 1 service found in the model, then the service is used as the inferred Shape ID. If no services are found, then code generation fails. If more than 1 service is found, then code generation fails. |
protocol | No | The Shape ID of the protocol used to generate serialization and deserialization. If not provided, the code generator will attempt to resolve the highest priority service protocol supported in code generation (registered through TypeScriptIntegration ). If no protocols are found, code generation will use serialization and deserialization error stubs. |
private | No | Whether the package is private in package.json . The default value is false . |
requiredMemberMode | No | NOT RECOMMENDED DUE TO BACKWARD COMPATIBILITY CONCERNS. Sets whether members marked with the @required trait are allowed to be undefined . See more details on the risks in TypeScriptSettings.RequiredMemberMode . The default value is nullable . |
createDefaultReadme | No | Whether to generate a default README.md for the package. The default value is false . |
disableDefaultValidation | No | Whether or not default validation is disabled. See the documentation for Smithy TypeScript SSDK validation to learn more. The default value is false . |
Adding customizations to Smithy TypeScript
Using third-party packages
Third-party packages may provide implementations and integrations for code generation, and can be consumed like any other Java dependency. For example, AWS SDK for JavaScript v3 implements AWS customizations, protocols, and other utilities used for code generating the SDK, and can be consumed by importing the software.amazon.smithy.typescript:smithy-aws-typescript-codegen
package.
In an idiomatic Smithy CLI project, the dependency can be added similar to how the core smithy-typescript-codegen
dependency is added in the section using Smithy TypeScript with the Smithy CLI.
In a Gradle project, the dependency can be added similar to how the core smithy-typescript-codegen
dependency is added in the section using Smithy TypeScript with Gradle.
If a third-party package does not publish artifacts to an external code repository (e.g. Maven), the code may need to be built from source and published to the build environment's Maven Local Repository, typically through a command similar to ./gradlew publishToMavenLocal
.
Note: Currently there is no utility to remove or disable integrations that are loaded. If a third-party package's integration has behavior that is not expected (e.g. customizing without reacting to the model, settings, or feature flags), it may be an sign that the underlying implementation does not follow best practices.
Customizations via TypeScriptIntegration
Smithy TypeScript code generation can be customized by implementing the TypeScriptIntegration
interface, which also extends the SmithyIntegration
interface. These integrations are typically implemented and packaged in Java Gradle projects that depend on smithy-typescript-codegen
(for the TypeScriptIntegration
interface) and built as consumable Java libraries.
Each TypeScriptIntegration
implementation consists of two paired changes:
-
An implementation of
TypeScriptIntegration
, and1// src/main/java/example/smithy/typescript/integration/ExampleSmithyTypeScriptIntegration.java 2 3package example.smithy.typescript.integration; 4 5// Import the TypeScriptIntegration interface 6import software.amazon.smithy.typescript.codegen.integration.TypeScriptIntegration; 7 8public final class ExampleSmithyTypeScriptIntegration implements TypeScriptIntegration { 9 // Implement TypeScriptIntegration or SmithyIntegration methods, e.g. SmithyIntegration::customize 10}
-
A corresponding entry in the service loader for
TypeScriptIntegration
1// src/main/resources/META-INF/services/software.amazon.smithy.typescript.codegen.integration.TypeScriptIntegration 2// Note that entry is the canonical name of the implemented TypeScriptIntegration 3// To add more integrations, add an entry per line 4 5example.smithy.typescript.integration.ExampleSmithyTypeScriptIntegration
Once the Java libary is built, the library can be consumed as a third-party package, and the integrations will automatically be loaded via Java SPI.
The easiest way to see how the individual methods on TypeScriptIntegration
(and by extension SmithyIntegration
) are used in the code generation process is by searching by usage at a given Smithy TypeScript version, as method usages are subject to change.
Note: if an existing integration point does not exist on
TypeScriptIntegration
orSmithyIntegration
, check if theRuntimeClientPlugin
abstraction has an integration point. If not, create a feature request with the incompatible use case.
Note: Although the
TypeScriptIntegration
interface is maintained with backward compatibility in mind, the interface may be subject to breaking changes as it is annotated with@SmithyUnstableApi
. Methods may also have additional individual annotations that should be noted (e.g.@SmithyInternalApi
).
An example of a Java Gradle project that provides customizations can be found in smithy-typescript-codegen-test/example-weather-customizations
.
TypeScript client configuration
During code generation, code generators should provide a default value for each client's input configuration property through a client's runtime configuration. If there are use cases in which configuration may need a specific set of values (e.g. specific features like using HTTP/2), writing a RuntimeExtension
that has those specific configuration property values may make sense.
For example, a team that publishes a client for the Weather
service in a package named @example/weather
may write and publish a RuntimeExtension
that provides the configuration values needed to use HTTP/2 with the service:
1// Http2HandlerRuntimeExtension.ts published in package @example/weather-http-2-runtime-extension 2 3import { RuntimeExtension, WeatherExtensionConfiguration } from "@example/weather"; 4import { NodeHttp2Handler } from "@smithy/node-http-handler"; 5 6export class Http2HandlerRuntimeExtension implements RuntimeExtension { 7 configure(extensionConfiguration: WeatherExtensionConfiguration): void { 8 console.log("Enabling HTTP/2"); 9 extensionConfiguration.setHttpHandler(new NodeHttp2Handler()); 10 } 11}
Then customers can opt-in to using the extension at runtime using the extensions
configuration property:
1import { WeatherClient } from "@example/weather"; 2import { Http2HandlerRuntimeExtension } from "@example/weather-http-2-runtime-extension"; 3 4const client = new WeatherClient({ 5 extensions: [new Http2HandlerRuntimeExtension()], 6});
For more documentation, see the typescript-client-codegen
section.
Local Development
This repository is in developer preview, so local changes may be needed to both build and test the code generators.
See the contributing guide for more details.
Using local code generation changes
Smithy TypeScript code generators depend on Smithy and the Smithy Gradle Plugin, and will by default use the version specified in gradle.properties
. Any changes to dependencies require recursively republishing dependent packages.
1Dependents of Smithy TypeScript 2└──Smithy TypeScript 3 ├── Smithy 4 └── Smithy Gradle Plugin
For simplicity, only Smithy and Smithy TypeScript instructions are documented.
Note: the Smithy Gradle Plugin is under heavy development, so it may be difficult to test different versions.
Smithy
If using local Smithy changes, build software.amazon.smithy.*
packages and publish the packages to a Maven Local Repository:
1git clone https://github.com/smithy-lang/smithy.git 2cd smithy 3# Make intended changes, e.g. checking out a certain commit 4./gradlew publishToMavenLocal
Then, update the gradle.properties
property smithyVersion
in the Smithy TypeScript repository locally to the artifacts' version if different than the current smithyVersion
.
Smithy TypeScript
If using local Smithy TypeScript changes, build the software.amazon.smithy.typescript.*
packages and publish them to a Maven Local Repository:
1git clone https://github.com/awslabs/smithy-typescript.git 2cd smithy-typescript 3# Make intended changes, e.g. bumping the codegen artifact version 4./gradlew publishToMavenLocal
Then, update the dependent package code to depend on the published version if different than the current version.
TypeScript packages changes
All TypeScript packages are included in a Yarn workspace at the root of the repository:
- Smithy Client SDK packages are in the
packages/
directory, and - Smithy Server SDK packages are in the
smithy-typescript-ssdk-libs/
directory.
At the root of the repository, scripts defined in the root package.json
are managed by Turbo. Commonly used commands during development include:
yarn build
: build all of the packages in the repositoryyarn test
: run the unit tests of all of the packages in the repositoryyarn test:integration
: build test clients insmithy-typescript-codegen-test
via thebuild-generated-test-packages.js
script, and then run the integration tests of all of the packages in the repository
Each individual package will have at least the build
script, and may have the test
and test:integration
scripts.
For Smithy Client SDK packages, changelogs and versioning are managed by changesets
. When making changes to these package, a changeset file will need to be added via yarn changeset add
with an appropriate changelog message and version bump. See the contribution guide for more details.
Testing
For both code generation and TypeScript package changes, unit tests and integration tests needs to pass.
- To run tests for TypeScript packages, run the following at the root level:
yarn test
. - To run tests for code generation, run the following at the root level:
./gradlew clean build check
. - To run integration tests that test both code generation and TypeScript packages using the test clients in
smithy-typescript-codegen-test
, run the following at the root level:yarn test:integration
.
All of these checks will also run in GitHub actions when submitting a pull request or merging to main
.
Updating smithy-typescript-codegen-test
models
The smithy-typescript-codegen-test
contains test models that test whether TypeScript packages compile correctly and code generated.
These models can be edited to test additional traits, integrations, and settings, but new projections and smithy models can also be added to test changes in isolation.
To use a generated artifact in an integration test, update the build-generated-test-packages.js
file to build and copy the generated artifacts to node_modules/
. Then, import the package like any other dependency in *.integ.spec.ts
test files.
Troubleshooting
Many Gradle issues can be fixed by stopping the Gradle daemon by running ./gradlew --stop
.
License
This library is licensed under the Apache 2.0 License.
No vulnerabilities found.
Reason
30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Reason
no dangerous workflow patterns detected
Reason
license file detected
Details
- Info: project has a license file: LICENSE:0
- Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0
Reason
security policy file detected
Details
- Info: security policy file detected: github.com/smithy-lang/.github/SECURITY.md:1
- Info: Found linked content: github.com/smithy-lang/.github/SECURITY.md:1
- Info: Found disclosure, vulnerability, and/or timelines in security policy: github.com/smithy-lang/.github/SECURITY.md:1
- Info: Found text in security policy: github.com/smithy-lang/.github/SECURITY.md:1
Reason
binaries present in source code
Details
- Warn: binary detected: gradle/wrapper/gradle-wrapper.jar:1
Reason
Found 23/30 approved changesets -- score normalized to 7
Reason
8 existing vulnerabilities detected
Details
- Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275
- Warn: Project is vulnerable to: GHSA-96g7-g7g9-jxw8
- Warn: Project is vulnerable to: GHSA-2p57-rm9w-gvfp
- Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv
- Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw
- Warn: Project is vulnerable to: MAL-2022-6180
- Warn: Project is vulnerable to: GHSA-4vvj-4cpr-p986
- Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
detected GitHub workflow tokens with excessive permissions
Details
- Warn: jobLevel 'contents' permission set to 'write': .github/workflows/release-npm-packages.yml:12
- Warn: jobLevel 'contents' permission set to 'write': .github/workflows/release-npm-ssdk-libs.yml:12
- Warn: no topLevel permission defined: .github/workflows/ci.yml:1
- Warn: no topLevel permission defined: .github/workflows/git-sync.yml:1
- Warn: no topLevel permission defined: .github/workflows/release-npm-packages.yml:1
- Warn: no topLevel permission defined: .github/workflows/release-npm-ssdk-libs.yml:1
- Warn: no topLevel permission defined: .github/workflows/update-smithy-gradle-plugin.yml:1
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/ci.yml/main?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/ci.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/ci.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:40: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/ci.yml/main?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:41: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/ci.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:42: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/ci.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:48: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/ci.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:66: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/ci.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:67: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/ci.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:86: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/ci.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:87: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/ci.yml/main?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:91: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/ci.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:93: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/ci.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:112: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/ci.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:113: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/ci.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:132: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/ci.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:137: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/ci.yml/main?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/git-sync.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/git-sync.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release-npm-packages.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/release-npm-packages.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release-npm-packages.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/release-npm-packages.yml/main?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/release-npm-packages.yml:30: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/release-npm-packages.yml/main?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/release-npm-packages.yml:61: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/release-npm-packages.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release-npm-ssdk-libs.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/release-npm-ssdk-libs.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release-npm-ssdk-libs.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/release-npm-ssdk-libs.yml/main?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/release-npm-ssdk-libs.yml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/release-npm-ssdk-libs.yml/main?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/release-npm-ssdk-libs.yml:44: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/release-npm-ssdk-libs.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/update-smithy-gradle-plugin.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/smithy-lang/smithy-typescript/update-smithy-gradle-plugin.yml/main?enable=pin
- Info: 0 out of 19 GitHub-owned GitHubAction dependencies pinned
- Info: 0 out of 8 third-party GitHubAction dependencies pinned
Reason
project is not fuzzed
Details
- Warn: no fuzzer integrations found
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
- Warn: 0 commits out of 23 are checked with a SAST tool
Score
5.3
/10
Last Scanned on 2024-11-25
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More