skills/decocms/deco-start/deco-apps-vtex-review

deco-apps-vtex-review

SKILL.md

VTEX apps-start Review & Fix

Comprehensive audit checklist for the VTEX integration in @decocms/apps-start. Use after porting or when debugging issues.

File Structure

apps-start/vtex/
├── client.ts              # vtexFetch, vtexFetchWithCookies, intelligentSearch, vtexIOGraphQL
├── middleware.ts           # extractVtexContext, propagateISCookies
├── actions/
│   ├── checkout.ts         # Cart mutations (addItems, updateItems, etc.)
│   ├── auth.ts             # classicSignIn, logout, sendEmailVerification
│   ├── session.ts          # createSession, editSession, deleteSession
│   ├── address.ts          # GraphQL address mutations
│   ├── misc.ts             # notifyMe, sendEvent, submitReview, deletePaymentToken
│   ├── newsletter.ts       # subscribe, updateNewsletterOptIn
│   ├── orders.ts           # cancelOrder
│   ├── profile.ts          # updateProfile, updateAddress
│   ├── wishlist.ts         # addItem, removeItem
│   └── trigger.ts          # Analytics trigger
├── loaders/
│   ├── cart.ts             # getCart (OrderForm)
│   ├── catalog.ts          # searchProducts, getCrossSelling, getCategoryTree
│   ├── legacy.ts           # legacyProductDetailsPage, legacyProductList, legacyPLP, legacySuggestions
│   ├── workflow.ts         # workflowProduct, workflowProducts
│   ├── search.ts           # getTopSearches, getProductIdByTerm
│   └── (14 more)
├── inline-loaders/         # TanStack-compatible loaders for sections
├── hooks/                  # Client-side React hooks (useCart, useUser, useWishlist)
└── utils/
    ├── transform.ts        # Canonical VTEX→schema.org mapping
    ├── types.ts            # VTEX API types
    ├── vtexId.ts           # VTEX_AUTH_COOKIE, buildAuthCookieHeader
    ├── segment.ts          # buildSegmentFromCookies, isAnonymous
    ├── intelligentSearch.ts # withDefaultParams, withDefaultFacets
    ├── similars.ts         # withIsSimilarTo
    └── enrichment.ts       # withSimulation

Audit Checklist

1. Cookie Propagation

VTEX APIs return Set-Cookie headers that must reach the browser. Standard vtexFetch discards them.

Pattern: Use vtexFetchWithCookies for any action that creates/modifies server state:

import { vtexFetchWithCookies } from "../client";
import type { VtexFetchResult } from "../client";

// Returns { data: T, setCookies: string[] }
const result = await vtexFetchWithCookies<OrderForm>(url, opts);

Where required: checkout.ts (all cart mutations), session.ts (create/edit), auth.ts (signIn, logout).

Where NOT needed: Read-only loaders, GraphQL queries.

2. Auth Cookie Headers

All authenticated VTEX IO GraphQL calls need both cookie variants:

VtexIdclientAutCookie={token}; VtexIdclientAutCookie_{account}={token}

Use the centralized helper:

import { buildAuthCookieHeader, VTEX_AUTH_COOKIE } from "../utils/vtexId";
import { getVtexConfig } from "../client";

const { account } = getVtexConfig();
const cookieHeader = buildAuthCookieHeader(authCookie, account);
// Pass as: { cookie: cookieHeader } or { Cookie: cookieHeader }

Audit: grep for hardcoded VtexIdclientAutCookie strings. Only vtexId.ts should define it.

rg "VtexIdclientAutCookie" vtex/ --glob '!vtex/utils/vtexId.ts'

Any match outside vtexId.ts (except JSDoc comments) is a bug.

3. expectedOrderFormSections

VTEX Checkout API returns incomplete OrderForm without explicit sections. Every POST to /api/checkout/pub/orderForm must include:

import { DEFAULT_EXPECTED_SECTIONS } from "../actions/checkout";

body: JSON.stringify({ expectedOrderFormSections: DEFAULT_EXPECTED_SECTIONS })

Audit: Check loaders/cart.ts and hooks/useCart.ts — both must send this body.

4. salesChannel (sc) Parameter

Missing sc causes wrong prices, ORD027, or invisible products.

Where required:

  • All /api/checkout/pub/orderForm/* endpoints → ?sc={sc}
  • /api/catalog_system/pub/products/search/*?sc={sc}
  • /buscaautocomplete&sc={sc}
  • Intelligent Search: handled by client.ts intelligentSearch() automatically

Audit:

rg "catalog_system/pub/products/search|buscaautocomplete|orderForm" vtex/ | rg -v "sc="

5. Intelligent Search Cookies

VTEX IS requires vtex_is_session and vtex_is_anonymous cookies (UUIDs).

Pattern in middleware.ts:

// Generate if missing
if (!cookieHeader.includes("vtex_is_session")) {
  const sessionId = crypto.randomUUID();
  // Set on response
}

6. HttpOnly Cookies

VtexIdclientAutCookie is HttpOnly — cannot be read via document.cookie.

Wrong: Client-side hooks checking document.cookie for auth status. Correct: useUser calls /api/sessions?items=profile.email server-side.

7. Hooks Completeness

Compare with original deco-cx/apps hooks:

Hook Must Have
useCart addItems, updateQuantity, removeItem, addCoupons, fetchCart
useUser Server-side session check via /api/sessions
useWishlist add, remove, toggle, isInWishlist

8. transform.ts Parity

All exported functions must match the original:

toProduct, toProductPage, pickSku, aggregateOffers, forceHttpsOnAssets,
sortProducts, filtersFromURL, mergeFacets, legacyFacetToFilter,
toFilter, categoryTreeToNavbar, toBrand, toReview, toInventories,
toPlace, toPostalAddress, parsePageType, normalizeFacet

Critical: seller: sellerId (not sellerName) in buildOffer.

9. Page Structure (schema.org)

Page Required Structure
PDP ProductDetailsPage with breadcrumbList + product (via toProductPage) + seo
PLP ProductListingPage with BreadcrumbList + filters + products + pageInfo + sortOptions + seo

10. No Debug Logs in Production

rg "console\.log" vtex/ --glob '*.ts'

Only acceptable: 1x startup log in client.ts. All others should be console.error or console.warn in catch blocks.

Common Fixes

Fix: Header uses string instead of constant

// Before
headers: { VtexidClientAutCookie: authCookie }
// After
import { VTEX_AUTH_COOKIE } from "../utils/vtexId";
headers: { [VTEX_AUTH_COOKIE]: authCookie }

Fix: Missing expectedOrderFormSections

// Before
await vtexFetch<OrderForm>(`/api/checkout/pub/orderForm`, { method: "POST", headers });
// After
import { DEFAULT_EXPECTED_SECTIONS } from "../actions/checkout";
await vtexFetch<OrderForm>(`/api/checkout/pub/orderForm`, {
  method: "POST", headers,
  body: JSON.stringify({ expectedOrderFormSections: DEFAULT_EXPECTED_SECTIONS }),
});

Fix: Missing salesChannel in catalog

// Before
return vtexFetch<T[]>(`/api/catalog_system/pub/products/search/?${params}`);
// After
const { salesChannel } = getVtexConfig();
if (salesChannel) params.set("sc", salesChannel);
return vtexFetch<T[]>(`/api/catalog_system/pub/products/search/?${params}`);

Validation

After all fixes, run:

# TypeScript
npx -p typescript tsc --noEmit

# No hardcoded cookie strings
rg "VtexIdclientAutCookie" vtex/ --glob '!vtex/utils/vtexId.ts' --glob '!*.md'

# No debug logs
rg "console\.log" vtex/ --glob '*.ts' --glob '!client.ts'

# No trailing whitespace
rg "\s+$" vtex/ --glob '*.ts'

All must return 0 results (except TypeScript which exits 0).

Weekly Installs
2
First Seen
5 days ago
Installed on
amp2
cline2
opencode2
cursor2
kimi-cli2
codex2