) {
- return config.setConfig(newConfig)
+const operations = {
+ login,
+ getAllPages,
+ getPage,
+ getSiteInfo,
+ getCustomerWishlist,
+ getAllProductPaths,
+ getAllProducts,
+ getProduct,
+}
+
+export const provider = { config, operations }
+
+export type Provider = typeof provider
+
+export type APIs =
+ | CartAPI
+ | CustomerAPI
+ | LoginAPI
+ | LogoutAPI
+ | SignupAPI
+ | ProductsAPI
+ | WishlistAPI
+
+export type BigcommerceAPI = CommerceAPI
+
+export function getCommerceApi
(
+ customProvider: P = provider as any
+): BigcommerceAPI
{
+ return commerceApi(customProvider)
}
diff --git a/framework/bigcommerce/api/operations/get-all-pages.ts b/framework/bigcommerce/api/operations/get-all-pages.ts
index 21c70c1dc..3a9b64b1f 100644
--- a/framework/bigcommerce/api/operations/get-all-pages.ts
+++ b/framework/bigcommerce/api/operations/get-all-pages.ts
@@ -1,45 +1,46 @@
+import type {
+ OperationContext,
+ OperationOptions,
+} from '@commerce/api/operations'
+import type { Page, GetAllPagesOperation } from '../../types/page'
import type { RecursivePartial, RecursiveRequired } from '../utils/types'
-import { BigcommerceConfig, getConfig } from '..'
-import { definitions } from '../definitions/store-content'
+import { BigcommerceConfig, Provider } from '..'
-export type Page = definitions['page_Full']
+export default function getAllPagesOperation({
+ commerce,
+}: OperationContext) {
+ async function getAllPages(opts?: {
+ config?: Partial
+ preview?: boolean
+ }): Promise
-export type GetAllPagesResult<
- T extends { pages: any[] } = { pages: Page[] }
-> = T
+ async function getAllPages(
+ opts: {
+ config?: Partial
+ preview?: boolean
+ } & OperationOptions
+ ): Promise
-async function getAllPages(opts?: {
- config?: BigcommerceConfig
- preview?: boolean
-}): Promise
+ async function getAllPages({
+ config,
+ preview,
+ }: {
+ url?: string
+ config?: Partial
+ preview?: boolean
+ } = {}): Promise {
+ const cfg = commerce.getConfig(config)
+ // RecursivePartial forces the method to check for every prop in the data, which is
+ // required in case there's a custom `url`
+ const { data } = await cfg.storeApiFetch<
+ RecursivePartial<{ data: Page[] }>
+ >('/v3/content/pages')
+ const pages = (data as RecursiveRequired) ?? []
-async function getAllPages(opts: {
- url: string
- config?: BigcommerceConfig
- preview?: boolean
-}): Promise>
-
-async function getAllPages({
- config,
- preview,
-}: {
- url?: string
- config?: BigcommerceConfig
- preview?: boolean
-} = {}): Promise {
- config = getConfig(config)
- // RecursivePartial forces the method to check for every prop in the data, which is
- // required in case there's a custom `url`
- const { data } = await config.storeApiFetch<
- RecursivePartial<{ data: Page[] }>
- >('/v3/content/pages')
- const pages = (data as RecursiveRequired) ?? []
-
- const retPages = {
- pages: preview ? pages : pages.filter((p) => p.is_visible),
+ return {
+ pages: preview ? pages : pages.filter((p) => p.is_visible),
+ }
}
- return retPages
+ return getAllPages
}
-
-export default getAllPages
diff --git a/framework/bigcommerce/api/operations/get-all-product-paths.ts b/framework/bigcommerce/api/operations/get-all-product-paths.ts
index 71522be35..da7b457eb 100644
--- a/framework/bigcommerce/api/operations/get-all-product-paths.ts
+++ b/framework/bigcommerce/api/operations/get-all-product-paths.ts
@@ -1,10 +1,12 @@
import type {
- GetAllProductPathsQuery,
- GetAllProductPathsQueryVariables,
-} from '../../schema'
+ OperationContext,
+ OperationOptions,
+} from '@commerce/api/operations'
+import type { GetAllProductPathsQuery } from '../../schema'
+import type { GetAllProductPathsOperation } from '../../types/product'
import type { RecursivePartial, RecursiveRequired } from '../utils/types'
import filterEdges from '../utils/filter-edges'
-import { BigcommerceConfig, getConfig } from '..'
+import { BigcommerceConfig, Provider } from '..'
export const getAllProductPathsQuery = /* GraphQL */ `
query getAllProductPaths($first: Int = 100) {
@@ -20,52 +22,45 @@ export const getAllProductPathsQuery = /* GraphQL */ `
}
`
-export type ProductPath = NonNullable<
- NonNullable[0]
->
+export default function getAllProductPathsOperation({
+ commerce,
+}: OperationContext) {
+ async function getAllProductPaths<
+ T extends GetAllProductPathsOperation
+ >(opts?: {
+ variables?: T['variables']
+ config?: BigcommerceConfig
+ }): Promise
-export type ProductPaths = ProductPath[]
+ async function getAllProductPaths(
+ opts: {
+ variables?: T['variables']
+ config?: BigcommerceConfig
+ } & OperationOptions
+ ): Promise
-export type { GetAllProductPathsQueryVariables }
+ async function getAllProductPaths({
+ query = getAllProductPathsQuery,
+ variables,
+ config,
+ }: {
+ query?: string
+ variables?: T['variables']
+ config?: BigcommerceConfig
+ } = {}): Promise {
+ config = commerce.getConfig(config)
+ // RecursivePartial forces the method to check for every prop in the data, which is
+ // required in case there's a custom `query`
+ const { data } = await config.fetch<
+ RecursivePartial
+ >(query, { variables })
+ const products = data.site?.products?.edges
-export type GetAllProductPathsResult<
- T extends { products: any[] } = { products: ProductPaths }
-> = T
-
-async function getAllProductPaths(opts?: {
- variables?: GetAllProductPathsQueryVariables
- config?: BigcommerceConfig
-}): Promise
-
-async function getAllProductPaths<
- T extends { products: any[] },
- V = any
->(opts: {
- query: string
- variables?: V
- config?: BigcommerceConfig
-}): Promise>
-
-async function getAllProductPaths({
- query = getAllProductPathsQuery,
- variables,
- config,
-}: {
- query?: string
- variables?: GetAllProductPathsQueryVariables
- config?: BigcommerceConfig
-} = {}): Promise {
- config = getConfig(config)
- // RecursivePartial forces the method to check for every prop in the data, which is
- // required in case there's a custom `query`
- const { data } = await config.fetch<
- RecursivePartial
- >(query, { variables })
- const products = data.site?.products?.edges
-
- return {
- products: filterEdges(products as RecursiveRequired),
+ return {
+ products: filterEdges(products as RecursiveRequired).map(
+ ({ node }) => node
+ ),
+ }
}
+ return getAllProductPaths
}
-
-export default getAllProductPaths
diff --git a/framework/bigcommerce/api/operations/get-all-products.ts b/framework/bigcommerce/api/operations/get-all-products.ts
index 0cd9737c2..c2652f5bf 100644
--- a/framework/bigcommerce/api/operations/get-all-products.ts
+++ b/framework/bigcommerce/api/operations/get-all-products.ts
@@ -1,12 +1,18 @@
+import type {
+ OperationContext,
+ OperationOptions,
+} from '@commerce/api/operations'
import type {
GetAllProductsQuery,
GetAllProductsQueryVariables,
} from '../../schema'
+import type { GetAllProductsOperation } from '../../types/product'
import type { RecursivePartial, RecursiveRequired } from '../utils/types'
import filterEdges from '../utils/filter-edges'
import setProductLocaleMeta from '../utils/set-product-locale-meta'
import { productConnectionFragment } from '../fragments/product'
-import { BigcommerceConfig, getConfig } from '..'
+import { BigcommerceConfig, Provider } from '..'
+import { normalizeProduct } from '../../lib/normalize'
export const getAllProductsQuery = /* GraphQL */ `
query getAllProducts(
@@ -50,83 +56,80 @@ export type GetAllProductsResult<
}
> = T
-const FIELDS = [
- 'products',
- 'featuredProducts',
- 'bestSellingProducts',
- 'newestProducts',
-]
-
-export type ProductTypes =
- | 'products'
- | 'featuredProducts'
- | 'bestSellingProducts'
- | 'newestProducts'
-
-export type ProductVariables = { field?: ProductTypes } & Omit<
- GetAllProductsQueryVariables,
- ProductTypes | 'hasLocale'
->
-
-async function getAllProducts(opts?: {
- variables?: ProductVariables
- config?: BigcommerceConfig
- preview?: boolean
-}): Promise
-
-async function getAllProducts<
- T extends Record,
- V = any
->(opts: {
- query: string
- variables?: V
- config?: BigcommerceConfig
- preview?: boolean
-}): Promise>
-
-async function getAllProducts({
- query = getAllProductsQuery,
- variables: { field = 'products', ...vars } = {},
- config,
-}: {
- query?: string
- variables?: ProductVariables
- config?: BigcommerceConfig
- preview?: boolean
-} = {}): Promise {
- config = getConfig(config)
-
- const locale = vars.locale || config.locale
- const variables: GetAllProductsQueryVariables = {
- ...vars,
- locale,
- hasLocale: !!locale,
+function getProductsType(
+ relevance?: GetAllProductsOperation['variables']['relevance']
+) {
+ switch (relevance) {
+ case 'featured':
+ return 'featuredProducts'
+ case 'best_selling':
+ return 'bestSellingProducts'
+ case 'newest':
+ return 'newestProducts'
+ default:
+ return 'products'
}
-
- if (!FIELDS.includes(field)) {
- throw new Error(
- `The field variable has to match one of ${FIELDS.join(', ')}`
- )
- }
-
- variables[field] = true
-
- // RecursivePartial forces the method to check for every prop in the data, which is
- // required in case there's a custom `query`
- const { data } = await config.fetch>(
- query,
- { variables }
- )
- const edges = data.site?.[field]?.edges
- const products = filterEdges(edges as RecursiveRequired)
-
- if (locale && config.applyLocale) {
- products.forEach((product: RecursivePartial) => {
- if (product.node) setProductLocaleMeta(product.node)
- })
- }
-
- return { products }
}
-export default getAllProducts
+export default function getAllProductsOperation({
+ commerce,
+}: OperationContext) {
+ async function getAllProducts(opts?: {
+ variables?: T['variables']
+ config?: Partial
+ preview?: boolean
+ }): Promise
+
+ async function getAllProducts(
+ opts: {
+ variables?: T['variables']
+ config?: Partial
+ preview?: boolean
+ } & OperationOptions
+ ): Promise
+
+ async function getAllProducts({
+ query = getAllProductsQuery,
+ variables: vars = {},
+ config: cfg,
+ }: {
+ query?: string
+ variables?: T['variables']
+ config?: Partial
+ preview?: boolean
+ } = {}): Promise {
+ const config = commerce.getConfig(cfg)
+ const { locale } = config
+ const field = getProductsType(vars.relevance)
+ const variables: GetAllProductsQueryVariables = {
+ locale,
+ hasLocale: !!locale,
+ }
+
+ variables[field] = true
+
+ if (vars.first) variables.first = vars.first
+ if (vars.ids) variables.entityIds = vars.ids.map((id) => Number(id))
+
+ // RecursivePartial forces the method to check for every prop in the data, which is
+ // required in case there's a custom `query`
+ const { data } = await config.fetch>(
+ query,
+ { variables }
+ )
+ const edges = data.site?.[field]?.edges
+ const products = filterEdges(edges as RecursiveRequired)
+
+ if (locale && config.applyLocale) {
+ products.forEach((product: RecursivePartial) => {
+ if (product.node) setProductLocaleMeta(product.node)
+ })
+ }
+
+ return {
+ products: products.map(({ node }) => normalizeProduct(node as any)),
+ }
+ }
+
+ return getAllProducts
+}
diff --git a/framework/bigcommerce/api/operations/get-customer-wishlist.ts b/framework/bigcommerce/api/operations/get-customer-wishlist.ts
index 2c1299b46..fc9487ffe 100644
--- a/framework/bigcommerce/api/operations/get-customer-wishlist.ts
+++ b/framework/bigcommerce/api/operations/get-customer-wishlist.ts
@@ -1,87 +1,81 @@
+import type {
+ OperationContext,
+ OperationOptions,
+} from '@commerce/api/operations'
+import type {
+ GetCustomerWishlistOperation,
+ Wishlist,
+} from '../../types/wishlist'
import type { RecursivePartial, RecursiveRequired } from '../utils/types'
-import { definitions } from '../definitions/wishlist'
-import { BigcommerceConfig, getConfig } from '..'
+import { BigcommerceConfig, Provider } from '..'
import getAllProducts, { ProductEdge } from './get-all-products'
-export type Wishlist = Omit & {
- items?: WishlistItem[]
-}
+export default function getCustomerWishlistOperation({
+ commerce,
+}: OperationContext) {
+ async function getCustomerWishlist<
+ T extends GetCustomerWishlistOperation
+ >(opts: {
+ variables: T['variables']
+ config?: BigcommerceConfig
+ includeProducts?: boolean
+ }): Promise
-export type WishlistItem = NonNullable<
- definitions['wishlist_Full']['items']
->[0] & {
- product?: ProductEdge['node']
-}
+ async function getCustomerWishlist(
+ opts: {
+ variables: T['variables']
+ config?: BigcommerceConfig
+ includeProducts?: boolean
+ } & OperationOptions
+ ): Promise
-export type GetCustomerWishlistResult<
- T extends { wishlist?: any } = { wishlist?: Wishlist }
-> = T
+ async function getCustomerWishlist({
+ config,
+ variables,
+ includeProducts,
+ }: {
+ url?: string
+ variables: T['variables']
+ config?: BigcommerceConfig
+ includeProducts?: boolean
+ }): Promise {
+ config = commerce.getConfig(config)
-export type GetCustomerWishlistVariables = {
- customerId: number
-}
+ const { data = [] } = await config.storeApiFetch<
+ RecursivePartial<{ data: Wishlist[] }>
+ >(`/v3/wishlists?customer_id=${variables.customerId}`)
+ const wishlist = data[0]
-async function getCustomerWishlist(opts: {
- variables: GetCustomerWishlistVariables
- config?: BigcommerceConfig
- includeProducts?: boolean
-}): Promise
+ if (includeProducts && wishlist?.items?.length) {
+ const ids = wishlist.items
+ ?.map((item) => (item?.product_id ? String(item?.product_id) : null))
+ .filter((id): id is string => !!id)
-async function getCustomerWishlist<
- T extends { wishlist?: any },
- V = any
->(opts: {
- url: string
- variables: V
- config?: BigcommerceConfig
- includeProducts?: boolean
-}): Promise>
-
-async function getCustomerWishlist({
- config,
- variables,
- includeProducts,
-}: {
- url?: string
- variables: GetCustomerWishlistVariables
- config?: BigcommerceConfig
- includeProducts?: boolean
-}): Promise {
- config = getConfig(config)
-
- const { data = [] } = await config.storeApiFetch<
- RecursivePartial<{ data: Wishlist[] }>
- >(`/v3/wishlists?customer_id=${variables.customerId}`)
- const wishlist = data[0]
-
- if (includeProducts && wishlist?.items?.length) {
- const entityIds = wishlist.items
- ?.map((item) => item?.product_id)
- .filter((id): id is number => !!id)
-
- if (entityIds?.length) {
- const graphqlData = await getAllProducts({
- variables: { first: 100, entityIds },
- config,
- })
- // Put the products in an object that we can use to get them by id
- const productsById = graphqlData.products.reduce<{
- [k: number]: ProductEdge
- }>((prods, p) => {
- prods[p.node.entityId] = p
- return prods
- }, {})
- // Populate the wishlist items with the graphql products
- wishlist.items.forEach((item) => {
- const product = item && productsById[item.product_id!]
- if (item && product) {
- item.product = product.node
- }
- })
+ if (ids?.length) {
+ const graphqlData = await commerce.getAllProducts({
+ variables: { first: 100, ids },
+ config,
+ })
+ // Put the products in an object that we can use to get them by id
+ const productsById = graphqlData.products.reduce<{
+ [k: number]: ProductEdge
+ }>((prods, p) => {
+ prods[Number(p.id)] = p as any
+ return prods
+ }, {})
+ // Populate the wishlist items with the graphql products
+ wishlist.items.forEach((item) => {
+ const product = item && productsById[item.product_id!]
+ if (item && product) {
+ // @ts-ignore Fix this type when the wishlist type is properly defined
+ item.product = product
+ }
+ })
+ }
}
+
+ return { wishlist: wishlist as RecursiveRequired }
}
- return { wishlist: wishlist as RecursiveRequired }
+ return getCustomerWishlist
}
-
-export default getCustomerWishlist
diff --git a/framework/bigcommerce/api/operations/get-page.ts b/framework/bigcommerce/api/operations/get-page.ts
index 3010dd34c..6a1fea9d0 100644
--- a/framework/bigcommerce/api/operations/get-page.ts
+++ b/framework/bigcommerce/api/operations/get-page.ts
@@ -1,53 +1,54 @@
+import type {
+ OperationContext,
+ OperationOptions,
+} from '@commerce/api/operations'
+import type { GetPageOperation, Page } from '../../types/page'
import type { RecursivePartial, RecursiveRequired } from '../utils/types'
-import { BigcommerceConfig, getConfig } from '..'
-import { definitions } from '../definitions/store-content'
+import type { BigcommerceConfig, Provider } from '..'
+import { normalizePage } from '../../lib/normalize'
-export type Page = definitions['page_Full']
+export default function getPageOperation({
+ commerce,
+}: OperationContext