UNPKG

@paykit-sdk/core

Version:

The Payment Toolkit for Typescript

125 lines (121 loc) 3.48 kB
'use strict'; // src/error.ts var PayKitError = class extends Error { code; statusCode; provider; method; context; constructor(message, options) { super(message); this.name = this.constructor.name; this.code = options?.code || "PAYKIT_ERROR"; this.statusCode = options?.statusCode || 500; this.provider = options?.provider; this.method = options?.method; this.context = options?.context; if (options?.cause) { this.cause = options.cause; } Error.captureStackTrace(this, this.constructor); } }; var OperationFailedError = class extends PayKitError { constructor(operation, provider, options) { const message = `Failed to ${operation}${provider ? ` with ${provider}` : ""}${options?.reason ? `: ${options.reason}` : ""}`; super(message, { code: "OPERATION_FAILED", statusCode: 500, provider, method: operation, cause: options?.cause }); this.stack = void 0; } }; // src/oauth2-token-manager.ts var OAuth2TokenManager = class { _accessToken = null; _expiresAt = 0; // epoch ms _refreshPromise = null; config; constructor(config) { this.config = { ...config, method: config.method ?? "POST", expiryBuffer: config.expiryBuffer ?? 300 }; } /** * Get a valid access token, refreshing if necessary */ getToken = async () => { if (this._accessToken && this._expiresAt > Date.now()) { return this._accessToken; } if (this._refreshPromise) return this._refreshPromise; this._refreshPromise = this._refreshToken().finally(() => { this._refreshPromise = null; }); return this._refreshPromise; }; _refreshToken = async () => { const credentials = Buffer.from( `${this.config.credentials.username}:${this.config.credentials.password}` ).toString("base64"); const headers = { Authorization: `Basic ${credentials}`, ...this.config.requestHeaders && { ...this.config.requestHeaders } }; const response = this.config.method === "GET" ? await this.config.client.get(this.config.tokenEndpoint, { headers }) : await this.config.client.post(this.config.tokenEndpoint, { headers, ...this.config.requestBody && { body: this.config.requestBody } }); if (!response.ok) { throw new OperationFailedError( "getAccessToken", this.config.provider, { cause: new Error( `Failed to obtain access token: ${JSON.stringify(response.value || response.error)}` ) } ); } const tokenData = this.config.responseAdapter( response.value ); if (!tokenData.accessToken || !tokenData.expiresIn) { throw new OperationFailedError( "getAccessToken", this.config.provider, { cause: new Error( "Invalid token response: missing accessToken or expiresIn" ) } ); } this._accessToken = tokenData.accessToken; this._expiresAt = Date.now() + (tokenData.expiresIn - this.config.expiryBuffer) * 1e3; return tokenData.accessToken; }; /** * Get authorization headers for API requests */ getAuthHeaders = async () => { const token = await this.getToken(); return { Authorization: `Bearer ${token}`, ...this.config.authHeaders && { ...this.config.authHeaders } }; }; }; exports.OAuth2TokenManager = OAuth2TokenManager;