Adding more migration changes

This commit is contained in:
Luis Alvarez 2021-03-18 20:16:35 -06:00
parent 90fb763602
commit df07a55740
6 changed files with 104 additions and 60 deletions

View File

@ -0,0 +1,46 @@
import { parseCartItem } from '../utils/parse-item'
import getCartCookie from '../utils/get-cart-cookie'
import type { CartHandlers } from '.'
import { normalizeCart } from '@framework/lib/normalize'
const addItem: CartHandlers['addItem'] = async ({
res,
body: { cartId, item },
config,
}) => {
if (!item) {
return res.status(400).json({
data: null,
errors: [{ message: 'Missing item' }],
})
}
if (!item.quantity) item.quantity = 1
const options = {
method: 'POST',
body: JSON.stringify({
line_items: [parseCartItem(item)],
...(!cartId && config.storeChannelId
? { channel_id: config.storeChannelId }
: {}),
}),
}
const { data } = cartId
? await config.storeApiFetch(
`/v3/carts/${cartId}/items?include=line_items.physical_items.options`,
options
)
: await config.storeApiFetch(
'/v3/carts?include=line_items.physical_items.options',
options
)
// Create or update the cart cookie
res.setHeader(
'Set-Cookie',
getCartCookie(config.cartCookie, data.id, config.cartCookieMaxAge)
)
res.status(200).json({ data: normalizeCart(data) })
}
export default addItem

View File

@ -1,7 +1,7 @@
import { CartHandlers as CartHandlersCore } from '@commerce/api'
import isAllowedMethod from '../utils/is-allowed-method'
import createApiHandler, {
BigcommerceApiHandler,
BigcommerceHandler,
} from '../utils/create-api-handler'
import { BigcommerceApiError } from '../utils/errors'
import getCart from './handlers/get-cart'
@ -14,14 +14,22 @@ import type {
AddCartItemHandlerBody,
UpdateCartItemHandlerBody,
RemoveCartItemHandlerBody,
Cart,
} from '../../types'
import { APIHandler } from '@commerce/api/utils/types'
import { CommerceAPI } from '..'
export type CartHandlers = {
getCart: BigcommerceHandler<BigcommerceCart, GetCartHandlerBody>
addItem: BigcommerceHandler<BigcommerceCart, AddCartItemHandlerBody>
updateItem: BigcommerceHandler<BigcommerceCart, UpdateCartItemHandlerBody>
removeItem: BigcommerceHandler<BigcommerceCart, RemoveCartItemHandlerBody>
export type CartHandlers<
C extends CommerceAPI = CommerceAPI
> = CartHandlersCore<
C,
{
getCart: APIHandler<C, CartHandlers<C>, Cart | null, GetCartHandlerBody>
addItem: APIHandler<C, CartHandlers<C>, Cart, AddCartItemHandlerBody>
updateItem: APIHandler<C, CartHandlers<C>, Cart, UpdateCartItemHandlerBody>
removeItem: APIHandler<C, CartHandlers<C>, Cart, RemoveCartItemHandlerBody>
}
>
const METHODS = ['GET', 'POST', 'PUT', 'DELETE']

View File

@ -104,7 +104,9 @@ export const provider = {
export type Provider = typeof provider
export class CommerceAPI<P extends Provider> extends CoreCommerceAPI<P> {
export class CommerceAPI<
P extends Provider = Provider
> extends CoreCommerceAPI<P> {
constructor(readonly provider: P = provider) {
super(provider)
}

View File

@ -1,9 +1,9 @@
import type { APIEndpoint } from '../utils/types'
import { CommerceAPIError } from '../utils/errors'
import isAllowedOperation from '../utils/is-allowed-operation'
import type { APIProvider, CartHandlers } from '..'
import type { CommerceAPI, CartHandlers } from '..'
const cartApi: APIEndpoint<APIProvider, CartHandlers<any>> = async (ctx) => {
const cartApi: APIEndpoint<CommerceAPI, CartHandlers<any>> = async (ctx) => {
const { req, res, handlers, config } = ctx
if (

View File

@ -1,16 +1,22 @@
import type { NextApiHandler } from 'next'
import type { RequestInit, Response } from '@vercel/fetch'
import type { APIEndpoint, APIHandler } from './utils/types'
import type { Cart } from '../types'
export type CartEndpoint = APIEndpoint<any, any, CartHandlers<any>, any>
export type CartEndpoint = APIEndpoint<any, any, CartHandlers<CommerceAPI>, any>
export type CartHandlers<Body extends { cartId: 'string' }> = {
getCart: APIHandler<any, CartHandlers<Body>, any, Body>
addItem: APIHandler<any, CartHandlers<Body>, any, Body>
updateItem: APIHandler<any, CartHandlers<Body>, any, Body>
removeItem: APIHandler<any, CartHandlers<Body>, any, Body>
export type CartHandlersBase<C> = {
getCart: APIHandler<any, CartHandlersBase<C>, Cart | null, any>
addItem: APIHandler<any, CartHandlersBase<C>, Cart, any>
updateItem: APIHandler<any, CartHandlersBase<C>, Cart, any>
removeItem: APIHandler<any, CartHandlersBase<C>, Cart, any>
}
export type CartHandlers<
C extends CommerceAPI,
T extends CartHandlersBase<C> = CartHandlersBase<C>
> = T
export type Endpoints = CartEndpoint
export type EndpointHandlers<E> = E extends APIEndpoint<any, any, infer T>
@ -21,17 +27,12 @@ export type EndpointOptions<E> = E extends APIEndpoint<any, any, any, infer T>
? T
: never
export type CoreAPIProvider = {
export type APIProvider = {
config: CommerceAPIConfig
}
export type APIProvider<P extends CoreAPIProvider = CoreAPIProvider> = P & {
getConfig(userConfig?: Partial<P['config']>): P['config']
setConfig(newConfig: Partial<P['config']>): void
}
export class CommerceAPI<
P extends CoreAPIProvider = CoreAPIProvider,
P extends APIProvider = APIProvider,
E extends Endpoints = Endpoints
> {
constructor(readonly provider: P) {
@ -55,14 +56,14 @@ export class CommerceAPI<
operations: EndpointHandlers<typeof context.handler>
options?: EndpointOptions<typeof context.handler>
}): NextApiHandler {
const provider = this
const commerce = this
const cfg = this.getConfig(context.config)
return function apiHandler(req, res) {
return context.handler({
req,
res,
provider,
commerce,
config: cfg,
handlers: context.operations,
options: context.options,
@ -71,23 +72,6 @@ export class CommerceAPI<
}
}
export function createAPIProvider<P extends CoreAPIProvider>(
provider: P
): APIProvider<P> {
return {
...provider,
getConfig(userConfig = {}) {
return Object.entries(userConfig).reduce(
(cfg, [key, value]) => Object.assign(cfg, { [key]: value }),
{ ...this.config }
)
},
setConfig(newConfig) {
Object.assign(this.config, newConfig)
},
}
}
export interface CommerceAPIConfig {
locale?: string
commerceUrl: string

View File

@ -1,21 +1,25 @@
import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next'
import type { APIProvider } from '..'
import type { NextApiRequest, NextApiResponse } from 'next'
import type { CommerceAPI } from '..'
export type APIResponse<Data = any> = {
data: Data
errors?: { message: string; code?: string }[]
}
export type ErrorData = { message: string; code?: string }
export type APIResponse<Data = any> =
| { data: Data; errors?: ErrorData[] }
// If `data` doesn't include `null`, then `null` is only allowed on errors
| (Data extends null
? { data: null; errors?: ErrorData[] }
: { data: null; errors: ErrorData[] })
export type APIHandlerContext<
P extends APIProvider,
H extends APIHandlers<P, Data> = {},
C extends CommerceAPI,
H extends APIHandlers<C> = {},
Data = any,
Options extends {} = {}
> = {
req: NextApiRequest
res: NextApiResponse<APIResponse<Data>>
provider: P
config: P['config']
commerce: C
config: C['provider']['config']
handlers: H
/**
* Custom configs that may be used by a particular handler
@ -24,22 +28,22 @@ export type APIHandlerContext<
}
export type APIHandler<
P extends APIProvider,
H extends APIHandlers<P, Data> = {},
C extends CommerceAPI,
H extends APIHandlers<C> = {},
Data = any,
Body = any,
Options extends {} = {}
> = (
context: APIHandlerContext<P, H, Data, Options> & { body: Body }
context: APIHandlerContext<C, H, Data, Options> & { body: Body }
) => void | Promise<void>
export type APIHandlers<P extends APIProvider, Data = any> = {
[k: string]: APIHandler<P, any, Data, any>
export type APIHandlers<C extends CommerceAPI, Data = any> = {
[k: string]: APIHandler<C, any, Data, any, any>
}
export type APIEndpoint<
P extends APIProvider = APIProvider,
H extends APIHandlers<P, Data> = {},
C extends CommerceAPI = CommerceAPI,
H extends APIHandlers<C> = {},
Data = any,
Options extends {} = {}
> = (context: APIHandlerContext<P, H, Data, Options>) => void | Promise<void>
> = (context: APIHandlerContext<C, H, Data, Options>) => void | Promise<void>