diff --git a/.env.template b/.env.template
index cf58e89c7..8685fd41d 100644
--- a/.env.template
+++ b/.env.template
@@ -1,4 +1,4 @@
-# Available providers: local, bigcommerce, shopify, swell, saleor, spree, ordercloud, vendure, kibocommerce, commercejs
+# Available providers: bigcommerce, shopify, swell, commercelayer
COMMERCE_PROVIDER=
BIGCOMMERCE_STOREFRONT_API_URL=
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 000000000..1e3e664b2
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,15 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "type": "pwa-msedge",
+ "request": "launch",
+ "name": "Launch Edge against localhost",
+ "url": "http://localhost:3000",
+ "webRoot": "${workspaceFolder}"
+ }
+ ]
+}
diff --git a/framework/commercelayer/.env.template b/framework/commercelayer/.env.template
new file mode 100644
index 000000000..46725853b
--- /dev/null
+++ b/framework/commercelayer/.env.template
@@ -0,0 +1,5 @@
+COMMERCE_PROVIDER=commercelayer
+
+COMMERCELAYER_CLIENT_ID=
+COMMERCELAYER_ENDPOINT=
+COMMERCELAYER_MARKET_SCOPE=
\ No newline at end of file
diff --git a/framework/commercelayer/README.md b/framework/commercelayer/README.md
new file mode 100644
index 000000000..82789aed5
--- /dev/null
+++ b/framework/commercelayer/README.md
@@ -0,0 +1,23 @@
+# Commerce Layer Provider
+
+⚠️ Please note that this provider is still a work in progress.
+
+Before getting started, you should do the following:
+
+- Create a Commerce Layer [developer account](https://commercelayer.io).
+- Create a new [organization](https://commercelayer.io/docs/data-model/users-and-organizations/) for your business.
+- Create an application with `sales_channel` kind.
+
+Next, copy the `.env.template` file in this directory to `.env.local` in the main directory (which will be ignored by Git):
+
+```bash
+cp framework/commercelayer/.env.template .env.local
+```
+
+Next, add the application credentials from your organization application dashboard in `.env.local`.
+
+## Contribute
+
+Our commitment to Open Source can be found [here](https://vercel.com/oss).
+
+If you find an issue with the provider or want a new feature, feel free to open a PR or [create a new issue](https://github.com/vercel/commerce/issues).
\ No newline at end of file
diff --git a/framework/commercelayer/api/endpoints/cart/index.ts b/framework/commercelayer/api/endpoints/cart/index.ts
new file mode 100644
index 000000000..491bf0ac9
--- /dev/null
+++ b/framework/commercelayer/api/endpoints/cart/index.ts
@@ -0,0 +1 @@
+export default function noopApi(...args: any[]): void {}
diff --git a/framework/commercelayer/api/endpoints/catalog/index.ts b/framework/commercelayer/api/endpoints/catalog/index.ts
new file mode 100644
index 000000000..491bf0ac9
--- /dev/null
+++ b/framework/commercelayer/api/endpoints/catalog/index.ts
@@ -0,0 +1 @@
+export default function noopApi(...args: any[]): void {}
diff --git a/framework/commercelayer/api/endpoints/catalog/products.ts b/framework/commercelayer/api/endpoints/catalog/products.ts
new file mode 100644
index 000000000..491bf0ac9
--- /dev/null
+++ b/framework/commercelayer/api/endpoints/catalog/products.ts
@@ -0,0 +1 @@
+export default function noopApi(...args: any[]): void {}
diff --git a/framework/commercelayer/api/endpoints/checkout/index.ts b/framework/commercelayer/api/endpoints/checkout/index.ts
new file mode 100644
index 000000000..491bf0ac9
--- /dev/null
+++ b/framework/commercelayer/api/endpoints/checkout/index.ts
@@ -0,0 +1 @@
+export default function noopApi(...args: any[]): void {}
diff --git a/framework/commercelayer/api/endpoints/customer/index.ts b/framework/commercelayer/api/endpoints/customer/index.ts
new file mode 100644
index 000000000..491bf0ac9
--- /dev/null
+++ b/framework/commercelayer/api/endpoints/customer/index.ts
@@ -0,0 +1 @@
+export default function noopApi(...args: any[]): void {}
diff --git a/framework/commercelayer/api/endpoints/login/index.ts b/framework/commercelayer/api/endpoints/login/index.ts
new file mode 100644
index 000000000..491bf0ac9
--- /dev/null
+++ b/framework/commercelayer/api/endpoints/login/index.ts
@@ -0,0 +1 @@
+export default function noopApi(...args: any[]): void {}
diff --git a/framework/commercelayer/api/endpoints/logout/index.ts b/framework/commercelayer/api/endpoints/logout/index.ts
new file mode 100644
index 000000000..491bf0ac9
--- /dev/null
+++ b/framework/commercelayer/api/endpoints/logout/index.ts
@@ -0,0 +1 @@
+export default function noopApi(...args: any[]): void {}
diff --git a/framework/commercelayer/api/endpoints/signup/index.ts b/framework/commercelayer/api/endpoints/signup/index.ts
new file mode 100644
index 000000000..491bf0ac9
--- /dev/null
+++ b/framework/commercelayer/api/endpoints/signup/index.ts
@@ -0,0 +1 @@
+export default function noopApi(...args: any[]): void {}
diff --git a/framework/commercelayer/api/endpoints/wishlist/index.tsx b/framework/commercelayer/api/endpoints/wishlist/index.tsx
new file mode 100644
index 000000000..491bf0ac9
--- /dev/null
+++ b/framework/commercelayer/api/endpoints/wishlist/index.tsx
@@ -0,0 +1 @@
+export default function noopApi(...args: any[]): void {}
diff --git a/framework/commercelayer/api/index.ts b/framework/commercelayer/api/index.ts
new file mode 100644
index 000000000..9f403d2b3
--- /dev/null
+++ b/framework/commercelayer/api/index.ts
@@ -0,0 +1,42 @@
+import type { CommerceAPI, CommerceAPIConfig } from '@commerce/api'
+import { getCommerceApi as commerceApi } from '@commerce/api'
+import createFetcher from './utils/fetch-local'
+
+import getAllPages from './operations/get-all-pages'
+import getPage from './operations/get-page'
+import getSiteInfo from './operations/get-site-info'
+import getCustomerWishlist from './operations/get-customer-wishlist'
+import getAllProductPaths from './operations/get-all-product-paths'
+import getAllProducts from './operations/get-all-products'
+import getProduct from './operations/get-product'
+
+export interface LocalConfig extends CommerceAPIConfig {}
+const config: LocalConfig = {
+ commerceUrl: '',
+ apiToken: '',
+ cartCookie: '',
+ customerCookie: '',
+ cartCookieMaxAge: 2592000,
+ fetch: createFetcher(() => getCommerceApi().getConfig()),
+}
+
+const operations = {
+ getAllPages,
+ getPage,
+ getSiteInfo,
+ getCustomerWishlist,
+ getAllProductPaths,
+ getAllProducts,
+ getProduct,
+}
+
+export const provider = { config, operations }
+
+export type Provider = typeof provider
+export type LocalAPI
= CommerceAPI
+
+export function getCommerceApi
(
+ customProvider: P = provider as any
+): LocalAPI
{
+ return commerceApi(customProvider as any)
+}
diff --git a/framework/commercelayer/api/operations/get-all-pages.ts b/framework/commercelayer/api/operations/get-all-pages.ts
new file mode 100644
index 000000000..b258fe70a
--- /dev/null
+++ b/framework/commercelayer/api/operations/get-all-pages.ts
@@ -0,0 +1,19 @@
+export type Page = { url: string }
+export type GetAllPagesResult = { pages: Page[] }
+import type { LocalConfig } from '../index'
+
+export default function getAllPagesOperation() {
+ function getAllPages({
+ config,
+ preview,
+ }: {
+ url?: string
+ config?: Partial
+ preview?: boolean
+ }): Promise {
+ return Promise.resolve({
+ pages: [],
+ })
+ }
+ return getAllPages
+}
diff --git a/framework/commercelayer/api/operations/get-all-product-paths.ts b/framework/commercelayer/api/operations/get-all-product-paths.ts
new file mode 100644
index 000000000..fff24e791
--- /dev/null
+++ b/framework/commercelayer/api/operations/get-all-product-paths.ts
@@ -0,0 +1,15 @@
+import data from '../../data.json'
+
+export type GetAllProductPathsResult = {
+ products: Array<{ path: string }>
+}
+
+export default function getAllProductPathsOperation() {
+ function getAllProductPaths(): Promise {
+ return Promise.resolve({
+ products: data.products.map(({ path }) => ({ path })),
+ })
+ }
+
+ return getAllProductPaths
+}
diff --git a/framework/commercelayer/api/operations/get-all-products.ts b/framework/commercelayer/api/operations/get-all-products.ts
new file mode 100644
index 000000000..21a04559d
--- /dev/null
+++ b/framework/commercelayer/api/operations/get-all-products.ts
@@ -0,0 +1,25 @@
+import { Product } from '@commerce/types/product'
+import { GetAllProductsOperation } from '@commerce/types/product'
+import type { OperationContext } from '@commerce/api/operations'
+import type { LocalConfig, Provider } from '../index'
+import data from '../../data.json'
+
+export default function getAllProductsOperation({
+ commerce,
+}: OperationContext) {
+ async function getAllProducts({
+ query = '',
+ variables,
+ config,
+ }: {
+ query?: string
+ variables?: T['variables']
+ config?: Partial
+ preview?: boolean
+ } = {}): Promise<{ products: Product[] | any[] }> {
+ return {
+ products: data.products,
+ }
+ }
+ return getAllProducts
+}
diff --git a/framework/commercelayer/api/operations/get-customer-wishlist.ts b/framework/commercelayer/api/operations/get-customer-wishlist.ts
new file mode 100644
index 000000000..8c34b9e87
--- /dev/null
+++ b/framework/commercelayer/api/operations/get-customer-wishlist.ts
@@ -0,0 +1,6 @@
+export default function getCustomerWishlistOperation() {
+ function getCustomerWishlist(): any {
+ return { wishlist: {} }
+ }
+ return getCustomerWishlist
+}
diff --git a/framework/commercelayer/api/operations/get-page.ts b/framework/commercelayer/api/operations/get-page.ts
new file mode 100644
index 000000000..b0cfdf58f
--- /dev/null
+++ b/framework/commercelayer/api/operations/get-page.ts
@@ -0,0 +1,13 @@
+export type Page = any
+export type GetPageResult = { page?: Page }
+
+export type PageVariables = {
+ id: number
+}
+
+export default function getPageOperation() {
+ function getPage(): Promise {
+ return Promise.resolve({})
+ }
+ return getPage
+}
diff --git a/framework/commercelayer/api/operations/get-product.ts b/framework/commercelayer/api/operations/get-product.ts
new file mode 100644
index 000000000..690b1aab9
--- /dev/null
+++ b/framework/commercelayer/api/operations/get-product.ts
@@ -0,0 +1,26 @@
+import type { LocalConfig } from '../index'
+import { Product } from '@commerce/types/product'
+import { GetProductOperation } from '@commerce/types/product'
+import data from '../../data.json'
+import type { OperationContext } from '@commerce/api/operations'
+
+export default function getProductOperation({
+ commerce,
+}: OperationContext) {
+ async function getProduct({
+ query = '',
+ variables,
+ config,
+ }: {
+ query?: string
+ variables?: T['variables']
+ config?: Partial
+ preview?: boolean
+ } = {}): Promise {
+ return {
+ product: data.products.find(({ slug }) => slug === variables!.slug),
+ }
+ }
+
+ return getProduct
+}
diff --git a/framework/commercelayer/api/operations/get-site-info.ts b/framework/commercelayer/api/operations/get-site-info.ts
new file mode 100644
index 000000000..d43ed8359
--- /dev/null
+++ b/framework/commercelayer/api/operations/get-site-info.ts
@@ -0,0 +1,43 @@
+import { OperationContext } from '@commerce/api/operations'
+import { Category } from '@commerce/types/site'
+import { LocalConfig } from '../index'
+
+export type GetSiteInfoResult<
+ T extends { categories: any[]; brands: any[] } = {
+ categories: Category[]
+ brands: any[]
+ }
+> = T
+
+export default function getSiteInfoOperation({}: OperationContext) {
+ function getSiteInfo({
+ query,
+ variables,
+ config: cfg,
+ }: {
+ query?: string
+ variables?: any
+ config?: Partial
+ preview?: boolean
+ } = {}): Promise {
+ return Promise.resolve({
+ categories: [
+ {
+ id: 'new-arrivals',
+ name: 'New Arrivals',
+ slug: 'new-arrivals',
+ path: '/new-arrivals',
+ },
+ {
+ id: 'featured',
+ name: 'Featured',
+ slug: 'featured',
+ path: '/featured',
+ },
+ ],
+ brands: [],
+ })
+ }
+
+ return getSiteInfo
+}
diff --git a/framework/commercelayer/api/operations/index.ts b/framework/commercelayer/api/operations/index.ts
new file mode 100644
index 000000000..086fdf83a
--- /dev/null
+++ b/framework/commercelayer/api/operations/index.ts
@@ -0,0 +1,6 @@
+export { default as getPage } from './get-page'
+export { default as getSiteInfo } from './get-site-info'
+export { default as getAllPages } from './get-all-pages'
+export { default as getProduct } from './get-product'
+export { default as getAllProducts } from './get-all-products'
+export { default as getAllProductPaths } from './get-all-product-paths'
diff --git a/framework/commercelayer/api/utils/fetch-local.ts b/framework/commercelayer/api/utils/fetch-local.ts
new file mode 100644
index 000000000..aa85cf27b
--- /dev/null
+++ b/framework/commercelayer/api/utils/fetch-local.ts
@@ -0,0 +1,34 @@
+import { FetcherError } from '@commerce/utils/errors'
+import type { GraphQLFetcher } from '@commerce/api'
+import type { LocalConfig } from '../index'
+import fetch from './fetch'
+
+const fetchGraphqlApi: (getConfig: () => LocalConfig) => GraphQLFetcher =
+ (getConfig) =>
+ async (query: string, { variables, preview } = {}, fetchOptions) => {
+ const config = getConfig()
+ const res = await fetch(config.commerceUrl, {
+ ...fetchOptions,
+ method: 'POST',
+ headers: {
+ ...fetchOptions?.headers,
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ query,
+ variables,
+ }),
+ })
+
+ const json = await res.json()
+ if (json.errors) {
+ throw new FetcherError({
+ errors: json.errors ?? [{ message: 'Failed to fetch for API' }],
+ status: res.status,
+ })
+ }
+
+ return { data: json.data, res }
+ }
+
+export default fetchGraphqlApi
diff --git a/framework/commercelayer/api/utils/fetch.ts b/framework/commercelayer/api/utils/fetch.ts
new file mode 100644
index 000000000..9d9fff3ed
--- /dev/null
+++ b/framework/commercelayer/api/utils/fetch.ts
@@ -0,0 +1,3 @@
+import zeitFetch from '@vercel/fetch'
+
+export default zeitFetch()
diff --git a/framework/commercelayer/auth/index.ts b/framework/commercelayer/auth/index.ts
new file mode 100644
index 000000000..36e757a89
--- /dev/null
+++ b/framework/commercelayer/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/commercelayer/auth/use-login.tsx b/framework/commercelayer/auth/use-login.tsx
new file mode 100644
index 000000000..28351dc7f
--- /dev/null
+++ b/framework/commercelayer/auth/use-login.tsx
@@ -0,0 +1,16 @@
+import { MutationHook } from '@commerce/utils/types'
+import useLogin, { UseLogin } from '@commerce/auth/use-login'
+
+export default useLogin as UseLogin
+
+export const handler: MutationHook = {
+ fetchOptions: {
+ query: '',
+ },
+ async fetcher() {
+ return null
+ },
+ useHook: () => () => {
+ return async function () {}
+ },
+}
diff --git a/framework/commercelayer/auth/use-logout.tsx b/framework/commercelayer/auth/use-logout.tsx
new file mode 100644
index 000000000..9b3fc3e44
--- /dev/null
+++ b/framework/commercelayer/auth/use-logout.tsx
@@ -0,0 +1,17 @@
+import { MutationHook } from '@commerce/utils/types'
+import useLogout, { UseLogout } from '@commerce/auth/use-logout'
+
+export default useLogout as UseLogout
+
+export const handler: MutationHook = {
+ fetchOptions: {
+ query: '',
+ },
+ async fetcher() {
+ return null
+ },
+ useHook:
+ ({ fetch }) =>
+ () =>
+ async () => {},
+}
diff --git a/framework/commercelayer/auth/use-signup.tsx b/framework/commercelayer/auth/use-signup.tsx
new file mode 100644
index 000000000..e9ad13458
--- /dev/null
+++ b/framework/commercelayer/auth/use-signup.tsx
@@ -0,0 +1,19 @@
+import { useCallback } from 'react'
+import useCustomer from '../customer/use-customer'
+import { MutationHook } from '@commerce/utils/types'
+import useSignup, { UseSignup } from '@commerce/auth/use-signup'
+
+export default useSignup as UseSignup
+
+export const handler: MutationHook = {
+ fetchOptions: {
+ query: '',
+ },
+ async fetcher() {
+ return null
+ },
+ useHook:
+ ({ fetch }) =>
+ () =>
+ () => {},
+}
diff --git a/framework/commercelayer/cart/index.ts b/framework/commercelayer/cart/index.ts
new file mode 100644
index 000000000..3b8ba990e
--- /dev/null
+++ b/framework/commercelayer/cart/index.ts
@@ -0,0 +1,4 @@
+export { default as useCart } from './use-cart'
+export { default as useAddItem } from './use-add-item'
+export { default as useRemoveItem } from './use-remove-item'
+export { default as useUpdateItem } from './use-update-item'
diff --git a/framework/commercelayer/cart/use-add-item.tsx b/framework/commercelayer/cart/use-add-item.tsx
new file mode 100644
index 000000000..7f3d1061f
--- /dev/null
+++ b/framework/commercelayer/cart/use-add-item.tsx
@@ -0,0 +1,17 @@
+import useAddItem, { UseAddItem } from '@commerce/cart/use-add-item'
+import { MutationHook } from '@commerce/utils/types'
+
+export default useAddItem as UseAddItem
+export const handler: MutationHook = {
+ fetchOptions: {
+ query: '',
+ },
+ async fetcher({ input, options, fetch }) {},
+ useHook:
+ ({ fetch }) =>
+ () => {
+ return async function addItem() {
+ return {}
+ }
+ },
+}
diff --git a/framework/commercelayer/cart/use-cart.tsx b/framework/commercelayer/cart/use-cart.tsx
new file mode 100644
index 000000000..b3e509a21
--- /dev/null
+++ b/framework/commercelayer/cart/use-cart.tsx
@@ -0,0 +1,42 @@
+import { useMemo } from 'react'
+import { SWRHook } from '@commerce/utils/types'
+import useCart, { UseCart } from '@commerce/cart/use-cart'
+
+export default useCart as UseCart
+
+export const handler: SWRHook = {
+ fetchOptions: {
+ query: '',
+ },
+ async fetcher() {
+ return {
+ id: '',
+ createdAt: '',
+ currency: { code: '' },
+ taxesIncluded: '',
+ lineItems: [],
+ lineItemsSubtotalPrice: '',
+ subtotalPrice: 0,
+ totalPrice: 0,
+ }
+ },
+ useHook:
+ ({ useData }) =>
+ (input) => {
+ return useMemo(
+ () =>
+ Object.create(
+ {},
+ {
+ isEmpty: {
+ get() {
+ return true
+ },
+ enumerable: true,
+ },
+ }
+ ),
+ []
+ )
+ },
+}
diff --git a/framework/commercelayer/cart/use-remove-item.tsx b/framework/commercelayer/cart/use-remove-item.tsx
new file mode 100644
index 000000000..b4ed583b8
--- /dev/null
+++ b/framework/commercelayer/cart/use-remove-item.tsx
@@ -0,0 +1,18 @@
+import { MutationHook } from '@commerce/utils/types'
+import useRemoveItem, { UseRemoveItem } from '@commerce/cart/use-remove-item'
+
+export default useRemoveItem as UseRemoveItem
+
+export const handler: MutationHook = {
+ fetchOptions: {
+ query: '',
+ },
+ async fetcher({ input, options, fetch }) {},
+ useHook:
+ ({ fetch }) =>
+ () => {
+ return async function removeItem(input) {
+ return {}
+ }
+ },
+}
diff --git a/framework/commercelayer/cart/use-update-item.tsx b/framework/commercelayer/cart/use-update-item.tsx
new file mode 100644
index 000000000..06d703f70
--- /dev/null
+++ b/framework/commercelayer/cart/use-update-item.tsx
@@ -0,0 +1,18 @@
+import { MutationHook } from '@commerce/utils/types'
+import useUpdateItem, { UseUpdateItem } from '@commerce/cart/use-update-item'
+
+export default useUpdateItem as UseUpdateItem
+
+export const handler: MutationHook = {
+ fetchOptions: {
+ query: '',
+ },
+ async fetcher({ input, options, fetch }) {},
+ useHook:
+ ({ fetch }) =>
+ () => {
+ return async function addItem() {
+ return {}
+ }
+ },
+}
diff --git a/framework/commercelayer/commerce.config.json b/framework/commercelayer/commerce.config.json
new file mode 100644
index 000000000..261211527
--- /dev/null
+++ b/framework/commercelayer/commerce.config.json
@@ -0,0 +1,9 @@
+{
+ "provider": "local",
+ "features": {
+ "wishlist": false,
+ "cart": false,
+ "search": false,
+ "customerAuth": false
+ }
+}
diff --git a/framework/commercelayer/customer/index.ts b/framework/commercelayer/customer/index.ts
new file mode 100644
index 000000000..6c903ecc5
--- /dev/null
+++ b/framework/commercelayer/customer/index.ts
@@ -0,0 +1 @@
+export { default as useCustomer } from './use-customer'
diff --git a/framework/commercelayer/customer/use-customer.tsx b/framework/commercelayer/customer/use-customer.tsx
new file mode 100644
index 000000000..41757cd0d
--- /dev/null
+++ b/framework/commercelayer/customer/use-customer.tsx
@@ -0,0 +1,15 @@
+import { SWRHook } from '@commerce/utils/types'
+import useCustomer, { UseCustomer } from '@commerce/customer/use-customer'
+
+export default useCustomer as UseCustomer
+export const handler: SWRHook = {
+ fetchOptions: {
+ query: '',
+ },
+ async fetcher({ input, options, fetch }) {},
+ useHook: () => () => {
+ return async function addItem() {
+ return {}
+ }
+ },
+}
diff --git a/framework/commercelayer/data.json b/framework/commercelayer/data.json
new file mode 100644
index 000000000..18c8ee718
--- /dev/null
+++ b/framework/commercelayer/data.json
@@ -0,0 +1,235 @@
+{
+ "products": [
+ {
+ "id": "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0LzU0NDczMjUwMjQ0MjA=",
+ "name": "New Short Sleeve T-Shirt",
+ "vendor": "Next.js",
+ "path": "/new-short-sleeve-t-shirt",
+ "slug": "new-short-sleeve-t-shirt",
+ "price": { "value": 25, "currencyCode": "USD" },
+ "descriptionHtml": "Show off your love for Next.js and Vercel with this unique, limited edition t-shirt. This design is part of a limited run, numbered drop at the June 2021 Next.js Conf. It features a unique, handcrafted triangle design. Get it while supplies last – only 200 of these shirts will be made! All proceeds will be donated to charity.
",
+ "images": [
+ {
+ "url": "/assets/drop-shirt-0.png",
+ "altText": "Shirt",
+ "width": 1000,
+ "height": 1000
+ },
+ {
+ "url": "/assets/drop-shirt-1.png",
+ "altText": "Shirt",
+ "width": 1000,
+ "height": 1000
+ },
+ {
+ "url": "/assets/drop-shirt-2.png",
+ "altText": "Shirt",
+ "width": 1000,
+ "height": 1000
+ }
+ ],
+ "variants": [
+ {
+ "id": "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0LzU0NDczMjUwMjQ0MjAss=",
+ "options": [
+ {
+ "__typename": "MultipleChoiceOption",
+ "id": "asd",
+ "displayName": "Size",
+ "values": [
+ {
+ "label": "XL"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "options": [
+ {
+ "id": "option-color",
+ "displayName": "Color",
+ "values": [
+ {
+ "label": "color",
+ "hexColors": ["#222"]
+ }
+ ]
+ },
+ {
+ "id": "option-size",
+ "displayName": "Size",
+ "values": [
+ {
+ "label": "S"
+ },
+ {
+ "label": "M"
+ },
+ {
+ "label": "L"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "Z2lkOi8vc2hvcGlmeS9Qcm9ksdWN0LzU0NDczMjUwMjQ0MjA=",
+ "name": "Lightweight Jacket",
+ "vendor": "Next.js",
+ "path": "/lightweight-jacket",
+ "slug": "lightweight-jacket",
+ "price": { "value": 249.99, "currencyCode": "USD" },
+ "descriptionHtml": "Show off your love for Next.js and Vercel with this unique, limited edition t-shirt. This design is part of a limited run, numbered drop at the June 2021 Next.js Conf. It features a unique, handcrafted triangle design. Get it while supplies last – only 200 of these shirts will be made! All proceeds will be donated to charity.
",
+ "images": [
+ {
+ "url": "/assets/lightweight-jacket-0.png",
+ "altText": "Lightweight Jacket",
+ "width": 1000,
+ "height": 1000
+ },
+ {
+ "url": "/assets/lightweight-jacket-1.png",
+ "altText": "Lightweight Jacket",
+ "width": 1000,
+ "height": 1000
+ },
+ {
+ "url": "/assets/lightweight-jacket-2.png",
+ "altText": "Lightweight Jacket",
+ "width": 1000,
+ "height": 1000
+ }
+ ],
+ "variants": [
+ {
+ "id": "Z2lkOid8vc2hvcGlmeS9Qcm9kdWN0LzU0NDczMjUwMjQ0MjAss=",
+ "options": [
+ {
+ "__typename": "MultipleChoiceOption",
+ "id": "asd",
+ "displayName": "Size",
+ "values": [
+ {
+ "label": "XL"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "options": [
+ {
+ "id": "option-color",
+ "displayName": "Color",
+ "values": [
+ {
+ "label": "color",
+ "hexColors": ["#222"]
+ }
+ ]
+ },
+ {
+ "id": "option-size",
+ "displayName": "Size",
+ "values": [
+ {
+ "label": "S"
+ },
+ {
+ "label": "M"
+ },
+ {
+ "label": "L"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "Z2lkOis8vc2hvcGlmsddeS9Qcm9kdWN0LzU0NDczMjUwMjQ0MjA=",
+ "name": "Shirt",
+ "vendor": "Next.js",
+ "path": "/shirt",
+ "slug": "shirt",
+ "price": { "value": 25, "currencyCode": "USD" },
+ "descriptionHtml": "Show off your love for Next.js and Vercel with this unique, limited edition t-shirt. This design is part of a limited run, numbered drop at the June 2021 Next.js Conf. It features a unique, handcrafted triangle design. Get it while supplies last – only 200 of these shirts will be made! All proceeds will be donated to charity.
",
+ "images": [
+ {
+ "url": "/assets/t-shirt-0.png",
+ "altText": "Shirt",
+ "width": 1000,
+ "height": 1000
+ },
+ {
+ "url": "/assets/t-shirt-1.png",
+ "altText": "Shirt",
+ "width": 1000,
+ "height": 1000
+ },
+ {
+ "url": "/assets/t-shirt-2.png",
+ "altText": "Shirt",
+ "width": 1000,
+ "height": 1000
+ },
+ {
+ "url": "/assets/t-shirt-3.png",
+ "altText": "Shirt",
+ "width": 1000,
+ "height": 1000
+ },
+ {
+ "url": "/assets/t-shirt-4.png",
+ "altText": "Shirt",
+ "width": 1000,
+ "height": 1000
+ }
+ ],
+ "variants": [
+ {
+ "id": "Z2lkOi8vc2hvcGlmeS9Qcms9kdWN0LzU0NDczMjUwMjQ0MjAss=",
+ "options": [
+ {
+ "__typename": "MultipleChoiceOption",
+ "id": "asd",
+ "displayName": "Size",
+ "values": [
+ {
+ "label": "XL"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "options": [
+ {
+ "id": "option-color",
+ "displayName": "Color",
+ "values": [
+ {
+ "label": "color",
+ "hexColors": ["#222"]
+ }
+ ]
+ },
+ {
+ "id": "option-size",
+ "displayName": "Size",
+ "values": [
+ {
+ "label": "S"
+ },
+ {
+ "label": "M"
+ },
+ {
+ "label": "L"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/framework/commercelayer/fetcher.ts b/framework/commercelayer/fetcher.ts
new file mode 100644
index 000000000..69943d1df
--- /dev/null
+++ b/framework/commercelayer/fetcher.ts
@@ -0,0 +1,11 @@
+import { Fetcher } from '@commerce/utils/types'
+
+export const fetcher: Fetcher = async () => {
+ console.log('FETCHER')
+ const res = await fetch('./data.json')
+ if (res.ok) {
+ const { data } = await res.json()
+ return data
+ }
+ throw res
+}
diff --git a/framework/commercelayer/index.tsx b/framework/commercelayer/index.tsx
new file mode 100644
index 000000000..2ec304f63
--- /dev/null
+++ b/framework/commercelayer/index.tsx
@@ -0,0 +1,32 @@
+import * as React from 'react'
+import { ReactNode } from 'react'
+import { localProvider } from './provider'
+import {
+ CommerceConfig,
+ CommerceProvider as CoreCommerceProvider,
+ useCommerce as useCoreCommerce,
+} from '@commerce'
+
+export const localConfig: CommerceConfig = {
+ locale: 'en-us',
+ cartCookie: 'session',
+}
+
+export function CommerceProvider({
+ children,
+ ...config
+}: {
+ children?: ReactNode
+ locale: string
+} & Partial) {
+ return (
+
+ {children}
+
+ )
+}
+
+export const useCommerce = () => useCoreCommerce()
diff --git a/framework/commercelayer/next.config.js b/framework/commercelayer/next.config.js
new file mode 100644
index 000000000..ce46b706f
--- /dev/null
+++ b/framework/commercelayer/next.config.js
@@ -0,0 +1,8 @@
+const commerce = require('./commerce.config.json')
+
+module.exports = {
+ commerce,
+ images: {
+ domains: ['localhost'],
+ },
+}
diff --git a/framework/commercelayer/product/index.ts b/framework/commercelayer/product/index.ts
new file mode 100644
index 000000000..426a3edcd
--- /dev/null
+++ b/framework/commercelayer/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/commercelayer/product/use-price.tsx b/framework/commercelayer/product/use-price.tsx
new file mode 100644
index 000000000..0174faf5e
--- /dev/null
+++ b/framework/commercelayer/product/use-price.tsx
@@ -0,0 +1,2 @@
+export * from '@commerce/product/use-price'
+export { default } from '@commerce/product/use-price'
diff --git a/framework/commercelayer/product/use-search.tsx b/framework/commercelayer/product/use-search.tsx
new file mode 100644
index 000000000..30e699537
--- /dev/null
+++ b/framework/commercelayer/product/use-search.tsx
@@ -0,0 +1,17 @@
+import { SWRHook } from '@commerce/utils/types'
+import useSearch, { UseSearch } from '@commerce/product/use-search'
+export default useSearch as UseSearch
+
+export const handler: SWRHook = {
+ fetchOptions: {
+ query: '',
+ },
+ async fetcher({ input, options, fetch }) {},
+ useHook: () => () => {
+ return {
+ data: {
+ products: [],
+ },
+ }
+ },
+}
diff --git a/framework/commercelayer/provider.ts b/framework/commercelayer/provider.ts
new file mode 100644
index 000000000..e6a2b0a21
--- /dev/null
+++ b/framework/commercelayer/provider.ts
@@ -0,0 +1,21 @@
+import { fetcher } from './fetcher'
+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'
+
+export type Provider = typeof localProvider
+export const localProvider = {
+ locale: 'en-us',
+ cartCookie: 'session',
+ fetcher: fetcher,
+ cart: { useCart, useAddItem, useUpdateItem, useRemoveItem },
+ customer: { useCustomer },
+ products: { useSearch },
+ auth: { useLogin, useLogout, useSignup },
+}
diff --git a/framework/commercelayer/wishlist/use-add-item.tsx b/framework/commercelayer/wishlist/use-add-item.tsx
new file mode 100644
index 000000000..75f067c3a
--- /dev/null
+++ b/framework/commercelayer/wishlist/use-add-item.tsx
@@ -0,0 +1,13 @@
+import { useCallback } from 'react'
+
+export function emptyHook() {
+ const useEmptyHook = async (options = {}) => {
+ return useCallback(async function () {
+ return Promise.resolve()
+ }, [])
+ }
+
+ return useEmptyHook
+}
+
+export default emptyHook
diff --git a/framework/commercelayer/wishlist/use-remove-item.tsx b/framework/commercelayer/wishlist/use-remove-item.tsx
new file mode 100644
index 000000000..a2d3a8a05
--- /dev/null
+++ b/framework/commercelayer/wishlist/use-remove-item.tsx
@@ -0,0 +1,17 @@
+import { useCallback } from 'react'
+
+type Options = {
+ includeProducts?: boolean
+}
+
+export function emptyHook(options?: Options) {
+ const useEmptyHook = async ({ id }: { id: string | number }) => {
+ return useCallback(async function () {
+ return Promise.resolve()
+ }, [])
+ }
+
+ return useEmptyHook
+}
+
+export default emptyHook
diff --git a/framework/commercelayer/wishlist/use-wishlist.tsx b/framework/commercelayer/wishlist/use-wishlist.tsx
new file mode 100644
index 000000000..9fe0e758f
--- /dev/null
+++ b/framework/commercelayer/wishlist/use-wishlist.tsx
@@ -0,0 +1,43 @@
+import { HookFetcher } from '@commerce/utils/types'
+import type { Product } from '@commerce/types/product'
+
+const defaultOpts = {}
+
+export type Wishlist = {
+ items: [
+ {
+ product_id: number
+ variant_id: number
+ id: number
+ product: Product
+ }
+ ]
+}
+
+export interface UseWishlistOptions {
+ includeProducts?: boolean
+}
+
+export interface UseWishlistInput extends UseWishlistOptions {
+ customerId?: number
+}
+
+export const fetcher: HookFetcher = () => {
+ return null
+}
+
+export function extendHook(
+ customFetcher: typeof fetcher,
+ // swrOptions?: SwrOptions
+ swrOptions?: any
+) {
+ const useWishlist = ({ includeProducts }: UseWishlistOptions = {}) => {
+ return { data: null }
+ }
+
+ useWishlist.extend = extendHook
+
+ return useWishlist
+}
+
+export default extendHook(fetcher)