mirror of
https://github.com/vercel/commerce.git
synced 2025-07-22 20:26:49 +00:00
Save token to cookie
This commit is contained in:
@@ -9,7 +9,7 @@ import { formatCart } from '../../utils/cart'
|
|||||||
const addItem: CartEndpoint['handlers']['addItem'] = async ({
|
const addItem: CartEndpoint['handlers']['addItem'] = async ({
|
||||||
res,
|
res,
|
||||||
body: { cartId, item },
|
body: { cartId, item },
|
||||||
config: { restFetch, cartCookie },
|
config: { restBuyerFetch, cartCookie, tokenCookie },
|
||||||
}) => {
|
}) => {
|
||||||
// Return an error if no item is present
|
// Return an error if no item is present
|
||||||
if (!item) {
|
if (!item) {
|
||||||
@@ -19,52 +19,74 @@ const addItem: CartEndpoint['handlers']['addItem'] = async ({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store token
|
||||||
|
let token
|
||||||
|
|
||||||
// Set the quantity if not present
|
// Set the quantity if not present
|
||||||
if (!item.quantity) item.quantity = 1
|
if (!item.quantity) item.quantity = 1
|
||||||
|
|
||||||
// Create an order if it doesn't exist
|
// Create an order if it doesn't exist
|
||||||
if (!cartId) {
|
if (!cartId) {
|
||||||
cartId = await restFetch('POST', `/orders/Outgoing`, {}).then(
|
const { ID, meta } = await restBuyerFetch(
|
||||||
(response: { ID: string }) => response.ID
|
'POST',
|
||||||
)
|
`/orders/Outgoing`,
|
||||||
}
|
{}
|
||||||
|
).then((response: { ID: string; meta: { token: string } }) => response)
|
||||||
|
|
||||||
// Set the cart cookie
|
// Set the cart id and token
|
||||||
res.setHeader(
|
cartId = ID
|
||||||
'Set-Cookie',
|
token = meta.token
|
||||||
serialize(cartCookie, cartId, {
|
|
||||||
maxAge: 60 * 60 * 24 * 30,
|
// Set the cart and token cookie
|
||||||
expires: new Date(Date.now() + 60 * 60 * 24 * 30 * 1000),
|
res.setHeader('Set-Cookie', [
|
||||||
secure: process.env.NODE_ENV === 'production',
|
serialize(tokenCookie, meta.token, {
|
||||||
path: '/',
|
maxAge: 60 * 60 * 24 * 30,
|
||||||
sameSite: 'lax',
|
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
|
// Store specs
|
||||||
let specs: RawVariant['Specs'] = []
|
let specs: RawVariant['Specs'] = []
|
||||||
|
|
||||||
// If a variant is present, fetch its specs
|
// If a variant is present, fetch its specs
|
||||||
if (item.variantId) {
|
if (item.variantId) {
|
||||||
specs = await restFetch(
|
specs = await restBuyerFetch(
|
||||||
'GET',
|
'GET',
|
||||||
`/me/products/${item.productId}/variants/${item.variantId}`
|
`/me/products/${item.productId}/variants/${item.variantId}`,
|
||||||
|
null,
|
||||||
|
{ token }
|
||||||
).then((res: RawVariant) => res.Specs)
|
).then((res: RawVariant) => res.Specs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the item to the order
|
// Add the item to the order
|
||||||
await restFetch('POST', `/orders/Outgoing/${cartId}/lineitems`, {
|
await restBuyerFetch(
|
||||||
ProductID: item.productId,
|
'POST',
|
||||||
Quantity: item.quantity,
|
`/orders/Outgoing/${cartId}/lineitems`,
|
||||||
Specs: specs,
|
{
|
||||||
})
|
ProductID: item.productId,
|
||||||
|
Quantity: item.quantity,
|
||||||
|
Specs: specs,
|
||||||
|
},
|
||||||
|
{ token }
|
||||||
|
)
|
||||||
|
|
||||||
// Get cart
|
// Get cart
|
||||||
const [cart, lineItems] = await Promise.all([
|
const [cart, lineItems] = await Promise.all([
|
||||||
restFetch('GET', `/orders/Outgoing/${cartId}`),
|
restBuyerFetch('GET', `/orders/Outgoing/${cartId}`, null, { token }),
|
||||||
restFetch('GET', `/orders/Outgoing/${cartId}/lineitems`).then(
|
restBuyerFetch('GET', `/orders/Outgoing/${cartId}/lineitems`, null, {
|
||||||
(response: { Items: OrdercloudLineItem[] }) => response.Items
|
token,
|
||||||
),
|
}).then((response: { Items: OrdercloudLineItem[] }) => response.Items),
|
||||||
])
|
])
|
||||||
|
|
||||||
// Format cart
|
// Format cart
|
||||||
|
@@ -7,9 +7,10 @@ import { formatCart } from '../../utils/cart'
|
|||||||
|
|
||||||
// Return current cart info
|
// Return current cart info
|
||||||
const getCart: CartEndpoint['handlers']['getCart'] = async ({
|
const getCart: CartEndpoint['handlers']['getCart'] = async ({
|
||||||
|
req,
|
||||||
res,
|
res,
|
||||||
body: { cartId },
|
body: { cartId },
|
||||||
config: { restFetch, cartCookie },
|
config: { restBuyerFetch, cartCookie, tokenCookie },
|
||||||
}) => {
|
}) => {
|
||||||
if (!cartId) {
|
if (!cartId) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
@@ -19,13 +20,23 @@ const getCart: CartEndpoint['handlers']['getCart'] = async ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Get token from cookies
|
||||||
|
const token = req.cookies[tokenCookie]
|
||||||
|
|
||||||
// Get cart
|
// Get cart
|
||||||
const cart = await restFetch('GET', `/orders/Outgoing/${cartId}`)
|
const cart = await restBuyerFetch(
|
||||||
|
'GET',
|
||||||
|
`/orders/Outgoing/${cartId}`,
|
||||||
|
null,
|
||||||
|
{ token }
|
||||||
|
)
|
||||||
|
|
||||||
// Get line items
|
// Get line items
|
||||||
const lineItems = await restFetch(
|
const lineItems = await restBuyerFetch(
|
||||||
'GET',
|
'GET',
|
||||||
`/orders/Outgoing/${cartId}/lineitems`
|
`/orders/Outgoing/${cartId}/lineitems`,
|
||||||
|
null,
|
||||||
|
{ token }
|
||||||
).then((response: { Items: OrdercloudLineItem[] }) => response.Items)
|
).then((response: { Items: OrdercloudLineItem[] }) => response.Items)
|
||||||
|
|
||||||
// Format cart
|
// Format cart
|
||||||
@@ -34,14 +45,17 @@ const getCart: CartEndpoint['handlers']['getCart'] = async ({
|
|||||||
// Return cart and errors
|
// Return cart and errors
|
||||||
res.status(200).json({ data: formattedCart, errors: [] })
|
res.status(200).json({ data: formattedCart, errors: [] })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Reset cart cookie
|
// Reset cart and token cookie
|
||||||
res.setHeader(
|
res.setHeader('Set-Cookie', [
|
||||||
'Set-Cookie',
|
|
||||||
serialize(cartCookie, cartId, {
|
serialize(cartCookie, cartId, {
|
||||||
maxAge: -1,
|
maxAge: -1,
|
||||||
path: '/',
|
path: '/',
|
||||||
})
|
}),
|
||||||
)
|
serialize(tokenCookie, cartId, {
|
||||||
|
maxAge: -1,
|
||||||
|
path: '/',
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
|
||||||
// Return empty cart
|
// Return empty cart
|
||||||
res.status(200).json({ data: null, errors: [] })
|
res.status(200).json({ data: null, errors: [] })
|
||||||
|
@@ -4,9 +4,10 @@ import { formatCart } from '../../utils/cart'
|
|||||||
import { OrdercloudLineItem } from '../../../types/cart'
|
import { OrdercloudLineItem } from '../../../types/cart'
|
||||||
|
|
||||||
const removeItem: CartEndpoint['handlers']['removeItem'] = async ({
|
const removeItem: CartEndpoint['handlers']['removeItem'] = async ({
|
||||||
|
req,
|
||||||
res,
|
res,
|
||||||
body: { cartId, itemId },
|
body: { cartId, itemId },
|
||||||
config: { restFetch },
|
config: { restBuyerFetch, tokenCookie },
|
||||||
}) => {
|
}) => {
|
||||||
if (!cartId || !itemId) {
|
if (!cartId || !itemId) {
|
||||||
return res.status(400).json({
|
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
|
// Remove the item to the order
|
||||||
await restFetch(
|
await restBuyerFetch(
|
||||||
'DELETE',
|
'DELETE',
|
||||||
`/orders/Outgoing/${cartId}/lineitems/${itemId}`
|
`/orders/Outgoing/${cartId}/lineitems/${itemId}`,
|
||||||
|
null,
|
||||||
|
{ token }
|
||||||
)
|
)
|
||||||
|
|
||||||
// Get cart
|
// Get cart
|
||||||
const [cart, lineItems] = await Promise.all([
|
const [cart, lineItems] = await Promise.all([
|
||||||
restFetch('GET', `/orders/Outgoing/${cartId}`),
|
restBuyerFetch('GET', `/orders/Outgoing/${cartId}`, null, { token }),
|
||||||
restFetch('GET', `/orders/Outgoing/${cartId}/lineitems`).then(
|
restBuyerFetch('GET', `/orders/Outgoing/${cartId}/lineitems`, null, {
|
||||||
(response: { Items: OrdercloudLineItem[] }) => response.Items
|
token,
|
||||||
),
|
}).then((response: { Items: OrdercloudLineItem[] }) => response.Items),
|
||||||
])
|
])
|
||||||
|
|
||||||
// Format cart
|
// Format cart
|
||||||
|
@@ -5,9 +5,10 @@ import type { CartEndpoint } from '.'
|
|||||||
import { formatCart } from '../../utils/cart'
|
import { formatCart } from '../../utils/cart'
|
||||||
|
|
||||||
const updateItem: CartEndpoint['handlers']['updateItem'] = async ({
|
const updateItem: CartEndpoint['handlers']['updateItem'] = async ({
|
||||||
|
req,
|
||||||
res,
|
res,
|
||||||
body: { cartId, itemId, item },
|
body: { cartId, itemId, item },
|
||||||
config: { restFetch },
|
config: { restBuyerFetch, tokenCookie },
|
||||||
}) => {
|
}) => {
|
||||||
if (!cartId || !itemId || !item) {
|
if (!cartId || !itemId || !item) {
|
||||||
return res.status(400).json({
|
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
|
// Store specs
|
||||||
let specs: RawVariant['Specs'] = []
|
let specs: RawVariant['Specs'] = []
|
||||||
|
|
||||||
// If a variant is present, fetch its specs
|
// If a variant is present, fetch its specs
|
||||||
if (item.variantId) {
|
if (item.variantId) {
|
||||||
specs = await restFetch(
|
specs = await restBuyerFetch(
|
||||||
'GET',
|
'GET',
|
||||||
`/me/products/${item.productId}/variants/${item.variantId}`
|
`/me/products/${item.productId}/variants/${item.variantId}`,
|
||||||
|
null,
|
||||||
|
{ token }
|
||||||
).then((res: RawVariant) => res.Specs)
|
).then((res: RawVariant) => res.Specs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the item to the order
|
// Add the item to the order
|
||||||
await restFetch(
|
await restBuyerFetch(
|
||||||
'PATCH',
|
'PATCH',
|
||||||
`/orders/Outgoing/${cartId}/lineitems/${itemId}`,
|
`/orders/Outgoing/${cartId}/lineitems/${itemId}`,
|
||||||
{
|
{
|
||||||
ProductID: item.productId,
|
ProductID: item.productId,
|
||||||
Quantity: item.quantity,
|
Quantity: item.quantity,
|
||||||
Specs: specs,
|
Specs: specs,
|
||||||
}
|
},
|
||||||
|
{ token }
|
||||||
)
|
)
|
||||||
|
|
||||||
// Get cart
|
// Get cart
|
||||||
const [cart, lineItems] = await Promise.all([
|
const [cart, lineItems] = await Promise.all([
|
||||||
restFetch('GET', `/orders/Outgoing/${cartId}`),
|
restBuyerFetch('GET', `/orders/Outgoing/${cartId}`, null, { token }),
|
||||||
restFetch('GET', `/orders/Outgoing/${cartId}/lineitems`).then(
|
restBuyerFetch('GET', `/orders/Outgoing/${cartId}/lineitems`, null, {
|
||||||
(response: { Items: OrdercloudLineItem[] }) => response.Items
|
token,
|
||||||
),
|
}).then((response: { Items: OrdercloudLineItem[] }) => response.Items),
|
||||||
])
|
])
|
||||||
|
|
||||||
// Format cart
|
// Format cart
|
||||||
|
@@ -3,7 +3,7 @@ import type { CheckoutEndpoint } from '.'
|
|||||||
const getCheckout: CheckoutEndpoint['handlers']['getCheckout'] = async ({
|
const getCheckout: CheckoutEndpoint['handlers']['getCheckout'] = async ({
|
||||||
res,
|
res,
|
||||||
body: { cartId },
|
body: { cartId },
|
||||||
config: { restFetch },
|
config: { restBuyerFetch },
|
||||||
}) => {
|
}) => {
|
||||||
// Return an error if no item is present
|
// Return an error if no item is present
|
||||||
if (!cartId) {
|
if (!cartId) {
|
||||||
@@ -14,12 +14,15 @@ const getCheckout: CheckoutEndpoint['handlers']['getCheckout'] = async ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register credit card
|
// Register credit card
|
||||||
const payments = await restFetch(
|
const payments = await restBuyerFetch(
|
||||||
'GET',
|
'GET',
|
||||||
`/orders/Outgoing/${cartId}/payments`
|
`/orders/Outgoing/${cartId}/payments`
|
||||||
).then((response: { Items: unknown[] }) => response.Items)
|
).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
|
(response: { ShippingAddressID: string }) => response.ShippingAddressID
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -3,7 +3,7 @@ import type { CheckoutEndpoint } from '.'
|
|||||||
const submitCheckout: CheckoutEndpoint['handlers']['submitCheckout'] = async ({
|
const submitCheckout: CheckoutEndpoint['handlers']['submitCheckout'] = async ({
|
||||||
res,
|
res,
|
||||||
body: { cartId },
|
body: { cartId },
|
||||||
config: { restFetch },
|
config: { restBuyerFetch },
|
||||||
}) => {
|
}) => {
|
||||||
// Return an error if no item is present
|
// Return an error if no item is present
|
||||||
if (!cartId) {
|
if (!cartId) {
|
||||||
@@ -14,7 +14,7 @@ const submitCheckout: CheckoutEndpoint['handlers']['submitCheckout'] = async ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Submit order
|
// Submit order
|
||||||
await restFetch('POST', `/orders/Outgoing/${cartId}/submit`, {})
|
await restBuyerFetch('POST', `/orders/Outgoing/${cartId}/submit`, {})
|
||||||
|
|
||||||
// Return cart and errors
|
// Return cart and errors
|
||||||
res.status(200).json({ data: null, errors: [] })
|
res.status(200).json({ data: null, errors: [] })
|
||||||
|
@@ -3,7 +3,7 @@ import type { CustomerAddressEndpoint } from '.'
|
|||||||
const addItem: CustomerAddressEndpoint['handlers']['addItem'] = async ({
|
const addItem: CustomerAddressEndpoint['handlers']['addItem'] = async ({
|
||||||
res,
|
res,
|
||||||
body: { item, cartId },
|
body: { item, cartId },
|
||||||
config: { restFetch },
|
config: { restBuyerFetch },
|
||||||
}) => {
|
}) => {
|
||||||
// Return an error if no item is present
|
// Return an error if no item is present
|
||||||
if (!item) {
|
if (!item) {
|
||||||
@@ -22,25 +22,23 @@ const addItem: CustomerAddressEndpoint['handlers']['addItem'] = async ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register address
|
// Register address
|
||||||
const address = await restFetch('POST', `/me/addresses`, {
|
const address = await restBuyerFetch('POST', `/me/addresses`, {
|
||||||
"AddressName": "main address",
|
AddressName: 'main address',
|
||||||
"CompanyName": item.company,
|
CompanyName: item.company,
|
||||||
"FirstName": item.firstName,
|
FirstName: item.firstName,
|
||||||
"LastName": item.lastName,
|
LastName: item.lastName,
|
||||||
"Street1": item.streetNumber,
|
Street1: item.streetNumber,
|
||||||
"Street2": item.streetNumber,
|
Street2: item.streetNumber,
|
||||||
"City": item.city,
|
City: item.city,
|
||||||
"State": item.city,
|
State: item.city,
|
||||||
"Zip": item.zipCode,
|
Zip: item.zipCode,
|
||||||
"Country": item.country.slice(0, 2).toLowerCase(),
|
Country: item.country.slice(0, 2).toLowerCase(),
|
||||||
"Shipping": true
|
Shipping: true,
|
||||||
}).then(
|
}).then((response: { ID: string }) => response.ID)
|
||||||
(response: {ID: string}) => response.ID
|
|
||||||
)
|
|
||||||
|
|
||||||
// Assign address to order
|
// Assign address to order
|
||||||
await restFetch('PATCH', `/orders/Outgoing/${cartId}`, {
|
await restBuyerFetch('PATCH', `/orders/Outgoing/${cartId}`, {
|
||||||
ShippingAddressID: address
|
ShippingAddressID: address,
|
||||||
})
|
})
|
||||||
|
|
||||||
return res.status(200).json({ data: null, errors: [] })
|
return res.status(200).json({ data: null, errors: [] })
|
||||||
|
@@ -10,7 +10,7 @@ const stripe = new Stripe(process.env.STRIPE_SECRET as string, {
|
|||||||
const addItem: CustomerCardEndpoint['handlers']['addItem'] = async ({
|
const addItem: CustomerCardEndpoint['handlers']['addItem'] = async ({
|
||||||
res,
|
res,
|
||||||
body: { item, cartId },
|
body: { item, cartId },
|
||||||
config: { restFetch },
|
config: { restBuyerFetch, restMiddlewareFetch },
|
||||||
}) => {
|
}) => {
|
||||||
// Return an error if no item is present
|
// Return an error if no item is present
|
||||||
if (!item) {
|
if (!item) {
|
||||||
@@ -41,7 +41,7 @@ const addItem: CustomerCardEndpoint['handlers']['addItem'] = async ({
|
|||||||
.then((res: { id: string }) => res.id)
|
.then((res: { id: string }) => res.id)
|
||||||
|
|
||||||
// Register credit card
|
// Register credit card
|
||||||
const creditCard = await restFetch('POST', `/me/creditcards`, {
|
const creditCard = await restBuyerFetch('POST', `/me/creditcards`, {
|
||||||
Token: token,
|
Token: token,
|
||||||
CardType: 'credit',
|
CardType: 'credit',
|
||||||
PartialAccountNumber: item.cardNumber.slice(-4),
|
PartialAccountNumber: item.cardNumber.slice(-4),
|
||||||
@@ -50,11 +50,23 @@ const addItem: CustomerCardEndpoint['handlers']['addItem'] = async ({
|
|||||||
}).then((response: OredercloudCreditCard) => response.ID)
|
}).then((response: OredercloudCreditCard) => response.ID)
|
||||||
|
|
||||||
// Assign payment to order
|
// Assign payment to order
|
||||||
await restFetch('POST', `/orders/Outgoing/${cartId}/payments`, {
|
const payment = await restBuyerFetch(
|
||||||
Accepted: true,
|
'POST',
|
||||||
Type: 'CreditCard',
|
`/orders/All/${cartId}/payments`,
|
||||||
CreditCardID: creditCard,
|
{
|
||||||
})
|
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: [] })
|
return res.status(200).json({ data: null, errors: [] })
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import type { CommerceAPI, CommerceAPIConfig } from '@commerce/api'
|
import type { CommerceAPI, CommerceAPIConfig } from '@commerce/api'
|
||||||
import { getCommerceApi as commerceApi } 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 createGraphqlFetcher from './utils/fetch-graphql'
|
||||||
|
|
||||||
import getAllPages from './operations/get-all-pages'
|
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 getAllProducts from './operations/get-all-products'
|
||||||
import getProduct from './operations/get-product'
|
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 {
|
export interface OrdercloudConfig extends CommerceAPIConfig {
|
||||||
restFetch: <T>(
|
restBuyerFetch: <T>(
|
||||||
method: string,
|
method: string,
|
||||||
resource: string,
|
resource: string,
|
||||||
body?: Record<string, unknown>,
|
body?: Record<string, unknown>,
|
||||||
fetchOptions?: Record<string, any>
|
fetchOptions?: Record<string, any>
|
||||||
) => Promise<T>,
|
) => Promise<T>
|
||||||
apiVersion: string;
|
restMiddlewareFetch: <T>(
|
||||||
|
method: string,
|
||||||
|
resource: string,
|
||||||
|
body?: Record<string, unknown>,
|
||||||
|
fetchOptions?: Record<string, any>
|
||||||
|
) => Promise<T>
|
||||||
|
apiVersion: string
|
||||||
|
tokenCookie: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const config: OrdercloudConfig = {
|
const config: OrdercloudConfig = {
|
||||||
@@ -28,8 +41,12 @@ const config: OrdercloudConfig = {
|
|||||||
apiVersion: API_VERSION,
|
apiVersion: API_VERSION,
|
||||||
cartCookie: CART_COOKIE,
|
cartCookie: CART_COOKIE,
|
||||||
customerCookie: CUSTOMER_COOKIE,
|
customerCookie: CUSTOMER_COOKIE,
|
||||||
|
tokenCookie: TOKEN_COOKIE,
|
||||||
cartCookieMaxAge: 2592000,
|
cartCookieMaxAge: 2592000,
|
||||||
restFetch: createRestFetcher(() => getCommerceApi().getConfig()),
|
restBuyerFetch: createBuyerFetcher(() => getCommerceApi().getConfig()),
|
||||||
|
restMiddlewareFetch: createMiddlewareFetcher(() =>
|
||||||
|
getCommerceApi().getConfig()
|
||||||
|
),
|
||||||
fetch: createGraphqlFetcher(() => getCommerceApi().getConfig()),
|
fetch: createGraphqlFetcher(() => getCommerceApi().getConfig()),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -17,10 +17,10 @@ export default function getAllProductPathsOperation({
|
|||||||
config?: Partial<OrdercloudConfig>
|
config?: Partial<OrdercloudConfig>
|
||||||
} = {}): Promise<T['data']> {
|
} = {}): Promise<T['data']> {
|
||||||
// Get fetch from the config
|
// Get fetch from the config
|
||||||
const { restFetch } = commerce.getConfig(config)
|
const { restBuyerFetch } = commerce.getConfig(config)
|
||||||
|
|
||||||
// Get all products
|
// Get all products
|
||||||
const rawProducts: RawProduct[] = await restFetch<{
|
const rawProducts: RawProduct[] = await restBuyerFetch<{
|
||||||
Items: RawProduct[]
|
Items: RawProduct[]
|
||||||
}>('GET', '/me/products').then((response) => response.Items)
|
}>('GET', '/me/products').then((response) => response.Items)
|
||||||
|
|
||||||
|
@@ -18,10 +18,10 @@ export default function getAllProductsOperation({
|
|||||||
preview?: boolean
|
preview?: boolean
|
||||||
} = {}): Promise<T['data']> {
|
} = {}): Promise<T['data']> {
|
||||||
// Get fetch from the config
|
// Get fetch from the config
|
||||||
const { restFetch } = commerce.getConfig(config)
|
const { restBuyerFetch } = commerce.getConfig(config)
|
||||||
|
|
||||||
// Get all products
|
// Get all products
|
||||||
const rawProducts: RawProduct[] = await restFetch<{
|
const rawProducts: RawProduct[] = await restBuyerFetch<{
|
||||||
Items: RawProduct[]
|
Items: RawProduct[]
|
||||||
}>('GET', '/me/products').then((response) => response.Items)
|
}>('GET', '/me/products').then((response) => response.Items)
|
||||||
|
|
||||||
|
@@ -19,22 +19,22 @@ export default function getProductOperation({
|
|||||||
preview?: boolean
|
preview?: boolean
|
||||||
} = {}): Promise<T['data']> {
|
} = {}): Promise<T['data']> {
|
||||||
// Get fetch from the config
|
// Get fetch from the config
|
||||||
const { restFetch } = commerce.getConfig(config)
|
const { restBuyerFetch } = commerce.getConfig(config)
|
||||||
|
|
||||||
// Get a single product
|
// Get a single product
|
||||||
const productPromise = restFetch<RawProduct>(
|
const productPromise = restBuyerFetch<RawProduct>(
|
||||||
'GET',
|
'GET',
|
||||||
`/me/products/${variables?.slug}`
|
`/me/products/${variables?.slug}`
|
||||||
)
|
)
|
||||||
|
|
||||||
// Get product specs
|
// Get product specs
|
||||||
const specsPromise = restFetch<{ Items: RawSpec[] }>(
|
const specsPromise = restBuyerFetch<{ Items: RawSpec[] }>(
|
||||||
'GET',
|
'GET',
|
||||||
`/me/products/${variables?.slug}/specs`
|
`/me/products/${variables?.slug}/specs`
|
||||||
).then((res) => res.Items)
|
).then((res) => res.Items)
|
||||||
|
|
||||||
// Get product variants
|
// Get product variants
|
||||||
const variantsPromise = restFetch<{ Items: RawVariant[] }>(
|
const variantsPromise = restBuyerFetch<{ Items: RawVariant[] }>(
|
||||||
'GET',
|
'GET',
|
||||||
`/me/products/${variables?.slug}/variants`
|
`/me/products/${variables?.slug}/variants`
|
||||||
).then((res) => res.Items)
|
).then((res) => res.Items)
|
||||||
|
@@ -23,10 +23,10 @@ export default function getSiteInfoOperation({
|
|||||||
preview?: boolean
|
preview?: boolean
|
||||||
} = {}): Promise<T['data']> {
|
} = {}): Promise<T['data']> {
|
||||||
// Get fetch from the config
|
// Get fetch from the config
|
||||||
const { restFetch } = commerce.getConfig(config)
|
const { restBuyerFetch } = commerce.getConfig(config)
|
||||||
|
|
||||||
// Get list of categories
|
// Get list of categories
|
||||||
const rawCategories: RawCategory[] = await restFetch<{
|
const rawCategories: RawCategory[] = await restBuyerFetch<{
|
||||||
Items: RawCategory[]
|
Items: RawCategory[]
|
||||||
}>('GET', `/me/categories`).then((response) => response.Items)
|
}>('GET', `/me/categories`).then((response) => response.Items)
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
|
import Cookies from 'js-cookie'
|
||||||
import vercelFetch from '@vercel/fetch'
|
import vercelFetch from '@vercel/fetch'
|
||||||
import { FetcherError } from '@commerce/utils/errors'
|
import { FetcherError } from '@commerce/utils/errors'
|
||||||
import jwt from 'jsonwebtoken'
|
|
||||||
|
|
||||||
import { OrdercloudConfig } from '../index'
|
import { OrdercloudConfig } from '../index'
|
||||||
|
|
||||||
@@ -8,7 +8,15 @@ import { OrdercloudConfig } from '../index'
|
|||||||
const fetch = vercelFetch()
|
const fetch = vercelFetch()
|
||||||
|
|
||||||
// Get token util
|
// Get token util
|
||||||
async function getToken(baseUrl: string) {
|
async function getToken({
|
||||||
|
baseUrl,
|
||||||
|
clientId,
|
||||||
|
clientSecret,
|
||||||
|
}: {
|
||||||
|
baseUrl: string
|
||||||
|
clientId: string
|
||||||
|
clientSecret?: string
|
||||||
|
}): Promise<string> {
|
||||||
// If not, get a new one and store it
|
// If not, get a new one and store it
|
||||||
const authResponse = await fetch(`${baseUrl}/oauth/token`, {
|
const authResponse = await fetch(`${baseUrl}/oauth/token`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -16,7 +24,7 @@ async function getToken(baseUrl: string) {
|
|||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
Accept: 'application/json',
|
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
|
// If something failed getting the auth response
|
||||||
@@ -32,68 +40,40 @@ async function getToken(baseUrl: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return the token
|
// 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<T>(
|
export async function fetchData<T>(opts: {
|
||||||
opts: {
|
token: string
|
||||||
path: string
|
path: string
|
||||||
method: string
|
method: string
|
||||||
baseUrl: string
|
config: OrdercloudConfig
|
||||||
apiVersion: string
|
fetchOptions?: Record<string, any>
|
||||||
fetchOptions?: Record<string, any>
|
body?: Record<string, unknown>
|
||||||
body?: Record<string, unknown>
|
}): Promise<T> {
|
||||||
},
|
|
||||||
retries = 0
|
|
||||||
): Promise<T> {
|
|
||||||
// Destructure opts
|
// Destructure opts
|
||||||
const { path, body, fetchOptions, baseUrl, apiVersion, method = 'GET' } = opts
|
const { path, body, fetchOptions, config, token, 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do the request with the correct headers
|
// Do the request with the correct headers
|
||||||
const dataResponse = await fetch(`${baseUrl}/${apiVersion}${path}`, {
|
const dataResponse = await fetch(
|
||||||
...fetchOptions,
|
`${config.commerceUrl}/${config.apiVersion}${path}`,
|
||||||
method,
|
{
|
||||||
headers: {
|
...fetchOptions,
|
||||||
...fetchOptions?.headers,
|
method,
|
||||||
'Content-Type': 'application/json',
|
headers: {
|
||||||
accept: 'application/json, text/plain, */*',
|
...fetchOptions?.headers,
|
||||||
authorization: `Bearer ${global.token}`,
|
'Content-Type': 'application/json',
|
||||||
},
|
accept: 'application/json, text/plain, */*',
|
||||||
body: body ? JSON.stringify(body) : undefined,
|
authorization: `Bearer ${token}`,
|
||||||
})
|
},
|
||||||
|
body: body ? JSON.stringify(body) : undefined,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// If something failed getting the data response
|
// If something failed getting the data response
|
||||||
if (!dataResponse.ok) {
|
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
|
// Get the body of it
|
||||||
const error = await dataResponse.textConverted()
|
const error = await dataResponse.textConverted()
|
||||||
|
|
||||||
@@ -106,14 +86,20 @@ export async function fetchData<T>(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Return data response as json
|
// Return data response as json
|
||||||
return (await dataResponse.json()) as Promise<T>
|
const data = (await dataResponse.json()) as Promise<T>
|
||||||
|
|
||||||
|
// Return data with meta
|
||||||
|
return {
|
||||||
|
meta: { token },
|
||||||
|
...data,
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// If response is empty return it as text
|
// If response is empty return it as text
|
||||||
return null as unknown as Promise<T>
|
return null as unknown as Promise<T>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const serverFetcher: (
|
export const createMiddlewareFetcher: (
|
||||||
getConfig: () => OrdercloudConfig
|
getConfig: () => OrdercloudConfig
|
||||||
) => <T>(
|
) => <T>(
|
||||||
method: string,
|
method: string,
|
||||||
@@ -129,17 +115,64 @@ const serverFetcher: (
|
|||||||
fetchOptions?: Record<string, any>
|
fetchOptions?: Record<string, any>
|
||||||
) => {
|
) => {
|
||||||
// Get provider config
|
// 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 the data and specify the expected type
|
||||||
return fetchData<T>({
|
return fetchData<T>({
|
||||||
|
token,
|
||||||
fetchOptions,
|
fetchOptions,
|
||||||
method,
|
method,
|
||||||
baseUrl: commerceUrl,
|
config,
|
||||||
apiVersion,
|
|
||||||
path,
|
path,
|
||||||
body,
|
body,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export default serverFetcher
|
export const createBuyerFetcher: (
|
||||||
|
getConfig: () => OrdercloudConfig
|
||||||
|
) => <T>(
|
||||||
|
method: string,
|
||||||
|
path: string,
|
||||||
|
body?: Record<string, unknown>,
|
||||||
|
fetchOptions?: Record<string, any>
|
||||||
|
) => Promise<T> =
|
||||||
|
(getConfig) =>
|
||||||
|
async <T>(
|
||||||
|
method: string,
|
||||||
|
path: string,
|
||||||
|
body?: Record<string, unknown>,
|
||||||
|
fetchOptions?: Record<string, any>
|
||||||
|
) => {
|
||||||
|
// 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<T>({
|
||||||
|
token: global.token as string,
|
||||||
|
fetchOptions,
|
||||||
|
config,
|
||||||
|
method,
|
||||||
|
path,
|
||||||
|
body,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
export const CART_COOKIE = 'ordercloud.cart'
|
export const CART_COOKIE = 'ordercloud.cart'
|
||||||
|
export const TOKEN_COOKIE = 'ordercloud.token'
|
||||||
export const CUSTOMER_COOKIE = 'ordercloud.customer'
|
export const CUSTOMER_COOKIE = 'ordercloud.customer'
|
||||||
export const API_URL = 'https://sandboxapi.ordercloud.io'
|
export const API_URL = 'https://sandboxapi.ordercloud.io'
|
||||||
export const API_VERSION = 'v1'
|
export const API_VERSION = 'v1'
|
||||||
|
Reference in New Issue
Block a user