Skip to Content

Finqu Storefront SDK

A TypeScript SDK for building custom Finqu storefronts with GraphQL, React hooks, and Puck  visual editor support.

Quick Start

Create a new storefront project:

pnpm create @finqu/storefront my-storefront cd my-storefront pnpm install pnpm dev

Installation

pnpm add @finqu/storefront-sdk

Peer Dependencies

The SDK has optional peer dependencies based on which features you use:

# For GraphQL client (framework-agnostic) pnpm add graphql graphql-request # For React hooks (client components) pnpm add graphql @apollo/client react # For Puck visual editor pnpm add @puckeditor/core # For typed GraphQL responses pnpm add @finqu/storefront-types

SDK Modules

The SDK provides four entry points for different use cases:

Import PathUse CaseEnvironment
@finqu/storefront-sdkPuck component types and utilitiesUniversal
@finqu/storefront-sdk/graphqlFramework-agnostic GraphQL clientUniversal
@finqu/storefront-sdk/serverServer-side client with cachingServer only
@finqu/storefront-sdk/reactReact hooks with ApolloClient components

GraphQL Client

Public Client (Framework-Agnostic)

Uses graphql-request under the hood. Works anywhere JavaScript runs.

import { createFinquClient, getProduct, getProductByHandle, getCatalogProducts } from "@finqu/storefront-sdk/graphql"; const client = createFinquClient({ publicKey: process.env.FINQU_PUBLIC_KEY!, endpoint: process.env.FINQU_ENDPOINT!, }); // Using typed helper functions const { product } = await getProduct(client, { id: "123" }); const { product: productByHandle } = await getProductByHandle(client, { handle: "my-product" }); const { catalog } = await getCatalogProducts(client, { first: 20 });

Server Client (Next.js Optimized)

For Server Components, API routes, and server-side rendering with Next.js fetch caching.

import { createFinquServerClient, getProduct, getProductByHandle, cachePresets } from "@finqu/storefront-sdk/server"; const client = createFinquServerClient({ secretKey: process.env.FINQU_SECRET_KEY!, // fq_secret_* key endpoint: process.env.FINQU_ENDPOINT!, }); // Server Component with ISR caching export default async function ProductPage({ params }) { const { product } = await getProductByHandle( client, { handle: params.handle }, cachePresets.products // { next: { revalidate: 60 } } ); return <ProductDetails product={product} />; }

Cache Presets

import { cachePresets } from "@finqu/storefront-sdk/server"; cachePresets.static; // Revalidate every hour (3600s) cachePresets.products; // Revalidate every 60s cachePresets.dynamic; // No cache (no-store) // With revalidation tags for on-demand invalidation cachePresets.withTags(["product", `product:${handle}`]);

React Hooks

Apollo-based hooks for client components with automatic caching.

Setup

Wrap your app with FinquProvider:

// app/providers.tsx "use client"; import { FinquProvider } from "@finqu/storefront-sdk/react"; export function Providers({ children }: { children: React.ReactNode }) { return ( <FinquProvider publicKey={process.env.NEXT_PUBLIC_FINQU_PUBLIC_KEY!} endpoint={process.env.NEXT_PUBLIC_FINQU_ENDPOINT!} > {children} </FinquProvider> ); }

Product Hooks

"use client"; import { useProduct, useProductByHandle, useCatalogProducts, useCatalogProductsLazy, } from "@finqu/storefront-sdk/react"; function ProductPage({ id }: { id: string }) { const { data, loading, error } = useProduct({ id }); if (loading) return <Skeleton />; if (error) return <Error message={error.message} />; if (!data?.product) return <NotFound />; return <ProductDetails product={data.product} />; } function ProductGrid() { const { data, loading, fetchMore } = useCatalogProducts({ first: 12, sortKey: "created", reverse: true, }); const loadMore = () => { const pageInfo = data?.catalog.products.pageInfo; if (pageInfo?.hasNextPage) { fetchMore({ variables: { after: pageInfo.endCursor }, }); } }; return ( <> <FilterSidebar filters={data?.catalog.products.filters} /> <Grid products={data?.catalog.products.nodes} /> <Button onClick={loadMore}>Load More</Button> </> ); }

Cart Hooks

"use client"; import { useCart, useCreateCart, useAddToCart, useUpdateCartLines, useRemoveFromCart, useApplyDiscountCode, useUpdateCartBuyerIdentity, useUpdateCartNote, } from "@finqu/storefront-sdk/react"; function AddToCartButton({ cartId, variantId }: { cartId: string; variantId: string }) { const [addToCart, { loading }] = useAddToCart(); const handleAdd = () => { addToCart({ variables: { cartId, lines: [{ merchandiseId: variantId, quantity: 1 }], }, }); }; return ( <Button onClick={handleAdd} disabled={loading}> Add to Cart </Button> ); } function CreateCartButton({ variantId }: { variantId: string }) { const [createCart, { loading }] = useCreateCart(); const handleClick = async () => { const { data } = await createCart({ variables: { input: { lines: [{ merchandiseId: variantId, quantity: 1 }], }, }, }); if (data?.cartCreate.cart) { localStorage.setItem("cartId", data.cartCreate.cart.id); } }; return ( <Button onClick={handleClick} disabled={loading}> Add to Cart </Button> ); }

ProductGroup (Category) Hooks

Finqu uses “ProductGroup” for categories/collections:

"use client"; import { useProductGroup, useProductGroupByHandle, useProductGroupWithProducts, useProductGroups, useProductGroupsLazy, } from "@finqu/storefront-sdk/react"; function CategoryPage({ handle }: { handle: string }) { const [activeFilters, setActiveFilters] = useState([]); const { data, loading, fetchMore } = useProductGroupWithProducts({ handle, first: 20, filters: activeFilters, }); if (!data?.productGroup) return <NotFound />; const loadMore = () => { const pageInfo = data.productGroup.products.pageInfo; if (pageInfo?.hasNextPage) { fetchMore({ variables: { after: pageInfo.endCursor }, }); } }; return ( <> <h1>{data.productGroup.title}</h1> <FilterSidebar filters={data.productGroup.products.filters} onFilterChange={setActiveFilters} /> <ProductGrid products={data.productGroup.products.nodes} /> <Button onClick={loadMore}>Load More</Button> </> ); }
"use client"; import { useNavigationMenu } from "@finqu/storefront-sdk/react"; function MainNav() { const { data } = useNavigationMenu({ handle: "main-menu" }); return ( <nav> {data?.menu?.links.map((link, index) => ( <NavLink key={index} link={link} /> ))} </nav> ); }

Generic Hooks

For custom queries and mutations:

import { useFinquQuery, useFinquLazyQuery, useFinquMutation } from "@finqu/storefront-sdk/react"; // Custom query const { data } = useFinquQuery(MY_CUSTOM_QUERY, { variables: { id: "123" } }); // Lazy query (triggered manually) const [loadData, { data, loading }] = useFinquLazyQuery(MY_CUSTOM_QUERY); // Mutation const [mutate, { loading }] = useFinquMutation(MY_CUSTOM_MUTATION);

GraphQL Fragments

Pre-built fragments for common Finqu types. Use them to build custom queries:

import { ProductFragment, CartFragment, ProductGroupFragment } from "@finqu/storefront-sdk/graphql"; const MY_CUSTOM_QUERY = ` query GetProductWithRelated($handle: String!) { product(handle: $handle) { ...Product } } ${ProductFragment} `;

Available Fragments

Product:

  • ImageFragment - Image with dimensions and metadata
  • ProductFragment - Full product with variants, options, manufacturer
  • ProductCardFragment - Minimal product for listings
  • ProductVariantFragment - Variant with pricing, stock, delivery
  • ProductVariantOptionFragment - Variant option selection
  • ProductOptionFragment - Product option with values
  • ProductOptionValueFragment - Product option value
  • ProductDiscountFragment - Product discount information
  • DeliveryTimeFragment - Delivery time information
  • ManufacturerFragment - Product manufacturer
  • CombinedListingFragment - Combined listing data

Cart:

  • CartFragment - Full cart with lines, discounts, addresses
  • CartSummaryFragment - Minimal cart for header display
  • CartLineItemFragment - Cart line with product details
  • CartDiscountFragment - Cart discount information
  • CartTaxLineFragment - Tax line information
  • CartPaymentMethodFragment - Payment method details
  • CartShippingMethodFragment - Shipping method details
  • AddressFragment - Shipping/billing address

Customer:

  • CustomerFragment - Full customer with address and loyalty info
  • CustomerBasicFragment - Basic customer information
  • CustomerWithAddressFragment - Customer with default address
  • CustomerAccessTokenFragment - Access token for authentication
  • CustomerUserErrorFragment - Customer operation errors
  • UserErrorFragment - Generic user errors
  • CurrencyFragment - Currency information
  • LocaleFragment - Locale information
  • LoyaltyDiscountProgressFragment - Loyalty program progress

ProductGroup (Categories):

  • ProductGroupFragment - Full category with filters and breadcrumbs
  • ProductGroupCardFragment - Category for navigation
  • ProductGroupWithBreadcrumbsFragment - Category with breadcrumb trail
  • ProductGroupWithProductsFragment - Category with products connection
  • FilterFragment - Faceted search filter
  • FilterValueFragment - Filter option value
  • PageInfoFragment - Pagination information

Puck Visual Editor

The SDK includes types and utilities for building Puck components.

Single File Components

// components/Hero.puck.tsx import { defineComponent, type ComponentConfig } from "@finqu/storefront-sdk"; interface HeroProps { title: string; subtitle: string; } export const category = "Marketing"; export const config: ComponentConfig<HeroProps> = { label: "Hero Banner", fields: { title: { type: "text" }, subtitle: { type: "textarea" }, }, render: ({ title, subtitle }) => ( <section> <h1>{title}</h1> <p>{subtitle}</p> </section> ), }; // Or use the defineComponent helper for type inference export const config = defineComponent({ label: "Hero Banner", fields: { title: { type: "text" }, subtitle: { type: "textarea" }, }, render: ({ title, subtitle }) => ( <section> <h1>{title}</h1> <p>{subtitle}</p> </section> ), });

Available Exports

import { defineComponent, // Helper for type-safe component config defineFields, // Helper for type-safe field definitions type PuckComponentConfig, // Component config type (deprecated, use ComponentConfig) type PuckComponentModule, // Module with category and config type ComponentCategory, // Category string type type StorefrontConfig, // Full Puck Config type type Config, // Re-exported from @puckeditor/core type Data, // Re-exported from @puckeditor/core type ComponentConfig, // Re-exported from @puckeditor/core type Fields, // Re-exported from @puckeditor/core } from "@finqu/storefront-sdk";

GraphQL Operations

The SDK exports typed helper functions and raw query strings for all operations:

Product Operations

import { getProduct, // Fetch product by ID getProductByHandle, // Fetch product by handle getCatalogProducts, // Fetch paginated products with filters GET_PRODUCT, // Raw query string GET_PRODUCT_BY_HANDLE, GET_CATALOG_PRODUCTS, } from "@finqu/storefront-sdk/graphql";

Cart Operations

import { getCart, // Fetch cart by ID createCart, // Create new cart addToCart, // Add items to cart updateCartLines, // Update line quantities removeFromCart, // Remove items from cart applyDiscountCode, // Apply discount code updateCartBuyerIdentity, // Update buyer info updateCartNote, // Update cart note // Raw query strings GET_CART, CREATE_CART, ADD_TO_CART, UPDATE_CART_LINES, REMOVE_FROM_CART, APPLY_DISCOUNT_CODE, UPDATE_CART_BUYER_IDENTITY, UPDATE_CART_NOTE, } from "@finqu/storefront-sdk/graphql";

ProductGroup Operations

import { getProductGroup, // Fetch by ID getProductGroupByHandle, // Fetch by handle getProductGroupWithProducts, // With products and filters getProductGroups, // Fetch multiple // Raw query strings GET_PRODUCT_GROUP, GET_PRODUCT_GROUP_BY_HANDLE, GET_PRODUCT_GROUP_WITH_PRODUCTS, GET_PRODUCT_GROUPS, } from "@finqu/storefront-sdk/graphql";
import { getNavigationMenu, GET_NAVIGATION_MENU } from "@finqu/storefront-sdk/graphql";

Server-Only Operations

The server module includes additional operations requiring authentication:

import { getCustomer, // Fetch customer by ID getCustomerByToken, // Fetch by access token getCustomerOrders, // Fetch customer orders getOrder, // Fetch a single order createCustomerAccessToken, // Login (create access token) deleteCustomerAccessToken, // Logout (delete access token) deleteCustomerAddress, // Delete customer address // Raw query strings GET_CUSTOMER, GET_CUSTOMER_BY_TOKEN, GET_CUSTOMER_ORDERS, GET_ORDER, CREATE_CUSTOMER_ACCESS_TOKEN, DELETE_CUSTOMER_ACCESS_TOKEN, DELETE_CUSTOMER_ADDRESS, // ... all public operations also available } from "@finqu/storefront-sdk/server";

TypeScript

The SDK is fully typed. Import types from @finqu/storefront-types for Finqu GraphQL schema types:

import type { Product, Cart, Customer, ProductGroup } from "@finqu/storefront-types";