UNPKG

observation-js

Version:

A fully-typed TypeScript client for the waarneming.nl API.

104 lines (103 loc) 3.36 kB
import { AuthenticationError } from './errors.js'; /** * @internal * Interceptor that automatically refreshes access tokens when a 401 error occurs. */ export class RefreshTokenInterceptor { client; isRefreshing = false; refreshPromise = null; maxRetries = 1; failedQueue = []; constructor(client) { this.client = client; } /** * Creates the response error handler for automatic token refresh. */ createResponseErrorHandler() { return async (error) => { if (!(error instanceof AuthenticationError)) { throw error; } const response = error.response; if (!response || response.status !== 401 || !this.client.hasRefreshToken()) { throw error; } const originalConfig = response.config; if (!originalConfig || originalConfig._retry) { throw error; } if (this.isRefreshing) { // Queue the request to be retried after refresh completes return new Promise((resolve, reject) => { this.failedQueue.push({ resolve, reject }); }); } originalConfig._retry = true; this.isRefreshing = true; try { await this.client.refreshAccessToken(); this.processQueue(null); return await this.retryOriginalRequest(originalConfig); } catch (refreshError) { this.processQueue(refreshError); throw error; } finally { this.isRefreshing = false; } }; } /** * Process all queued requests after token refresh */ processQueue(error) { this.failedQueue.forEach(({ resolve, reject }) => { if (error) { reject(error); } else { resolve(null); } }); this.failedQueue = []; } /** * Retries the original request with the new access token. */ async retryOriginalRequest(config) { const headers = new Headers(config.headers); if (this.client.hasAccessToken()) { headers.set('Authorization', `Bearer ${this.client.getCurrentAccessToken()}`); } const url = config.url; if (!url) { throw new Error('Original request URL not found'); } const newConfig = { ...config, headers, }; const response = await fetch(url, newConfig); // Attach config to response for potential future retries response.config = newConfig; if (!response.ok) { const body = await response.text(); let errorBody = null; try { errorBody = body ? JSON.parse(body) : null; } catch { errorBody = body; } if (response.status === 401 || response.status === 403) { throw new AuthenticationError(response, errorBody); } throw new Error(`Request failed with status ${response.status}`); } const text = await response.text(); return text ? JSON.parse(text) : {}; } }