4
0
forked from crowetic/commerce

Update types (#831)

* Update product types

* Cart types progress, add zod & initial schema validator

* Update normalize.ts

* Update with-schema-parser.ts

* Updated types, schemas & providers

* Fix providers after schema parse errors

* Fix paths

* More provider fixes

* Fix kibocommerce & commercejs

* Add customer updated types & fixes

* Add checkout & customer types

* Import core types only from commerce

* Update tsconfig.json

* Convert hooks interfaces to types

* Requested changes

* Change to relative paths

* Move Zod dependency
This commit is contained in:
Catalin Pinte 2022-10-05 09:02:29 +03:00 committed by GitHub
parent 8398a96215
commit 6c2610584d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
291 changed files with 1992 additions and 1808 deletions

View File

@ -23,8 +23,8 @@ Demo live at: [demo.vercel.store](https://demo.vercel.store/)
> To run a minimal version of Next.js Commerce you can start with the default local provider `@vercel/commerce-local` that has disabled all features (cart, auth) and use static files for the backend > To run a minimal version of Next.js Commerce you can start with the default local provider `@vercel/commerce-local` that has disabled all features (cart, auth) and use static files for the backend
```bash ```bash
pnpm install # run this command in root folder of the mono repo pnpm install & pnpm build # run this commands in root folder of the mono repo
pnpm dev pnpm dev # run this commands in the site folder
``` ```
> If you encounter any problems while installing and running for the first time, please see the Troubleshoot section > If you encounter any problems while installing and running for the first time, please see the Troubleshoot section
@ -111,10 +111,11 @@ Our commitment to Open Source can be found [here](https://vercel.com/oss).
1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device. 1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device.
2. Create a new branch `git checkout -b MY_BRANCH_NAME` 2. Create a new branch `git checkout -b MY_BRANCH_NAME`
3. Install the dependencies: `pnpm install` 3. Install the dependencies: `pnpm install`
4. Duplicate `site/.env.template` and rename it to `site/.env.local` 4. Build the packages: `pnpm build`
5. Add proper store values to `site/.env.local` 5. Duplicate `site/.env.template` and rename it to `site/.env.local`
6. Run `pnpm dev` to build the packages and watch for code changes 6. Add proper store values to `site/.env.local`
7. Run `pnpm turbo run build` to check the build after your changes 7. Run `cd site` & `pnpm dev` to watch for code changes
8. Run `pnpm turbo run build` to check the build after your changes
## Work in progress ## Work in progress
@ -191,7 +192,7 @@ info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this comm
The error usually occurs when running `pnpm dev` inside of the `/site/` folder after installing a fresh repository. The error usually occurs when running `pnpm dev` inside of the `/site/` folder after installing a fresh repository.
In order to fix this, run `pnpm dev` in the monorepo root folder first. In order to fix this, run `pnpm build` in the monorepo root folder first.
> Using `pnpm dev` from the root is recommended for developing, which will run watch mode on all packages. > Using `pnpm dev` from the root is recommended for developing, which will run watch mode on all packages.

View File

@ -1130,7 +1130,7 @@ export interface definitions {
*/ */
search_keywords?: string search_keywords?: string
/** /**
* Image URL used for this category on the storefront. Images can be uploaded via form file post to `/brands/{brandId}/image`, or by providing a publicly accessible URL in this field. * Image URL used for this category on the storefront. Images can be uploaded via form file post to `/{brandId}/image`, or by providing a publicly accessible URL in this field.
*/ */
image_url?: string image_url?: string
custom_url?: definitions['customUrl_Full'] custom_url?: definitions['customUrl_Full']

View File

@ -2,7 +2,7 @@
import { normalizeCart } from '../../../lib/normalize' import { normalizeCart } from '../../../lib/normalize'
import { BigcommerceApiError } from '../../utils/errors' import { BigcommerceApiError } from '../../utils/errors'
import getCartCookie from '../../utils/get-cart-cookie' import getCartCookie from '../../utils/get-cart-cookie'
import type { BigcommerceCart } from '../../../types/cart' import type { BigcommerceCart } from '../../../types'
import type { CartEndpoint } from '.' import type { CartEndpoint } from '.'
// Return current cart info // Return current cart info

View File

@ -1,6 +1,6 @@
import { GetAPISchema, createEndpoint } from '@vercel/commerce/api' import { GetAPISchema, createEndpoint } from '@vercel/commerce/api'
import cartEndpoint from '@vercel/commerce/api/endpoints/cart' import cartEndpoint from '@vercel/commerce/api/endpoints/cart'
import type { CartSchema } from '../../../types/cart' import type { CartSchema } from '@vercel/commerce/types/cart'
import type { BigcommerceAPI } from '../..' import type { BigcommerceAPI } from '../..'
import getCart from './get-cart' import getCart from './get-cart'
import addItem from './add-item' import addItem from './add-item'

View File

@ -1,6 +1,6 @@
import { GetAPISchema, createEndpoint } from '@vercel/commerce/api' import { GetAPISchema, createEndpoint } from '@vercel/commerce/api'
import productsEndpoint from '@vercel/commerce/api/endpoints/catalog/products' import productsEndpoint from '@vercel/commerce/api/endpoints/catalog/products'
import type { ProductsSchema } from '../../../../types/product' import type { ProductsSchema } from '@vercel/commerce/types/product'
import type { BigcommerceAPI } from '../../..' import type { BigcommerceAPI } from '../../..'
import getProducts from './get-products' import getProducts from './get-products'

View File

@ -1,6 +1,6 @@
import { GetAPISchema, createEndpoint } from '@vercel/commerce/api' import { GetAPISchema, createEndpoint } from '@vercel/commerce/api'
import checkoutEndpoint from '@vercel/commerce/api/endpoints/checkout' import checkoutEndpoint from '@vercel/commerce/api/endpoints/checkout'
import type { CheckoutSchema } from '../../../types/checkout' import type { CheckoutSchema } from '@vercel/commerce/types/checkout'
import type { BigcommerceAPI } from '../..' import type { BigcommerceAPI } from '../..'
import getCheckout from './get-checkout' import getCheckout from './get-checkout'

View File

@ -47,7 +47,19 @@ const getLoggedInCustomer: CustomerEndpoint['handlers']['getLoggedInCustomer'] =
}) })
} }
return res.status(200).json({ data: { customer } }) return res.status(200).json({
data: {
customer: {
id: String(customer.entityId),
firstName: customer.firstName,
lastName: customer.lastName,
email: customer.email,
company: customer.company,
phone: customer.phone,
notes: customer.notes,
},
},
})
} }
res.status(200).json({ data: null }) res.status(200).json({ data: null })

View File

@ -1,6 +1,6 @@
import { GetAPISchema, createEndpoint } from '@vercel/commerce/api' import { GetAPISchema, createEndpoint } from '@vercel/commerce/api'
import customerEndpoint from '@vercel/commerce/api/endpoints/customer' import customerEndpoint from '@vercel/commerce/api/endpoints/customer'
import type { CustomerSchema } from '../../../types/customer' import type { CustomerSchema } from '@vercel/commerce/types/customer'
import type { BigcommerceAPI } from '../..' import type { BigcommerceAPI } from '../..'
import getLoggedInCustomer from './get-logged-in-customer' import getLoggedInCustomer from './get-logged-in-customer'

View File

@ -1,6 +1,6 @@
import { GetAPISchema, createEndpoint } from '@vercel/commerce/api' import { GetAPISchema, createEndpoint } from '@vercel/commerce/api'
import loginEndpoint from '@vercel/commerce/api/endpoints/login' import loginEndpoint from '@vercel/commerce/api/endpoints/login'
import type { LoginSchema } from '../../../types/login' import type { LoginSchema } from '@vercel/commerce/types/login'
import type { BigcommerceAPI } from '../..' import type { BigcommerceAPI } from '../..'
import login from './login' import login from './login'

View File

@ -1,6 +1,6 @@
import { GetAPISchema, createEndpoint } from '@vercel/commerce/api' import { GetAPISchema, createEndpoint } from '@vercel/commerce/api'
import logoutEndpoint from '@vercel/commerce/api/endpoints/logout' import logoutEndpoint from '@vercel/commerce/api/endpoints/logout'
import type { LogoutSchema } from '../../../types/logout' import type { LogoutSchema } from '@vercel/commerce/types/logout'
import type { BigcommerceAPI } from '../..' import type { BigcommerceAPI } from '../..'
import logout from './logout' import logout from './logout'

View File

@ -1,6 +1,6 @@
import { GetAPISchema, createEndpoint } from '@vercel/commerce/api' import { GetAPISchema, createEndpoint } from '@vercel/commerce/api'
import signupEndpoint from '@vercel/commerce/api/endpoints/signup' import signupEndpoint from '@vercel/commerce/api/endpoints/signup'
import type { SignupSchema } from '../../../types/signup' import type { SignupSchema } from '@vercel/commerce/types/signup'
import type { BigcommerceAPI } from '../..' import type { BigcommerceAPI } from '../..'
import signup from './signup' import signup from './signup'

View File

@ -1,7 +1,6 @@
import type { Wishlist } from '../../../types/wishlist' import type { Wishlist } from '@vercel/commerce/types/wishlist'
import type { WishlistEndpoint } from '.' import type { WishlistEndpoint } from '.'
import getCustomerId from '../../utils/get-customer-id' import getCustomerId from '../../utils/get-customer-id'
import getCustomerWishlist from '../../operations/get-customer-wishlist'
// Return wishlist info // Return wishlist info
const getWishlist: WishlistEndpoint['handlers']['getWishlist'] = async ({ const getWishlist: WishlistEndpoint['handlers']['getWishlist'] = async ({

View File

@ -1,6 +1,6 @@
import { GetAPISchema, createEndpoint } from '@vercel/commerce/api' import { GetAPISchema, createEndpoint } from '@vercel/commerce/api'
import wishlistEndpoint from '@vercel/commerce/api/endpoints/wishlist' import wishlistEndpoint from '@vercel/commerce/api/endpoints/wishlist'
import type { WishlistSchema } from '../../../types/wishlist' import type { WishlistSchema } from '@vercel/commerce/types/wishlist'
import type { BigcommerceAPI } from '../..' import type { BigcommerceAPI } from '../..'
import getWishlist from './get-wishlist' import getWishlist from './get-wishlist'
import addItem from './add-item' import addItem from './add-item'

View File

@ -1,5 +1,4 @@
import type { Wishlist } from '../../../types/wishlist' import type { Wishlist } from '@vercel/commerce/types/wishlist'
import getCustomerWishlist from '../../operations/get-customer-wishlist'
import getCustomerId from '../../utils/get-customer-id' import getCustomerId from '../../utils/get-customer-id'
import type { WishlistEndpoint } from '.' import type { WishlistEndpoint } from '.'

View File

@ -2,10 +2,13 @@ import type {
OperationContext, OperationContext,
OperationOptions, OperationOptions,
} from '@vercel/commerce/api/operations' } from '@vercel/commerce/api/operations'
import type { Page, GetAllPagesOperation } from '../../types/page' import type { GetAllPagesOperation } from '@vercel/commerce/types/page'
import type { RecursivePartial, RecursiveRequired } from '../utils/types' import type { RecursivePartial, RecursiveRequired } from '../utils/types'
import { BigcommerceConfig, Provider } from '..' import { BigcommerceConfig, Provider } from '..'
import { definitions } from '../definitions/store-content'
import { normalizePage } from '../../lib/normalize'
export default function getAllPagesOperation({ export default function getAllPagesOperation({
commerce, commerce,
}: OperationContext<Provider>) { }: OperationContext<Provider>) {
@ -33,12 +36,14 @@ export default function getAllPagesOperation({
// RecursivePartial forces the method to check for every prop in the data, which is // RecursivePartial forces the method to check for every prop in the data, which is
// required in case there's a custom `url` // required in case there's a custom `url`
const { data } = await cfg.storeApiFetch< const { data } = await cfg.storeApiFetch<
RecursivePartial<{ data: Page[] }> RecursivePartial<{ data: definitions['page_Full'][] }>
>('/v3/content/pages') >('/v3/content/pages')
const pages = (data as RecursiveRequired<typeof data>) ?? [] const pages = (data as RecursiveRequired<typeof data>) ?? []
return { return {
pages: preview ? pages : pages.filter((p) => p.is_visible), pages: preview
? pages.map(normalizePage)
: pages.filter((p) => p.is_visible).map(normalizePage),
} }
} }

View File

@ -3,7 +3,7 @@ import type {
OperationOptions, OperationOptions,
} from '@vercel/commerce/api/operations' } from '@vercel/commerce/api/operations'
import type { GetAllProductPathsQuery } from '../../../schema' import type { GetAllProductPathsQuery } from '../../../schema'
import type { GetAllProductPathsOperation } from '../../types/product' import type { GetAllProductPathsOperation } from '@vercel/commerce/types/product'
import type { RecursivePartial, RecursiveRequired } from '../utils/types' import type { RecursivePartial, RecursiveRequired } from '../utils/types'
import filterEdges from '../utils/filter-edges' import filterEdges from '../utils/filter-edges'
import { BigcommerceConfig, Provider } from '..' import { BigcommerceConfig, Provider } from '..'

View File

@ -6,7 +6,7 @@ import type {
GetAllProductsQuery, GetAllProductsQuery,
GetAllProductsQueryVariables, GetAllProductsQueryVariables,
} from '../../../schema' } from '../../../schema'
import type { GetAllProductsOperation } from '../../types/product' import type { GetAllProductsOperation } from '@vercel/commerce/types/product'
import type { RecursivePartial, RecursiveRequired } from '../utils/types' import type { RecursivePartial, RecursiveRequired } from '../utils/types'
import filterEdges from '../utils/filter-edges' import filterEdges from '../utils/filter-edges'
import setProductLocaleMeta from '../utils/set-product-locale-meta' import setProductLocaleMeta from '../utils/set-product-locale-meta'

View File

@ -5,7 +5,7 @@ import type {
import type { import type {
GetCustomerWishlistOperation, GetCustomerWishlistOperation,
Wishlist, Wishlist,
} from '../../types/wishlist' } from '@vercel/commerce/types/wishlist'
import type { RecursivePartial, RecursiveRequired } from '../utils/types' import type { RecursivePartial, RecursiveRequired } from '../utils/types'
import { BigcommerceConfig, Provider } from '..' import { BigcommerceConfig, Provider } from '..'
import getAllProducts, { ProductEdge } from './get-all-products' import getAllProducts, { ProductEdge } from './get-all-products'
@ -49,7 +49,7 @@ export default function getCustomerWishlistOperation({
if (includeProducts && wishlist?.items?.length) { if (includeProducts && wishlist?.items?.length) {
const ids = wishlist.items const ids = wishlist.items
?.map((item) => (item?.product_id ? String(item?.product_id) : null)) ?.map((item) => (item?.productId ? String(item?.productId) : null))
.filter((id): id is string => !!id) .filter((id): id is string => !!id)
if (ids?.length) { if (ids?.length) {
@ -66,7 +66,7 @@ export default function getCustomerWishlistOperation({
}, {}) }, {})
// Populate the wishlist items with the graphql products // Populate the wishlist items with the graphql products
wishlist.items.forEach((item) => { wishlist.items.forEach((item) => {
const product = item && productsById[item.product_id!] const product = item && productsById[Number(item.productId)]
if (item && product) { if (item && product) {
// @ts-ignore Fix this type when the wishlist type is properly defined // @ts-ignore Fix this type when the wishlist type is properly defined
item.product = product item.product = product

View File

@ -2,7 +2,7 @@ import type {
OperationContext, OperationContext,
OperationOptions, OperationOptions,
} from '@vercel/commerce/api/operations' } from '@vercel/commerce/api/operations'
import type { GetPageOperation, Page } from '../../types/page' import type { GetPageOperation, Page } from '@vercel/commerce/types/page'
import type { RecursivePartial, RecursiveRequired } from '../utils/types' import type { RecursivePartial, RecursiveRequired } from '../utils/types'
import type { BigcommerceConfig, Provider } from '..' import type { BigcommerceConfig, Provider } from '..'
import { normalizePage } from '../../lib/normalize' import { normalizePage } from '../../lib/normalize'

View File

@ -2,7 +2,7 @@ import type {
OperationContext, OperationContext,
OperationOptions, OperationOptions,
} from '@vercel/commerce/api/operations' } from '@vercel/commerce/api/operations'
import type { GetProductOperation } from '../../types/product' import type { GetProductOperation } from '@vercel/commerce/types/product'
import type { GetProductQuery, GetProductQueryVariables } from '../../../schema' import type { GetProductQuery, GetProductQueryVariables } from '../../../schema'
import setProductLocaleMeta from '../utils/set-product-locale-meta' import setProductLocaleMeta from '../utils/set-product-locale-meta'
import { productInfoFragment } from '../fragments/product' import { productInfoFragment } from '../fragments/product'
@ -100,7 +100,7 @@ export default function getAllProductPathsOperation({
const variables: GetProductQueryVariables = { const variables: GetProductQueryVariables = {
locale, locale,
hasLocale: !!locale, hasLocale: !!locale,
path: slug ? `/${slug}/` : vars.path!, path: slug ? `/${slug}` : vars.path!,
} }
const { data } = await config.fetch<GetProductQuery>(query, { variables }) const { data } = await config.fetch<GetProductQuery>(query, { variables })
const product = data.site?.route?.node const product = data.site?.route?.node

View File

@ -2,12 +2,12 @@ import type {
OperationContext, OperationContext,
OperationOptions, OperationOptions,
} from '@vercel/commerce/api/operations' } from '@vercel/commerce/api/operations'
import type { GetSiteInfoOperation } from '../../types/site' import type { GetSiteInfoOperation } from '@vercel/commerce/types/site'
import type { GetSiteInfoQuery } from '../../../schema' import type { GetSiteInfoQuery } from '../../../schema'
import filterEdges from '../utils/filter-edges' import filterEdges from '../utils/filter-edges'
import type { BigcommerceConfig, Provider } from '..' import type { BigcommerceConfig, Provider } from '..'
import { categoryTreeItemFragment } from '../fragments/category-tree' import { categoryTreeItemFragment } from '../fragments/category-tree'
import { normalizeCategory } from '../../lib/normalize' import { normalizeBrand, normalizeCategory } from '../../lib/normalize'
// Get 3 levels of categories // Get 3 levels of categories
export const getSiteInfoQuery = /* GraphQL */ ` export const getSiteInfoQuery = /* GraphQL */ `
@ -79,7 +79,7 @@ export default function getSiteInfoOperation({
return { return {
categories: categories ?? [], categories: categories ?? [],
brands: filterEdges(brands), brands: filterEdges(brands).map(normalizeBrand),
} }
} }

View File

@ -3,7 +3,7 @@ import type {
OperationContext, OperationContext,
OperationOptions, OperationOptions,
} from '@vercel/commerce/api/operations' } from '@vercel/commerce/api/operations'
import type { LoginOperation } from '../../types/login' import type { LoginOperation } from '@vercel/commerce/types/login'
import type { LoginMutation } from '../../../schema' import type { LoginMutation } from '../../../schema'
import type { RecursivePartial } from '../utils/types' import type { RecursivePartial } from '../utils/types'
import concatHeader from '../utils/concat-cookie' import concatHeader from '../utils/concat-cookie'

View File

@ -1,5 +1,5 @@
import type { WishlistItemBody } from '../../types/wishlist' import type { WishlistItemBody } from '@vercel/commerce/types/wishlist'
import type { CartItemBody, OptionSelections } from '../../types/cart' import type { CartItemBody, SelectedOption } from '@vercel/commerce/types/cart'
type BCWishlistItemBody = { type BCWishlistItemBody = {
product_id: number product_id: number
@ -10,7 +10,7 @@ type BCCartItemBody = {
product_id: number product_id: number
variant_id: number variant_id: number
quantity?: number quantity?: number
option_selections?: OptionSelections[] option_selections?: SelectedOption[]
} }
export const parseWishlistItem = ( export const parseWishlistItem = (
@ -24,5 +24,5 @@ export const parseCartItem = (item: CartItemBody): BCCartItemBody => ({
quantity: item.quantity, quantity: item.quantity,
product_id: Number(item.productId), product_id: Number(item.productId),
variant_id: Number(item.variantId), variant_id: Number(item.variantId),
option_selections: item.optionSelections, option_selections: item.optionsSelected,
}) })

View File

@ -2,7 +2,7 @@ import { useCallback } from 'react'
import type { MutationHook } from '@vercel/commerce/utils/types' import type { MutationHook } from '@vercel/commerce/utils/types'
import { CommerceError } from '@vercel/commerce/utils/errors' import { CommerceError } from '@vercel/commerce/utils/errors'
import useLogin, { UseLogin } from '@vercel/commerce/auth/use-login' import useLogin, { UseLogin } from '@vercel/commerce/auth/use-login'
import type { LoginHook } from '../types/login' import type { LoginHook } from '@vercel/commerce/types/login'
import useCustomer from '../customer/use-customer' import useCustomer from '../customer/use-customer'
export default useLogin as UseLogin<typeof handler> export default useLogin as UseLogin<typeof handler>

View File

@ -1,7 +1,7 @@
import { useCallback } from 'react' import { useCallback } from 'react'
import type { MutationHook } from '@vercel/commerce/utils/types' import type { MutationHook } from '@vercel/commerce/utils/types'
import useLogout, { UseLogout } from '@vercel/commerce/auth/use-logout' import useLogout, { UseLogout } from '@vercel/commerce/auth/use-logout'
import type { LogoutHook } from '../types/logout' import type { LogoutHook } from '@vercel/commerce/types/logout'
import useCustomer from '../customer/use-customer' import useCustomer from '../customer/use-customer'
export default useLogout as UseLogout<typeof handler> export default useLogout as UseLogout<typeof handler>

View File

@ -1,8 +1,8 @@
import { useCallback } from 'react' import { useCallback } from 'react'
import type { MutationHook } from '@vercel/commerce/utils/types' import type { MutationHook } from '@vercel/commerce/utils/types'
import { CommerceError } from '@vercel/commerce/utils/errors' import { CommerceError } from '@vercel/commerce/utils/errors'
import useSignup, { UseSignup } from '@vercel/commerce/auth/use-signup' import useSignup, { type UseSignup } from '@vercel/commerce/auth/use-signup'
import type { SignupHook } from '../types/signup' import type { SignupHook } from '@vercel/commerce/types/signup'
import useCustomer from '../customer/use-customer' import useCustomer from '../customer/use-customer'
export default useSignup as UseSignup<typeof handler> export default useSignup as UseSignup<typeof handler>

View File

@ -4,8 +4,14 @@ import type {
HookFetcherContext, HookFetcherContext,
} from '@vercel/commerce/utils/types' } from '@vercel/commerce/utils/types'
import { ValidationError } from '@vercel/commerce/utils/errors' import { ValidationError } from '@vercel/commerce/utils/errors'
import useRemoveItem, { UseRemoveItem } from '@vercel/commerce/cart/use-remove-item' import useRemoveItem, {
import type { Cart, LineItem, RemoveItemHook } from '@vercel/commerce/types/cart' UseRemoveItem,
} from '@vercel/commerce/cart/use-remove-item'
import type {
Cart,
LineItem,
RemoveItemHook,
} from '@vercel/commerce/types/cart'
import useCart from './use-cart' import useCart from './use-cart'
export type RemoveItemFn<T = any> = T extends LineItem export type RemoveItemFn<T = any> = T extends LineItem

View File

@ -1,6 +1,8 @@
import { SWRHook } from '@vercel/commerce/utils/types' import type { SWRHook } from '@vercel/commerce/utils/types'
import useCustomer, { UseCustomer } from '@vercel/commerce/customer/use-customer' import useCustomer, {
import type { CustomerHook } from '../types/customer' type UseCustomer,
} from '@vercel/commerce/customer/use-customer'
import type { CustomerHook } from '@vercel/commerce/types/customer'
export default useCustomer as UseCustomer<typeof handler> export default useCustomer as UseCustomer<typeof handler>

View File

@ -1,7 +1,9 @@
import type { Product } from '../types/product' import type { Page } from '@vercel/commerce/types/page'
import type { Cart, BigcommerceCart, LineItem } from '../types/cart' import type { Product } from '@vercel/commerce/types/product'
import type { Page } from '../types/page' import type { Cart, LineItem } from '@vercel/commerce/types/cart'
import type { BCCategory, Category } from '../types/site' import type { Category, Brand } from '@vercel/commerce/types/site'
import type { BigcommerceCart, BCCategory, BCBrand } from '../types'
import { definitions } from '../api/definitions/store-content' import { definitions } from '../api/definitions/store-content'
import update from './immutability' import update from './immutability'
import getSlug from './get-slug' import getSlug from './get-slug'
@ -12,7 +14,7 @@ function normalizeProductOption(productOption: any) {
} = productOption } = productOption
return { return {
id: entityId, id: String(entityId),
values: edges?.map(({ node }: any) => node), values: edges?.map(({ node }: any) => node),
...rest, ...rest,
} }
@ -41,7 +43,7 @@ export function normalizeProduct(productNode: any): Product {
variants: { variants: {
$apply: ({ edges }: any) => $apply: ({ edges }: any) =>
edges?.map(({ node: { entityId, productOptions, ...rest } }: any) => ({ edges?.map(({ node: { entityId, productOptions, ...rest } }: any) => ({
id: entityId, id: String(entityId),
options: productOptions?.edges options: productOptions?.edges
? productOptions.edges.map(normalizeProductOption) ? productOptions.edges.map(normalizeProductOption)
: [], : [],
@ -54,7 +56,7 @@ export function normalizeProduct(productNode: any): Product {
: [], : [],
}, },
brand: { brand: {
$apply: (brand: any) => (brand?.entityId ? brand?.entityId : null), $apply: (brand: any) => (brand?.id ? brand.id : null),
}, },
slug: { slug: {
$set: path?.replace(/^\/+|\/+$/g, ''), $set: path?.replace(/^\/+|\/+$/g, ''),
@ -75,7 +77,8 @@ export function normalizePage(page: definitions['page_Full']): Page {
name: page.name, name: page.name,
is_visible: page.is_visible, is_visible: page.is_visible,
sort_order: page.sort_order, sort_order: page.sort_order,
body: page.body, body: page.body ?? '',
url: page.url,
} }
} }
@ -134,3 +137,12 @@ export function normalizeCategory(category: BCCategory): Category {
path: category.path, path: category.path,
} }
} }
export function normalizeBrand(brand: BCBrand): Brand {
return {
id: `${brand.node.entityId}`,
name: brand.node.name,
slug: getSlug(brand.node.path),
path: brand.node.path,
}
}

View File

@ -1,6 +1,6 @@
import { SWRHook } from '@vercel/commerce/utils/types' import { SWRHook } from '@vercel/commerce/utils/types'
import useSearch, { UseSearch } from '@vercel/commerce/product/use-search' import useSearch, { UseSearch } from '@vercel/commerce/product/use-search'
import type { SearchProductsHook } from '../types/product' import type { SearchProductsHook } from '@vercel/commerce/types/product'
export default useSearch as UseSearch<typeof handler> export default useSearch as UseSearch<typeof handler>

View File

@ -0,0 +1,32 @@
import type { GetSiteInfoQuery } from '../schema'
export type BCCategory = NonNullable<
GetSiteInfoQuery['site']['categoryTree']
>[0]
export type BCBrand = NonNullable<
NonNullable<GetSiteInfoQuery['site']['brands']['edges']>[0]
>
// TODO: this type should match:
// https://developer.bigcommerce.com/api-reference/cart-checkout/server-server-cart-api/cart/getacart#responses
export type BigcommerceCart = {
id: string
parent_id?: string
customer_id: number
email: string
currency: { code: string }
tax_included: boolean
base_amount: number
discount_amount: number
cart_amount: number
line_items: {
custom_items: any[]
digital_items: any[]
gift_certificates: any[]
physical_items: any[]
}
created_time: string
discounts?: { id: number; discounted_amount: number }[]
// TODO: add missing fields
}

View File

@ -1,66 +0,0 @@
import * as Core from '@vercel/commerce/types/cart'
export * from '@vercel/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 BigcommerceCart = {
id: string
parent_id?: string
customer_id: number
email: string
currency: { code: string }
tax_included: boolean
base_amount: number
discount_amount: number
cart_amount: number
line_items: {
custom_items: any[]
digital_items: any[]
gift_certificates: any[]
physical_items: any[]
}
created_time: string
discounts?: { id: number; discounted_amount: number }[]
// TODO: add missing fields
}
/**
* Extend core cart types
*/
export type Cart = Core.Cart & {
lineItems: 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<CartTypes>
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<CartTypes>
export type CartHandlers = Core.CartHandlers<CartTypes>
export type GetCartHandler = CartHandlers['getCart']
export type AddItemHandler = CartHandlers['addItem']
export type UpdateItemHandler = CartHandlers['updateItem']
export type RemoveItemHandler = CartHandlers['removeItem']

View File

@ -1 +0,0 @@
export * from '@vercel/commerce/types/checkout'

View File

@ -1 +0,0 @@
export * from '@vercel/commerce/types/common'

View File

@ -1,5 +0,0 @@
import * as Core from '@vercel/commerce/types/customer'
export * from '@vercel/commerce/types/customer'
export type CustomerSchema = Core.CustomerSchema

View File

@ -1,25 +0,0 @@
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,
}

View File

@ -1,8 +0,0 @@
import * as Core from '@vercel/commerce/types/login'
import type { LoginMutationVariables } from '../../schema'
export * from '@vercel/commerce/types/login'
export type LoginOperation = Core.LoginOperation & {
variables: LoginMutationVariables
}

View File

@ -1 +0,0 @@
export * from '@vercel/commerce/types/logout'

View File

@ -1,11 +0,0 @@
import * as Core from '@vercel/commerce/types/page'
export * from '@vercel/commerce/types/page'
export type Page = Core.Page
export type PageTypes = {
page: Page
}
export type GetAllPagesOperation = Core.GetAllPagesOperation<PageTypes>
export type GetPageOperation = Core.GetPageOperation<PageTypes>

View File

@ -1 +0,0 @@
export * from '@vercel/commerce/types/product'

View File

@ -1 +0,0 @@
export * from '@vercel/commerce/types/signup'

View File

@ -1,19 +0,0 @@
import * as Core from '@vercel/commerce/types/site'
import type { GetSiteInfoQuery, GetSiteInfoQueryVariables } from '../../schema'
export * from '@vercel/commerce/types/site'
export type BCCategory = NonNullable<
GetSiteInfoQuery['site']['categoryTree']
>[0]
export type Brand = NonNullable<
NonNullable<GetSiteInfoQuery['site']['brands']['edges']>[0]
>
export type SiteTypes = {
category: Core.Category
brand: Brand
}
export type GetSiteInfoOperation = Core.GetSiteInfoOperation<SiteTypes>

View File

@ -1,24 +0,0 @@
import * as Core from '@vercel/commerce/types/wishlist'
import { definitions } from '../api/definitions/wishlist'
import type { ProductEdge } from '../api/operations/get-all-products'
export * from '@vercel/commerce/types/wishlist'
export type WishlistItem = NonNullable<
definitions['wishlist_Full']['items']
>[0] & {
product?: ProductEdge['node']
}
export type Wishlist = Omit<definitions['wishlist_Full'], 'items'> & {
items?: WishlistItem[]
}
export type WishlistTypes = {
wishlist: Wishlist
itemBody: Core.WishlistItemBody
}
export type WishlistSchema = Core.WishlistSchema<WishlistTypes>
export type GetCustomerWishlistOperation =
Core.GetCustomerWishlistOperation<WishlistTypes>

View File

@ -1,8 +1,10 @@
import { useCallback } from 'react' import { useCallback } from 'react'
import type { MutationHook } from '@vercel/commerce/utils/types' import type { MutationHook } from '@vercel/commerce/utils/types'
import { CommerceError } from '@vercel/commerce/utils/errors' import { CommerceError } from '@vercel/commerce/utils/errors'
import useAddItem, { UseAddItem } from '@vercel/commerce/wishlist/use-add-item' import useAddItem, {
import type { AddItemHook } from '../types/wishlist' type UseAddItem,
} from '@vercel/commerce/wishlist/use-add-item'
import type { AddItemHook } from '@vercel/commerce/types/wishlist'
import useCustomer from '../customer/use-customer' import useCustomer from '../customer/use-customer'
import useWishlist from './use-wishlist' import useWishlist from './use-wishlist'

View File

@ -2,9 +2,9 @@ import { useCallback } from 'react'
import type { MutationHook } from '@vercel/commerce/utils/types' import type { MutationHook } from '@vercel/commerce/utils/types'
import { CommerceError } from '@vercel/commerce/utils/errors' import { CommerceError } from '@vercel/commerce/utils/errors'
import useRemoveItem, { import useRemoveItem, {
UseRemoveItem, type UseRemoveItem,
} from '@vercel/commerce/wishlist/use-remove-item' } from '@vercel/commerce/wishlist/use-remove-item'
import type { RemoveItemHook } from '../types/wishlist' import type { RemoveItemHook } from '@vercel/commerce/types/wishlist'
import useCustomer from '../customer/use-customer' import useCustomer from '../customer/use-customer'
import useWishlist from './use-wishlist' import useWishlist from './use-wishlist'

View File

@ -1,11 +1,11 @@
import { useMemo } from 'react' import { useMemo } from 'react'
import { SWRHook } from '@vercel/commerce/utils/types' import { SWRHook } from '@vercel/commerce/utils/types'
import useWishlist, { import useWishlist, {
UseWishlist, type UseWishlist,
} from '@vercel/commerce/wishlist/use-wishlist' } from '@vercel/commerce/wishlist/use-wishlist'
import useCustomer from '../customer/use-customer' import useCustomer from '../customer/use-customer'
import type { GetWishlistHook } from '../types/wishlist' import type { GetWishlistHook } from '@vercel/commerce/types/wishlist'
export default useWishlist as UseWishlist<typeof handler> export default useWishlist as UseWishlist<typeof handler>
export const handler: SWRHook<GetWishlistHook> = { export const handler: SWRHook<GetWishlistHook> = {
@ -32,7 +32,7 @@ export const handler: SWRHook<GetWishlistHook> = {
const { data: customer } = useCustomer() const { data: customer } = useCustomer()
const response = useData({ const response = useData({
input: [ input: [
['customerId', customer?.entityId], ['customerId', customer?.id],
['includeProducts', input?.includeProducts], ['includeProducts', input?.includeProducts],
], ],
swrOptions: { swrOptions: {

View File

@ -52,7 +52,8 @@
"import-cwd": "^3.0.0", "import-cwd": "^3.0.0",
"js-cookie": "^3.0.1", "js-cookie": "^3.0.1",
"swr": "^1.3.0", "swr": "^1.3.0",
"node-fetch": "^2.6.7" "node-fetch": "^2.6.7",
"zod": "^3.19.0"
}, },
"peerDependencies": { "peerDependencies": {
"next": "^12", "next": "^12",

View File

@ -3,58 +3,60 @@ import { CommerceAPIError } from '../utils/errors'
import isAllowedOperation from '../utils/is-allowed-operation' import isAllowedOperation from '../utils/is-allowed-operation'
import type { GetAPISchema } from '..' import type { GetAPISchema } from '..'
const cartEndpoint: GetAPISchema<any, CartSchema<any>>['endpoint']['handler'] = const cartEndpoint: GetAPISchema<
async (ctx) => { any,
const { req, res, handlers, config } = ctx CartSchema
>['endpoint']['handler'] = async (ctx) => {
const { req, res, handlers, config } = ctx
if ( if (
!isAllowedOperation(req, res, { !isAllowedOperation(req, res, {
GET: handlers['getCart'], GET: handlers['getCart'],
POST: handlers['addItem'], POST: handlers['addItem'],
PUT: handlers['updateItem'], PUT: handlers['updateItem'],
DELETE: handlers['removeItem'], DELETE: handlers['removeItem'],
}) })
) { ) {
return return
}
const { cookies } = req
const cartId = cookies[config.cartCookie]
try {
// Return current cart info
if (req.method === 'GET') {
const body = { cartId }
return await handlers['getCart']({ ...ctx, body })
}
// Create or add an item to the cart
if (req.method === 'POST') {
const body = { ...req.body, cartId }
return await handlers['addItem']({ ...ctx, body })
}
// Update item in cart
if (req.method === 'PUT') {
const body = { ...req.body, cartId }
return await handlers['updateItem']({ ...ctx, body })
}
// Remove an item from the cart
if (req.method === 'DELETE') {
const body = { ...req.body, cartId }
return await handlers['removeItem']({ ...ctx, body })
}
} catch (error) {
console.error(error)
const message =
error instanceof CommerceAPIError
? 'An unexpected error ocurred with the Commerce API'
: 'An unexpected error ocurred'
res.status(500).json({ data: null, errors: [{ message }] })
}
} }
const { cookies } = req
const cartId = cookies[config.cartCookie]
try {
// Return current cart info
if (req.method === 'GET') {
const body = { cartId }
return await handlers['getCart']({ ...ctx, body })
}
// Create or add an item to the cart
if (req.method === 'POST') {
const body = { ...req.body, cartId }
return await handlers['addItem']({ ...ctx, body })
}
// Update item in cart
if (req.method === 'PUT') {
const body = { ...req.body, cartId }
return await handlers['updateItem']({ ...ctx, body })
}
// Remove an item from the cart
if (req.method === 'DELETE') {
const body = { ...req.body, cartId }
return await handlers['removeItem']({ ...ctx, body })
}
} catch (error) {
console.error(error)
const message =
error instanceof CommerceAPIError
? 'An unexpected error ocurred with the Commerce API'
: 'An unexpected error ocurred'
res.status(500).json({ data: null, errors: [{ message }] })
}
}
export default cartEndpoint export default cartEndpoint

View File

@ -6,7 +6,7 @@ import isAllowedOperation from '../../utils/is-allowed-operation'
const customerEndpoint: GetAPISchema< const customerEndpoint: GetAPISchema<
any, any,
CustomerSchema<any> CustomerSchema
>['endpoint']['handler'] = async (ctx) => { >['endpoint']['handler'] = async (ctx) => {
const { req, res, handlers } = ctx const { req, res, handlers } = ctx

View File

@ -5,7 +5,7 @@ import type { GetAPISchema } from '..'
const loginEndpoint: GetAPISchema< const loginEndpoint: GetAPISchema<
any, any,
LoginSchema<any> LoginSchema
>['endpoint']['handler'] = async (ctx) => { >['endpoint']['handler'] = async (ctx) => {
const { req, res, handlers } = ctx const { req, res, handlers } = ctx

View File

@ -5,7 +5,7 @@ import type { GetAPISchema } from '..'
const wishlistEndpoint: GetAPISchema< const wishlistEndpoint: GetAPISchema<
any, any,
WishlistSchema<any> WishlistSchema
>['endpoint']['handler'] = async (ctx) => { >['endpoint']['handler'] = async (ctx) => {
const { req, res, handlers, config } = ctx const { req, res, handlers, config } = ctx

View File

@ -11,11 +11,14 @@ import type { WishlistSchema } from '../types/wishlist'
import type { CheckoutSchema } from '../types/checkout' import type { CheckoutSchema } from '../types/checkout'
import type { CustomerCardSchema } from '../types/customer/card' import type { CustomerCardSchema } from '../types/customer/card'
import type { CustomerAddressSchema } from '../types/customer/address' import type { CustomerAddressSchema } from '../types/customer/address'
import { withOperationCallback } from './utils/with-operation-callback'
import { import {
defaultOperations,
OPERATIONS, OPERATIONS,
AllOperations, AllOperations,
APIOperations, APIOperations,
defaultOperations,
} from './operations' } from './operations'
export type APISchemas = export type APISchemas =
@ -106,7 +109,10 @@ export function getCommerceApi<P extends APIProvider>(
OPERATIONS.forEach((k) => { OPERATIONS.forEach((k) => {
const op = ops[k] const op = ops[k]
if (op) { if (op) {
commerce[k] = op({ commerce }) as AllOperations<P>[typeof k] commerce[k] = withOperationCallback(
k,
op({ commerce })
) as AllOperations<P>[typeof k]
} }
}) })

View File

@ -25,6 +25,13 @@ export const OPERATIONS = [
'getProduct', 'getProduct',
] as const ] as const
export type Operation = {
[O in AllowedOperations]: {
name: O
data: Awaited<ReturnType<Operations<APIProvider>[O]>>
}
}[AllowedOperations]
export const defaultOperations = OPERATIONS.reduce((ops, k) => { export const defaultOperations = OPERATIONS.reduce((ops, k) => {
ops[k] = noop ops[k] = noop
return ops return ops

View File

@ -1,4 +1,7 @@
import { ZodError } from 'zod'
import type { Response } from '@vercel/fetch' import type { Response } from '@vercel/fetch'
import { CommerceError } from '../../utils/errors'
export class CommerceAPIError extends Error { export class CommerceAPIError extends Error {
status: number status: number
@ -20,3 +23,25 @@ export class CommerceNetworkError extends Error {
this.name = 'CommerceNetworkError' this.name = 'CommerceNetworkError'
} }
} }
export const getOperationError = (operation: string, error: unknown) => {
if (error instanceof ZodError) {
return new CommerceError({
code: 'SCHEMA_VALIDATION_ERROR',
message:
`The ${operation} operation returned invalid data and has ${
error.issues.length
} parse ${error.issues.length === 1 ? 'error' : 'errors'}: \n` +
error.issues
.map(
(e, index) =>
`Error #${index + 1} ${
e.path.length > 0 ? `Path: ${e.path.join('.')}, ` : ''
}Code: ${e.code}, Message: ${e.message}`
)
.join('\n'),
})
}
return error
}

View File

@ -0,0 +1,42 @@
import type { AllowedOperations, Operation } from '../operations'
import { z } from 'zod'
import { getOperationError } from './errors'
import { pageSchema } from '../../schemas/page'
import { siteInfoSchema } from '../../schemas/site'
import { productSchema, productsPathsSchema } from '../../schemas/product'
export const withOperationCallback =
(name: AllowedOperations, fn: (...args: any[]) => Promise<any>) =>
async (...args: any[]) => {
try {
const data = await fn(...args)
parse({ name, data })
return data
} catch (error) {
throw getOperationError(name, error)
}
}
const parse = ({ name, data }: Operation) => {
switch (name) {
case 'getProduct':
productSchema.nullable().parse(data.product)
break
case 'getAllProducts':
z.array(productSchema).parse(data.products)
break
case 'getAllProductPaths':
productsPathsSchema.parse(data.products)
break
case 'getPage':
pageSchema.nullable().parse(data.page)
break
case 'getAllPages':
z.array(pageSchema).parse(data.pages)
break
case 'getSiteInfo':
siteInfoSchema.parse(data)
break
}
}

View File

@ -5,7 +5,7 @@ import type { LoginHook } from '../types/login'
import type { Provider } from '..' import type { Provider } from '..'
export type UseLogin< export type UseLogin<
H extends MutationHook<LoginHook<any>> = MutationHook<LoginHook> H extends MutationHook<LoginHook> = MutationHook<LoginHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<LoginHook> = mutationFetcher export const fetcher: HookFetcherFn<LoginHook> = mutationFetcher

View File

@ -5,7 +5,7 @@ import type { LogoutHook } from '../types/logout'
import type { Provider } from '..' import type { Provider } from '..'
export type UseLogout< export type UseLogout<
H extends MutationHook<LogoutHook<any>> = MutationHook<LogoutHook> H extends MutationHook<LogoutHook> = MutationHook<LogoutHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<LogoutHook> = mutationFetcher export const fetcher: HookFetcherFn<LogoutHook> = mutationFetcher

View File

@ -5,7 +5,7 @@ import type { SignupHook } from '../types/signup'
import type { Provider } from '..' import type { Provider } from '..'
export type UseSignup< export type UseSignup<
H extends MutationHook<SignupHook<any>> = MutationHook<SignupHook> H extends MutationHook<SignupHook> = MutationHook<SignupHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<SignupHook> = mutationFetcher export const fetcher: HookFetcherFn<SignupHook> = mutationFetcher

View File

@ -5,7 +5,7 @@ import type { AddItemHook } from '../types/cart'
import type { Provider } from '..' import type { Provider } from '..'
export type UseAddItem< export type UseAddItem<
H extends MutationHook<AddItemHook<any>> = MutationHook<AddItemHook> H extends MutationHook<AddItemHook> = MutationHook<AddItemHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<AddItemHook> = mutationFetcher export const fetcher: HookFetcherFn<AddItemHook> = mutationFetcher

View File

@ -4,9 +4,8 @@ import type { SWRHook, HookFetcherFn } from '../utils/types'
import type { GetCartHook } from '../types/cart' import type { GetCartHook } from '../types/cart'
import { Provider, useCommerce } from '..' import { Provider, useCommerce } from '..'
export type UseCart< export type UseCart<H extends SWRHook<GetCartHook> = SWRHook<GetCartHook>> =
H extends SWRHook<GetCartHook<any>> = SWRHook<GetCartHook> ReturnType<H['useHook']>
> = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<GetCartHook> = async ({ export const fetcher: HookFetcherFn<GetCartHook> = async ({
options, options,

View File

@ -5,7 +5,7 @@ import type { RemoveItemHook } from '../types/cart'
import type { Provider } from '..' import type { Provider } from '..'
export type UseRemoveItem< export type UseRemoveItem<
H extends MutationHook<RemoveItemHook<any>> = MutationHook<RemoveItemHook> H extends MutationHook<RemoveItemHook> = MutationHook<RemoveItemHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<RemoveItemHook> = mutationFetcher export const fetcher: HookFetcherFn<RemoveItemHook> = mutationFetcher

View File

@ -5,7 +5,7 @@ import type { UpdateItemHook } from '../types/cart'
import type { Provider } from '..' import type { Provider } from '..'
export type UseUpdateItem< export type UseUpdateItem<
H extends MutationHook<UpdateItemHook<any>> = MutationHook<UpdateItemHook> H extends MutationHook<UpdateItemHook> = MutationHook<UpdateItemHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<UpdateItemHook> = mutationFetcher export const fetcher: HookFetcherFn<UpdateItemHook> = mutationFetcher

View File

@ -7,7 +7,7 @@ import { useHook, useSWRHook } from '../utils/use-hook'
import { Provider, useCommerce } from '..' import { Provider, useCommerce } from '..'
export type UseCheckout< export type UseCheckout<
H extends SWRHook<GetCheckoutHook<any>> = SWRHook<GetCheckoutHook> H extends SWRHook<GetCheckoutHook> = SWRHook<GetCheckoutHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<GetCheckoutHook> = async ({ export const fetcher: HookFetcherFn<GetCheckoutHook> = async ({

View File

@ -6,9 +6,7 @@ import { useHook, useMutationHook } from '../utils/use-hook'
import { mutationFetcher } from '../utils/default-fetcher' import { mutationFetcher } from '../utils/default-fetcher'
export type UseSubmitCheckout< export type UseSubmitCheckout<
H extends MutationHook< H extends MutationHook<SubmitCheckoutHook> = MutationHook<SubmitCheckoutHook>
SubmitCheckoutHook<any>
> = MutationHook<SubmitCheckoutHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<SubmitCheckoutHook> = mutationFetcher export const fetcher: HookFetcherFn<SubmitCheckoutHook> = mutationFetcher

View File

@ -6,7 +6,7 @@ import { useHook, useMutationHook } from '../../utils/use-hook'
import { mutationFetcher } from '../../utils/default-fetcher' import { mutationFetcher } from '../../utils/default-fetcher'
export type UseAddItem< export type UseAddItem<
H extends MutationHook<AddItemHook<any>> = MutationHook<AddItemHook> H extends MutationHook<AddItemHook> = MutationHook<AddItemHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<AddItemHook> = mutationFetcher export const fetcher: HookFetcherFn<AddItemHook> = mutationFetcher

View File

@ -7,7 +7,7 @@ import { useHook, useSWRHook } from '../../utils/use-hook'
import { Provider, useCommerce } from '../..' import { Provider, useCommerce } from '../..'
export type UseAddresses< export type UseAddresses<
H extends SWRHook<GetAddressesHook<any>> = SWRHook<GetAddressesHook> H extends SWRHook<GetAddressesHook> = SWRHook<GetAddressesHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<GetAddressesHook> = async ({ export const fetcher: HookFetcherFn<GetAddressesHook> = async ({

View File

@ -6,7 +6,7 @@ import { useHook, useMutationHook } from '../../utils/use-hook'
import { mutationFetcher } from '../../utils/default-fetcher' import { mutationFetcher } from '../../utils/default-fetcher'
export type UseRemoveItem< export type UseRemoveItem<
H extends MutationHook<RemoveItemHook<any>> = MutationHook<RemoveItemHook> H extends MutationHook<RemoveItemHook> = MutationHook<RemoveItemHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<RemoveItemHook> = mutationFetcher export const fetcher: HookFetcherFn<RemoveItemHook> = mutationFetcher

View File

@ -6,7 +6,7 @@ import { useHook, useMutationHook } from '../../utils/use-hook'
import { mutationFetcher } from '../../utils/default-fetcher' import { mutationFetcher } from '../../utils/default-fetcher'
export type UseUpdateItem< export type UseUpdateItem<
H extends MutationHook<UpdateItemHook<any>> = MutationHook<UpdateItemHook> H extends MutationHook<UpdateItemHook> = MutationHook<UpdateItemHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<UpdateItemHook> = mutationFetcher export const fetcher: HookFetcherFn<UpdateItemHook> = mutationFetcher

View File

@ -6,7 +6,7 @@ import { useHook, useMutationHook } from '../../utils/use-hook'
import { mutationFetcher } from '../../utils/default-fetcher' import { mutationFetcher } from '../../utils/default-fetcher'
export type UseAddItem< export type UseAddItem<
H extends MutationHook<AddItemHook<any>> = MutationHook<AddItemHook> H extends MutationHook<AddItemHook> = MutationHook<AddItemHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<AddItemHook> = mutationFetcher export const fetcher: HookFetcherFn<AddItemHook> = mutationFetcher

View File

@ -6,9 +6,8 @@ import Cookies from 'js-cookie'
import { useHook, useSWRHook } from '../../utils/use-hook' import { useHook, useSWRHook } from '../../utils/use-hook'
import { Provider, useCommerce } from '../..' import { Provider, useCommerce } from '../..'
export type UseCards< export type UseCards<H extends SWRHook<GetCardsHook> = SWRHook<GetCardsHook>> =
H extends SWRHook<GetCardsHook<any>> = SWRHook<GetCardsHook> ReturnType<H['useHook']>
> = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<GetCardsHook> = async ({ export const fetcher: HookFetcherFn<GetCardsHook> = async ({
options, options,

View File

@ -6,7 +6,7 @@ import { useHook, useMutationHook } from '../../utils/use-hook'
import { mutationFetcher } from '../../utils/default-fetcher' import { mutationFetcher } from '../../utils/default-fetcher'
export type UseRemoveItem< export type UseRemoveItem<
H extends MutationHook<RemoveItemHook<any>> = MutationHook<RemoveItemHook> H extends MutationHook<RemoveItemHook> = MutationHook<RemoveItemHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<RemoveItemHook> = mutationFetcher export const fetcher: HookFetcherFn<RemoveItemHook> = mutationFetcher

View File

@ -6,7 +6,7 @@ import { useHook, useMutationHook } from '../../utils/use-hook'
import { mutationFetcher } from '../../utils/default-fetcher' import { mutationFetcher } from '../../utils/default-fetcher'
export type UseUpdateItem< export type UseUpdateItem<
H extends MutationHook<UpdateItemHook<any>> = MutationHook<UpdateItemHook> H extends MutationHook<UpdateItemHook> = MutationHook<UpdateItemHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<UpdateItemHook> = mutationFetcher export const fetcher: HookFetcherFn<UpdateItemHook> = mutationFetcher

View File

@ -5,7 +5,7 @@ import type { HookFetcherFn, SWRHook } from '../utils/types'
import type { Provider } from '..' import type { Provider } from '..'
export type UseCustomer< export type UseCustomer<
H extends SWRHook<CustomerHook<any>> = SWRHook<CustomerHook> H extends SWRHook<CustomerHook> = SWRHook<CustomerHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<CustomerHook> = SWRFetcher export const fetcher: HookFetcherFn<CustomerHook> = SWRFetcher

View File

@ -5,7 +5,7 @@ import type { SearchProductsHook } from '../types/product'
import type { Provider } from '..' import type { Provider } from '..'
export type UseSearch< export type UseSearch<
H extends SWRHook<SearchProductsHook<any>> = SWRHook<SearchProductsHook> H extends SWRHook<SearchProductsHook> = SWRHook<SearchProductsHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<SearchProductsHook> = SWRFetcher export const fetcher: HookFetcherFn<SearchProductsHook> = SWRFetcher

View File

@ -0,0 +1,18 @@
import { z } from 'zod'
export const pageSchema = z.object({
id: z.string(),
name: z.string(),
url: z.string().startsWith('/').optional(),
body: z.string(),
is_visible: z.boolean().optional(),
sort_order: z.number().optional(),
})
export const pagesPathsSchema = z.array(
z.object({
page: z.object({
path: z.string().startsWith('/'),
}),
})
)

View File

@ -0,0 +1,60 @@
import { z } from 'zod'
export const productPriceSchema = z.object({
value: z.number(),
currencyCode: z.string().max(3).optional(),
retailPrice: z.number().optional(),
})
export const productOptionSchema = z.object({
id: z.string(),
displayName: z.string(),
values: z.array(
z.object({
label: z.string(),
hexColors: z.array(z.string()).optional(),
})
),
})
export const productImageSchema = z.object({
url: z.string().url().or(z.string().startsWith('/')),
alt: z.string().optional(),
width: z.number().optional(),
height: z.number().optional(),
})
export const productVariantSchema = z.object({
id: z.string(),
sku: z.string().nullish(),
name: z.string().optional(),
options: z.array(productOptionSchema),
image: productImageSchema.optional(),
})
export const productSchema = z.object({
id: z.string(),
name: z.string(),
description: z.string(),
descriptionHtml: z.string().optional(),
sku: z.string().nullish(),
slug: z.string(),
path: z.string().startsWith('/'),
images: z.array(productImageSchema),
variants: z.array(productVariantSchema),
price: productPriceSchema,
options: z.array(productOptionSchema),
vendor: z.string().optional(),
})
export const productsPathsSchema = z.array(
z.object({ path: z.string().startsWith('/') })
)
export const searchProductBodySchema = z.object({
search: z.string(),
categoryId: z.string(),
brandId: z.string().optional(),
sort: z.string().optional(),
locale: z.string().optional(),
})

View File

@ -0,0 +1,18 @@
import { z } from 'zod'
export const siteInfoSchema = z.object({
categories: z.array(
z.object({
id: z.string(),
name: z.string(),
path: z.string().startsWith('/'),
})
),
brands: z.array(
z.object({
id: z.string(),
name: z.string(),
path: z.string().startsWith('/'),
})
),
})

View File

@ -1,177 +1,264 @@
import type { Discount, Measurement, Image } from './common' import type { Discount, Image, Measurement } from './common'
export type SelectedOption = { // TODO: This should use the same type as the `ProductVariant` type from `product.ts`
// The option's id. export interface ProductVariant {
id?: string /**
// The product options name. * The unique identifier for the variant.
name: string */
/// The product options value.
value: string
}
export type LineItem = {
id: string id: string
variantId: string /**
productId: string * The SKU (stock keeping unit) associated with the product variant.
*/
sku?: string
/**
* The product variants name, or the product's name.
*/
name: string name: string
quantity: number /**
discounts: Discount[] * The product variants price after all discounts are applied.
// A human-friendly unique string automatically generated from the products name */
path: string
variant: ProductVariant
options?: SelectedOption[]
}
export type ProductVariant = {
id: string
// The SKU (stock keeping unit) associated with the product variant.
sku: string
// The product variants title, or the product's name.
name: string
// Whether a customer needs to provide a shipping address when placing
// an order for the product variant.
requiresShipping: boolean
// The product variants price after all discounts are applied.
price: number price: number
// Product variants price, as quoted by the manufacturer/distributor. /**
* The product variants price before discounts are applied.
*/
listPrice: number listPrice: number
// Image associated with the product variant. Falls back to the product image /**
// if no image is available. * Indicates if the variant is available for sale.
image?: Image */
// Indicates whether this product variant is in stock.
isInStock?: boolean
// Indicates if the product variant is available for sale.
availableForSale?: boolean availableForSale?: boolean
// The variant's weight. If a weight was not explicitly specified on the /**
// variant this will be the product's weight. * Whether a customer needs to provide a shipping address when placing
* an order for the product variant.
*/
requiresShipping?: boolean
/**
* The image associated with the variant.
*/
image?: Image
/**
* The variant's weight. If a weight was not explicitly specified on the
* variant, this will be the product's weight.
*/
weight?: Measurement weight?: Measurement
// The variant's height. If a height was not explicitly specified on the /**
// variant, this will be the product's height. * The variant's height. If a height was not explicitly specified on the
* variant, this will be the product's height.
*/
height?: Measurement height?: Measurement
// The variant's width. If a width was not explicitly specified on the /**
// variant, this will be the product's width. * The variant's width. If a width was not explicitly specified on the
* variant, this will be the product's width.
*/
width?: Measurement width?: Measurement
// The variant's depth. If a depth was not explicitly specified on the /**
// variant, this will be the product's depth. * The variant's depth. If a depth was not explicitly specified on the
* variant, this will be the product's depth.
*/
depth?: Measurement depth?: Measurement
} }
// Shopping cart, a.k.a Checkout export interface SelectedOption {
export type Cart = { /**
* The unique identifier for the option.
*/
id?: string
/**
* The product options name, such as "Color" or "Size".
*/
name: string
/**
* The product options value, such as "Red" or "XL".
*/
value: string
}
export interface LineItem {
/**
* The unique identifier for the line item.
*/
id: string id: string
// ID of the customer to which the cart belongs. /**
* The unique identifier for the product variant.
*/
variantId: string
/**
* The unique identifier for the product, if the variant is not provided.
*/
productId: string
/**
* This is usually the product's name.
*/
name: string
/**
* The quantity of the product variant in the line item.
*/
quantity: number
/**
* List of discounts applied to the line item.
*/
discounts: Discount[]
/**
* A human-friendly unique string automatically generated from the products name.
*/
path: string
/**
* The product variant.
*/
variant: ProductVariant
/**
* List of selected options, to be used when displaying the line item, such as Color: Red, Size: XL.
*/
options?: SelectedOption[]
}
/**
* Shopping cart, a.k.a Checkout
*/
export interface Cart {
/**
* The unique identifier for the cart.
*/
id: string
/**
* ID of the customer to which the cart belongs.
*/
customerId?: string customerId?: string
// The email assigned to this cart /**
* The URL of the cart.
*/
url?: string
/**
* The email assigned to this cart.
*/
email?: string email?: string
// The date and time when the cart was created. /**
* The date and time when the cart was created.
*/
createdAt: string createdAt: string
// The currency used for this cart /**
* The currency used for this cart */
currency: { code: string } currency: { code: string }
// Specifies if taxes are included in the line items. /**
* Indicates if taxes are included in the line items.
*/
taxesIncluded: boolean taxesIncluded: boolean
/**
* List of cart line items.
*/
lineItems: LineItem[] lineItems: LineItem[]
// The sum of all the prices of all the items in the cart. /**
// Duties, taxes, shipping and discounts excluded. * The sum of all the pricexs of all the items in the cart.
* Duties, taxes, shipping and discounts excluded.
*/
lineItemsSubtotalPrice: number lineItemsSubtotalPrice: number
// Price of the cart before duties, shipping and taxes. /**
* Price of the cart before duties, shipping and taxes.*/
subtotalPrice: number subtotalPrice: number
// The sum of all the prices of all the items in the cart. /**
// Duties, taxes and discounts included. * The sum of all the prices of all the items in the cart.
* Duties, taxes and discounts included.
*/
totalPrice: number totalPrice: number
// Discounts that have been applied on the cart. /**
* Discounts that have been applied on the cart.
*/
discounts?: Discount[] discounts?: Discount[]
} }
/** /**
* Base cart item body used for cart mutations * Base cart item body used for cart mutations
*/ */
export type CartItemBody = { export interface CartItemBody {
/**
* The unique identifier for the product variant.
*/
variantId: string variantId: string
/**
* The unique identifier for the product, if the variant is not provided.
*/
productId?: string productId?: string
/**
* The quantity of the product variant.
*/
quantity?: number quantity?: number
/**
* The product variant's selected options.
*/
optionsSelected?: SelectedOption[]
} }
/** /**
* Hooks schema * Cart Hooks for add, update and remove items from the cart
*/ */
export type CartHooks = {
export type CartTypes = { getCart: GetCartHook
cart?: Cart addItem: AddItemHook
item: LineItem updateItem: UpdateItemHook
itemBody: CartItemBody removeItem: RemoveItemHook
} }
export type CartHooks<T extends CartTypes = CartTypes> = { export type GetCartHook = {
getCart: GetCartHook<T> data: Cart | null
addItem: AddItemHook<T>
updateItem: UpdateItemHook<T>
removeItem: RemoveItemHook<T>
}
export type GetCartHook<T extends CartTypes = CartTypes> = {
data: T['cart'] | null
input: {} input: {}
fetcherInput: { cartId?: string } fetcherInput: { cartId?: string }
swrState: { isEmpty: boolean } swrState: { isEmpty: boolean }
} }
export type AddItemHook<T extends CartTypes = CartTypes> = { export type AddItemHook = {
data: T['cart'] data: Cart
input?: T['itemBody'] input?: CartItemBody
fetcherInput: T['itemBody'] fetcherInput: CartItemBody
body: { item: T['itemBody'] } body: { item: CartItemBody }
actionInput: T['itemBody'] actionInput: CartItemBody
} }
export type UpdateItemHook<T extends CartTypes = CartTypes> = { export type UpdateItemHook = {
data: T['cart'] | null data: Cart | null | undefined
input: { item?: T['item']; wait?: number } input: { item?: LineItem; wait?: number }
fetcherInput: { itemId: string; item: T['itemBody'] } fetcherInput: { itemId: string; item: CartItemBody }
body: { itemId: string; item: T['itemBody'] } body: { itemId: string; item: CartItemBody }
actionInput: T['itemBody'] & { id: string } actionInput: CartItemBody & { id: string }
} }
export type RemoveItemHook<T extends CartTypes = CartTypes> = { export type RemoveItemHook = {
data: T['cart'] | null data: Cart | null | undefined
input: { item?: T['item'] } input: { item?: LineItem }
fetcherInput: { itemId: string } fetcherInput: { itemId: string }
body: { itemId: string } body: { itemId: string }
actionInput: { id: string } actionInput: { id: string }
} }
/** /**
* API Schema * Cart API endpoitns & handlers for add, update and remove items from the cart
*/ */
export type CartSchema = {
export type CartSchema<T extends CartTypes = CartTypes> = {
endpoint: { endpoint: {
options: {} options: {}
handlers: CartHandlers<T> handlers: CartHandlers
} }
} }
export type CartHandlers<T extends CartTypes = CartTypes> = { export type CartHandlers = {
getCart: GetCartHandler<T> getCart: GetCartHandler
addItem: AddItemHandler<T> addItem: AddItemHandler
updateItem: UpdateItemHandler<T> updateItem: UpdateItemHandler
removeItem: RemoveItemHandler<T> removeItem: RemoveItemHandler
} }
export type GetCartHandler<T extends CartTypes = CartTypes> = GetCartHook<T> & { export type GetCartHandler = GetCartHook & {
body: { cartId?: string } body: { cartId?: string }
} }
export type AddItemHandler<T extends CartTypes = CartTypes> = AddItemHook<T> & { export type AddItemHandler = AddItemHook & {
body: { cartId: string } body: { cartId: string }
} }
export type UpdateItemHandler<T extends CartTypes = CartTypes> = export type UpdateItemHandler = UpdateItemHook & {
UpdateItemHook<T> & { data: Cart
data: T['cart'] body: { cartId: string }
body: { cartId: string } }
}
export type RemoveItemHandler<T extends CartTypes = CartTypes> = export type RemoveItemHandler = RemoveItemHook & {
RemoveItemHook<T> & { body: { cartId: string }
body: { cartId: string } }
}

View File

@ -1,57 +1,89 @@
import type { UseSubmitCheckout } from '../checkout/use-submit-checkout' import type { UseSubmitCheckout } from '../checkout/use-submit-checkout'
import type { Address, AddressFields } from './customer/address' import type { AddressFields } from './customer/address'
import type { Card, CardFields } from './customer/card' import type { Card, CardFields } from './customer/card'
import type { LineItem } from './cart'
// Index export interface Checkout {
export type Checkout = any /**
* Indicates if the checkout has payment iformation collected.
export type CheckoutTypes = { */
card?: Card | CardFields hasPayment: boolean
address?: Address | AddressFields /**
checkout?: Checkout * Indicates if the checkout has shipping information collected.
hasPayment?: boolean */
hasShipping?: boolean hasShipping: boolean
/**
* The unique identifier for the address that the customer has selected for shipping.
*/
addressId: string
/**
* The list of payment cards that the customer has available.
*/
payments?: Card[]
/**
* The unique identifier of the card that the customer has selected for payment.
*/
cardId?: string
/**
* List of items in the checkout.
*/
lineItems?: LineItem[]
} }
export type SubmitCheckoutHook<T extends CheckoutTypes = CheckoutTypes> = { export interface CheckoutBody {
data: T /**
input?: T * The unique identifier for the cart.
fetcherInput: T */
body: { item: T } cartId?: string
actionInput: T /**
* The Card information.
* @see CardFields
*/
card: CardFields
/**
* The Address information.
* @see AddressFields
*/
address: AddressFields
} }
export type GetCheckoutHook<T extends CheckoutTypes = CheckoutTypes> = { export type SubmitCheckoutHook = {
data: T['checkout'] | null data: Checkout
input?: CheckoutBody
fetcherInput: CheckoutBody
body: { item: CheckoutBody }
actionInput: CheckoutBody
}
export type GetCheckoutHook = {
data: Checkout | null
input: {} input: {}
fetcherInput: { cartId?: string } fetcherInput: { cartId?: string }
swrState: { isEmpty: boolean } swrState: { isEmpty: boolean }
mutations: { submit: UseSubmitCheckout } mutations: { submit: UseSubmitCheckout }
} }
export type CheckoutHooks<T extends CheckoutTypes = CheckoutTypes> = { export type CheckoutHooks = {
submitCheckout?: SubmitCheckoutHook<T> submitCheckout?: SubmitCheckoutHook
getCheckout: GetCheckoutHook<T> getCheckout: GetCheckoutHook
} }
export type GetCheckoutHandler<T extends CheckoutTypes = CheckoutTypes> = export type GetCheckoutHandler = GetCheckoutHook & {
GetCheckoutHook<T> & { body: { cartId: string }
body: { cartId: string }
}
export type SubmitCheckoutHandler<T extends CheckoutTypes = CheckoutTypes> =
SubmitCheckoutHook<T> & {
body: { cartId: string }
}
export type CheckoutHandlers<T extends CheckoutTypes = CheckoutTypes> = {
getCheckout: GetCheckoutHandler<T>
submitCheckout?: SubmitCheckoutHandler<T>
} }
export type CheckoutSchema<T extends CheckoutTypes = CheckoutTypes> = { export type SubmitCheckoutHandler = SubmitCheckoutHook & {
body: { cartId: string }
}
export type CheckoutHandlers = {
getCheckout: GetCheckoutHandler
submitCheckout?: SubmitCheckoutHandler
}
export type CheckoutSchema = {
endpoint: { endpoint: {
options: {} options: {}
handlers: CheckoutHandlers<T> handlers: CheckoutHandlers
} }
} }

View File

@ -1,16 +1,36 @@
export type Discount = { export interface Discount {
// The value of the discount, can be an amount or percentage /**
* The value of the discount, can be an amount or percentage.
*/
value: number value: number
} }
export type Measurement = { export interface Measurement {
/**
* The measurement's value.
*/
value: number value: number
/**
* The measurement's unit, such as "KILOGRAMS", "GRAMS", "POUNDS" & "OOUNCES".
*/
unit: 'KILOGRAMS' | 'GRAMS' | 'POUNDS' | 'OUNCES' unit: 'KILOGRAMS' | 'GRAMS' | 'POUNDS' | 'OUNCES'
} }
export type Image = { export interface Image {
/**
* The URL of the image.
*/
url: string url: string
altText?: string /**
* A word or phrase that describes the content of an image.
*/
alt?: string
/**
* The image's width.
*/
width?: number width?: number
/**
* The image's height.
*/
height?: number height?: number
} }

View File

@ -1,111 +1,123 @@
export interface Address { export interface Address {
/**
* The unique identifier for the address.
*/
id: string id: string
/**
* The customer's first name.
*/
mask: string mask: string
} }
export interface AddressFields { export interface AddressFields {
/**
* The type of address.
* @example "billing, shipping"
*/
type: string type: string
/**
* The customer's first name.
*/
firstName: string firstName: string
/**
* The customer's last name.
*/
lastName: string lastName: string
/**
* Company name.
*/
company: string company: string
/**
* The customer's billing address street number.
*/
streetNumber: string streetNumber: string
/**
* The customer's billing address apartment number.
*/
apartments: string apartments: string
/**
* The customer's billing address zip code.
*/
zipCode: string zipCode: string
/**
* The customer's billing address city.
*/
city: string city: string
/**
* The customer's billing address country.
*/
country: string country: string
} }
export type CustomerAddressTypes = { /**
address?: Address * Hooks for managing a customer's addresses.
fields: AddressFields */
}
export type GetAddressesHook< export type GetAddressesHook = {
T extends CustomerAddressTypes = CustomerAddressTypes data: Address[] | null
> = {
data: T['address'][] | null
input: {} input: {}
fetcherInput: { cartId?: string } fetcherInput: { cartId?: string }
swrState: { isEmpty: boolean } swrState: { isEmpty: boolean }
} }
export type AddItemHook<T extends CustomerAddressTypes = CustomerAddressTypes> = export type AddItemHook = {
{ data: Address
data: T['address'] input?: AddressFields
input?: T['fields'] fetcherInput: AddressFields
fetcherInput: T['fields'] body: { item: AddressFields }
body: { item: T['fields'] } actionInput: AddressFields
actionInput: T['fields']
}
export type UpdateItemHook<
T extends CustomerAddressTypes = CustomerAddressTypes
> = {
data: T['address'] | null
input: { item?: T['fields']; wait?: number }
fetcherInput: { itemId: string; item: T['fields'] }
body: { itemId: string; item: T['fields'] }
actionInput: T['fields'] & { id: string }
} }
export type RemoveItemHook< export type UpdateItemHook = {
T extends CustomerAddressTypes = CustomerAddressTypes data: Address | null
> = { input: { item?: AddressFields; wait?: number }
data: T['address'] | null fetcherInput: { itemId: string; item: AddressFields }
input: { item?: T['address'] } body: { itemId: string; item: AddressFields }
actionInput: AddressFields & { id: string }
}
export type RemoveItemHook = {
data: Address | null | undefined
input: { item?: Address }
fetcherInput: { itemId: string } fetcherInput: { itemId: string }
body: { itemId: string } body: { itemId: string }
actionInput: { id: string } actionInput: { id: string }
} }
export type CustomerAddressHooks< export type CustomerAddressHooks = {
T extends CustomerAddressTypes = CustomerAddressTypes getAddresses: GetAddressesHook
> = { addItem: AddItemHook
getAddresses: GetAddressesHook<T> updateItem: UpdateItemHook
addItem: AddItemHook<T> removeItem: RemoveItemHook
updateItem: UpdateItemHook<T>
removeItem: RemoveItemHook<T>
} }
export type AddressHandler< /**
T extends CustomerAddressTypes = CustomerAddressTypes * API endpoints for managing a customer's addresses.
> = GetAddressesHook<T> & { */
body: { cartId?: string }
}
export type AddItemHandler< export type AddItemHandler = AddItemHook & {
T extends CustomerAddressTypes = CustomerAddressTypes
> = AddItemHook<T> & {
body: { cartId: string } body: { cartId: string }
} }
export type UpdateItemHandler< export type UpdateItemHandler = UpdateItemHook & {
T extends CustomerAddressTypes = CustomerAddressTypes data: Address
> = UpdateItemHook<T> & {
data: T['address']
body: { cartId: string } body: { cartId: string }
} }
export type RemoveItemHandler< export type RemoveItemHandler = RemoveItemHook & {
T extends CustomerAddressTypes = CustomerAddressTypes
> = RemoveItemHook<T> & {
body: { cartId: string } body: { cartId: string }
} }
export type CustomerAddressHandlers< export type CustomerAddressHandlers = {
T extends CustomerAddressTypes = CustomerAddressTypes getAddresses: GetAddressesHook
> = { addItem: AddItemHandler
getAddresses: GetAddressesHook<T> updateItem: UpdateItemHandler
addItem: AddItemHandler<T> removeItem: RemoveItemHandler
updateItem: UpdateItemHandler<T>
removeItem: RemoveItemHandler<T>
} }
export type CustomerAddressSchema< export type CustomerAddressSchema = {
T extends CustomerAddressTypes = CustomerAddressTypes
> = {
endpoint: { endpoint: {
options: {} options: {}
handlers: CustomerAddressHandlers<T> handlers: CustomerAddressHandlers
} }
} }

View File

@ -1,102 +1,139 @@
export interface Card { export interface Card {
/**
* Unique identifier for the card.
*/
id: string id: string
/**
* Masked card number. Contains only the last 4 digits.
* @example "4242"
*/
mask: string mask: string
/**
* The card's brand.
* @example "Visa, Mastercard, etc."
*/
provider: string provider: string
} }
/**
* The fields required to create a new card.
*/
export interface CardFields { export interface CardFields {
/**
* Name on the card.
*/
cardHolder: string cardHolder: string
/**
* The card's number, consisting of 16 digits.
*/
cardNumber: string cardNumber: string
/**
* The card's expiry month and year, in the format MM/YY.
* @example "01/25"
*/
cardExpireDate: string cardExpireDate: string
/**
* The card's security code, consisting of 3 digits.
*/
cardCvc: string cardCvc: string
/**
* The customer's first name.
*/
firstName: string firstName: string
/**
* The customer's last name.
*/
lastName: string lastName: string
/**
* Company name.
*/
company: string company: string
/**
* The customer's billing address street number.
*/
streetNumber: string streetNumber: string
/**
* The customer's billing address zip code.
*/
zipCode: string zipCode: string
/**
* The customer's billing address city.
*/
city: string city: string
/**
* The customer's billing address country.
*/
country: string country: string
} }
export type CustomerCardTypes = { /**
card?: Card * Hooks for managing a customer's cards.
fields: CardFields */
}
export type GetCardsHook<T extends CustomerCardTypes = CustomerCardTypes> = { export type GetCardsHook = {
data: T['card'][] | null data: Card[] | null
input: {} input: {}
fetcherInput: { cartId?: string } fetcherInput: { cartId?: string }
swrState: { isEmpty: boolean } swrState: { isEmpty: boolean }
} }
export type AddItemHook<T extends CustomerCardTypes = CustomerCardTypes> = { export type AddItemHook = {
data: T['card'] data: Card
input?: T['fields'] input?: CardFields
fetcherInput: T['fields'] fetcherInput: CardFields
body: { item: T['fields'] } body: { item: CardFields }
actionInput: T['fields'] actionInput: CardFields
} }
export type UpdateItemHook<T extends CustomerCardTypes = CustomerCardTypes> = { export type UpdateItemHook = {
data: T['card'] | null data: Card | null | undefined
input: { item?: T['fields']; wait?: number } input: { item?: CardFields; wait?: number }
fetcherInput: { itemId: string; item: T['fields'] } fetcherInput: { itemId: string; item: CardFields }
body: { itemId: string; item: T['fields'] } body: { itemId: string; item: CardFields }
actionInput: T['fields'] & { id: string } actionInput: CardFields & { id: string }
} }
export type RemoveItemHook<T extends CustomerCardTypes = CustomerCardTypes> = { export type RemoveItemHook = {
data: T['card'] | null data: Card | null | undefined
input: { item?: T['card'] } input: { item?: Card }
fetcherInput: { itemId: string } fetcherInput: { itemId: string }
body: { itemId: string } body: { itemId: string }
actionInput: { id: string } actionInput: { id: string }
} }
export type CustomerCardHooks<T extends CustomerCardTypes = CustomerCardTypes> = export interface CustomerCardHooks {
{ getCards: GetCardsHook
getCards: GetCardsHook<T> addItem: AddItemHook
addItem: AddItemHook<T> updateItem: UpdateItemHook
updateItem: UpdateItemHook<T> removeItem: RemoveItemHook
removeItem: RemoveItemHook<T>
}
export type CardsHandler<T extends CustomerCardTypes = CustomerCardTypes> =
GetCardsHook<T> & {
body: { cartId?: string }
}
export type AddItemHandler<T extends CustomerCardTypes = CustomerCardTypes> =
AddItemHook<T> & {
body: { cartId: string }
}
export type UpdateItemHandler<T extends CustomerCardTypes = CustomerCardTypes> =
UpdateItemHook<T> & {
data: T['card']
body: { cartId: string }
}
export type RemoveItemHandler<T extends CustomerCardTypes = CustomerCardTypes> =
RemoveItemHook<T> & {
body: { cartId: string }
}
export type CustomerCardHandlers<
T extends CustomerCardTypes = CustomerCardTypes
> = {
getCards: GetCardsHook<T>
addItem: AddItemHandler<T>
updateItem: UpdateItemHandler<T>
removeItem: RemoveItemHandler<T>
} }
export type CustomerCardSchema< /**
T extends CustomerCardTypes = CustomerCardTypes * Customer card API handlers.
> = { */
export type AddItemHandler = AddItemHook & {
body: { cartId: string }
}
export type UpdateItemHandler = UpdateItemHook & {
data: Card
body: { cartId: string }
}
export type RemoveItemHandler = RemoveItemHook & {
body: { cartId: string }
}
export type CustomerCardHandlers = {
getCards: GetCardsHook
addItem: AddItemHandler
updateItem: UpdateItemHandler
removeItem: RemoveItemHandler
}
export type CustomerCardSchema = {
endpoint: { endpoint: {
options: {} options: {}
handlers: CustomerCardHandlers<T> handlers: CustomerCardHandlers
} }
} }

View File

@ -1,24 +1,53 @@
export * as Card from './card' export * as Card from './card'
export * as Address from './address' export * as Address from './address'
// TODO: define this type export interface Customer {
export type Customer = any /**
* The unique identifier for the customer.
export type CustomerTypes = { */
customer: Customer id: string
/**
* The customer's first name.
*/
firstName: string
/**
* The customer's last name.
*/
lastName: string
/**
* The customer's email address.
*/
email?: string
/**
* The customer's phone number.
* @optional
*/
phone?: string
/**
* The customer's company name.
*/
company?: string
/**
* The customer's notes.
*/
notes?: string
/**
* Indicates wathever the customer accepts marketing, such as email newsletters.
*/
acceptsMarketing?: boolean
} }
export type CustomerHook<T extends CustomerTypes = CustomerTypes> = { export type CustomerHook = {
data: T['customer'] | null data: Customer | null | undefined
fetchData: { customer: T['customer'] } | null fetchData: { customer: Customer } | null
} }
export type CustomerSchema<T extends CustomerTypes = CustomerTypes> = { export type CustomerSchema = {
endpoint: { endpoint: {
options: {} options: {}
handlers: { handlers: {
getLoggedInCustomer: { getLoggedInCustomer: {
data: { customer: T['customer'] } | null data: { customer: Customer } | null
} }
} }
} }

View File

@ -1,24 +1,26 @@
export type LoginBody = { export interface LoginBody {
/**
* The user's email address.
*/
email: string email: string
/**
* The user's password.
*/
password: string password: string
} }
export type LoginTypes = { export type LoginHook = {
body: LoginBody
}
export type LoginHook<T extends LoginTypes = LoginTypes> = {
data: null data: null
actionInput: LoginBody actionInput: LoginBody
fetcherInput: LoginBody fetcherInput: LoginBody
body: T['body'] body: LoginBody
} }
export type LoginSchema<T extends LoginTypes = LoginTypes> = { export type LoginSchema = {
endpoint: { endpoint: {
options: {} options: {}
handlers: { handlers: {
login: LoginHook<T> login: LoginHook
} }
} }
} }

View File

@ -1,17 +1,15 @@
export type LogoutTypes = { export type LogoutHook = {
body: { redirectTo?: string }
}
export type LogoutHook<T extends LogoutTypes = LogoutTypes> = {
data: null data: null
body: T['body'] body: {
redirectTo?: string
}
} }
export type LogoutSchema<T extends LogoutTypes = LogoutTypes> = { export type LogoutSchema = {
endpoint: { endpoint: {
options: {} options: {}
handlers: { handlers: {
logout: LogoutHook<T> logout: LogoutHook
} }
} }
} }

View File

@ -1,28 +1,43 @@
// TODO: define this type
export type Page = { export type Page = {
// ID of the Web page. /**
* The unique identifier for the page.
*/
id: string id: string
// Page name, as displayed on the storefront. /**
* Page name, as displayed on the storefront.
*/
name: string name: string
// Relative URL on the storefront for this page. /**
* Relative URL on the storefront for this page.
*/
url?: string url?: string
// HTML or variable that populates this pages `<body>` element, in default/desktop view. Required in POST if page type is `raw`. /**
* HTML or variable that populates this pages `<body>` element, in default/desktop view. Required in POST if page type is `raw`.
*/
body: string body: string
// If true, this page appears in the storefronts navigation menu. /**
* If true, this page appears in the storefronts navigation menu.
*/
is_visible?: boolean is_visible?: boolean
// Order in which this page should display on the storefront. (Lower integers specify earlier display.) /**
* Order in which this page should display on the storefront. (Lower integers specify earlier display.)
*/
sort_order?: number sort_order?: number
} }
export type PageTypes = { /**
page: Page * Operation to get all pages.
*/
export type GetAllPagesOperation = {
data: { pages: Page[] }
} }
export type GetAllPagesOperation<T extends PageTypes = PageTypes> = { export type GetPageOperation = {
data: { pages: T['page'][] } data: { page?: Page }
} variables: {
/**
export type GetPageOperation<T extends PageTypes = PageTypes> = { * The unique identifier of the page.
data: { page?: T['page'] } */
variables: { id: string } id: string
}
} }

View File

@ -1,91 +1,207 @@
export type ProductImage = { import { Image } from './common'
url: string
alt?: string
}
export type ProductPrice = { export interface ProductPrice {
/**
* The price after all discounts are applied.
*/
value: number value: number
/**
* The currency code for the price. This is a 3-letter ISO 4217 code.
* @example USD
*/
currencyCode?: 'USD' | 'EUR' | 'ARS' | 'GBP' | string currencyCode?: 'USD' | 'EUR' | 'ARS' | 'GBP' | string
/**
* The retail price of the product. This can be used to mark a product as on sale, when `retailPrice` is higher than the price a.k.a `value`.
*/
retailPrice?: number retailPrice?: number
salePrice?: number
listPrice?: number
extendedSalePrice?: number
extendedListPrice?: number
} }
export type ProductOption = { export interface ProductOption {
__typename?: 'MultipleChoiceOption' __typename?: 'MultipleChoiceOption'
/**
* The unique identifier for the option.
*/
id: string id: string
/**
* The product options name.
* @example `Color` or `Size`
*/
displayName: string displayName: string
/**
* List of option values.
* @example `["Red", "Green", "Blue"]`
*/
values: ProductOptionValues[] values: ProductOptionValues[]
} }
export type ProductOptionValues = { export interface ProductOptionValues {
/**
* A string that uniquely identifies the option value.
*/
label: string label: string
/**
* List of hex colors used to display the actual colors in the swatches instead of the name.
*/
hexColors?: string[] hexColors?: string[]
} }
export type ProductVariant = { export interface ProductVariant {
id: string | number /**
* The unique identifier for the variant.
*/
id: string
/**
* The SKU (stock keeping unit) associated with the product variant.
*/
sku?: string
/**
* The product variants name, or the product's name.
*/
name?: string
/**
* List of product options.
*/
options: ProductOption[] options: ProductOption[]
/**
* The product variants price after all discounts are applied.
*/
price?: ProductPrice
/**
* The retail price of the product. This can be used to mark a product as on sale, when `retailPrice` is higher than the `price`.
*/
retailPrice?: ProductPrice
/**
* Indicates if the variant is available for sale.
*/
availableForSale?: boolean availableForSale?: boolean
/**
* Whether a customer needs to provide a shipping address when placing an order for the product variant.
*/
requiresShipping?: boolean
/**
* The image associated with the variant.
*/
image?: Image
} }
export type Product = { export interface Product {
/**
* The unique identifier for the product.
*/
id: string id: string
/**
* The name of the product.
*/
name: string name: string
/**
* Stripped description of the product, single line.
*/
description: string description: string
/**
* The description of the product, complete with HTML formatting.
*/
descriptionHtml?: string descriptionHtml?: string
/**
* The SKU (stock keeping unit) associated with the product.
*/
sku?: string sku?: string
/**
* A human-friendly unique string for the product, automatically generated from its title.
*/
slug?: string slug?: string
/**
* Relative URL on the storefront for the product.
*/
path?: string path?: string
images: ProductImage[] /**
* List of images associated with the product.
*/
images: Image[]
/**
* List of the products variants.
*/
variants: ProductVariant[] variants: ProductVariant[]
/**
* The product's base price. Could be the minimum value, or default variant price.
*/
price: ProductPrice price: ProductPrice
/**
* List of product's options.
*/
options: ProductOption[] options: ProductOption[]
/**
* The products vendor name.
*/
vendor?: string vendor?: string
} }
export type SearchProductsBody = { export interface SearchProductsBody {
/**
* The search query string to filter the products by.
*/
search?: string search?: string
categoryId?: string | number /**
brandId?: string | number * The category ID to filter the products by.
*/
categoryId?: string
/**
* The brand ID to filter the products by.
*/
brandId?: string
/**
* The sort key to sort the products by.
* @example 'trending-desc' | 'latest-desc' | 'price-asc' | 'price-desc'
*/
sort?: string sort?: string
/**
* The locale code, used to localize the product data (if the provider supports it).
*/
locale?: string locale?: string
} }
export type ProductTypes = { /**
product: Product * Fetches a list of products based on the given search criteria.
searchBody: SearchProductsBody */
} export type SearchProductsHook = {
export type SearchProductsHook<T extends ProductTypes = ProductTypes> = {
data: { data: {
products: T['product'][] /**
* List of products matching the query.
*/
products: Product[]
/**
* Indicates if there are any products matching the query.
*/
found: boolean found: boolean
} }
body: T['searchBody'] body: SearchProductsBody
input: T['searchBody'] input: SearchProductsBody
fetcherInput: T['searchBody'] fetcherInput: SearchProductsBody
} }
export type ProductsSchema<T extends ProductTypes = ProductTypes> = { /**
* Product API schema
*/
export type ProductsSchema = {
endpoint: { endpoint: {
options: {} options: {}
handlers: { handlers: {
getProducts: SearchProductsHook<T> getProducts: SearchProductsHook
} }
} }
} }
export type GetAllProductPathsOperation<T extends ProductTypes = ProductTypes> = /**
{ * Product operations
data: { products: Pick<T['product'], 'path'>[] } */
variables: { first?: number }
}
export type GetAllProductsOperation<T extends ProductTypes = ProductTypes> = { export type GetAllProductPathsOperation = {
data: { products: T['product'][] } data: { products: Pick<Product, 'path'>[] }
variables: { first?: number }
}
export type GetAllProductsOperation = {
data: { products: Product[] }
variables: { variables: {
relevance?: 'featured' | 'best_selling' | 'newest' relevance?: 'featured' | 'best_selling' | 'newest'
ids?: string[] ids?: string[]
@ -93,7 +209,7 @@ export type GetAllProductsOperation<T extends ProductTypes = ProductTypes> = {
} }
} }
export type GetProductOperation<T extends ProductTypes = ProductTypes> = { export type GetProductOperation = {
data: { product?: T['product'] } data: { product?: Product }
variables: { path: string; slug?: never } | { path?: never; slug: string } variables: { path: string; slug?: never } | { path?: never; slug: string }
} }

View File

@ -1,26 +1,34 @@
export type SignupBody = { export interface SignupBody {
/**
* The user's first name.
*/
firstName: string firstName: string
/**
* The user's last name.
*/
lastName: string lastName: string
/**
* The user's email address.
*/
email: string email: string
/**
* The user's password.
*/
password: string password: string
} }
export type SignupTypes = { export type SignupHook = {
body: SignupBody
}
export type SignupHook<T extends SignupTypes = SignupTypes> = {
data: null data: null
body: T['body'] body: SignupBody
actionInput: T['body'] actionInput: SignupBody
fetcherInput: T['body'] fetcherInput: SignupBody
} }
export type SignupSchema<T extends SignupTypes = SignupTypes> = { export type SignupSchema = {
endpoint: { endpoint: {
options: {} options: {}
handlers: { handlers: {
signup: SignupHook<T> signup: SignupHook
} }
} }
} }

View File

@ -1,20 +1,51 @@
export type Category = { export interface Category {
/**
* Unique identifier for the category.
*/
id: string id: string
/**
* Name of the category.
*/
name: string name: string
/**
* A human-friendly unique string for the category, automatically generated from its name.
* @example "t-shirts"
*/
slug: string slug: string
/**
* Relative URL on the storefront for the category.
* @example /t-shirts
*/
path: string path: string
} }
export type Brand = any export interface Brand {
/**
export type SiteTypes = { * Unique identifier for the brand.
category: Category */
brand: Brand id: string
/**
* Name of the brand.
*/
name: string
/**
* A human-friendly unique string for the category, automatically generated from its name.
* @example "acme"
*/
slug: string
/**
* Relative URL on the storefront for this brand.
* @example "/acme"
*/
path: string
} }
export type GetSiteInfoOperation<T extends SiteTypes = SiteTypes> = { /**
* Operation to get site information. This includes categories and brands.
*/
export type GetSiteInfoOperation = {
data: { data: {
categories: T['category'][] categories: Category[]
brands: T['brand'][] brands: Brand[]
} }
} }

View File

@ -1,60 +1,97 @@
// TODO: define this type import { Product } from './product'
export type Wishlist = any
export type WishlistItemBody = { export interface WishlistItem {
variantId: string | number /**
* The unique identifier for the item.
*/
id: string
/**
* The unique identifier for the product associated with the wishlist item.
*/
productId: string productId: string
/**
* The unique identifier for the product variant associated with the wishlist item.
*/
variantId: string
/**
* The product associated with the wishlist item.
*/
product: Product
} }
export type WishlistTypes = { export interface Wishlist {
wishlist: Wishlist /**
itemBody: WishlistItemBody * The unique identifier for the wishlist.
*/
id: string
/**
* List of items in the wishlist.
*/
items: WishlistItem[]
/**
* Some providers require a token to add an item to a wishlist
*/
token?: string
} }
export type GetWishlistHook<T extends WishlistTypes = WishlistTypes> = { export interface WishlistItemBody {
data: T['wishlist'] | null /**
* The unique identifier for the product variant to associate with the wishlist.
*/
variantId: string
/**
* The unique identifier for the product to associate with the wishlist.
*/
productId: string
/**
* Some providers require to provide a token to make a request
*/
wishlistToken?: string
}
export type GetWishlistHook = {
data: Wishlist | null | undefined
body: { includeProducts?: boolean } body: { includeProducts?: boolean }
input: { includeProducts?: boolean } input: { includeProducts?: boolean }
fetcherInput: { customerId: string; includeProducts?: boolean } fetcherInput: { customerId: string; includeProducts?: boolean }
swrState: { isEmpty: boolean } swrState: { isEmpty: boolean }
} }
export type AddItemHook<T extends WishlistTypes = WishlistTypes> = { export type AddItemHook = {
data: T['wishlist'] data: Wishlist | null | undefined
body: { item: T['itemBody'] } body: { item: WishlistItemBody }
fetcherInput: { item: T['itemBody'] } fetcherInput: { item: WishlistItemBody }
actionInput: T['itemBody'] actionInput: WishlistItemBody
} }
export type RemoveItemHook<T extends WishlistTypes = WishlistTypes> = { export type RemoveItemHook = {
data: T['wishlist'] | null data: Wishlist | null | undefined
body: { itemId: string } body: { itemId: string; wishlistToken?: string }
fetcherInput: { itemId: string } fetcherInput: { itemId: string; wishlistToken?: string }
actionInput: { id: string } actionInput: { id: string }
input: { wishlist?: { includeProducts?: boolean } } input: { wishlist?: { includeProducts?: boolean } }
} }
export type WishlistSchema<T extends WishlistTypes = WishlistTypes> = { export type WishlistSchema = {
endpoint: { endpoint: {
options: {} options: {}
handlers: { handlers: {
getWishlist: GetWishlistHook<T> & { getWishlist: GetWishlistHook & {
data: T['wishlist'] | null data: Wishlist | null
body: { customerToken?: string } body: { customerToken?: string }
} }
addItem: AddItemHook<T> & { addItem: AddItemHook & {
body: { customerToken?: string } body: { customerToken?: string }
} }
removeItem: RemoveItemHook<T> & { removeItem: RemoveItemHook & {
body: { customerToken?: string } body: { customerToken?: string }
} }
} }
} }
} }
export type GetCustomerWishlistOperation< export type GetCustomerWishlistOperation = {
T extends WishlistTypes = WishlistTypes data: { wishlist?: Wishlist }
> = {
data: { wishlist?: T['wishlist'] }
variables: { customerId: string } variables: { customerId: string }
} }

View File

@ -5,7 +5,7 @@ import type { AddItemHook } from '../types/wishlist'
import type { Provider } from '..' import type { Provider } from '..'
export type UseAddItem< export type UseAddItem<
H extends MutationHook<AddItemHook<any>> = MutationHook<AddItemHook> H extends MutationHook<AddItemHook> = MutationHook<AddItemHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher = mutationFetcher export const fetcher = mutationFetcher

View File

@ -5,7 +5,7 @@ import type { RemoveItemHook } from '../types/wishlist'
import type { Provider } from '..' import type { Provider } from '..'
export type UseRemoveItem< export type UseRemoveItem<
H extends MutationHook<RemoveItemHook<any>> = MutationHook<RemoveItemHook> H extends MutationHook<RemoveItemHook> = MutationHook<RemoveItemHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<RemoveItemHook> = mutationFetcher export const fetcher: HookFetcherFn<RemoveItemHook> = mutationFetcher

View File

@ -5,7 +5,7 @@ import type { GetWishlistHook } from '../types/wishlist'
import type { Provider } from '..' import type { Provider } from '..'
export type UseWishlist< export type UseWishlist<
H extends SWRHook<GetWishlistHook<any>> = SWRHook<GetWishlistHook> H extends SWRHook<GetWishlistHook> = SWRHook<GetWishlistHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<GetWishlistHook> = SWRFetcher export const fetcher: HookFetcherFn<GetWishlistHook> = SWRFetcher

View File

@ -1,6 +1,6 @@
import { GetAPISchema, createEndpoint } from '@vercel/commerce/api' import { GetAPISchema, createEndpoint } from '@vercel/commerce/api'
import checkoutEndpoint from '@vercel/commerce/api/endpoints/checkout' import checkoutEndpoint from '@vercel/commerce/api/endpoints/checkout'
import type { CheckoutSchema } from '../../../types/checkout' import type { CheckoutSchema } from '@vercel/commerce/types/checkout'
import type { CommercejsAPI } from '../..' import type { CommercejsAPI } from '../..'
import submitCheckout from './submit-checkout' import submitCheckout from './submit-checkout'

View File

@ -1,6 +1,6 @@
import { GetAPISchema, createEndpoint } from '@vercel/commerce/api' import { GetAPISchema, createEndpoint } from '@vercel/commerce/api'
import loginEndpoint from '@vercel/commerce/api/endpoints/login' import loginEndpoint from '@vercel/commerce/api/endpoints/login'
import type { LoginSchema } from '../../../types/login' import type { LoginSchema } from '@vercel/commerce/types/login'
import type { CommercejsAPI } from '../..' import type { CommercejsAPI } from '../..'
import login from './login' import login from './login'

View File

@ -1,5 +1,5 @@
import type { CommercejsConfig } from '..' import type { CommercejsConfig } from '..'
import { GetAllPagesOperation } from '../../types/page' import { GetAllPagesOperation } from '@vercel/commerce/types/page'
export type Page = { url: string } export type Page = { url: string }
export type GetAllPagesResult = { pages: Page[] } export type GetAllPagesResult = { pages: Page[] }

View File

@ -1,9 +1,5 @@
import type { OperationContext } from '@vercel/commerce/api/operations' import type { OperationContext } from '@vercel/commerce/api/operations'
import type { import type { GetAllProductPathsOperation } from '@vercel/commerce/types/product'
GetAllProductPathsOperation,
CommercejsProduct,
} from '../../types/product'
import type { CommercejsConfig, Provider } from '..' import type { CommercejsConfig, Provider } from '..'
export type GetAllProductPathsResult = { export type GetAllProductPathsResult = {
@ -22,7 +18,7 @@ export default function getAllProductPathsOperation({
const { data } = await sdkFetch('products', 'list') const { data } = await sdkFetch('products', 'list')
// Match a path for every product retrieved // Match a path for every product retrieved
const productPaths = data.map(({ permalink }: CommercejsProduct) => ({ const productPaths = data.map(({ permalink }: { permalink: string }) => ({
path: `/${permalink}`, path: `/${permalink}`,
})) }))

View File

@ -1,5 +1,5 @@
import type { OperationContext } from '@vercel/commerce/api/operations' import type { OperationContext } from '@vercel/commerce/api/operations'
import type { GetAllProductsOperation } from '../../types/product' import type { GetAllProductsOperation } from '@vercel/commerce/types/product'
import type { CommercejsConfig, Provider } from '../index' import type { CommercejsConfig, Provider } from '../index'
import { normalizeProduct } from '../../utils/normalize-product' import { normalizeProduct } from '../../utils/normalize-product'

View File

@ -1,4 +1,4 @@
import { GetPageOperation } from '../../types/page' import { GetPageOperation } from '@vercel/commerce/types/page'
export type Page = any export type Page = any
export type GetPageResult = { page?: Page } export type GetPageResult = { page?: Page }

Some files were not shown because too many files have changed in this diff Show More