diff --git a/lib/bigcommerce/cart.tsx b/lib/bigcommerce/cart.tsx
new file mode 100644
index 000000000..f0bb46ac2
--- /dev/null
+++ b/lib/bigcommerce/cart.tsx
@@ -0,0 +1,13 @@
+import {
+ CartProvider as CommerceCartProvider,
+ useCart as useCommerceCart,
+} from '../commerce/cart';
+import { Cart } from './index';
+
+export function CartProvider({ children }) {
+ return {children};
+}
+
+export function useCart() {
+ return useCommerceCart();
+}
diff --git a/lib/bigcommerce/index.tsx b/lib/bigcommerce/index.tsx
new file mode 100644
index 000000000..1f53b07d8
--- /dev/null
+++ b/lib/bigcommerce/index.tsx
@@ -0,0 +1,78 @@
+import {
+ CommerceProvider,
+ Connector,
+ HookResolver,
+ useCommerce as useComm,
+} from '../commerce';
+
+export type Cart = any;
+
+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 data.errors[0];
+ }
+ return { message: await getText(res) };
+}
+
+async function fetcher(
+ url: string,
+ query: string,
+ resolver: HookResolver
+) {
+ const res = await fetch(url);
+
+ if (res.ok) {
+ return res.json();
+ }
+
+ throw await getError(res);
+}
+
+export const bigcommerce: Connector = {
+ hooks: {
+ useCart: {
+ query: '',
+ resolver() {
+ return;
+ },
+ },
+ useAddItem: {
+ query: '',
+ resolver() {
+ return;
+ },
+ },
+ useUpdateItem: {
+ query: '',
+ resolver() {
+ return;
+ },
+ },
+ useRemoveItem: {
+ query: '',
+ resolver() {
+ return;
+ },
+ },
+ },
+ locale: 'en-us',
+ fetcher,
+};
+
+// TODO: The connector should be extendable when a developer is using it
+export function BigcommerceProvider({ children }) {
+ return (
+ {children}
+ );
+}
+
+export const useCommerce = () => useComm();
diff --git a/lib/commerce/cart.tsx b/lib/commerce/cart.tsx
new file mode 100644
index 000000000..12f420186
--- /dev/null
+++ b/lib/commerce/cart.tsx
@@ -0,0 +1,35 @@
+import { createContext, useContext } from 'react';
+import useSWR, { responseInterface } from 'swr';
+import { Cart, useCommerce } from '.';
+
+export type CartResponse = responseInterface & {
+ isEmpty: boolean;
+};
+
+const CartContext = createContext>(null);
+
+function getCartCookie() {
+ // TODO: Figure how the cart should be persisted
+ return null;
+}
+
+export function CartProvider({ children }) {
+ const { hooks, fetcher } = useCommerce();
+ const { useCart } = hooks;
+ const cartId = getCartCookie();
+ const response = useSWR(
+ () => (cartId ? [useCart.url, useCart.query, useCart.resolver] : null),
+ fetcher
+ );
+ const isEmpty = true;
+
+ return (
+
+ {children}
+
+ );
+}
+
+export function useCart() {
+ return useContext(CartContext) as CartResponse;
+}
diff --git a/lib/commerce/index.tsx b/lib/commerce/index.tsx
new file mode 100644
index 000000000..ac05c008e
--- /dev/null
+++ b/lib/commerce/index.tsx
@@ -0,0 +1,53 @@
+import { createContext, ReactNode, useContext } from 'react';
+
+const Commerce = createContext>(null);
+
+export type Cart = any;
+
+export type CommerceProps = {
+ children?: ReactNode;
+ connector: Connector;
+};
+
+export type Connector = {
+ hooks: {
+ useCart: Hook;
+ useAddItem: Hook;
+ useUpdateItem: Hook;
+ useRemoveItem: Hook;
+ };
+ fetcher: Fetcher;
+ locale: string;
+};
+
+export type Hook = {
+ query?: string;
+ url?: string;
+ resolver: HookResolver;
+};
+
+export type HookResolver = (
+ fetcher: Fetcher,
+ context: ResolverContext
+) => T | Promise;
+
+export type Fetcher = (...args: any) => T | Promise;
+
+export type ResolverContext = {
+ query?: string;
+ locale: string;
+};
+
+export function CommerceProvider({ children, connector }: CommerceProps) {
+ if (!connector) {
+ throw new Error(
+ 'CommerceProvider requires a valid headless commerce connector'
+ );
+ }
+
+ return {children};
+}
+
+export function useCommerce() {
+ return useContext(Commerce) as Connector;
+}