import type { JsonCompatible, JsonPrimitive, JsonObject, JsonArray } from '@wdio/types' import type { GetValueOptions } from './types.js' let baseUrlResolve: (value: string) => void const baseUrlPromise = new Promise((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 => { 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'}`) }