@basetime/a2w-api-ts
Version:
Client library that communicates with the addtowallet API.
107 lines (106 loc) • 3.75 kB
TypeScript
import { Logger } from '../Logger';
import { Authed } from '../types/Authed';
import { AuthProvider } from './AuthProvider';
/**
* Seconds of clock-skew margin applied to cached token expiry.
*
* A cached `Authed` is treated as expired this many seconds before its real
* `expiresAt`, so we trigger a refresh before the token actually expires mid-request.
*/
export declare const TOKEN_SKEW_SECONDS = 30;
/**
* Abstract base class shared by every {@link AuthProvider} implementation in the SDK.
*
* Centralises three concerns that every provider needs and that are easy to get wrong:
*
* 1. **In-flight dedup.** When many parallel requests arrive without a cached token,
* only one network round-trip fires; the rest await the same promise.
* 2. **Clock-skew margin.** Cached tokens are considered expired
* {@link TOKEN_SKEW_SECONDS} seconds early so we never send a doomed request.
* 3. **Real refresh-token support.** `refresh()` exchanges the cached refresh token at
* `/auth/apiRefresh` and falls back to a fresh grant on failure.
*
* Subclasses only have to implement {@link fetchAuthed}, which performs the
* provider-specific initial grant (key/secret, oauth code, ...).
*/
export default abstract class BaseAuthProvider implements AuthProvider {
/**
* The last successful authentication.
*/
protected authed?: Authed;
/**
* Promise of an in-flight `fetchAuthed()` call, used to dedupe concurrent
* `authenticate()` invocations. Cleared in a `finally` after the request settles.
*/
protected pendingAuth?: Promise<Authed>;
/**
* Promise of an in-flight `refresh()` call, used to dedupe concurrent
* `refresh()` invocations.
*/
protected pendingRefresh?: Promise<Authed>;
/**
* The logger.
*/
protected logger: Logger;
/**
* The API base URL used for auth requests.
*/
protected baseUrl: string;
/**
* Constructor.
*
* @param logger The logger to use.
* @param baseUrl The API base URL to send auth requests to.
*/
constructor(logger?: Logger, baseUrl?: string);
/**
* @inheritdoc
*/
setLogger: (logger: Logger) => void;
/**
* @inheritdoc
*/
setBaseUrl: (baseUrl: string) => void;
/**
* @inheritdoc
*/
getAuthed: () => Authed | undefined;
/**
* @inheritdoc
*/
authenticate: () => Promise<string>;
/**
* @inheritdoc
*/
refresh: () => Promise<string>;
/**
* Returns whether the cached `Authed` is still usable.
*
* A token is considered fresh when it exists and its `expiresAt` is more than
* {@link TOKEN_SKEW_SECONDS} seconds in the future.
*/
protected isTokenFresh: () => boolean;
/**
* Exchanges a refresh token at `/auth/apiRefresh` for a fresh `Authed`.
*
* @param refreshToken The cached refresh token.
*/
protected exchangeRefreshToken: (refreshToken: string) => Promise<Authed>;
/**
* Performs the provider-specific initial grant.
*
* Subclasses POST their credentials to the appropriate `/auth/*` endpoint and return
* the parsed `Authed` value. The base class handles caching, dedup, and refresh.
*/
protected abstract fetchAuthed(): Promise<Authed>;
}
/**
* Parses an auth response into an `Authed`, throwing a descriptive error on failure.
*
* Used by both {@link BaseAuthProvider.exchangeRefreshToken} and subclass
* `fetchAuthed()` implementations to avoid duplicating the hand-rolled shape check.
*
* @param raw The raw response body.
* @param endpoint The endpoint path (used in error messages).
*/
export declare const parseAuthed: (raw: unknown, endpoint: string) => Authed;