>
+ fetchProducts: typeof fetchProducts
+}
+
+const PROJECT_KEY = process.env.CTP_PROJECT_KEY || 'projectKey'
+const CLIENT_ID = process.env.CTP_CLIENT_ID || 'projectKey'
+const CLIENT_SECRET = process.env.CTP_CLIENT_SECRET || 'projectKey'
+const AUTH_URL = process.env.CTP_AUTH_URL || 'projectKey'
+const API_URL = process.env.CTP_API_URL || 'projectKey'
+const CONCURRENCY = process.env.CTP_CONCURRENCY || 0
+
+if (!API_URL) {
+ throw new Error(
+ `The environment variable CTP_API_URL is missing and it's required to access your store`
+ )
+}
+
+if (!PROJECT_KEY) {
+ throw new Error(
+ `The environment variable CTP_PROJECT_KEY is missing and it's required to access your store`
+ )
+}
+
+if (!AUTH_URL) {
+ throw new Error(
+ `The environment variables CTP_AUTH_URL have to be set in order to access your store`
+ )
+}
+
+const ONE_DAY = 60 * 60 * 24
+
+const config: CommercetoolsConfig = {
+ locale: '',
+ commerceUrl: '',
+ host: API_URL,
+ projectKey: PROJECT_KEY,
+ clientId: CLIENT_ID,
+ clientSecret: CLIENT_SECRET,
+ oauthHost: AUTH_URL,
+ concurrency: CONCURRENCY,
+ apiToken: '',
+ cartCookie: '',
+ cartCookieMaxAge: 0,
+ customerCookie: '',
+ fetch: fetchGraphql,
+ fetchProducts: fetchProducts,
+}
+
+const operations = {
+ getAllPages,
+ getPage,
+ getAllProductPaths,
+ getAllProducts,
+ getProduct,
+ getSiteInfo,
+ getCustomerWishlist,
+ login,
+}
+
+export const provider = { config, operations }
+
+export type Provider = typeof provider
+
+export type CommercetoolsAPI = CommerceAPI
+
+export function getCommerceApi
(
+ customProvider: P = provider as any
+): CommercetoolsAPI
{
+ return commerceApi(customProvider)
+}
diff --git a/framework/commercetools/api/operations/get-all-pages.ts b/framework/commercetools/api/operations/get-all-pages.ts
new file mode 100644
index 000000000..078157687
--- /dev/null
+++ b/framework/commercetools/api/operations/get-all-pages.ts
@@ -0,0 +1,40 @@
+import { CommercetoolsConfig, Provider } from '@framework/api'
+import { OperationContext } from '@commerce/api/operations'
+
+export type Page = any
+
+export type GetAllPagesResult<
+ T extends { pages: any[] } = { pages: Page[] }
+> = T
+
+export default function getAllPagesOperation({
+ commerce,
+}: OperationContext) {
+ async function getAllPages(opts?: {
+ config?: Partial
+ preview?: boolean
+ }): Promise
+
+ async function getAllPages(opts: {
+ url: string
+ config?: Partial
+ preview?: boolean
+ }): Promise>
+
+ async function getAllPages({
+ config: cfg,
+ preview,
+ }: {
+ url?: string
+ config?: Partial
+ preview?: boolean
+ } = {}): Promise {
+ const config = commerce.getConfig(cfg)
+
+ return {
+ pages: [],
+ }
+ }
+
+ return getAllPages
+}
diff --git a/framework/commercetools/api/operations/get-all-product-paths.ts b/framework/commercetools/api/operations/get-all-product-paths.ts
new file mode 100644
index 000000000..483aa5a45
--- /dev/null
+++ b/framework/commercetools/api/operations/get-all-product-paths.ts
@@ -0,0 +1,50 @@
+import { OperationContext, OperationOptions } from '@commerce/api/operations'
+import { GetAllProductPathsOperation } from '@commerce/types/product'
+import { CommercetoolsConfig, Provider } from '@framework/api'
+
+export type GetAllProductPathsResult = {
+ products: Array<{ node: { path: string } }>
+}
+
+export default function getAllProductPathsOperation({
+ commerce,
+}: OperationContext) {
+ async function getAllProductPaths<
+ T extends GetAllProductPathsOperation
+ >(opts?: {
+ variables?: T['variables']
+ config?: CommercetoolsConfig
+ }): Promise
+
+ async function getAllProductPaths(
+ opts: {
+ variables?: T['variables']
+ config?: CommercetoolsConfig
+ } & OperationOptions
+ ): Promise
+
+ async function getAllProductPaths({
+ query,
+ variables,
+ config: cfg,
+ }: {
+ query?: string
+ variables?: T['variables']
+ config?: CommercetoolsConfig
+ } = {}): Promise {
+ const config = commerce.getConfig(cfg)
+ // RecursivePartial forces the method to check for every prop in the data, which is
+ // required in case there's a custom `query`
+ const data: any = await config.fetchProducts(query)
+ const paths = data.body.results.map((prod: any) => ({
+ // TODO: TEC-264: Handle the locale properly
+ path: `/${prod.slug.en}`,
+ }))
+
+ return {
+ products: paths,
+ }
+ }
+
+ return getAllProductPaths
+}
diff --git a/framework/commercetools/api/operations/get-all-products.ts b/framework/commercetools/api/operations/get-all-products.ts
new file mode 100644
index 000000000..04bc2da5d
--- /dev/null
+++ b/framework/commercetools/api/operations/get-all-products.ts
@@ -0,0 +1,31 @@
+import { Product } from '@commerce/types/product'
+import { Provider, CommercetoolsConfig } from '@framework/api'
+import { normalizeProduct } from '@framework/lib/normalize'
+import { OperationContext } from '@commerce/api/operations'
+
+export default function getAllProductsOperation({
+ commerce,
+}: OperationContext) {
+ async function getAllProducts(opts?: {
+ config?: Partial
+ preview?: boolean
+ }): Promise<{ products: Product[] }>
+
+ async function getAllProducts({
+ config: cfg,
+ }: {
+ config?: Partial
+ preview?: boolean
+ } = {}): Promise<{ products: Product[] | any[] }> {
+ const config = commerce.getConfig(cfg)
+ const data: any = await config.fetchProducts()
+
+ const prods = data.body.results.map((prod: any) => normalizeProduct(prod))
+
+ return {
+ products: prods,
+ }
+ }
+
+ return getAllProducts
+}
diff --git a/framework/commercetools/api/operations/get-customer-wishlist.ts b/framework/commercetools/api/operations/get-customer-wishlist.ts
new file mode 100644
index 000000000..4ca0d879d
--- /dev/null
+++ b/framework/commercetools/api/operations/get-customer-wishlist.ts
@@ -0,0 +1,23 @@
+import { OperationContext } from '@commerce/api/operations'
+import { Provider, CommercetoolsConfig } from '@framework/api'
+
+export default function getCustomerWishlistOperation({
+ commerce,
+}: OperationContext) {
+ async function getCustomerWishlist({
+ config: cfg,
+ variables,
+ includeProducts,
+ }: {
+ url?: string
+ variables: any
+ config?: Partial
+ includeProducts?: boolean
+ }): Promise {
+ // Not implemented yet
+ const config = commerce.getConfig(cfg)
+ return { wishlist: {} }
+ }
+
+ return getCustomerWishlist
+}
diff --git a/framework/commercetools/api/operations/get-page.ts b/framework/commercetools/api/operations/get-page.ts
new file mode 100644
index 000000000..68d32125f
--- /dev/null
+++ b/framework/commercetools/api/operations/get-page.ts
@@ -0,0 +1,45 @@
+import { CommercetoolsConfig, Provider } from '@framework/api'
+import { OperationContext } from '@commerce/api/operations'
+
+export type Page = any
+
+export type GetPageResult = T
+
+export type PageVariables = {
+ id: number
+}
+
+export default function getPageOperation({
+ commerce,
+}: OperationContext) {
+ async function getPage(opts: {
+ url?: string
+ variables: PageVariables
+ config?: Partial
+ preview?: boolean
+ }): Promise
+
+ async function getPage(opts: {
+ url: string
+ variables: V
+ config?: Partial
+ preview?: boolean
+ }): Promise>
+
+ async function getPage({
+ url,
+ variables,
+ config: cfg,
+ preview,
+ }: {
+ url?: string
+ variables: PageVariables
+ config?: Partial
+ preview?: boolean
+ }): Promise {
+ const config = commerce.getConfig(cfg)
+ return {}
+ }
+
+ return getPage
+}
diff --git a/framework/commercetools/api/operations/get-product.ts b/framework/commercetools/api/operations/get-product.ts
new file mode 100644
index 000000000..589fb4dd3
--- /dev/null
+++ b/framework/commercetools/api/operations/get-product.ts
@@ -0,0 +1,38 @@
+import { Product } from '@commerce/types/product'
+import { OperationContext } from '@commerce/api/operations'
+import { Provider, CommercetoolsConfig } from '@framework/api'
+import { normalizeProduct } from '@framework/lib/normalize'
+
+export default function getProductOperation({
+ commerce,
+}: OperationContext) {
+ async function getProduct({
+ variables,
+ config: cfg,
+ }: {
+ variables: {
+ slug?: string
+ id?: string
+ locale?: string
+ }
+ config?: Partial
+ preview?: boolean
+ }): Promise {
+ const config = commerce.getConfig(cfg)
+
+ // TODO: TEC-264: Handle the locale properly
+ const queryArg = {
+ where: `slug(en="${variables.slug}")`,
+ }
+ const projection = await config.fetchProducts(queryArg)
+ const product = projection.body.results[0]
+
+ if (product) {
+ return { product: normalizeProduct(product) }
+ }
+
+ return {}
+ }
+
+ return getProduct
+}
diff --git a/framework/commercetools/api/operations/get-site-info.ts b/framework/commercetools/api/operations/get-site-info.ts
new file mode 100644
index 000000000..d1a113fdf
--- /dev/null
+++ b/framework/commercetools/api/operations/get-site-info.ts
@@ -0,0 +1,39 @@
+import { Provider, CommercetoolsConfig } from '@framework/api'
+import { OperationContext } from '@commerce/api/operations'
+import { Category } from '@commerce/types/site'
+import { getAllCategoriesAndBrandsQuery } from '@framework/utils/queries/get-category'
+import { normalizeSite } from '@framework/lib/normalize'
+
+export type GetSiteInfoResult<
+ T extends { categories: any[]; brands: any[] } = {
+ categories: Category[]
+ brands: any[]
+ }
+> = T
+
+export default function getSiteInfoOperation({
+ commerce,
+}: OperationContext) {
+ async function getSiteInfo({
+ query = getAllCategoriesAndBrandsQuery,
+ variables,
+ config: cfg,
+ }: {
+ query?: string
+ variables?: any
+ config?: Partial
+ preview?: boolean
+ } = {}): Promise {
+ const config = commerce.getConfig(cfg)
+ const {
+ data: { categories, productTypes },
+ }: any = await config.fetch(query)
+ const ctCategories = categories.results
+ const ctBrands =
+ productTypes?.results[0]?.attributeDefinitions?.results[0]?.type?.values
+ ?.results
+ return normalizeSite(ctCategories, ctBrands)
+ }
+
+ return getSiteInfo
+}
diff --git a/framework/commercetools/api/operations/login.ts b/framework/commercetools/api/operations/login.ts
new file mode 100644
index 000000000..501890992
--- /dev/null
+++ b/framework/commercetools/api/operations/login.ts
@@ -0,0 +1,43 @@
+import type { ServerResponse } from 'http'
+import type {
+ OperationContext,
+ OperationOptions,
+} from '@commerce/api/operations'
+import { Provider, CommercetoolsConfig } from '@framework/api'
+
+export default function loginOperation({
+ commerce,
+}: OperationContext) {
+ async function login(opts: {
+ variables: T['variables']
+ config?: Partial
+ res: ServerResponse
+ }): Promise
+
+ async function login(
+ opts: {
+ variables: T['variables']
+ config?: Partial
+ res: ServerResponse
+ } & OperationOptions
+ ): Promise
+
+ async function login({
+ query = '',
+ variables,
+ res: response,
+ config: cfg,
+ }: {
+ query?: string
+ variables: T['variables']
+ res: ServerResponse
+ config?: Partial
+ }): Promise {
+ const config = commerce.getConfig(cfg)
+ return {
+ result: '',
+ }
+ }
+
+ return login
+}
diff --git a/framework/commercetools/api/utils/errors.ts b/framework/commercetools/api/utils/errors.ts
new file mode 100644
index 000000000..49839fa69
--- /dev/null
+++ b/framework/commercetools/api/utils/errors.ts
@@ -0,0 +1,25 @@
+import type { Response } from '@vercel/fetch'
+
+// Used for GraphQL errors
+export class CommercetoolsGraphQLError extends Error {}
+
+export class CommercetoolsApiError extends Error {
+ status: number
+ res: Response
+ data: any
+
+ constructor(msg: string, res: Response, data?: any) {
+ super(msg)
+ this.name = 'CommercetoolsApiError'
+ this.status = res.status
+ this.res = res
+ this.data = data
+ }
+}
+
+export class CommercetoolsNetworkError extends Error {
+ constructor(msg: string) {
+ super(msg)
+ this.name = 'CommercetoolsNetworkError'
+ }
+}
diff --git a/framework/commercetools/api/utils/fetch-graphql-api.ts b/framework/commercetools/api/utils/fetch-graphql-api.ts
new file mode 100644
index 000000000..579596aac
--- /dev/null
+++ b/framework/commercetools/api/utils/fetch-graphql-api.ts
@@ -0,0 +1,37 @@
+import { FetcherError } from '@commerce/utils/errors'
+import type { GraphQLFetcher } from '@commerce/api'
+import Commercetools from '@framework/utils/commercetools'
+import { provider } from '@framework/api'
+
+const fetchGraphqlApi: GraphQLFetcher = async (
+ query: string,
+ { variables } = {}
+) => {
+ const { config } = provider
+ const commercetools = Commercetools({
+ clientId: config.clientId,
+ clientSecret: config.clientSecret,
+ projectKey: config.projectKey,
+ host: config.host,
+ oauthHost: config.oauthHost,
+ concurrency: config.concurrency,
+ })
+ const { requestExecute } = commercetools
+ try {
+ const result = await requestExecute
+ .graphql()
+ .post({
+ body: {
+ query,
+ variables,
+ },
+ })
+ .execute()
+
+ return result.body
+ } catch (err) {
+ throw err
+ }
+}
+
+export default fetchGraphqlApi
diff --git a/framework/commercetools/api/utils/fetch-products.ts b/framework/commercetools/api/utils/fetch-products.ts
new file mode 100644
index 000000000..56501199b
--- /dev/null
+++ b/framework/commercetools/api/utils/fetch-products.ts
@@ -0,0 +1,33 @@
+import Commercetools from '@framework/utils/commercetools'
+import { provider } from '@framework/api'
+
+const fetchProducts = async (query?: any, isSearch?: boolean) => {
+ const { config } = provider
+ const commercetools = Commercetools({
+ clientId: config.clientId,
+ clientSecret: config.clientSecret,
+ projectKey: config.projectKey,
+ host: config.host,
+ oauthHost: config.oauthHost,
+ concurrency: config.concurrency,
+ })
+ const { requestExecute } = commercetools
+ try {
+ if (isSearch) {
+ return await requestExecute
+ .productProjections()
+ .search()
+ .get({ queryArgs: query })
+ .execute()
+ } else {
+ return await requestExecute
+ .productProjections()
+ .get({ queryArgs: query })
+ .execute()
+ }
+ } catch (err) {
+ throw err
+ }
+}
+
+export default fetchProducts
diff --git a/framework/commercetools/api/utils/fetch.ts b/framework/commercetools/api/utils/fetch.ts
new file mode 100644
index 000000000..9d9fff3ed
--- /dev/null
+++ b/framework/commercetools/api/utils/fetch.ts
@@ -0,0 +1,3 @@
+import zeitFetch from '@vercel/fetch'
+
+export default zeitFetch()
diff --git a/framework/commercetools/auth/index.ts b/framework/commercetools/auth/index.ts
new file mode 100644
index 000000000..6e321b17f
--- /dev/null
+++ b/framework/commercetools/auth/index.ts
@@ -0,0 +1,3 @@
+// export { default as useLogin } from './use-login'
+// export { default as useLogout } from './use-logout'
+// export { default as useSignup } from './use-signup'
diff --git a/framework/commercetools/auth/use-login.ts b/framework/commercetools/auth/use-login.ts
new file mode 100644
index 000000000..e69de29bb
diff --git a/framework/commercetools/auth/use-logout.ts b/framework/commercetools/auth/use-logout.ts
new file mode 100644
index 000000000..e69de29bb
diff --git a/framework/commercetools/auth/use-signup.ts b/framework/commercetools/auth/use-signup.ts
new file mode 100644
index 000000000..e69de29bb
diff --git a/framework/commercetools/cart/index.ts b/framework/commercetools/cart/index.ts
new file mode 100644
index 000000000..0782570b1
--- /dev/null
+++ b/framework/commercetools/cart/index.ts
@@ -0,0 +1,4 @@
+// export { default as useAddItem } from './use-add-item'
+// export { default as useCart } from './use-cart'
+// export { default as useRemoveItem } from './use-remove-item'
+// export { default as useUpdateItem } from './use-update-item'
diff --git a/framework/commercetools/cart/use-add-item.ts b/framework/commercetools/cart/use-add-item.ts
new file mode 100644
index 000000000..e69de29bb
diff --git a/framework/commercetools/cart/use-cart.ts b/framework/commercetools/cart/use-cart.ts
new file mode 100644
index 000000000..e69de29bb
diff --git a/framework/commercetools/cart/use-remove-item.ts b/framework/commercetools/cart/use-remove-item.ts
new file mode 100644
index 000000000..e69de29bb
diff --git a/framework/commercetools/cart/use-update-item.ts b/framework/commercetools/cart/use-update-item.ts
new file mode 100644
index 000000000..e69de29bb
diff --git a/framework/commercetools/commerce.config.json b/framework/commercetools/commerce.config.json
new file mode 100644
index 000000000..b40393a75
--- /dev/null
+++ b/framework/commercetools/commerce.config.json
@@ -0,0 +1,9 @@
+{
+ "provider": "commercetools",
+ "features": {
+ "wishlist": false,
+ "customer": false,
+ "cart": false,
+ "auth": false
+ }
+}
diff --git a/framework/commercetools/customer/index.ts b/framework/commercetools/customer/index.ts
new file mode 100644
index 000000000..89f003631
--- /dev/null
+++ b/framework/commercetools/customer/index.ts
@@ -0,0 +1 @@
+// export { default as useCustomer } from './use-customer'
diff --git a/framework/commercetools/customer/use-customer.ts b/framework/commercetools/customer/use-customer.ts
new file mode 100644
index 000000000..e69de29bb
diff --git a/framework/commercetools/fetcher.ts b/framework/commercetools/fetcher.ts
new file mode 100644
index 000000000..f8ca0c578
--- /dev/null
+++ b/framework/commercetools/fetcher.ts
@@ -0,0 +1,41 @@
+import { FetcherError } from '@commerce/utils/errors'
+import type { Fetcher } from '@commerce/utils/types'
+
+async function getText(res: Response) {
+ try {
+ return (await res.text()) || res.statusText
+ } catch (error) {
+ return res.statusText
+ }
+}
+
+async function getError(res: Response) {
+ if (res.headers.get('Content-Type')?.includes('application/json')) {
+ const data = await res.json()
+ return new FetcherError({ errors: data.errors, status: res.status })
+ }
+ return new FetcherError({ message: await getText(res), status: res.status })
+}
+
+const fetcher: Fetcher = async ({
+ url,
+ method = 'GET',
+ variables,
+ body: bodyObj,
+}) => {
+ const hasBody = Boolean(variables || bodyObj)
+ const body = hasBody
+ ? JSON.stringify(variables ? { variables } : bodyObj)
+ : undefined
+ const headers = hasBody ? { 'Content-Type': 'application/json' } : undefined
+ const res = await fetch(url!, { method, body, headers })
+
+ if (res.ok) {
+ const { data } = await res.json()
+ return data
+ }
+
+ throw await getError(res)
+}
+
+export default fetcher
diff --git a/framework/commercetools/index.tsx b/framework/commercetools/index.tsx
new file mode 100644
index 000000000..87c7bdae4
--- /dev/null
+++ b/framework/commercetools/index.tsx
@@ -0,0 +1,38 @@
+import type { ReactNode } from 'react'
+import {
+ CommerceConfig,
+ CommerceProvider as CoreCommerceProvider,
+ useCommerce as useCoreCommerce,
+} from '@commerce'
+import {
+ commercetoolsProvider,
+ CommercetoolsProvider,
+} from '@framework/provider'
+
+export { commercetoolsProvider }
+export type { CommercetoolsProvider }
+
+export const commercetoolsConfig: CommerceConfig = {
+ locale: 'en-US',
+ cartCookie: '',
+}
+
+export type CommercetoolsConfig = Partial
+
+export type CommercetoolsProps = {
+ children?: ReactNode
+ locale: string
+} & CommercetoolsConfig
+
+export function CommerceProvider({ children, ...config }: CommercetoolsProps) {
+ return (
+
+ {children}
+
+ )
+}
+
+export const useCommerce = () => useCoreCommerce()
diff --git a/framework/commercetools/lib/array-to-tree.ts b/framework/commercetools/lib/array-to-tree.ts
new file mode 100644
index 000000000..f220a4cbe
--- /dev/null
+++ b/framework/commercetools/lib/array-to-tree.ts
@@ -0,0 +1,70 @@
+export type HasParent = { id: string; parent?: { id: string } | null }
+export type TreeNode = T & {
+ children: Array>
+ expanded: boolean
+}
+export type RootNode = {
+ id?: string
+ children: Array>
+}
+
+export function arrayToTree(
+ nodes: T[],
+ currentState?: RootNode
+): RootNode {
+ const topLevelNodes: Array> = []
+ const mappedArr: { [id: string]: TreeNode } = {}
+ const currentStateMap = treeToMap(currentState)
+
+ // First map the nodes of the array to an object -> create a hash table.
+ for (const node of nodes) {
+ mappedArr[node.id] = { ...(node as any), children: [] }
+ }
+
+ for (const id of nodes.map((n) => n.id)) {
+ if (mappedArr.hasOwnProperty(id)) {
+ const mappedElem = mappedArr[id]
+ mappedElem.expanded = currentStateMap.get(id)?.expanded ?? false
+ const parent = mappedElem.parent
+ if (!parent) {
+ continue
+ }
+ // If the element is not at the root level, add it to its parent array of children.
+ const parentIsRoot = !mappedArr[parent.id]
+ if (!parentIsRoot) {
+ if (mappedArr[parent.id]) {
+ mappedArr[parent.id].children.push(mappedElem)
+ } else {
+ mappedArr[parent.id] = { children: [mappedElem] } as any
+ }
+ } else {
+ topLevelNodes.push(mappedElem)
+ }
+ }
+ }
+ // // tslint:disable-next-line:no-non-null-assertion
+ // const rootId = topLevelNodes.length ? topLevelNodes[0].id : undefined
+ // const children = topLevelNodes.length ? topLevelNodes[0].children : []
+ // return { id: "root", children: topLevelNodes }
+
+ return { children: topLevelNodes }
+}
+
+/**
+ * Converts an existing tree (as generated by the arrayToTree function) into a flat
+ * Map. This is used to persist certain states (e.g. `expanded`) when re-building the
+ * tree.
+ */
+function treeToMap(
+ tree?: RootNode
+): Map> {
+ const nodeMap = new Map>()
+ function visit(node: TreeNode) {
+ nodeMap.set(node.id, node)
+ node.children.forEach(visit)
+ }
+ if (tree) {
+ visit(tree as TreeNode)
+ }
+ return nodeMap
+}
diff --git a/framework/commercetools/lib/get-slug.ts b/framework/commercetools/lib/get-slug.ts
new file mode 100644
index 000000000..329c5a27e
--- /dev/null
+++ b/framework/commercetools/lib/get-slug.ts
@@ -0,0 +1,5 @@
+// Remove trailing and leading slash, usually included in nodes
+// returned by the BigCommerce API
+const getSlug = (path: string) => path.replace(/^\/|\/$/g, '')
+
+export default getSlug
diff --git a/framework/commercetools/lib/normalize.ts b/framework/commercetools/lib/normalize.ts
new file mode 100644
index 000000000..da3118adf
--- /dev/null
+++ b/framework/commercetools/lib/normalize.ts
@@ -0,0 +1,185 @@
+import type {
+ CommercetoolsProduct,
+ Product,
+ ProductVariant,
+ CommercetoolsProductVariant,
+ CommerceToolsProductPrice,
+ ProductPrice,
+} from '@framework/types/product'
+import type {
+ Cart,
+ CommercetoolsCart,
+ CommercetoolsLineItems,
+ LineItem,
+} from '@framework/types/cart'
+
+import type {
+ CommercetoolsBrands,
+ CommercetoolsCategory,
+ Category,
+ Brand,
+} from '@framework/types/site'
+
+import { arrayToTree } from '@framework/lib/array-to-tree'
+
+function normalizeVariants(
+ variants: CommercetoolsProductVariant[],
+ published: boolean
+): ProductVariant[] {
+ return variants.map((variant) => {
+ return {
+ id: variant.id,
+ options: [],
+ availableForSale: published,
+ }
+ })
+}
+
+function normalizePrice(price: CommerceToolsProductPrice): ProductPrice {
+ const value =
+ price.discounted && price.discounted.value
+ ? price.discounted.value.centAmount
+ : price.value.centAmount
+ return {
+ value: value / 100,
+ currencyCode: price.value.currencyCode,
+ retailPrice: 0,
+ salePrice: 0,
+ listPrice: 0,
+ extendedListPrice: 0,
+ extendedSalePrice: 0,
+ }
+}
+
+export function normalizeProduct(data: CommercetoolsProduct): Product {
+ return {
+ id: data.id,
+ name: data.name.en,
+ description:
+ data.description && data.description.en
+ ? data.description.en
+ : 'No description',
+ slug: data.slug.en,
+ path: data.slug.en,
+ images: data.masterVariant.images,
+ variants: normalizeVariants(data.variants, data.published),
+ options: [],
+ price: normalizePrice(
+ data.masterVariant.price
+ ? data.masterVariant.price
+ : data.masterVariant.prices[0]
+ ),
+ sku: data.masterVariant.sku,
+ }
+}
+
+function convertTaxMode(data: CommercetoolsCart): boolean {
+ return data && data.taxMode && data.taxMode === 'Disabled'
+ ? false
+ : data && data.taxMode
+ ? true
+ : false
+}
+export function normalizeCart(data: CommercetoolsCart): Cart {
+ const totalPrice =
+ data.taxedPrice &&
+ data.taxedPrice.totalGross &&
+ data.taxedPrice.totalGross.centAmount
+ ? data.taxedPrice.totalGross.centAmount / 100
+ : data.totalPrice.centAmount / 100
+ return {
+ id: data.id,
+ customerId: data.customerId,
+ email: data.customerEmail,
+ createdAt: data.createdAt,
+ currency: { code: data.totalPrice.currencyCode },
+ taxesIncluded: convertTaxMode(data),
+ lineItems: data.lineItems.map((item) => normalizeLineItem(item)),
+ lineItemsSubtotalPrice: 0,
+ subtotalPrice: 0,
+ totalPrice,
+ discounts: [],
+ }
+}
+
+function normalizeLineItem(item: CommercetoolsLineItems): LineItem {
+ const price =
+ item.price && item.price.value && item.price.value.centAmount
+ ? item.price.value.centAmount
+ : item.variant.prices[0].value.centAmount
+ return {
+ id: item.id,
+ variantId: item.variant.id,
+ productId: item.productId,
+ name: item.name,
+ quantity: item.quantity,
+ variant: {
+ id: item.variant.id,
+ sku: item.variant.sku,
+ name: item.variant.key,
+ image: {
+ url:
+ item.variant.images &&
+ item.variant.images[0] &&
+ item.variant.images[0].url
+ ? item.variant.images[0].url
+ : '',
+ width:
+ item.variant.images &&
+ item.variant.images[0] &&
+ item.variant.images[0].dimensions &&
+ item.variant.images[0].dimensions.w
+ ? item.variant.images[0].dimensions.w
+ : undefined,
+ height:
+ item.variant.images &&
+ item.variant.images[0] &&
+ item.variant.images[0].dimensions &&
+ item.variant.images[0].dimensions.h
+ ? item.variant.images[0].dimensions.h
+ : undefined,
+ },
+ requiresShipping: false,
+ price: price / 100,
+ listPrice: 0,
+ },
+ path: item.productSlug,
+ discounts: [],
+ }
+}
+
+type Site = { categories: any[]; brands: Brand[] }
+
+export function normalizeSite(
+ ctCategories: CommercetoolsCategory[],
+ ctBrands: CommercetoolsBrands[]
+): Site {
+ const categories = ctCategories.map((ctCategory) => {
+ return {
+ id: ctCategory.id,
+ // TODO: TEC-264 we need to handle locale properly
+ name: ctCategory.name,
+ slug: ctCategory.slug,
+ path: ctCategory.slug,
+ //add a random parentId to add in children array
+ parent: ctCategory.parent ? ctCategory.parent : { id: 'idRoot' },
+ }
+ })
+
+ const treeCategories = arrayToTree(categories).children
+
+ const brands = ctBrands.map((ctBrand) => {
+ return {
+ node: {
+ name: ctBrand.label,
+ path: `brands/${ctBrand.key}`,
+ entityId: ctBrand.key,
+ },
+ }
+ })
+
+ return {
+ categories: treeCategories,
+ brands,
+ }
+}
diff --git a/framework/commercetools/next.config.js b/framework/commercetools/next.config.js
new file mode 100644
index 000000000..06887bece
--- /dev/null
+++ b/framework/commercetools/next.config.js
@@ -0,0 +1,8 @@
+const commerce = require('./commerce.config.json')
+
+module.exports = {
+ commerce,
+ images: {
+ domains: ['s3-eu-west-1.amazonaws.com'],
+ },
+}
diff --git a/framework/commercetools/product/index.ts b/framework/commercetools/product/index.ts
new file mode 100644
index 000000000..426a3edcd
--- /dev/null
+++ b/framework/commercetools/product/index.ts
@@ -0,0 +1,2 @@
+export { default as usePrice } from './use-price'
+export { default as useSearch } from './use-search'
diff --git a/framework/commercetools/product/use-price.ts b/framework/commercetools/product/use-price.ts
new file mode 100644
index 000000000..0174faf5e
--- /dev/null
+++ b/framework/commercetools/product/use-price.ts
@@ -0,0 +1,2 @@
+export * from '@commerce/product/use-price'
+export { default } from '@commerce/product/use-price'
diff --git a/framework/commercetools/product/use-search.ts b/framework/commercetools/product/use-search.ts
new file mode 100644
index 000000000..873974bb5
--- /dev/null
+++ b/framework/commercetools/product/use-search.ts
@@ -0,0 +1,54 @@
+import { SWRHook } from '@commerce/utils/types'
+import useSearch, { UseSearch } from '@commerce/product/use-search'
+import { Product } from '@commerce/types/product'
+import type { SearchProductsHook } from '../../commerce/types/product'
+
+export default useSearch as UseSearch
+
+export type SearchProductsInput = {
+ search?: string
+ categoryId?: string
+ brandId?: string
+ sort?: string
+ locale?: string
+}
+
+export type SearchProductsData = {
+ products: Product[]
+ found: boolean
+}
+
+export const handler: SWRHook = {
+ fetchOptions: {
+ url: 'api/catalog/products',
+ method: 'GET',
+ },
+ async fetcher({ input, options, fetch }) {
+ const { search, categoryId, brandId, sort } = input
+ const url = new URL(options.url!, 'http://a')
+
+ if (search) url.searchParams.set('search', search)
+ if (categoryId) url.searchParams.set('categoryId', String(categoryId))
+ if (brandId) url.searchParams.set('brandId', String(brandId))
+ if (sort) url.searchParams.set('sort', sort)
+
+ return await fetch({
+ url: url.pathname + url.search,
+ method: options.method,
+ })
+ },
+ useHook: ({ useData }) => (input = {}) => {
+ return useData({
+ input: [
+ ['search', input.search],
+ ['categoryId', input.categoryId],
+ ['brandId', input.brandId],
+ ['sort', input.sort],
+ ],
+ swrOptions: {
+ revalidateOnFocus: false,
+ ...input.swrOptions,
+ },
+ })
+ },
+}
diff --git a/framework/commercetools/provider.ts b/framework/commercetools/provider.ts
new file mode 100644
index 000000000..525fd7549
--- /dev/null
+++ b/framework/commercetools/provider.ts
@@ -0,0 +1,24 @@
+import { Provider } from '@commerce'
+// import { handler as useCart } from './cart/use-cart'
+// import { handler as useAddItem } from './cart/use-add-item'
+// import { handler as useUpdateItem } from './cart/use-update-item'
+// import { handler as useRemoveItem } from './cart/use-remove-item'
+// import { handler as useCustomer } from './customer/use-customer'
+import { handler as useSearch } from './product/use-search'
+// import { handler as useLogin } from './auth/use-login'
+// import { handler as useLogout } from './auth/use-logout'
+// import { handler as useSignup } from './auth/use-signup'
+import fetcher from './fetcher'
+
+// Export a provider with the CommerceHooks
+export const commercetoolsProvider: Provider = {
+ locale: 'en-us',
+ cartCookie: 'session',
+ fetcher,
+ // cart: { useCart, useAddItem, useUpdateItem, useRemoveItem },
+ // customer: { useCustomer },
+ products: { useSearch },
+ // auth: { useLogin, useLogout, useSignup }
+}
+
+export type CommercetoolsProvider = typeof commercetoolsProvider
diff --git a/framework/commercetools/types/cart.ts b/framework/commercetools/types/cart.ts
new file mode 100644
index 000000000..ef27465f2
--- /dev/null
+++ b/framework/commercetools/types/cart.ts
@@ -0,0 +1,103 @@
+import * as Core from '@commerce/types/cart'
+import * as Products from './product'
+export * from '@commerce/types/cart'
+// TODO: this type should match:
+// https://developer.bigcommerce.com/api-reference/cart-checkout/server-server-cart-api/cart/getacart#responses
+export type CommercetoolsCart = {
+ id: string
+ version: number
+ customerId: string
+ customerEmail: string
+ createdAt: string
+ lastModifiedAt: string
+ lineItems: CommercetoolsLineItems[]
+ totalPrice: {
+ currencyCode: string
+ centAmount: number
+ }
+ cartState: string
+ inventoryMode: string
+ taxMode: string
+ taxRoundingMode: string
+ taxedPrice?: TaxedItemPrice
+ discountCodes: discountCodes[]
+}
+export type TaxedItemPrice = {
+ totalNet: Products.Money
+ totalGross: Products.Money
+}
+export type CommercetoolsLineItems = {
+ id: string
+ productId: string
+ productSlug: Products.LocalString
+ name: {
+ en: string
+ }
+ variant: Products.CommercetoolsProductVariant
+ price: Products.CommerceToolsProductPrice
+ totalPrice: totalPrice
+ quantity: number
+ state: {
+ quantity: number
+ state: {
+ id: string
+ key: string
+ version: number
+ createdAt: string
+ lastModifiedAt: string
+ }
+ }
+ priceMode: string
+}
+export type discountCodes = {
+ discountCode: {
+ id: string
+ version: number
+ createdAt: string
+ lastModifiedAt: string
+ code: string
+ cartDiscounts: {
+ id: string
+ version: number
+ createdAt: string
+ lastModifiedAt: string
+ name: string
+ isActive: boolean
+ }
+ }
+}
+export type totalPrice = {
+ currencyCode: string
+ centAmount: number
+}
+/**
+ * Extend core cart types
+ */
+export type Cart = Core.Cart & {
+ lineItems: Core.LineItem[]
+}
+export type LineItem = Core.LineItem
+export type OptionSelections = {
+ option_id: number
+ option_value: number | string
+}
+export type CartItemBody = Core.CartItemBody & {
+ productId: string // The product id is always required for BC
+ optionSelections?: OptionSelections
+}
+export type CartTypes = {
+ cart: Cart
+ item: Core.LineItem
+ itemBody: CartItemBody
+}
+export type CartHooks = Core.CartHooks
+export type GetCartHook = CartHooks['getCart']
+export type AddItemHook = CartHooks['addItem']
+export type UpdateItemHook = CartHooks['updateItem']
+export type RemoveItemHook = CartHooks['removeItem']
+export type CartSchema = Core.CartSchema
+export type CartHandlers = Core.CartHandlers
+export type GetCartHandler = CartHandlers['getCart']
+export type AddItemHandler = CartHandlers['addItem']
+export type UpdateItemHandler = CartHandlers['updateItem']
+export type RemoveItemHandler = CartHandlers['removeItem']
diff --git a/framework/commercetools/types/checkout.ts b/framework/commercetools/types/checkout.ts
new file mode 100644
index 000000000..4e2412ef6
--- /dev/null
+++ b/framework/commercetools/types/checkout.ts
@@ -0,0 +1 @@
+export * from '@commerce/types/checkout'
diff --git a/framework/commercetools/types/common.ts b/framework/commercetools/types/common.ts
new file mode 100644
index 000000000..b52c33a4d
--- /dev/null
+++ b/framework/commercetools/types/common.ts
@@ -0,0 +1 @@
+export * from '@commerce/types/common'
diff --git a/framework/commercetools/types/customer.ts b/framework/commercetools/types/customer.ts
new file mode 100644
index 000000000..75cee4531
--- /dev/null
+++ b/framework/commercetools/types/customer.ts
@@ -0,0 +1,20 @@
+import * as Core from '@commerce/types/customer'
+
+export * from '@commerce/types/customer'
+
+export type Customers = {
+ id: string
+ version: number
+ createdAt: string
+ lastModifiedAt: string
+ email: string
+ password: string
+ isEmailVerified: boolean
+}
+
+// get Customer
+export type GetCustomerById = {
+ id: string
+}
+
+export type CustomerSchema = Core.CustomerSchema
diff --git a/framework/commercetools/types/index.ts b/framework/commercetools/types/index.ts
new file mode 100644
index 000000000..7ab0b7f64
--- /dev/null
+++ b/framework/commercetools/types/index.ts
@@ -0,0 +1,25 @@
+import * as Cart from './cart'
+import * as Checkout from './checkout'
+import * as Common from './common'
+import * as Customer from './customer'
+import * as Login from './login'
+import * as Logout from './logout'
+import * as Page from './page'
+import * as Product from './product'
+import * as Signup from './signup'
+import * as Site from './site'
+import * as Wishlist from './wishlist'
+
+export type {
+ Cart,
+ Checkout,
+ Common,
+ Customer,
+ Login,
+ Logout,
+ Page,
+ Product,
+ Signup,
+ Site,
+ Wishlist,
+}
diff --git a/framework/commercetools/types/login.ts b/framework/commercetools/types/login.ts
new file mode 100644
index 000000000..db536076f
--- /dev/null
+++ b/framework/commercetools/types/login.ts
@@ -0,0 +1,13 @@
+import * as Core from '@commerce/types/login'
+import type { LoginMutationVariables } from '../schema'
+
+export * from '@commerce/types/login'
+
+export type CommercetoolsLogin = {
+ email: string
+ password: string
+}
+
+export type LoginOperation = Core.LoginOperation & {
+ variables: LoginMutationVariables
+}
diff --git a/framework/commercetools/types/logout.ts b/framework/commercetools/types/logout.ts
new file mode 100644
index 000000000..9f0a466af
--- /dev/null
+++ b/framework/commercetools/types/logout.ts
@@ -0,0 +1 @@
+export * from '@commerce/types/logout'
diff --git a/framework/commercetools/types/page.ts b/framework/commercetools/types/page.ts
new file mode 100644
index 000000000..2bccfade2
--- /dev/null
+++ b/framework/commercetools/types/page.ts
@@ -0,0 +1,11 @@
+import * as Core from '@commerce/types/page'
+export * from '@commerce/types/page'
+
+export type Page = Core.Page
+
+export type PageTypes = {
+ page: Page
+}
+
+export type GetAllPagesOperation = Core.GetAllPagesOperation
+export type GetPageOperation = Core.GetPageOperation
diff --git a/framework/commercetools/types/product.ts b/framework/commercetools/types/product.ts
new file mode 100644
index 000000000..f304e3aa3
--- /dev/null
+++ b/framework/commercetools/types/product.ts
@@ -0,0 +1,66 @@
+import * as Core from '@commerce/types/product'
+export type CommercetoolsProduct = {
+ id: string
+ name: LocalString
+ description: LocalString
+ slug: LocalString
+ metaDescription: LocalString
+ masterVariant: CommercetoolsProductVariant
+ variants: CommercetoolsProductVariant[]
+ published: boolean
+}
+export type CommercetoolsProductVariant = {
+ id: string
+ key: string
+ sku: string
+ images: Images[]
+ price?: CommerceToolsProductPrice
+ prices: CommerceToolsProductPrice[]
+ attributes: ProductAttributes[]
+}
+export type ProductAttributes = {
+ name: string
+ value: string | AttributeDefinition | boolean | number
+}
+export type AttributeDefinition = {
+ key: string
+ label: string
+}
+export type Images = {
+ url: string
+ dimensions: {
+ w: number
+ h: number
+ }
+}
+export type CommerceToolsProductPrice = {
+ id: string
+ value: Money
+ discounted: DiscountedPrice
+}
+export type DiscountedPrice = {
+ value: Money
+}
+export type Money = {
+ type: string
+ currencyCode: string
+ centAmount: number
+ fractionDigits: number
+}
+export type LocalString = {
+ en: string
+ 'es-AR': string
+ 'es-CL': string
+ 'es-PE': string
+ de: string
+}
+// get Product
+export type GetProductById = {
+ id: string
+}
+export type Product = Core.Product
+export type ProductVariant = Core.ProductVariant
+export type ProductPrice = Core.ProductPrice
+export type ProductOption = Core.ProductOption
+export type ProductOptionValue = Core.ProductOptionValues
+export type ProductImage = Core.ProductImage
diff --git a/framework/commercetools/types/signup.ts b/framework/commercetools/types/signup.ts
new file mode 100644
index 000000000..58543c6f6
--- /dev/null
+++ b/framework/commercetools/types/signup.ts
@@ -0,0 +1 @@
+export * from '@commerce/types/signup'
diff --git a/framework/commercetools/types/site.ts b/framework/commercetools/types/site.ts
new file mode 100644
index 000000000..0fbafdfe9
--- /dev/null
+++ b/framework/commercetools/types/site.ts
@@ -0,0 +1,13 @@
+import * as Core from '@commerce/types/site'
+export type CommercetoolsCategory = {
+ id: string
+ name: string
+ slug: string
+ parent: { id: string }
+}
+export type CommercetoolsBrands = {
+ key: string
+ label?: string
+}
+export type Brand = Core.Brand
+export type Category = Core.Category
diff --git a/framework/commercetools/types/wishlist.ts b/framework/commercetools/types/wishlist.ts
new file mode 100644
index 000000000..1e148b88c
--- /dev/null
+++ b/framework/commercetools/types/wishlist.ts
@@ -0,0 +1,23 @@
+import * as Core from '@commerce/types/wishlist'
+import { definitions } from '../api/definitions/wishlist'
+import type { ProductEdge } from '../api/operations/get-all-products'
+
+export * from '@commerce/types/wishlist'
+
+export type WishlistItem = NonNullable<
+ definitions['wishlist_Full']['items']
+>[0] & {
+ product?: ProductEdge['node']
+}
+
+export type Wishlist = Omit & {
+ items?: WishlistItem[]
+}
+
+export type WishlistTypes = {
+ wishlist: Wishlist
+ itemBody: Core.WishlistItemBody
+}
+
+export type WishlistSchema = Core.WishlistSchema
+export type GetCustomerWishlistOperation = Core.GetCustomerWishlistOperation
diff --git a/framework/commercetools/utils/commercetools/index.ts b/framework/commercetools/utils/commercetools/index.ts
new file mode 100644
index 000000000..a80b47aea
--- /dev/null
+++ b/framework/commercetools/utils/commercetools/index.ts
@@ -0,0 +1,51 @@
+import { createAuthMiddlewareForClientCredentialsFlow } from '@commercetools/sdk-middleware-auth'
+import { createHttpMiddleware } from '@commercetools/sdk-middleware-http'
+import { createQueueMiddleware } from '@commercetools/sdk-middleware-queue'
+import { createClient } from '@commercetools/sdk-client'
+import { createApiBuilderFromCtpClient } from '@commercetools/platform-sdk'
+import fetch from 'node-fetch'
+
+interface Props {
+ clientId: string
+ clientSecret: string
+ projectKey: string
+ host: string
+ oauthHost: string
+ concurrency: string | number
+}
+
+export default ({
+ clientId,
+ clientSecret,
+ projectKey,
+ host,
+ oauthHost,
+ concurrency = 10,
+}: Props) => {
+ interface Commercetools {
+ requestExecute: any
+ }
+
+ const ctpClient = createClient({
+ middlewares: [
+ createAuthMiddlewareForClientCredentialsFlow({
+ host: oauthHost,
+ projectKey,
+ credentials: {
+ clientId,
+ clientSecret,
+ },
+ fetch,
+ }),
+ createQueueMiddleware({ concurrency }),
+ createHttpMiddleware({ host, fetch }),
+ ],
+ })
+
+ const apiRoot = createApiBuilderFromCtpClient(ctpClient)
+ const commercetools = {
+ requestExecute: apiRoot.withProjectKey({ projectKey }),
+ }
+
+ return commercetools
+}
diff --git a/framework/commercetools/utils/queries/get-category.ts b/framework/commercetools/utils/queries/get-category.ts
new file mode 100644
index 000000000..b681ac4bc
--- /dev/null
+++ b/framework/commercetools/utils/queries/get-category.ts
@@ -0,0 +1,29 @@
+export const getAllCategoriesAndBrandsQuery = /* GraphQL */ `
+ query getCategoriesAndBrands {
+ categories {
+ results {
+ id
+ name(locale: "en")
+ slug(locale: "en")
+ }
+ }
+ productTypes {
+ results {
+ attributeDefinitions(includeNames: "designer") {
+ results {
+ type {
+ ... on EnumAttributeDefinitionType {
+ values {
+ results {
+ key
+ label
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+`
diff --git a/framework/commercetools/utils/queries/get-product-query.ts b/framework/commercetools/utils/queries/get-product-query.ts
new file mode 100644
index 000000000..138a9940e
--- /dev/null
+++ b/framework/commercetools/utils/queries/get-product-query.ts
@@ -0,0 +1,30 @@
+const getProductQuery =
+ /* GraphQL */
+ `
+ query getProductQuery($id: String!, $locale: Locale) {
+ product(id: $id) {
+ id
+ masterData {
+ current {
+ name(locale: $locale)
+ metaDescription(locale: $locale)
+ slug(locale: $locale)
+ masterVariant {
+ prices {
+ value {
+ centAmount
+ currencyCode
+ }
+ }
+ sku
+ images {
+ url
+ }
+ }
+ }
+ }
+ }
+ }
+ `
+
+export default getProductQuery
diff --git a/framework/commercetools/wishlist/index.ts b/framework/commercetools/wishlist/index.ts
new file mode 100644
index 000000000..6493beb1b
--- /dev/null
+++ b/framework/commercetools/wishlist/index.ts
@@ -0,0 +1,3 @@
+// export { default as useAddItem } from './use-add-item'
+// export { default as useWishlist } from './use-wishlist'
+// export { default as useRemoveItem } from './use-remove-item'
diff --git a/framework/commercetools/wishlist/use-add-item.ts b/framework/commercetools/wishlist/use-add-item.ts
new file mode 100644
index 000000000..e69de29bb
diff --git a/framework/commercetools/wishlist/use-remove-item.ts b/framework/commercetools/wishlist/use-remove-item.ts
new file mode 100644
index 000000000..e69de29bb
diff --git a/framework/commercetools/wishlist/use-wishlist.ts b/framework/commercetools/wishlist/use-wishlist.ts
new file mode 100644
index 000000000..e69de29bb
diff --git a/global.d.ts b/global.d.ts
index 498a1f9fe..3826995f3 100644
--- a/global.d.ts
+++ b/global.d.ts
@@ -1,2 +1,6 @@
// Declarations for modules without types
declare module 'next-themes'
+declare module '@commercetools/sdk-middleware-auth'
+declare module '@commercetools/sdk-middleware-http'
+declare module '@commercetools/sdk-middleware-queue'
+declare module '@commercetools/sdk-client'
diff --git a/package.json b/package.json
index 85daa3158..6bb23b15f 100644
--- a/package.json
+++ b/package.json
@@ -19,6 +19,11 @@
"node": "14.x"
},
"dependencies": {
+ "@commercetools/platform-sdk": "^1.13.0",
+ "@commercetools/sdk-client": "^2.1.2",
+ "@commercetools/sdk-middleware-auth": "^6.1.4",
+ "@commercetools/sdk-middleware-http": "^6.0.11",
+ "@commercetools/sdk-middleware-queue": "^2.1.4",
"@reach/portal": "^0.11.2",
"@vercel/fetch": "^6.1.0",
"autoprefixer": "^10.2.4",
diff --git a/tsconfig.json b/tsconfig.json
index 96e4359e5..1d19b894e 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -22,8 +22,8 @@
"@components/*": ["components/*"],
"@commerce": ["framework/commerce"],
"@commerce/*": ["framework/commerce/*"],
- "@framework": ["framework/shopify"],
- "@framework/*": ["framework/shopify/*"]
+ "@framework": ["framework/commercetools"],
+ "@framework/*": ["framework/commercetools/*"]
}
},
"include": ["next-env.d.ts", "**/*.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"],
diff --git a/yarn.lock b/yarn.lock
index 1b1fce30e..d67d19b03 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -464,6 +464,43 @@
lodash "^4.17.13"
to-fast-properties "^2.0.0"
+"@commercetools/platform-sdk@^1.13.0":
+ version "1.14.0"
+ resolved "https://registry.yarnpkg.com/@commercetools/platform-sdk/-/platform-sdk-1.14.0.tgz#7e5410eb7ff56d8ed3a5422dccdac67bbd2e6156"
+ integrity sha512-JclsCi0H8VpR3rwt5ZVHXXKGLCy56UwM6RkB3esuxTYarg3p5sMDXVRiCUchoSyr1rScf4/ksjO3mNzKxEPd5g==
+ dependencies:
+ "@commercetools/sdk-client" "^2.1.1"
+ "@commercetools/sdk-middleware-auth" "^6.0.4"
+ "@commercetools/sdk-middleware-http" "^6.0.4"
+ "@commercetools/sdk-middleware-logger" "^2.1.1"
+
+"@commercetools/sdk-client@^2.1.1", "@commercetools/sdk-client@^2.1.2":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/@commercetools/sdk-client/-/sdk-client-2.1.2.tgz#fe1e442f67a385f103470669784c0fa20d7a2314"
+ integrity sha512-YPpK39pkjfedjS1/BFg2d7CrvTeN7vIS5vfiqEkKOtAoUxiNkugv59gRSoh2Em8SOccxyM/skpgHyTqfmJzXug==
+
+"@commercetools/sdk-middleware-auth@^6.0.4", "@commercetools/sdk-middleware-auth@^6.1.4":
+ version "6.1.4"
+ resolved "https://registry.yarnpkg.com/@commercetools/sdk-middleware-auth/-/sdk-middleware-auth-6.1.4.tgz#c5f464ae1627336715681e4590b63777e034c890"
+ integrity sha512-49R1DWsA+pNHH7/2K6QU5wnJSXabljKA8dvzs5HcbLwutlDp3Io0XHgIJa9qpfYhgW6k0h9dPICcLbESrQBXYw==
+ dependencies:
+ node-fetch "^2.3.0"
+
+"@commercetools/sdk-middleware-http@^6.0.11", "@commercetools/sdk-middleware-http@^6.0.4":
+ version "6.0.11"
+ resolved "https://registry.yarnpkg.com/@commercetools/sdk-middleware-http/-/sdk-middleware-http-6.0.11.tgz#0ca16cefe881b68c1d2b77ddbd3a48733a5ee062"
+ integrity sha512-9Keb5rv6fvdA9qdehBEjk/JMrAzlBbg76TodsvhCZZZteaO0+ybjFgtV0ekdGyI4awxOxgsiPDZrTmQNvnI5Wg==
+
+"@commercetools/sdk-middleware-logger@^2.1.1":
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/@commercetools/sdk-middleware-logger/-/sdk-middleware-logger-2.1.1.tgz#9283fdc8c403a7e2d4d06637e6015770b864e64a"
+ integrity sha512-k/Jm3lsWbszPBHtPAvu0rINTq398p4ddv0zbAH8R4p6Yc1GkBEy6tNgHPzX/eFskI/qerPy9IsW1xK8pqgtHHQ==
+
+"@commercetools/sdk-middleware-queue@^2.1.4":
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/@commercetools/sdk-middleware-queue/-/sdk-middleware-queue-2.1.4.tgz#d8b162ff83fc553cc5abef8599571389874983d6"
+ integrity sha512-8TxeUb+jdSemUt/wd9hEcPl2uK2sTRPd5BEwXzOYAlyQJBXMMju2GMo5ASDWz7xjKLoijEuY86Jo7D9JSP8DPQ==
+
"@csstools/convert-colors@^1.4.0":
version "1.4.0"
resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7"
@@ -4486,7 +4523,7 @@ node-emoji@^1.8.1:
dependencies:
lodash.toarray "^4.4.0"
-node-fetch@2.6.1, node-fetch@^2.6.1:
+node-fetch@2.6.1, node-fetch@^2.3.0, node-fetch@^2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==