All files Client.js

97.72% Statements 86/88
87.5% Branches 35/40
100% Functions 13/13
97.72% Lines 86/88

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 891x 1x 1x 1x 1x 27x 27x 1x 1x 27x 26x 27x 27x 27x 27x 27x 27x 1x 1x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 1x 1x 23x 1x 1x 1x 1x 1x 1x 1x 23x 23x 23x 23x 1x 23x 23x 23x 1x 1x 1x 1x 1x 1x 23x 1x 1x 23x 22x 22x 23x 1x 1x 1x 21x 21x 23x 1x 1x 1x     23x 1x 1x 23x 23x 23x 23x 23x 23x 23x 1x 1x 1x 1x 1x 1x 1x  
export default class InsigniaClient {
    #baseUrl;
    #cookies = new Map();
 
    constructor(baseUrl) {
        this.#baseUrl = InsigniaClient._resolve(baseUrl);
    }
 
    static _resolve(baseUrl) {
        const envBaseUrl = typeof process !== 'undefined'
            ? process.env?.INSIGNIA_EDUCATION_API_BASE_URL ?? null
            : null;
 
        baseUrl = baseUrl ?? envBaseUrl ?? 'https://insigniaeducation.com';
        baseUrl = baseUrl.replace(/\/$/, '');
        return baseUrl;
    }
 
    #headers() {
        const headers = {
            'Accept': 'application/json',
            'Content-Type': 'application/json',
        };
 
        const cookie = this.#cookieHeader();
        if (cookie) headers.Cookie = cookie;
 
        return headers;
    }
 
    #cookieHeader() {
        if (typeof window !== 'undefined' || this.#cookies.size === 0) return null;
 
        return Array.from(this.#cookies.entries())
            .map(([name, value]) => `${name}=${value}`)
            .join('; ');
    }
 
    #storeCookies(response) {
        if (typeof window !== 'undefined') return;
 
        const headers = response.headers;
        const setCookies = typeof headers?.getSetCookie === 'function'
            ? headers.getSetCookie()
            : [headers?.get?.('set-cookie')].filter(Boolean);
 
        for (const setCookie of setCookies) {
            const [pair] = setCookie.split(';');
            const separator = pair.indexOf('=');
            if (separator === -1) continue;
 
            this.#cookies.set(pair.slice(0, separator), pair.slice(separator + 1));
        }
    }
 
    async #parseResponse(response) {
        if ([204, 205].includes(response.status)) return null;
 
        try {
            if (typeof response.text === 'function') {
                const text = await response.text();
                return text === '' ? null : JSON.parse(text);
            }
 
            return await response.json();
        } catch (error) {
            if (error instanceof SyntaxError && error.message.includes('Unexpected end')) {
                return null;
            }
            throw error;
        }
    }
 
    async #request(method, path, body = null) {
        const options = { method, headers: this.#headers(), credentials: 'include' };
        if (body !== null) options.body = JSON.stringify(body);
        const response = await fetch(`${this.#baseUrl}${path}`, options);
        this.#storeCookies(response);
        const data = await this.#parseResponse(response);
        return data?.success ? data.response : data;
    }
 
    get(path)               { return this.#request('GET',    path); }
    post(path, body = null) { return this.#request('POST',   path, body); }
    put(path, body = null)  { return this.#request('PUT',    path, body); }
    patch(path, body = null){ return this.#request('PATCH',  path, body); }
    del(path)               { return this.#request('DELETE', path); }
}