import { FetcherError } from '@vercel/commerce/utils/errors' import { OrdercloudConfig } from '../index' export let token: string | null = null // Get token util async function getToken({ baseUrl, clientId, clientSecret, }: { baseUrl: string clientId: string clientSecret?: string }): Promise<{ access_token: string expires_in: number refresh_token: string token_type: string }> { // If not, get a new one and store it const authResponse = await fetch(`${baseUrl}/oauth/token`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', Accept: 'application/json', }, body: `client_id=${clientId}&client_secret=${clientSecret}&grant_type=client_credentials`, }) // If something failed getting the auth response if (!authResponse.ok) { // Get the body of it const error = await authResponse.json() console.log(JSON.stringify(error, null, 2)) // And return an error throw new FetcherError({ errors: [{ message: error.error_description.Code }], status: error.error_description.HttpStatus, }) } // Return the token return authResponse.json() } export async function fetchData(opts: { token: string path: string method: string config: OrdercloudConfig fetchOptions?: Record body?: Record }): Promise { // Destructure opts const { path, body, fetchOptions, config, token, method = 'GET' } = opts let url = `${config.commerceUrl}/${config.apiVersion}${path}` if (fetchOptions?.anonToken) { url += `?anonUserToken=${encodeURIComponent(token)}` } // Do the request with the correct headers const dataResponse = await fetch(url, { ...fetchOptions, method, headers: { ...fetchOptions?.headers, 'Content-Type': 'application/json', accept: 'application/json, text/plain, */*', authorization: `Bearer ${token}`, }, body: body ? JSON.stringify(body) : undefined, }) // If something failed getting the data response if (!dataResponse.ok) { let errors try { // Get the body of it const error = await dataResponse.json() errors = error.Errors } catch (e) { const message = await dataResponse.text() errors = [{ message }] } throw new FetcherError({ errors, status: dataResponse.status, }) } try { // Return data response as json return (await dataResponse.json()) as Promise } catch (error) { // If response is empty return it as text return null as unknown as Promise } } export const createBuyerFetcher: ( getConfig: () => OrdercloudConfig ) => ( method: string, path: string, body?: Record, fetchOptions?: Record ) => Promise = (getConfig) => async ( method: string, path: string, body?: Record, fetchOptions?: Record ) => { if (fetchOptions?.token) { token = fetchOptions?.token } // Get provider config const config = getConfig() let meta: any = {} if (!token) { const newToken = await getToken({ baseUrl: config.commerceUrl, clientId: process.env.ORDERCLOUD_BUYER_CLIENT_ID as string, }) token = newToken.access_token meta.token = newToken } // Return the data and specify the expected type const data = await fetchData({ token, fetchOptions, config, method, path, body, }) return { ...data, meta, } }