UNPKG

@basetime/a2w-api-ts

Version:

Client library that communicates with the addtowallet API.

107 lines (106 loc) 3.75 kB
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;