UNPKG

@techsio/storefront-data

Version:

Medusa-first storefront data layer built on TanStack Query.

193 lines (139 loc) • 4.98 kB
--- name: migrate-custom-hooks-to-storefront-data description: > Load this skill when replacing app-local Medusa hooks, query utilities, or service wrappers with the preset-first @techsio/storefront-data surface. Use it for migration cutovers, preserving storefront-specific callbacks, and removing dual source-of-truth behavior instead of running legacy and shared data layers in parallel. type: lifecycle library: "@techsio/storefront-data" library_version: "0.1.0" requires: - setup-storefront-platform-in-next-app sources: - "TechsioCZ/new-engine:libs/storefront-data/README.md" - "TechsioCZ/new-engine:libs/storefront-data/AGENTS.md" - "TechsioCZ/new-engine:apps/frontend-demo/README.md" - "TechsioCZ/new-engine:apps/n1/AGENTS.md" --- This skill builds on `setup-storefront-platform-in-next-app`. Use it once the new preset seam exists in the app. # Migrate custom hooks to storefront-data ## Setup Start by centralizing the new preset seam before replacing feature code. ```ts // src/lib/storefront.ts import { createMedusaSdk } from "@techsio/storefront-data/shared/medusa-client" import { createLocalStorageValueStore } from "@techsio/storefront-data/shared/storage-value-store" import { createMedusaStorefrontPreset } from "@techsio/storefront-data/medusa/preset" const sdk = createMedusaSdk({ baseUrl: process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL ?? "http://localhost:9000", publishableKey: process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY ?? "", }) export const storefront = createMedusaStorefrontPreset({ sdk, queryKeyNamespace: "n1", cart: { hooks: { cartStorage: createLocalStorageValueStore({ key: "n1-cart-id" }), }, }, }) ``` ## Core Patterns ### Replace one vertical feature block at a time ```tsx "use client" import { storefront } from "@/src/lib/storefront" export function ProductList({ regionId }: { regionId: string }) { const query = storefront.hooks.products.useProducts({ region_id: regionId, limit: 24, }) if (query.isLoading) return <div>Loading...</div> return <div>{query.products.length}</div> } ``` The goal is a clean cutover for one screen or feature block, followed by deletion of the old implementation for that block. ### Keep storefront-specific UX by wrapping the shared hook, not forking it ```ts // src/lib/auth-hooks.ts import { storefront } from "@/src/lib/storefront" const track = (event: string) => { console.log(event) } export function useLoginWithAnalytics() { return storefront.hooks.auth.useLogin({ onSuccess: () => { track("login_success") }, }) } ``` ### Delete the legacy query helpers after the cutover ```ts // before export const productQueryKey = (params: ProductParams) => ["n1-products", params] // after export const productQueryKey = storefront.queryKeys.products.list ``` If the screen already reads and writes through the preset, keeping the old query helper around only invites drift back into the app. ## Common Mistakes ### CRITICAL Old and new data layers on the same screen Wrong: ```ts const legacy = useLegacyProducts(params) const shared = storefront.hooks.products.useProducts(params) ``` Correct: ```ts const products = storefront.hooks.products.useProducts(params) ``` Parallel legacy and shared reads create duplicate requests, conflicting query keys, and no single source of truth. Source: maintainer interview, `libs/storefront-data/AGENTS.md`, `libs/storefront-data/README.md` ### HIGH Feature migration before preset centralization Wrong: ```ts export const useN1Products = () => storefront.hooks.products.useProducts({}) export const useN1Cart = () => storefront.hooks.cart.useCart({}) ``` Correct: ```ts export const storefront = createMedusaStorefrontPreset({ sdk, queryKeyNamespace: "n1", }) ``` If the preset seam is not centralized first, query keys, storage, field defaults, and adapters stay scattered across the app. Source: `libs/storefront-data/README.md`, maintainer interview ### HIGH Losing storefront-specific callbacks during replacement Wrong: ```ts export const useLogin = storefront.hooks.auth.useLogin ``` Correct: ```ts export function useLogin() { return storefront.hooks.auth.useLogin({ onSuccess: () => { toast.success("Logged in") track("login_success") }, }) } ``` Legacy wrappers often exist only because they carry storefront-specific analytics, debug hooks, or UX side effects. Source: maintainer interview ### MEDIUM Keeping proven common logic app-local Wrong: ```ts export const useCustomOrders = () => useQuery({ queryKey: ["n1-orders"], queryFn: loadOrders }) ``` Correct: ```ts const orders = storefront.hooks.orders.useOrders({ limit: 20 }) ``` Once a second storefront needs the same backend behavior, leaving it local recreates the duplication problem the migration is trying to remove. Source: maintainer interview See also: `decide-app-specific-overrides-vs-shared-platform` for promotion rules.