Cargando documentación…
Cargando documentación…
@notheadless/sdk
Una API al estilo Prisma/Drizzle sobre los endpoints REST de Storefront: where, select, orderBy, limit y relaciones con with.
Recorré una categoría (siguiendo todas las páginas) o buscá muchos productos por id o handle.
// Recorrer: sigue la paginación sola, páginas 2…N en paralelo
const all = await nube.products.findMany({
where: { categoryId: 41184206 },
orderBy: "price-ascending", // "best-selling" | "price-ascending" | "price-descending"
select: { id: true, name: true, variants: true },
limit: 500, // tope opcional
})
// Búsqueda: cualquier cantidad de ids/handles, en lotes de 30, respetando el orden de entrada
const picks = await nube.products.findMany({ where: { ids: [369801113, 369801233] } })
const byHandle = await nube.products.findMany({ where: { handles: ["taza-capybara-ritual-tranqui"] } })orderBy es un error de tipos, no un 400 en runtime: la API no permite sort_by con ids/handles, así que el tipo tampoco.const p = await nube.products.findUnique({ where: { handle: "peluche-capybara-modo-siesta" }, select: { id: true, name: true } })
if (!p) notFound() // 404 → null
const q = await nube.products.findUniqueOrThrow({ where: { id: 369801113 } }) // lanza NubeError(resource_not_found)Las búsquedas son exactas: { id } nunca cae en una coincidencia por handle (la ruta REST de detalle sí lo hace), así que siempre obtenés lo que pediste. Las llamadas hechas en el mismo tick se agrupan en batch en un solo request.
const bestSeller = await nube.products.findFirst({ where: { categoryId }, orderBy: "best-selling" })
const total = await nube.products.count({ where: { categoryId } }) // un request mínimo (per_page=1)
const hits = await nube.products.search({ query: "capybara", select: { id: true, name: true }, limit: 10 })Para UIs paginadas, traé una página junto con su metadata. Para procesar catálogos grandes sin tener todo en memoria, hacé streaming con un iterador async:
const { data, pagination } = await nube.products.paginate({ page: 2, perPage: 24, where: { categoryId } })
// pagination: { page: 2, perPage: 24, total: 140, totalPages: 6 }
for await (const product of nube.products.iterate({ select: { id: true, variants: true } })) {
await index(product) // trae la página siguiente recién cuando llegás
}const roots = await nube.categories.findMany({ where: { parentId: 0 } })
const recent = await nube.categories.findMany({ where: { updatedAt: { gte: new Date("2026-09-01") } } })
const one = await nube.categories.findUnique({ where: { handle: "mundo-capy" } })
const n = await nube.categories.count()| Prop | Tipo | Descripción |
|---|---|---|
| parentId | number | Hijas directas de una categoría. 0 = categorías raíz. |
| handle | string | Coincidencia exacta de handle. |
| sinceId | number | Categorías con un id mayor a este. |
| createdAt / updatedAt | { gte?, lte? } | Rangos de fechas, como Date o string ISO. |
Cargá datos relacionados en una sola llamada. Las relaciones corren en paralelo, y sus select también están tipados:
const capy = await nube.categories.findUniqueOrThrow({
where: { handle: "mundo-capy" },
select: { id: true, name: true },
with: {
children: { select: { name: true, handle: true } },
products: { select: { id: true, name: true, images: true }, orderBy: "best-selling", limit: 12 },
},
})
capy.children[0].handle // string
capy.products[0].images // ProductImage[]Toda la jerarquía como un árbol anidado, a partir de un único escaneo en paralelo de todas las categorías:
const tree = await nube.categories.tree({ select: { name: true, handle: true } })
// [{ name, handle, children: [{ name, handle, children: [...] }] }]
const subtree = await nube.categories.tree({ rootId: 41184206 })const options = await nube.shipping.quote({ zipCode: "1414", variantId: 1605355917, quantity: 1 })
// [{ code, name, price: "2500.00", daysUntil: { start, end, … } | null, … }]