From 4ab3cf5214f328e7737615fe4db76cb2f5fd4faa Mon Sep 17 00:00:00 2001 From: goncy Date: Thu, 30 Sep 2021 14:56:04 -0300 Subject: [PATCH] Save token to cookie --- .../ordercloud/api/endpoints/cart/add-item.ts | 76 ++++++--- .../ordercloud/api/endpoints/cart/get-cart.ts | 32 +++- .../api/endpoints/cart/remove-item.ts | 20 ++- .../api/endpoints/cart/update-item.ts | 25 ++- .../api/endpoints/checkout/get-checkout.ts | 9 +- .../api/endpoints/checkout/submit-checkout.ts | 4 +- .../endpoints/customer/address/add-item.ts | 34 ++-- .../api/endpoints/customer/card/add-item.ts | 26 ++- framework/ordercloud/api/index.ts | 29 +++- .../api/operations/get-all-product-paths.ts | 4 +- .../api/operations/get-all-products.ts | 4 +- .../ordercloud/api/operations/get-product.ts | 8 +- .../api/operations/get-site-info.ts | 4 +- framework/ordercloud/api/utils/fetch-rest.ts | 159 +++++++++++------- framework/ordercloud/constants.ts | 1 + 15 files changed, 274 insertions(+), 161 deletions(-) diff --git a/framework/ordercloud/api/endpoints/cart/add-item.ts b/framework/ordercloud/api/endpoints/cart/add-item.ts index 197f58a0e..28d372bd0 100644 --- a/framework/ordercloud/api/endpoints/cart/add-item.ts +++ b/framework/ordercloud/api/endpoints/cart/add-item.ts @@ -9,7 +9,7 @@ import { formatCart } from '../../utils/cart' const addItem: CartEndpoint['handlers']['addItem'] = async ({ res, body: { cartId, item }, - config: { restFetch, cartCookie }, + config: { restBuyerFetch, cartCookie, tokenCookie }, }) => { // Return an error if no item is present if (!item) { @@ -19,52 +19,74 @@ const addItem: CartEndpoint['handlers']['addItem'] = async ({ }) } + // Store token + let token + // Set the quantity if not present if (!item.quantity) item.quantity = 1 // Create an order if it doesn't exist if (!cartId) { - cartId = await restFetch('POST', `/orders/Outgoing`, {}).then( - (response: { ID: string }) => response.ID - ) - } + const { ID, meta } = await restBuyerFetch( + 'POST', + `/orders/Outgoing`, + {} + ).then((response: { ID: string; meta: { token: string } }) => response) - // Set the cart cookie - res.setHeader( - 'Set-Cookie', - serialize(cartCookie, cartId, { - maxAge: 60 * 60 * 24 * 30, - expires: new Date(Date.now() + 60 * 60 * 24 * 30 * 1000), - secure: process.env.NODE_ENV === 'production', - path: '/', - sameSite: 'lax', - }) - ) + // Set the cart id and token + cartId = ID + token = meta.token + + // Set the cart and token cookie + res.setHeader('Set-Cookie', [ + serialize(tokenCookie, meta.token, { + maxAge: 60 * 60 * 24 * 30, + expires: new Date(Date.now() + 60 * 60 * 24 * 30 * 1000), + secure: process.env.NODE_ENV === 'production', + path: '/', + sameSite: 'lax', + }), + serialize(cartCookie, cartId, { + maxAge: 60 * 60 * 24 * 30, + expires: new Date(Date.now() + 60 * 60 * 24 * 30 * 1000), + secure: process.env.NODE_ENV === 'production', + path: '/', + sameSite: 'lax', + }), + ]) + } // Store specs let specs: RawVariant['Specs'] = [] // If a variant is present, fetch its specs if (item.variantId) { - specs = await restFetch( + specs = await restBuyerFetch( 'GET', - `/me/products/${item.productId}/variants/${item.variantId}` + `/me/products/${item.productId}/variants/${item.variantId}`, + null, + { token } ).then((res: RawVariant) => res.Specs) } // Add the item to the order - await restFetch('POST', `/orders/Outgoing/${cartId}/lineitems`, { - ProductID: item.productId, - Quantity: item.quantity, - Specs: specs, - }) + await restBuyerFetch( + 'POST', + `/orders/Outgoing/${cartId}/lineitems`, + { + ProductID: item.productId, + Quantity: item.quantity, + Specs: specs, + }, + { token } + ) // Get cart const [cart, lineItems] = await Promise.all([ - restFetch('GET', `/orders/Outgoing/${cartId}`), - restFetch('GET', `/orders/Outgoing/${cartId}/lineitems`).then( - (response: { Items: OrdercloudLineItem[] }) => response.Items - ), + restBuyerFetch('GET', `/orders/Outgoing/${cartId}`, null, { token }), + restBuyerFetch('GET', `/orders/Outgoing/${cartId}/lineitems`, null, { + token, + }).then((response: { Items: OrdercloudLineItem[] }) => response.Items), ]) // Format cart diff --git a/framework/ordercloud/api/endpoints/cart/get-cart.ts b/framework/ordercloud/api/endpoints/cart/get-cart.ts index 0340600e0..7ea077b54 100644 --- a/framework/ordercloud/api/endpoints/cart/get-cart.ts +++ b/framework/ordercloud/api/endpoints/cart/get-cart.ts @@ -7,9 +7,10 @@ import { formatCart } from '../../utils/cart' // Return current cart info const getCart: CartEndpoint['handlers']['getCart'] = async ({ + req, res, body: { cartId }, - config: { restFetch, cartCookie }, + config: { restBuyerFetch, cartCookie, tokenCookie }, }) => { if (!cartId) { return res.status(400).json({ @@ -19,13 +20,23 @@ const getCart: CartEndpoint['handlers']['getCart'] = async ({ } try { + // Get token from cookies + const token = req.cookies[tokenCookie] + // Get cart - const cart = await restFetch('GET', `/orders/Outgoing/${cartId}`) + const cart = await restBuyerFetch( + 'GET', + `/orders/Outgoing/${cartId}`, + null, + { token } + ) // Get line items - const lineItems = await restFetch( + const lineItems = await restBuyerFetch( 'GET', - `/orders/Outgoing/${cartId}/lineitems` + `/orders/Outgoing/${cartId}/lineitems`, + null, + { token } ).then((response: { Items: OrdercloudLineItem[] }) => response.Items) // Format cart @@ -34,14 +45,17 @@ const getCart: CartEndpoint['handlers']['getCart'] = async ({ // Return cart and errors res.status(200).json({ data: formattedCart, errors: [] }) } catch (error) { - // Reset cart cookie - res.setHeader( - 'Set-Cookie', + // Reset cart and token cookie + res.setHeader('Set-Cookie', [ serialize(cartCookie, cartId, { maxAge: -1, path: '/', - }) - ) + }), + serialize(tokenCookie, cartId, { + maxAge: -1, + path: '/', + }), + ]) // Return empty cart res.status(200).json({ data: null, errors: [] }) diff --git a/framework/ordercloud/api/endpoints/cart/remove-item.ts b/framework/ordercloud/api/endpoints/cart/remove-item.ts index 40a39aa3a..ea9c46e4c 100644 --- a/framework/ordercloud/api/endpoints/cart/remove-item.ts +++ b/framework/ordercloud/api/endpoints/cart/remove-item.ts @@ -4,9 +4,10 @@ import { formatCart } from '../../utils/cart' import { OrdercloudLineItem } from '../../../types/cart' const removeItem: CartEndpoint['handlers']['removeItem'] = async ({ + req, res, body: { cartId, itemId }, - config: { restFetch }, + config: { restBuyerFetch, tokenCookie }, }) => { if (!cartId || !itemId) { return res.status(400).json({ @@ -15,18 +16,23 @@ const removeItem: CartEndpoint['handlers']['removeItem'] = async ({ }) } + // Get token from cookies + const token = req.cookies[tokenCookie] + // Remove the item to the order - await restFetch( + await restBuyerFetch( 'DELETE', - `/orders/Outgoing/${cartId}/lineitems/${itemId}` + `/orders/Outgoing/${cartId}/lineitems/${itemId}`, + null, + { token } ) // Get cart const [cart, lineItems] = await Promise.all([ - restFetch('GET', `/orders/Outgoing/${cartId}`), - restFetch('GET', `/orders/Outgoing/${cartId}/lineitems`).then( - (response: { Items: OrdercloudLineItem[] }) => response.Items - ), + restBuyerFetch('GET', `/orders/Outgoing/${cartId}`, null, { token }), + restBuyerFetch('GET', `/orders/Outgoing/${cartId}/lineitems`, null, { + token, + }).then((response: { Items: OrdercloudLineItem[] }) => response.Items), ]) // Format cart diff --git a/framework/ordercloud/api/endpoints/cart/update-item.ts b/framework/ordercloud/api/endpoints/cart/update-item.ts index e10ccc0ad..20113baee 100644 --- a/framework/ordercloud/api/endpoints/cart/update-item.ts +++ b/framework/ordercloud/api/endpoints/cart/update-item.ts @@ -5,9 +5,10 @@ import type { CartEndpoint } from '.' import { formatCart } from '../../utils/cart' const updateItem: CartEndpoint['handlers']['updateItem'] = async ({ + req, res, body: { cartId, itemId, item }, - config: { restFetch }, + config: { restBuyerFetch, tokenCookie }, }) => { if (!cartId || !itemId || !item) { return res.status(400).json({ @@ -16,34 +17,40 @@ const updateItem: CartEndpoint['handlers']['updateItem'] = async ({ }) } + // Get token from cookies + const token = req.cookies[tokenCookie] + // Store specs let specs: RawVariant['Specs'] = [] // If a variant is present, fetch its specs if (item.variantId) { - specs = await restFetch( + specs = await restBuyerFetch( 'GET', - `/me/products/${item.productId}/variants/${item.variantId}` + `/me/products/${item.productId}/variants/${item.variantId}`, + null, + { token } ).then((res: RawVariant) => res.Specs) } // Add the item to the order - await restFetch( + await restBuyerFetch( 'PATCH', `/orders/Outgoing/${cartId}/lineitems/${itemId}`, { ProductID: item.productId, Quantity: item.quantity, Specs: specs, - } + }, + { token } ) // Get cart const [cart, lineItems] = await Promise.all([ - restFetch('GET', `/orders/Outgoing/${cartId}`), - restFetch('GET', `/orders/Outgoing/${cartId}/lineitems`).then( - (response: { Items: OrdercloudLineItem[] }) => response.Items - ), + restBuyerFetch('GET', `/orders/Outgoing/${cartId}`, null, { token }), + restBuyerFetch('GET', `/orders/Outgoing/${cartId}/lineitems`, null, { + token, + }).then((response: { Items: OrdercloudLineItem[] }) => response.Items), ]) // Format cart diff --git a/framework/ordercloud/api/endpoints/checkout/get-checkout.ts b/framework/ordercloud/api/endpoints/checkout/get-checkout.ts index 6cef3d4c1..b46e64ba2 100644 --- a/framework/ordercloud/api/endpoints/checkout/get-checkout.ts +++ b/framework/ordercloud/api/endpoints/checkout/get-checkout.ts @@ -3,7 +3,7 @@ import type { CheckoutEndpoint } from '.' const getCheckout: CheckoutEndpoint['handlers']['getCheckout'] = async ({ res, body: { cartId }, - config: { restFetch }, + config: { restBuyerFetch }, }) => { // Return an error if no item is present if (!cartId) { @@ -14,12 +14,15 @@ const getCheckout: CheckoutEndpoint['handlers']['getCheckout'] = async ({ } // Register credit card - const payments = await restFetch( + const payments = await restBuyerFetch( 'GET', `/orders/Outgoing/${cartId}/payments` ).then((response: { Items: unknown[] }) => response.Items) - const address = await restFetch('GET', `/orders/Outgoing/${cartId}`).then( + const address = await restBuyerFetch( + 'GET', + `/orders/Outgoing/${cartId}` + ).then( (response: { ShippingAddressID: string }) => response.ShippingAddressID ) diff --git a/framework/ordercloud/api/endpoints/checkout/submit-checkout.ts b/framework/ordercloud/api/endpoints/checkout/submit-checkout.ts index ada347f67..80cce6fbd 100644 --- a/framework/ordercloud/api/endpoints/checkout/submit-checkout.ts +++ b/framework/ordercloud/api/endpoints/checkout/submit-checkout.ts @@ -3,7 +3,7 @@ import type { CheckoutEndpoint } from '.' const submitCheckout: CheckoutEndpoint['handlers']['submitCheckout'] = async ({ res, body: { cartId }, - config: { restFetch }, + config: { restBuyerFetch }, }) => { // Return an error if no item is present if (!cartId) { @@ -14,7 +14,7 @@ const submitCheckout: CheckoutEndpoint['handlers']['submitCheckout'] = async ({ } // Submit order - await restFetch('POST', `/orders/Outgoing/${cartId}/submit`, {}) + await restBuyerFetch('POST', `/orders/Outgoing/${cartId}/submit`, {}) // Return cart and errors res.status(200).json({ data: null, errors: [] }) diff --git a/framework/ordercloud/api/endpoints/customer/address/add-item.ts b/framework/ordercloud/api/endpoints/customer/address/add-item.ts index 7e913e8a0..434c2400d 100644 --- a/framework/ordercloud/api/endpoints/customer/address/add-item.ts +++ b/framework/ordercloud/api/endpoints/customer/address/add-item.ts @@ -3,7 +3,7 @@ import type { CustomerAddressEndpoint } from '.' const addItem: CustomerAddressEndpoint['handlers']['addItem'] = async ({ res, body: { item, cartId }, - config: { restFetch }, + config: { restBuyerFetch }, }) => { // Return an error if no item is present if (!item) { @@ -22,25 +22,23 @@ const addItem: CustomerAddressEndpoint['handlers']['addItem'] = async ({ } // Register address - const address = await restFetch('POST', `/me/addresses`, { - "AddressName": "main address", - "CompanyName": item.company, - "FirstName": item.firstName, - "LastName": item.lastName, - "Street1": item.streetNumber, - "Street2": item.streetNumber, - "City": item.city, - "State": item.city, - "Zip": item.zipCode, - "Country": item.country.slice(0, 2).toLowerCase(), - "Shipping": true - }).then( - (response: {ID: string}) => response.ID - ) + const address = await restBuyerFetch('POST', `/me/addresses`, { + AddressName: 'main address', + CompanyName: item.company, + FirstName: item.firstName, + LastName: item.lastName, + Street1: item.streetNumber, + Street2: item.streetNumber, + City: item.city, + State: item.city, + Zip: item.zipCode, + Country: item.country.slice(0, 2).toLowerCase(), + Shipping: true, + }).then((response: { ID: string }) => response.ID) // Assign address to order - await restFetch('PATCH', `/orders/Outgoing/${cartId}`, { - ShippingAddressID: address + await restBuyerFetch('PATCH', `/orders/Outgoing/${cartId}`, { + ShippingAddressID: address, }) return res.status(200).json({ data: null, errors: [] }) diff --git a/framework/ordercloud/api/endpoints/customer/card/add-item.ts b/framework/ordercloud/api/endpoints/customer/card/add-item.ts index 8c5ad6a33..ad7dead7c 100644 --- a/framework/ordercloud/api/endpoints/customer/card/add-item.ts +++ b/framework/ordercloud/api/endpoints/customer/card/add-item.ts @@ -10,7 +10,7 @@ const stripe = new Stripe(process.env.STRIPE_SECRET as string, { const addItem: CustomerCardEndpoint['handlers']['addItem'] = async ({ res, body: { item, cartId }, - config: { restFetch }, + config: { restBuyerFetch, restMiddlewareFetch }, }) => { // Return an error if no item is present if (!item) { @@ -41,7 +41,7 @@ const addItem: CustomerCardEndpoint['handlers']['addItem'] = async ({ .then((res: { id: string }) => res.id) // Register credit card - const creditCard = await restFetch('POST', `/me/creditcards`, { + const creditCard = await restBuyerFetch('POST', `/me/creditcards`, { Token: token, CardType: 'credit', PartialAccountNumber: item.cardNumber.slice(-4), @@ -50,11 +50,23 @@ const addItem: CustomerCardEndpoint['handlers']['addItem'] = async ({ }).then((response: OredercloudCreditCard) => response.ID) // Assign payment to order - await restFetch('POST', `/orders/Outgoing/${cartId}/payments`, { - Accepted: true, - Type: 'CreditCard', - CreditCardID: creditCard, - }) + const payment = await restBuyerFetch( + 'POST', + `/orders/All/${cartId}/payments`, + { + Type: 'CreditCard', + CreditCardID: creditCard, + } + ).then((response: { ID: string }) => response.ID) + + // Accept payment to order + await restMiddlewareFetch( + 'PATCH', + `/orders/All/${cartId}/payments/${payment}`, + { + Accepted: true, + } + ) return res.status(200).json({ data: null, errors: [] }) } diff --git a/framework/ordercloud/api/index.ts b/framework/ordercloud/api/index.ts index 6f0d08cf5..df62843ab 100644 --- a/framework/ordercloud/api/index.ts +++ b/framework/ordercloud/api/index.ts @@ -1,6 +1,6 @@ import type { CommerceAPI, CommerceAPIConfig } from '@commerce/api' import { getCommerceApi as commerceApi } from '@commerce/api' -import createRestFetcher from './utils/fetch-rest' +import { createBuyerFetcher, createMiddlewareFetcher } from './utils/fetch-rest' import createGraphqlFetcher from './utils/fetch-graphql' import getAllPages from './operations/get-all-pages' @@ -10,16 +10,29 @@ import getAllProductPaths from './operations/get-all-product-paths' import getAllProducts from './operations/get-all-products' import getProduct from './operations/get-product' -import { API_URL, API_VERSION, CART_COOKIE, CUSTOMER_COOKIE } from '../constants' +import { + API_URL, + API_VERSION, + CART_COOKIE, + CUSTOMER_COOKIE, + TOKEN_COOKIE, +} from '../constants' export interface OrdercloudConfig extends CommerceAPIConfig { - restFetch: ( + restBuyerFetch: ( method: string, resource: string, body?: Record, fetchOptions?: Record - ) => Promise, - apiVersion: string; + ) => Promise + restMiddlewareFetch: ( + method: string, + resource: string, + body?: Record, + fetchOptions?: Record + ) => Promise + apiVersion: string + tokenCookie: string } const config: OrdercloudConfig = { @@ -28,8 +41,12 @@ const config: OrdercloudConfig = { apiVersion: API_VERSION, cartCookie: CART_COOKIE, customerCookie: CUSTOMER_COOKIE, + tokenCookie: TOKEN_COOKIE, cartCookieMaxAge: 2592000, - restFetch: createRestFetcher(() => getCommerceApi().getConfig()), + restBuyerFetch: createBuyerFetcher(() => getCommerceApi().getConfig()), + restMiddlewareFetch: createMiddlewareFetcher(() => + getCommerceApi().getConfig() + ), fetch: createGraphqlFetcher(() => getCommerceApi().getConfig()), } diff --git a/framework/ordercloud/api/operations/get-all-product-paths.ts b/framework/ordercloud/api/operations/get-all-product-paths.ts index e8966539c..1ac23c033 100644 --- a/framework/ordercloud/api/operations/get-all-product-paths.ts +++ b/framework/ordercloud/api/operations/get-all-product-paths.ts @@ -17,10 +17,10 @@ export default function getAllProductPathsOperation({ config?: Partial } = {}): Promise { // Get fetch from the config - const { restFetch } = commerce.getConfig(config) + const { restBuyerFetch } = commerce.getConfig(config) // Get all products - const rawProducts: RawProduct[] = await restFetch<{ + const rawProducts: RawProduct[] = await restBuyerFetch<{ Items: RawProduct[] }>('GET', '/me/products').then((response) => response.Items) diff --git a/framework/ordercloud/api/operations/get-all-products.ts b/framework/ordercloud/api/operations/get-all-products.ts index 6e1020e5d..6af24d945 100644 --- a/framework/ordercloud/api/operations/get-all-products.ts +++ b/framework/ordercloud/api/operations/get-all-products.ts @@ -18,10 +18,10 @@ export default function getAllProductsOperation({ preview?: boolean } = {}): Promise { // Get fetch from the config - const { restFetch } = commerce.getConfig(config) + const { restBuyerFetch } = commerce.getConfig(config) // Get all products - const rawProducts: RawProduct[] = await restFetch<{ + const rawProducts: RawProduct[] = await restBuyerFetch<{ Items: RawProduct[] }>('GET', '/me/products').then((response) => response.Items) diff --git a/framework/ordercloud/api/operations/get-product.ts b/framework/ordercloud/api/operations/get-product.ts index 9fba59b3a..864f931d4 100644 --- a/framework/ordercloud/api/operations/get-product.ts +++ b/framework/ordercloud/api/operations/get-product.ts @@ -19,22 +19,22 @@ export default function getProductOperation({ preview?: boolean } = {}): Promise { // Get fetch from the config - const { restFetch } = commerce.getConfig(config) + const { restBuyerFetch } = commerce.getConfig(config) // Get a single product - const productPromise = restFetch( + const productPromise = restBuyerFetch( 'GET', `/me/products/${variables?.slug}` ) // Get product specs - const specsPromise = restFetch<{ Items: RawSpec[] }>( + const specsPromise = restBuyerFetch<{ Items: RawSpec[] }>( 'GET', `/me/products/${variables?.slug}/specs` ).then((res) => res.Items) // Get product variants - const variantsPromise = restFetch<{ Items: RawVariant[] }>( + const variantsPromise = restBuyerFetch<{ Items: RawVariant[] }>( 'GET', `/me/products/${variables?.slug}/variants` ).then((res) => res.Items) diff --git a/framework/ordercloud/api/operations/get-site-info.ts b/framework/ordercloud/api/operations/get-site-info.ts index 247b2aa07..95188c58e 100644 --- a/framework/ordercloud/api/operations/get-site-info.ts +++ b/framework/ordercloud/api/operations/get-site-info.ts @@ -23,10 +23,10 @@ export default function getSiteInfoOperation({ preview?: boolean } = {}): Promise { // Get fetch from the config - const { restFetch } = commerce.getConfig(config) + const { restBuyerFetch } = commerce.getConfig(config) // Get list of categories - const rawCategories: RawCategory[] = await restFetch<{ + const rawCategories: RawCategory[] = await restBuyerFetch<{ Items: RawCategory[] }>('GET', `/me/categories`).then((response) => response.Items) diff --git a/framework/ordercloud/api/utils/fetch-rest.ts b/framework/ordercloud/api/utils/fetch-rest.ts index ecd63715a..a083cc58b 100644 --- a/framework/ordercloud/api/utils/fetch-rest.ts +++ b/framework/ordercloud/api/utils/fetch-rest.ts @@ -1,6 +1,6 @@ +import Cookies from 'js-cookie' import vercelFetch from '@vercel/fetch' import { FetcherError } from '@commerce/utils/errors' -import jwt from 'jsonwebtoken' import { OrdercloudConfig } from '../index' @@ -8,7 +8,15 @@ import { OrdercloudConfig } from '../index' const fetch = vercelFetch() // Get token util -async function getToken(baseUrl: string) { +async function getToken({ + baseUrl, + clientId, + clientSecret, +}: { + baseUrl: string + clientId: string + clientSecret?: string +}): Promise { // If not, get a new one and store it const authResponse = await fetch(`${baseUrl}/oauth/token`, { method: 'POST', @@ -16,7 +24,7 @@ async function getToken(baseUrl: string) { 'Content-Type': 'application/x-www-form-urlencoded', Accept: 'application/json', }, - body: `client_id=${process.env.ORDERCLOUD_CLIENT_ID}&client_secret=${process.env.ORDERCLOUD_CLIENT_SECRET}&grant_type=client_credentials`, + body: `client_id=${clientId}&client_secret=${clientSecret}&grant_type=client_credentials`, }) // If something failed getting the auth response @@ -32,68 +40,40 @@ async function getToken(baseUrl: string) { } // Return the token - return authResponse.json().then((response) => response.access_token) + return authResponse + .json() + .then((response: { access_token: string }) => response.access_token) } -export async function fetchData( - opts: { - path: string - method: string - baseUrl: string - apiVersion: string - fetchOptions?: Record - body?: Record - }, - retries = 0 -): Promise { +export async function fetchData(opts: { + token: string + path: string + method: string + config: OrdercloudConfig + fetchOptions?: Record + body?: Record +}): Promise { // Destructure opts - const { path, body, fetchOptions, baseUrl, apiVersion, method = 'GET' } = opts - - // Decode token - const decoded = jwt.decode(global.token as string) as jwt.JwtPayload | null - - // If token is not present or its expired, get a new one and store it - if ( - !global.token || - (typeof decoded?.exp === 'number' && decoded?.exp * 1000 < +new Date()) - ) { - // Get a new one - const token = await getToken(baseUrl) - - // Store it - global.token = token - } + const { path, body, fetchOptions, config, token, method = 'GET' } = opts // Do the request with the correct headers - const dataResponse = await fetch(`${baseUrl}/${apiVersion}${path}`, { - ...fetchOptions, - method, - headers: { - ...fetchOptions?.headers, - 'Content-Type': 'application/json', - accept: 'application/json, text/plain, */*', - authorization: `Bearer ${global.token}`, - }, - body: body ? JSON.stringify(body) : undefined, - }) + const dataResponse = await fetch( + `${config.commerceUrl}/${config.apiVersion}${path}`, + { + ...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) { - // If token is expired - if (dataResponse.status === 401) { - // Get a new one - const token = await getToken(baseUrl) - - // Store it - global.token = token - } - - // And if retries left - if (retries < 2) { - // Refetch - return fetchData(opts, retries + 1) - } - // Get the body of it const error = await dataResponse.textConverted() @@ -106,14 +86,20 @@ export async function fetchData( try { // Return data response as json - return (await dataResponse.json()) as Promise + const data = (await dataResponse.json()) as Promise + + // Return data with meta + return { + meta: { token }, + ...data, + } } catch (error) { // If response is empty return it as text return null as unknown as Promise } } -const serverFetcher: ( +export const createMiddlewareFetcher: ( getConfig: () => OrdercloudConfig ) => ( method: string, @@ -129,17 +115,64 @@ const serverFetcher: ( fetchOptions?: Record ) => { // Get provider config - const { commerceUrl, apiVersion } = getConfig() + const config = getConfig() + + // Get a token + const token = await getToken({ + baseUrl: config.commerceUrl, + clientId: process.env.ORDERCLOUD_MIDDLEWARE_CLIENT_ID as string, + clientSecret: process.env.ORDERCLOUD_MIDDLEWARE_CLIENT_SECRET, + }) // Return the data and specify the expected type return fetchData({ + token, fetchOptions, method, - baseUrl: commerceUrl, - apiVersion, + config, path, body, }) } -export default serverFetcher +export const createBuyerFetcher: ( + getConfig: () => OrdercloudConfig +) => ( + method: string, + path: string, + body?: Record, + fetchOptions?: Record +) => Promise = + (getConfig) => + async ( + method: string, + path: string, + body?: Record, + fetchOptions?: Record + ) => { + // Get provider config + const config = getConfig() + + // If a token was passed, set it on global + if (fetchOptions?.token) { + global.token = fetchOptions.token + } + + // Get a token + if (!global.token) { + global.token = await getToken({ + baseUrl: config.commerceUrl, + clientId: process.env.ORDERCLOUD_BUYER_CLIENT_ID as string, + }) + } + + // Return the data and specify the expected type + return fetchData({ + token: global.token as string, + fetchOptions, + config, + method, + path, + body, + }) + } diff --git a/framework/ordercloud/constants.ts b/framework/ordercloud/constants.ts index 0c7ad21b3..d89b13f64 100644 --- a/framework/ordercloud/constants.ts +++ b/framework/ordercloud/constants.ts @@ -1,4 +1,5 @@ export const CART_COOKIE = 'ordercloud.cart' +export const TOKEN_COOKIE = 'ordercloud.token' export const CUSTOMER_COOKIE = 'ordercloud.customer' export const API_URL = 'https://sandboxapi.ordercloud.io' export const API_VERSION = 'v1'