8 packages headless,
cada um com responsabilidade clara
Importe só o que precisar. Troque um adapter sem reescrever o resto. Cada package é uma classe ou conjunto de funções puras com dependências injetadas.
@kmee/shop-types Foundation
Tipos compartilhados (Product, ProductDetail, Cart, Brand, Category) e helpers puros. Contrato AuthProvider e Logger. Importado por todos os outros packages.
Principais exports
ProductProductDetailCartAuthProviderLoggerformatPriceapplyFilters import { formatPrice, applyFilters } from "@kmee/shop-types"
formatPrice({ value: 49.9 }, { locale: "pt-BR", currency: "BRL" })
// → "R$ 49,90"
applyFilters(products, { categories: ["Films"] }, { min: 10, max: 100 }) @kmee/shopinvader-client Backend client
Cliente headless para o Odoo via Shopinvader. CartService, SalesService, AddressService, DeliveryCarriersService, LeadsService em cima de OdooHttpClient com retry, timeout e auth injetável.
Principais exports
OdooHttpClientCartServiceSalesServiceAddressServiceDeliveryCarriersServiceLeadsService import { OdooHttpClient, SalesService } from "@kmee/shopinvader-client"
const sales = new SalesService(
new OdooHttpClient({
baseUrl,
auth,
getExtraHeaders: async () => ({ apikey: SUPABASE_ANON_KEY }),
}),
)
const orders = await sales.list({ limit: 10 }) @kmee/elasticsearch-shop Search & catalog
Cliente Elasticsearch para listagens, busca e detalhe de produto, categorias e brands. ProductService faz collapse por model.name, suporta filtro por tag, fallback de slug por wildcard, e Levenshtein para escolher melhor hit.
Principais exports
ProductServicesearchCategoriessearchBrands import { ProductService } from "@kmee/elasticsearch-shop"
const products = new ProductService(esConfig)
await products.search({ searchTerm: "vinyl", page: 1, pageSize: 12 })
await products.getByURLKey("oratape-mt80p")
await products.getRelatedProducts([{ name: "ThermoFlex Plus" }]) @kmee/supabase-auth-shop Auth adapter
Adapter que implementa AuthProvider em cima de @supabase/supabase-js. Plugue numa OdooHttpClient e o token Supabase atravessa para o Odoo automaticamente.
Principais exports
createSupabaseAuthProvider import { createSupabaseAuthProvider } from "@kmee/supabase-auth-shop"
const auth = createSupabaseAuthProvider(supabase)
// auth implementa AuthProvider — plugue em OdooHttpClient.
await auth.getToken() // → access_token ou null
await auth.isAuthenticated() // → false para anônimos por default @kmee/shop-storage Local persistence
Persistência local: CartStorage (UUID + dados do carrinho com expiry) e CartItemsMetadataStorage (min_order_qty por item). Chaves de storage configuráveis.
Principais exports
CartStorageCartItemsMetadataStorage import { CartStorage } from "@kmee/shop-storage"
const cartStorage = new CartStorage({
cartKey: "myshop_cart",
uuidKey: "myshop_cart_uuid",
expiryDays: 60,
})
cartStorage.getOrCreateCartUuid()
cartStorage.saveCartData({ uuid, items: [], lastUpdated: 0 }) @kmee/admin-session Admin auth
Sessão admin: JWT em cookie HttpOnly (jose), helpers de cookie para Next.js, getClientIp agnóstico de runtime, e AdminRateLimiter com store plugável (MemoryRateLimitStore por default; troque por Redis/KV em produção).
Principais exports
signAdminSessionJwtverifyAdminSessionTokenAdminRateLimitergetClientIp import {
signAdminSessionJwt,
AdminRateLimiter,
getClientIp,
} from "@kmee/admin-session"
const limiter = new AdminRateLimiter()
const ip = getClientIp(request.headers)
const decision = await limiter.assertAllowed(ip)
if (!decision.ok) return new Response("rate limited", { status: 429 })
const token = await signAdminSessionJwt({ secret: SECRET }) @kmee/shop-react React layer
Providers e hooks React para conectar tudo na app: <CartProvider>, <WishlistProvider>, <SupabaseAuthProvider>, useProductsPage, useCategoriesPage, useBrandsAndCategories.
Principais exports
CartProviderWishlistProviderSupabaseAuthProvideruseCartuseWishlistuseAuthuseProductsPage import { useCart, useWishlist, useAuth } from "@kmee/shop-react"
const { cart, addToCart, removeItem, loading } = useCart()
const { items, add, isInWishlist } = useWishlist()
const { user, signInWithPassword, signOut } = useAuth() @kmee/shop-ui UI components
Componentes opinados (Tailwind + Radix): primitives (Button, Badge, Skeleton, Sheet, DropdownMenu, Select, Input, Tabs, Table) e ~20 componentes de domínio. Tema via CSS vars + Tailwind preset compatível com shadcn.
Principais exports
ProductCardAddToCartButtonCartDrawerProductGalleryProductFiltersHeroCarouselGlobalHeaderFooter // tailwind.config.ts do cliente
import shopUiPreset from "@kmee/shop-ui/tailwind-preset"
export default {
presets: [shopUiPreset],
content: [
"./app/**/*.{ts,tsx}",
"./node_modules/@kmee/shop-ui/src/**/*.{ts,tsx}",
],
} Como compor
Você consome apenas o que faz sentido para a sua app.
// lib/clients.ts — composição típica num app Next.js
import { createClient } from "@supabase/supabase-js"
import { createSupabaseAuthProvider } from "@kmee/supabase-auth-shop"
import { OdooHttpClient, CartService, SalesService } from "@kmee/shopinvader-client"
import { ProductService } from "@kmee/elasticsearch-shop"
import { CartStorage } from "@kmee/shop-storage"
export const supabase = createClient(URL, ANON_KEY)
const auth = createSupabaseAuthProvider(supabase)
const odoo = new OdooHttpClient({ baseUrl, auth })
export const cart = new CartService(odoo)
export const sales = new SalesService(odoo)
export const products = new ProductService(esConfig)
export const cartStorage = new CartStorage()
Cada classe é um ponto de composição. O OdooHttpClient recebe o auth provider; o CartService recebe o client; o CartProvider (lado React) recebe o service. Nada amarrado.
Quer um package customizado?
Tem caso de uso que não cabe nas 8 libs? A KMEE desenvolve adapters específicos (gateway de pagamento, ERP terceiro, marketplace).