Skip to content

Commit

Permalink
(fix, ts): Support OAuth for SDKs that set neverThrowErrors (#3729)
Browse files Browse the repository at this point in the history
  • Loading branch information
amckinney authored May 29, 2024
1 parent 82d15a0 commit 8071e87
Show file tree
Hide file tree
Showing 625 changed files with 42,928 additions and 20 deletions.
24 changes: 19 additions & 5 deletions generators/typescript/sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,34 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.20.1] - 2024-05-20
## [0.20.2] - 2024-05-29

- Fix: Remove instances of `node:stream` so that the generated SDK is Webpack + Next.js compatible.
- Fix: The OAuth token provider supports SDKs that enable the `neverThrowErrors` setting.
If the OAuth token provider fails to retrieve and/or refresh an access token, an error
will _not_ be thrown. Instead, the original access token will be used and the user will be
able to act upon an error available on the response. For example,

## [0.20.1-rc0] - 2024-05-20
```ts
const response = await client.user.get(...)
if (!response.ok) {
// Handle the response.error ...
}
```

## [0.20.1] - 2024-05-29

- Fix: Remove instances of `node:stream` so that the generated SDK is Webpack + Next.js compatible.

## [0.20.1-rc0] - 2024-05-29

- (Pre-emptive) Fix: URL encoded bodies are now appropriately encoded within the fetcher.

## [0.20.0-rc1] - 2024-05-20
## [0.20.0-rc1] - 2024-05-24

- Fix: Pass `abortSignal` to `Stream` for server-sent-events and JSON streams so that the user
can opt out and break from a stream.

## [0.20.0-rc0] - 2024-05-20
## [0.20.0-rc0] - 2024-05-24

- Feature: Add `abortSignal` to `RequestOptions`. SDK consumers can now specify an
an arbitrary abort signal that can interrupt the API call.
Expand Down
2 changes: 1 addition & 1 deletion generators/typescript/sdk/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.20.1
0.20.2
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,19 @@ export class OAuthTokenProviderGenerator {
public static OAUTH_CLIENT_SECRET_PROPERTY_NAME = "clientSecret";
public static OAUTH_AUTH_CLIENT_PROPERTY_NAME = "authClient";

constructor(private ir: IntermediateRepresentation) {}
private ir: IntermediateRepresentation;
private neverThrowErrors: boolean;

constructor({
intermediateRepresentation,
neverThrowErrors
}: {
intermediateRepresentation: IntermediateRepresentation;
neverThrowErrors: boolean;
}) {
this.ir = intermediateRepresentation;
this.neverThrowErrors = neverThrowErrors;
}

public getExportedFilePath(): ExportedFilePath {
return {
Expand Down Expand Up @@ -236,6 +248,7 @@ export class OAuthTokenProviderGenerator {
const accessTokenProperty = this.responsePropertyToDotDelimitedAccessor({
responseProperty: responseProperties.accessToken
});
const handleNeverThrowErrors = this.getNeverThrowErrorsHandler();
if (responseProperties.expiresIn != null) {
const expiresInProperty = this.responsePropertyToDotDelimitedAccessor({
responseProperty: responseProperties.expiresIn
Expand All @@ -246,6 +259,7 @@ export class OAuthTokenProviderGenerator {
${clientIdProperty}: await core.Supplier.get(this._clientId),
${clientSecretProperty}: await core.Supplier.get(this._clientSecret),
});
${handleNeverThrowErrors}
this._accessToken = tokenResponse.${accessTokenProperty};
this._expiresAt = this.getExpiresAt(tokenResponse.${expiresInProperty}, this.BUFFER_IN_MINUTES);
return this._accessToken;
Expand All @@ -258,12 +272,21 @@ export class OAuthTokenProviderGenerator {
${clientIdProperty}: await core.Supplier.get(this._clientId),
${clientSecretProperty}: await core.Supplier.get(this._clientSecret),
});
${handleNeverThrowErrors}
this._accessToken = tokenResponse.${accessTokenProperty};
return this._accessToken;
}
`;
}

private getNeverThrowErrorsHandler(): Code {
return this.neverThrowErrors
? code`if (!tokenResponse.ok) {
return this._accessToken ?? "";
}`
: code``;
}

private getExpiresAtMethod({
responseProperties
}: {
Expand All @@ -285,11 +308,13 @@ export class OAuthTokenProviderGenerator {
}: {
responseProperty: ResponseProperty;
}): string {
const prefix = this.neverThrowErrors ? "body." : "";
const propertyPath = responseProperty.propertyPath;
if (propertyPath == null || propertyPath.length === 0) {
return responseProperty.property.name.name.camelCase.unsafeName;
return prefix + responseProperty.property.name.name.camelCase.unsafeName;
}
return (
prefix +
propertyPath.map((name) => name.camelCase.unsafeName).join(".") +
"." +
responseProperty.property.name.name.camelCase.unsafeName
Expand Down
5 changes: 4 additions & 1 deletion generators/typescript/sdk/generator/src/SdkGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,10 @@ export class SdkGenerator {
});
this.requestWrapperGenerator = new RequestWrapperGenerator();
this.environmentsGenerator = new EnvironmentsGenerator();
this.oauthTokenProviderGenerator = new OAuthTokenProviderGenerator(intermediateRepresentation);
this.oauthTokenProviderGenerator = new OAuthTokenProviderGenerator({
intermediateRepresentation,
neverThrowErrors: this.config.neverThrowErrors
});
this.sdkClientClassGenerator = new SdkClientClassGenerator({
intermediateRepresentation,
errorResolver: this.errorResolver,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { FernFileContext } from "../FernFileContext";
import { IdGenerator } from "../IdGenerator";
import { EndpointResolver } from "../resolvers/EndpointResolver";
import { PropertyResolver } from "../resolvers/PropertyResolver";
import { isRootFernFilepath } from "../utils/isRootFernFilepath";
import { RefreshTokenEndpoint } from "./convertOAuthUtils";

export async function convertOAuthRefreshEndpoint({
Expand All @@ -24,10 +25,9 @@ export async function convertOAuthRefreshEndpoint({
endpointReference: {
endpointId: IdGenerator.generateEndpointIdFromResolvedEndpoint(resolvedEndpoint),
serviceId: IdGenerator.generateServiceIdFromFernFilepath(resolvedEndpoint.file.fernFilepath),
subpackageId:
resolvedEndpoint.file.fernFilepath.file != null
? IdGenerator.generateSubpackageId(resolvedEndpoint.file.fernFilepath)
: undefined
subpackageId: !isRootFernFilepath({ fernFilePath: resolvedEndpoint.file.fernFilepath })
? IdGenerator.generateSubpackageId(resolvedEndpoint.file.fernFilepath)
: undefined
},
requestProperties: {
refreshToken: await propertyResolver.resolveRequestPropertyOrThrow({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { FernFileContext } from "../FernFileContext";
import { IdGenerator } from "../IdGenerator";
import { EndpointResolver } from "../resolvers/EndpointResolver";
import { PropertyResolver } from "../resolvers/PropertyResolver";
import { isRootFernFilepath } from "../utils/isRootFernFilepath";
import { TokenEndpoint } from "./convertOAuthUtils";

export async function convertOAuthTokenEndpoint({
Expand All @@ -24,10 +25,9 @@ export async function convertOAuthTokenEndpoint({
endpointReference: {
endpointId: IdGenerator.generateEndpointIdFromResolvedEndpoint(resolvedEndpoint),
serviceId: IdGenerator.generateServiceIdFromFernFilepath(resolvedEndpoint.file.fernFilepath),
subpackageId:
resolvedEndpoint.file.fernFilepath.file != null
? IdGenerator.generateSubpackageId(resolvedEndpoint.file.fernFilepath)
: undefined
subpackageId: !isRootFernFilepath({ fernFilePath: resolvedEndpoint.file.fernFilepath })
? IdGenerator.generateSubpackageId(resolvedEndpoint.file.fernFilepath)
: undefined
},
requestProperties: {
clientId: await propertyResolver.resolveRequestPropertyOrThrow({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { FernFilepath } from "@fern-api/ir-sdk";

export function isRootFernFilepath({ fernFilePath }: { fernFilePath: FernFilepath }): boolean {
return fernFilePath.packagePath.length === 0 && fernFilePath.file == null;
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 8071e87

Please sign in to comment.