@sp-api-sdk/auth
Version:
Login with Amazon (LWA) authentication for the Amazon Selling Partner API (SP-API)
362 lines (293 loc) • 12 kB
text/typescript
import { AxiosError } from "axios";
//#region ../../node_modules/.pnpm/type-fest@5.8.0/node_modules/type-fest/source/is-any.d.ts
/**
Returns a boolean for whether the given type is `any`.
@link https://stackoverflow.com/a/49928360/1490091
Useful in type utilities, such as disallowing `any`s to be passed to a function.
@example
```
import type {IsAny} from 'type-fest';
const typedObject = {a: 1, b: 2} as const;
const anyObject: any = {a: 1, b: 2};
function get<O extends (IsAny<O> extends true ? {} : Record<string, number>), K extends keyof O = keyof O>(object: O, key: K) {
return object[key];
}
const typedA = get(typedObject, 'a');
//=> 1
const anyA = get(anyObject, 'a');
//=> any
```
@category Type Guard
@category Utilities
*/
type IsAny<T> = 0 extends 1 & NoInfer<T> ? true : false;
//#endregion
//#region ../../node_modules/.pnpm/type-fest@5.8.0/node_modules/type-fest/source/is-never.d.ts
/**
Returns a boolean for whether the given type is `never`.
@link https://github.com/microsoft/TypeScript/issues/31751#issuecomment-498526919
@link https://stackoverflow.com/a/53984913/10292952
@link https://www.zhenghao.io/posts/ts-never
Useful in type utilities, such as checking if something does not occur.
@example
```
import type {IsNever, And} from 'type-fest';
type A = IsNever<never>;
//=> true
type B = IsNever<any>;
//=> false
type C = IsNever<unknown>;
//=> false
type D = IsNever<never[]>;
//=> false
type E = IsNever<object>;
//=> false
type F = IsNever<string>;
//=> false
```
@example
```
import type {IsNever} from 'type-fest';
type IsTrue<T> = T extends true ? true : false;
// When a distributive conditional is instantiated with `never`, the entire conditional results in `never`.
type A = IsTrue<never>;
//=> never
// If you don't want that behaviour, you can explicitly add an `IsNever` check before the distributive conditional.
type IsTrueFixed<T> =
IsNever<T> extends true ? false : T extends true ? true : false;
type B = IsTrueFixed<never>;
//=> false
```
@category Type Guard
@category Utilities
*/
type IsNever<T> = [T] extends [never] ? true : false;
//#endregion
//#region ../../node_modules/.pnpm/type-fest@5.8.0/node_modules/type-fest/source/if.d.ts
/**
An if-else-like type that resolves depending on whether the given `boolean` type is `true` or `false`.
Use-cases:
- You can use this in combination with `Is*` types to create an if-else-like experience. For example, `If<IsAny<any>, 'is any', 'not any'>`.
Note:
- Returns a union of if branch and else branch if the given type is `boolean` or `any`. For example, `If<boolean, 'Y', 'N'>` will return `'Y' | 'N'`.
- Returns the else branch if the given type is `never`. For example, `If<never, 'Y', 'N'>` will return `'N'`.
@example
```
import type {If} from 'type-fest';
type A = If<true, 'yes', 'no'>;
//=> 'yes'
type B = If<false, 'yes', 'no'>;
//=> 'no'
type C = If<boolean, 'yes', 'no'>;
//=> 'yes' | 'no'
type D = If<any, 'yes', 'no'>;
//=> 'yes' | 'no'
type E = If<never, 'yes', 'no'>;
//=> 'no'
```
@example
```
import type {If, IsAny, IsNever} from 'type-fest';
type A = If<IsAny<unknown>, 'is any', 'not any'>;
//=> 'not any'
type B = If<IsNever<never>, 'is never', 'not never'>;
//=> 'is never'
```
@example
```
import type {If, IsEqual} from 'type-fest';
type IfEqual<T, U, IfBranch, ElseBranch> = If<IsEqual<T, U>, IfBranch, ElseBranch>;
type A = IfEqual<string, string, 'equal', 'not equal'>;
//=> 'equal'
type B = IfEqual<string, number, 'equal', 'not equal'>;
//=> 'not equal'
```
Note: Sometimes using the `If` type can make an implementation non–tail-recursive, which can impact performance. In such cases, it’s better to use a conditional directly. Refer to the following example:
@example
```
import type {If, IsEqual, StringRepeat} from 'type-fest';
type HundredZeroes = StringRepeat<'0', 100>;
// The following implementation is not tail recursive
type Includes<S extends string, Char extends string> =
S extends `${infer First}${infer Rest}`
? If<IsEqual<First, Char>,
'found',
Includes<Rest, Char>>
: 'not found';
// Hence, instantiations with long strings will fail
// @ts-expect-error
type Fails = Includes<HundredZeroes, '1'>;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Error: Type instantiation is excessively deep and possibly infinite.
// However, if we use a simple conditional instead of `If`, the implementation becomes tail-recursive
type IncludesWithoutIf<S extends string, Char extends string> =
S extends `${infer First}${infer Rest}`
? IsEqual<First, Char> extends true
? 'found'
: IncludesWithoutIf<Rest, Char>
: 'not found';
// Now, instantiations with long strings will work
type Works = IncludesWithoutIf<HundredZeroes, '1'>;
//=> 'not found'
```
@category Type Guard
@category Utilities
*/
type If<Type extends boolean, IfBranch, ElseBranch> = IsNever<Type> extends true ? ElseBranch : Type extends true ? IfBranch : ElseBranch;
//#endregion
//#region ../../node_modules/.pnpm/type-fest@5.8.0/node_modules/type-fest/source/internal/type.d.ts
/**
An if-else-like type that resolves depending on whether the given type is `any` or `never`.
@example
```
// When `T` is neither `any` nor `never` (like `string`) => Returns `IfNot` branch
type A = IfNotAnyOrNever<string, {ifNot: 'VALID'; ifAny: 'IS_ANY'; ifNever: 'IS_NEVER'}>;
//=> 'VALID'
// When `T` is `any` => Returns `IfAny` branch
type B = IfNotAnyOrNever<any, {ifNot: 'VALID'; ifAny: 'IS_ANY'; ifNever: 'IS_NEVER'}>;
//=> 'IS_ANY'
// When `T` is `never` => Returns `IfNever` branch
type C = IfNotAnyOrNever<never, {ifNot: 'VALID'; ifAny: 'IS_ANY'; ifNever: 'IS_NEVER'}>;
//=> 'IS_NEVER'
```
Note: Wrapping a tail-recursive type with `IfNotAnyOrNever` makes the implementation non-tail-recursive. To fix this, move the recursion into a helper type. Refer to the following example:
@example
```ts
import type {StringRepeat} from 'type-fest';
type NineHundredNinetyNineSpaces = StringRepeat<' ', 999>;
// The following implementation is not tail recursive
type TrimLeft<S extends string> = IfNotAnyOrNever<S, {ifNot: S extends ` ${infer R}` ? TrimLeft<R> : S}>;
// Hence, instantiations with long strings will fail
// @ts-expect-error
type T1 = TrimLeft<NineHundredNinetyNineSpaces>;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Error: Type instantiation is excessively deep and possibly infinite.
// To fix this, move the recursion into a helper type
type TrimLeftOptimised<S extends string> = IfNotAnyOrNever<S, {ifNot: _TrimLeftOptimised<S>}>;
type _TrimLeftOptimised<S extends string> = S extends ` ${infer R}` ? _TrimLeftOptimised<R> : S;
type T2 = TrimLeftOptimised<NineHundredNinetyNineSpaces>;
//=> ''
```
*/
type IfNotAnyOrNever<T, Cases extends {
ifNot: unknown;
ifAny?: unknown;
ifNever?: unknown;
}> = IsAny<T> extends true ? 'ifAny' extends keyof Cases ? Cases['ifAny'] : any : IsNever<T> extends true ? 'ifNever' extends keyof Cases ? Cases['ifNever'] : never : Cases['ifNot'];
//#endregion
//#region ../../node_modules/.pnpm/type-fest@5.8.0/node_modules/type-fest/source/require-exactly-one.d.ts
/**
Create a type that requires exactly one of the given keys and disallows more, while keeping the remaining keys as is.
Use-cases:
- Creating interfaces for components that only need one of the keys to display properly.
- Declaring generic keys in a single place for a single use-case that gets narrowed down via `RequireExactlyOne`.
The caveat with `RequireExactlyOne` is that TypeScript doesn't always know at compile time every key that will exist at runtime. Therefore `RequireExactlyOne` can't do anything to prevent extra keys it doesn't know about.
@example
```
import type {RequireExactlyOne} from 'type-fest';
type Responder = {
text: () => string;
json: () => string;
secure: boolean;
};
const responder: RequireExactlyOne<Responder, 'text' | 'json'> = {
// Adding a `text` key here would cause a compile error.
json: () => '{"message": "ok"}',
secure: true,
};
```
@category Object
*/
type RequireExactlyOne<ObjectType, KeysType extends keyof ObjectType = keyof ObjectType> = IfNotAnyOrNever<ObjectType, {
ifNot: If<IsNever<KeysType>, never, _RequireExactlyOne<ObjectType, If<IsAny<KeysType>, keyof ObjectType, KeysType>>>;
}>;
type _RequireExactlyOne<ObjectType, KeysType extends keyof ObjectType> = { [Key in KeysType]: (Required<Pick<ObjectType, Key>> & Partial<Record<Exclude<KeysType, Key>, never>>); }[KeysType] & Omit<ObjectType, KeysType>;
//#endregion
//#region src/types/scope.d.ts
/** Authorization scopes for grantless Selling Partner API operations. */
declare enum AuthorizationScope {
/** Scope for the Notifications API. */
NOTIFICATIONS = "sellingpartnerapi::notifications",
/** Scope for rotating application client credentials. */
CLIENT_CREDENTIAL_ROTATION = "sellingpartnerapi::client_credential:rotation"
}
//#endregion
//#region src/types/access-token.d.ts
interface BaseAccessTokenQuery {
client_id: string;
client_secret: string;
}
type RefreshTokenAccessTokenQuery = {
grant_type: 'refresh_token';
refresh_token: string;
} & BaseAccessTokenQuery;
type ClientCredentialsAccessTokenQuery = {
grant_type: 'client_credentials';
scope: string;
} & BaseAccessTokenQuery;
/** Request body for the LWA token endpoint. */
type AccessTokenQuery = RefreshTokenAccessTokenQuery | ClientCredentialsAccessTokenQuery;
/** Response body from the LWA token endpoint. */
interface AccessTokenData {
access_token: string;
refresh_token?: string;
token_type: string;
expires_in: number;
}
//#endregion
//#region src/error.d.ts
/**
Error thrown when an LWA token request fails.
Wraps the underlying Axios error with a human-readable message that includes
the HTTP status code (or "No response" for network errors).
*/
declare class SellingPartnerApiAuthError extends AxiosError<AccessTokenData, AccessTokenQuery> {
/** The original error message from the failed HTTP request. */
readonly innerMessage: string;
constructor(error: AxiosError<AccessTokenData, AccessTokenQuery>);
}
//#endregion
//#region src/index.d.ts
/**
Configuration parameters for Selling Partner API authentication.
Both `clientId` and `clientSecret` fall back to the `LWA_CLIENT_ID` and
`LWA_CLIENT_SECRET` environment variables when omitted.
`refreshToken` falls back to `LWA_REFRESH_TOKEN`.
*/
interface SellingPartnerAuthParameters {
/** LWA client identifier. Defaults to the `LWA_CLIENT_ID` environment variable. */
clientId?: string;
/** LWA client secret. Defaults to the `LWA_CLIENT_SECRET` environment variable. */
clientSecret?: string;
/** LWA refresh token. Defaults to the `LWA_REFRESH_TOKEN` environment variable. Mutually exclusive with `scopes`. */
refreshToken?: string;
/** Authorization scopes for grantless operations. Mutually exclusive with `refreshToken`. */
scopes?: AuthorizationScope[];
}
/**
Handles Login with Amazon (LWA) OAuth token management for the Selling Partner API.
Supports both refresh-token and grantless (scope-based) authentication flows.
Tokens are cached and automatically refreshed when expired. Concurrent calls
to {@link getAccessToken} are deduplicated into a single request.
*/
declare class SellingPartnerApiAuth {
#private;
private readonly clientId;
private readonly clientSecret;
private readonly refreshToken?;
private readonly scopes?;
constructor(parameters: RequireExactlyOne<SellingPartnerAuthParameters, 'refreshToken' | 'scopes'>);
/**
Returns a valid LWA access token, refreshing it if expired.
Concurrent calls while a refresh is in progress share the same request.
@returns The access token string.
*/
getAccessToken(): Promise<string>;
/**
Expiration date of the currently cached access token, or `undefined` if no token has been fetched yet.
*/
protected get accessTokenExpiration(): Date | undefined;
}
//#endregion
export { AuthorizationScope, SellingPartnerApiAuth, SellingPartnerApiAuthError, SellingPartnerAuthParameters };
//# sourceMappingURL=index.d.cts.map