🏡 index : quine-global/webdriverio.git

import type { JsonCompatible, JsonPrimitive, JsonObject, JsonArray } from '@wdio/types'
import type { GetValueOptions } from './types.js'

let baseUrlResolve: (value: string) => void
const baseUrlPromise = new Promise<string>((resolve) => {
    baseUrlResolve = resolve
})

const headers = {
    'Content-Type': 'application/json'
}

let isBaseUrlReady = false
export const setPort = (port: number) => {
    /**
     * if someone calls `setValue` in `onPrepare` we don't have a base url
     * set as the launcher is called after user hooks. In this case we need
     * to wait until it is set and flush all messages.
     */
    baseUrlResolve(`http://localhost:${port}`)
    isBaseUrlReady = true
}

/**
 * make a request to the server to get a value from the store
 * @param   {string} key
 * @returns {*}
 */
export const getValue = async (key: string): Promise<string | number | boolean | JsonObject | JsonArray | null | undefined> => {
    if (!isBaseUrlReady) {
        throw new Error('Attempting to use `getValue` before the server has been initialized.')
    }
    const baseUrl = await baseUrlPromise
    const res = await fetch(`${baseUrl}/${key}`, {
        method: 'get',
        headers
    }).catch(errHandler)
    const responseBody = await res.json()
    return responseBody.value ?? undefined
}

/**
 * make a request to the server to set a value to the store
 * @param {string}  key
 * @param {*}       value `store[key]` value (plain object)
 */
export const setValue = async (key: string, value: JsonCompatible | JsonPrimitive) => {
    const setPromise = baseUrlPromise.then((baseUrl) => {
        return fetch(`${baseUrl}/`, {
            method: 'post',
            body: JSON.stringify({ key, value }),
            headers
        }).catch(errHandler)
    })

    return isBaseUrlReady ? (await setPromise).status : Promise.resolve()
}

/**
 *
 * @param {string}  key
 * @param {*}       value
 */
export const setResourcePool = async (key: string, value: JsonArray) => {
    const setPromise = baseUrlPromise.then((baseUrl) => {
        return fetch(`${baseUrl}/pool`, {
            method: 'post',
            body: JSON.stringify({ key, value }),
            headers
        }).catch(errHandler)
    })

    return isBaseUrlReady ? (await setPromise).status : Promise.resolve()
}

/**
 *
 * @param {string}  key
 * @param {*}       value
 */
export const getValueFromPool = async (key: string, options?: GetValueOptions) => {
    if (!isBaseUrlReady) {
        throw new Error('Attempting to use `getValueFromPool` before the server has been initialized.')
    }
    const baseUrl = await baseUrlPromise
    const res = await fetch(`${baseUrl}/pool/${key}${typeof options?.timeout === 'number' ? `?timeout=${options.timeout}` : '' }`, {
        method: 'get',
        headers
    }).catch(errHandler)
    const responseBody = await res.json()
    return responseBody.value ?? undefined
}

/**
 *
 * @param {string}  key
 * @param {*}       value
 */
export const addValueToPool = async (key: string, value: JsonPrimitive | JsonCompatible) => {
    if (!isBaseUrlReady) {
        throw new Error('Attempting to use `addValueToPool` before the server has been initialized.')
    }
    const baseUrl = await baseUrlPromise
    const res = await fetch(`${baseUrl}/pool/${key}`, {
        method: 'post',
        body: JSON.stringify({ value }),
        headers
    }).catch(errHandler)
    return res.status
}

const errHandler= async (err: Error) => {
    throw new Error(`${err.message || 'Shared store server threw an error'}`)
}