UNPKG

@techsio/storefront-data

Version:

Medusa-first storefront data layer built on TanStack Query.

209 lines (160 loc) • 5.91 kB
# Storefront Data (`@techsio/storefront-data`) Medusa-first storefront data layer built on TanStack Query. The library is intentionally opinionated: - use explicit file-level imports, not package-root barrels - compose one preset per storefront - keep Medusa quirks inside Medusa services and preset wiring - keep app DTOs and read models in the app unless reused by a second storefront ## Recommended integration path For Medusa storefronts, the primary entrypoint is `createMedusaStorefrontPreset`. A preset owns: - query keys - services - hooks - flows - shared cache semantics - cart persistence wiring That lets each storefront keep a thin local composition module for: - SDK instance - localized error mapping - product field defaults - address adapters - customer-specific policy ## Install ```bash pnpm add @techsio/storefront-data @medusajs/js-sdk @medusajs/types @tanstack/react-query react react-dom ``` If you use Next.js, transpile the package: ```js const nextConfig = { transpilePackages: ["@techsio/storefront-data"], } ``` ## Client provider ```tsx import { StorefrontDataProvider } from "@techsio/storefront-data/client/provider" export function Providers({ children }) { return <StorefrontDataProvider>{children}</StorefrontDataProvider> } ``` ## Preset-first example ```ts import { createLocalStorageValueStore } from "@techsio/storefront-data/shared/storage-value-store" import { createMedusaStorefrontPreset } from "@techsio/storefront-data/medusa/preset" import { sdk } from "@/lib/medusa-client" const cartStorage = createLocalStorageValueStore({ key: "shop-cart-id", }) export const storefront = createMedusaStorefrontPreset({ sdk, queryKeyNamespace: "shop", cart: { hooks: { cartStorage, }, }, }) ``` Use the preset from thin app wrappers or directly in app code: ```ts const { products, cart, checkout } = storefront.hooks const { cart: cartFlow, checkout: checkoutFlow } = storefront.flows ``` ## Sane defaults vs custom adapters The library exports shared address contracts from `shared/address` and a small opinionated default in `checkout/address`. Use the default when your storefront shape is close to the built-in checkout address model: ```ts import { createCheckoutCartAddressAdapter, createCheckoutCustomerAddressAdapter, } from "@techsio/storefront-data/checkout/address" ``` If your storefront has its own form DTO, formatting, localization, or patch semantics, keep the adapter local to the app and implement the shared adapter contract instead. ## Query options The stable public query-options surface is intentionally small. Use domain hooks for most reads, and use query-option helpers when you need SSR, loader, or manual prefetch integration. ```ts import { createOrderHooks } from "@techsio/storefront-data/orders/hooks" const orderHooks = createOrderHooks({ service, buildListParams: (input) => ({ ...input }), }) const listQuery = orderHooks.getListQueryOptions({ limit: 20, offset: 0 }) const detailQuery = orderHooks.getDetailQueryOptions({ id: "order_1" }) ``` ```ts import { createProductHooks } from "@techsio/storefront-data/products/hooks" const productHooks = createProductHooks({ service, buildListParams: (input) => ({ ...input }), buildDetailParams: (input) => ({ ...input }), }) const listQuery = productHooks.getListQueryOptions({ limit: 20, region_id: "reg_1", }) ``` ## SSR example ```tsx import { dehydrate, HydrationBoundary } from "@tanstack/react-query" import { getServerQueryClient } from "@techsio/storefront-data/server/get-query-client" export default async function Page() { const queryClient = getServerQueryClient() await queryClient.prefetchQuery(productHooks.getListQueryOptions({ limit: 20 })) return ( <HydrationBoundary state={dehydrate(queryClient)}> <ProductsPage /> </HydrationBoundary> ) } ``` ## Stable public subpaths Use explicit file-level imports. There is no supported package-root import. Core subpaths: - `@techsio/storefront-data/client/provider` - `@techsio/storefront-data/server/get-query-client` - `@techsio/storefront-data/shared/address` - `@techsio/storefront-data/shared/cache-config` - `@techsio/storefront-data/shared/local-storage` - `@techsio/storefront-data/shared/medusa-client` - `@techsio/storefront-data/shared/query-client` - `@techsio/storefront-data/shared/query-keys` - `@techsio/storefront-data/shared/region` - `@techsio/storefront-data/shared/region-context` - `@techsio/storefront-data/shared/storage-value-store` - `@techsio/storefront-data/medusa/preset` Domain subpaths: - `@techsio/storefront-data/<domain>/hooks` - `@techsio/storefront-data/<domain>/medusa-service` - `@techsio/storefront-data/<domain>/query-keys` - `@techsio/storefront-data/<domain>/query-options` where the domain exposes SSR/query-option helpers - `@techsio/storefront-data/<domain>/types` Product-list utilities: - `@techsio/storefront-data/product-lists/utils` Supported domains: - `auth` - `cart` - `catalog` - `categories` - `checkout` - `collections` - `customers` - `orders` - `product-lists` - `products` - `regions` ## Notes - Prefetch helpers default to skipping only fresh cache entries (`skipMode: "fresh"`). - Suspense queries are not cancellable through TanStack Query. - Query keys normalize plain-object params and strip `enabled` from query-key inputs. - The default checkout helpers are optional. The shared contract is the stable part. - App-level read models such as category registries should stay in the app until reused by another storefront. ## Development ```bash pnpm -C libs/storefront-data build pnpm -C libs/storefront-data lint pnpm -C libs/storefront-data test pnpm -C libs/storefront-data validate:release ``` Releases are tag-gated. A tag such as `storefront-data-v0.1.0` must exactly match the package version before the trusted-publishing workflow can publish it.