diff --git a/src/blutui.spec.ts b/src/blutui.spec.ts index 7f3a903..98b6df3 100644 --- a/src/blutui.spec.ts +++ b/src/blutui.spec.ts @@ -47,6 +47,22 @@ describe('Blutui', () => { }) }) + describe('when access token and fetch function are provided to the constructor', () => { + it('initalizes', async () => { + // Example from JWT.io + const token = + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c' + expect( + () => + new Blutui(token, { + request: { + fetch: fetch, + }, + }) + ).not.toThrow() + }) + }) + describe('version', () => { it('matches the version in `package.json`', async () => { const blutui = new Blutui('eyJhbGciOi') diff --git a/src/blutui.ts b/src/blutui.ts index ae6886b..ad17b06 100644 --- a/src/blutui.ts +++ b/src/blutui.ts @@ -53,12 +53,16 @@ export class Blutui { const useAgent: string = `blutui-node/${VERSION}` - this.client = new Client(this.baseURL, { - headers: { - Authorization: `Bearer ${this.accessToken}`, - 'User-Agent': useAgent, + this.client = new Client( + this.baseURL, + { + headers: { + Authorization: `Bearer ${this.accessToken}`, + 'User-Agent': useAgent, + }, }, - }) + options.request?.fetch + ) } /** diff --git a/src/types.ts b/src/types.ts index 76320ab..6e74e06 100644 --- a/src/types.ts +++ b/src/types.ts @@ -3,7 +3,8 @@ export interface BlutuiOptions { apiHostname?: string request?: { - fetch?: typeof fetch + // biome-ignore lint/suspicious/noExplicitAny: We want developers to be able to use node-fetch + fetch?: any } } diff --git a/src/utils/client.ts b/src/utils/client.ts index f4b4da9..0411308 100644 --- a/src/utils/client.ts +++ b/src/utils/client.ts @@ -3,10 +3,24 @@ import { FetchException } from '../exceptions' const API_VERSION = 'v1' export class Client { + private readonly _fetchFn + + /** + * Create a new client instance. + */ constructor( readonly baseURL: string, - readonly options?: RequestInit - ) {} + readonly options?: RequestInit, + fetchFn?: typeof fetch + ) { + this._fetchFn = fetchFn || globalThis.fetch + + if (!this._fetchFn) { + throw new Error( + 'Fetch function not defined in the global scope and no replacement was provided.' + ) + } + } async get( path: string, @@ -80,7 +94,7 @@ export class Client { } private async fetch(url: string, options?: RequestInit) { - const response = await fetch(url, { + const response = await this._fetchFn(url, { ...this.options, ...options, headers: {