Saltar al contenido principal

SDK Helper

Las apps NubeSDK se ejecutan dentro de un web worker aislado, sin acceso directo al DOM. Todo lo que hace la app: leer el estado, renderizar componentes, navegar y almacenar datos pasa por la instancia del SDK que el runtime entrega al punto de entrada App(nube).

En la práctica, esa instancia nube termina pasando por todas las funciones y componentes de la app, y algunos patrones se repiten en cada proyecto: leer la página actual, estrechar tipos de página, renderizar un componente por producto, mostrar un toast al recibir un evento.

@tiendanube/nube-sdk-helper concentra esos patrones en un conjunto de utilidades pequeño y fuertemente tipado.

Instalación

npm install @tiendanube/nube-sdk-helper @tiendanube/nube-sdk-types

@tiendanube/nube-sdk-types es una peer dependency y debe instalarse junto con el paquete helper.

Registrar la instancia

El runtime entrega la instancia del SDK solo como argumento del punto de entrada. La idea central del helper es simple: registrá una vez, y todos los demás helpers llegan a ella por su cuenta, sin necesidad de pasar nube por toda la jerarquía de la app.

src/App.ts
import {
setNubeInstance,
getCurrentState,
ui,
} from "@tiendanube/nube-sdk-helper";
import type { NubeSDK } from "@tiendanube/nube-sdk-types";

export function App(nube: NubeSDK) {
setNubeInstance(nube); // call this first, before anything else

const state = getCurrentState();
ui.showToast(`You are on the ${state.location.page.type} page`);
}

Tres funciones gestionan la instancia:

  • setNubeInstance(nube): registra la instancia (llamá una vez al inicio del App).
  • getNubeInstance(): devuelve la instancia registrada, lanzando un error descriptivo si aún no fue registrada.
  • clearNubeInstance(): limpia la instancia (útil en tests).

Por qué esto importa

Con la instancia registrada globalmente, las acciones más comunes se convierten en funciones independientes que podés llamar desde cualquier lugar: un componente anidado, un módulo utilitario, un event handler, sin necesidad de recibir nube como parámetro.

import { navigate, setNubeInstance, ui } from "@tiendanube/nube-sdk-helper";
import type { NubeSDK } from "@tiendanube/nube-sdk-types";

export function App(nube: NubeSDK) {
setNubeInstance(nube); // call this first, before any other helper
}

// En cualquier otra parte de la app, sin `nube` en el scope:
function onCheckoutClick() {
navigate("/checkout"); // routes to the path internally via the SDK instance
ui.showToast("Taking you to checkout...", "info");
}

Sin el helper, sería necesario tener una referencia a nube en el scope y llamar a nube.getBrowserAPIs().navigate(...), además de construir el componente de toast a mano. El helper reduce ambos a una sola línea.

Lo mismo aplica para el almacenamiento en el browser:

import { browser, setNubeInstance } from "@tiendanube/nube-sdk-helper";
import type { NubeSDK } from "@tiendanube/nube-sdk-types";

export async function App(nube: NubeSDK) {
setNubeInstance(nube); // call this first, before any other helper

await browser.asyncLocalStorage.setItem("seen-banner", "true");
const seen = await browser.asyncLocalStorage.getItem("seen-banner");
}

Leer el estado con selectores

Los selectores siguen un patrón consistente: llamados sin argumento, leen el estado actual del SDK; pasando un estado explícito, se convierten en funciones puras.

import {
getCartItems,
getCustomer,
getPageType,
setNubeInstance,
} from "@tiendanube/nube-sdk-helper";
import type { NubeSDK } from "@tiendanube/nube-sdk-types";

export function App(nube: NubeSDK) {
setNubeInstance(nube); // call this first, before any other helper

// Sin argumento: lee el estado actual de la instancia del SDK.
const items = getCartItems();
const pageType = getPageType();
const customer = getCustomer();
}
Testeabilidad

Pasá un estado mock a cualquier selector y se comporta como una función pura: sin efectos secundarios, sin depender de la instancia registrada. Este patrón aplica a toda la familia de selectores.

Guards

Los guards cumplen una doble función: validan en runtime y estrechan el tipo para TypeScript, desbloqueando los datos específicos de la página tipados por el compilador.

import {
getCurrentState,
isProductPage,
setNubeInstance,
} from "@tiendanube/nube-sdk-helper";
import type { NubeSDK } from "@tiendanube/nube-sdk-types";

export function App(nube: NubeSDK) {
setNubeInstance(nube); // call this first, before any other helper

const { page } = getCurrentState().location;

if (isProductPage(page)) {
// `page` is now narrowed to a ProductPage, so `page.data.product` is typed.
console.log(page.data.product.name);
}
}
Validación y tipado juntos

A diferencia de un cast (as ProductPage), los guards verifican la estructura en runtime antes de estrechar el tipo. Si la condición no pasa, TypeScript no expone page.data.product.

Hay un guard para casi toda estructura encontrada en una app NubeSDK:

  • Páginas: isProductPage, isCategoryPage, isCheckoutPage, isHomePage, isAllProductsPage, isSearchPage
  • Carrito: isCart, isCartItem, isCartValidationSuccess, isCartValidationPending, isCartValidationFail
  • Dominio: isStore, isCustomer, isPayment, isShipping, isAddress, y más
  • Componentes / datos de página: isNubeComponent, hasProductList, hasSections, hasSingleProduct, isSectionWithProducts

Getters

Además de los selectores de estado, los getters exponen los metadatos inyectados por el runtime sobre la app. Uno útil es getScriptURL, que analiza la URL desde donde se cargó el script de la app (cacheada como una URL congelada):

import {
getScriptParam,
getScriptURL,
setNubeInstance,
} from "@tiendanube/nube-sdk-helper";
import type { NubeSDK } from "@tiendanube/nube-sdk-types";

export function App(nube: NubeSDK) {
setNubeInstance(nube); // call this first, before any other helper

const url = getScriptURL();
console.log("Script origin:", url.origin);
console.log("Script pathname:", url.pathname);

// Read configuration passed as query params on the script URL, e.g. ?variant=b
const variant = getScriptParam("variant"); // string | null
}

Esta es la forma idiomática de configurar una app desde la tag de script, sin necesidad de una solicitud adicional.

Page matching

pageMatch y onPage resuelven el mismo problema desde dos ángulos. pageMatch despacha una vez contra un estado provisto, y cada handler recibe el payload correctamente tipado para su página. onPage envuelve pageMatch, pero suscribe a la navegación, re-ejecutándose en cada cambio de página y devolviendo una función de cancelación.

Usá pageMatch para una decisión puntual basada en el estado actual:

import {
getCurrentState,
pageMatch,
setNubeInstance,
} from "@tiendanube/nube-sdk-helper";
import type { NubeSDK } from "@tiendanube/nube-sdk-types";

export function App(nube: NubeSDK) {
setNubeInstance(nube); // call this first, before any other helper

// Runs once against the state you pass in.
pageMatch(getCurrentState(), {
product: (state, product) => console.log("Product:", product.name),
checkout: (state, checkout) => console.log("Step:", checkout.step),
});
}

Usá onPage para reaccionar continuamente a la navegación del usuario:

import { onPage, setNubeInstance } from "@tiendanube/nube-sdk-helper";
import type { NubeSDK } from "@tiendanube/nube-sdk-types";

export function App(nube: NubeSDK) {
setNubeInstance(nube); // call this first, before any other helper

const stop = onPage({
product: (state, product) => console.log("Viewing product:", product.id),
checkout: (state, checkout) => {
if (checkout.step === "success") console.log("Purchase complete");
},
// category / home handlers are optional
});

// Call stop() later, when you no longer need to react to navigation.
void stop;
}

Para checkout específicamente, onCheckoutStep permite reaccionar a un step particular:

import { onCheckoutStep, setNubeInstance } from "@tiendanube/nube-sdk-helper";
import type { NubeSDK } from "@tiendanube/nube-sdk-types";

export function App(nube: NubeSDK) {
setNubeInstance(nube); // call this first, before any other helper

onCheckoutStep({
success: () => console.log("Purchase complete"),
});
}

Render

Una necesidad frecuente es renderizar algo en un slot de grilla de producto: un badge, un label, un ícono. forEachProduct extrae todos los productos del estado actual (independientemente del tipo de página), los mapea a través de una factory de renderizado, descarta resultados vacíos y asigna automáticamente un key único a partir del id del producto.

import {
forEachProduct,
onPage,
setNubeInstance,
} from "@tiendanube/nube-sdk-helper";
import type { NubeSDK } from "@tiendanube/nube-sdk-types";
import { Badge } from "./components/Badge";

export function App(nube: NubeSDK) {
setNubeInstance(nube);

// Renderiza un badge sobre cada imagen de producto en la grilla del home.
onPage({
home: () => {
nube.render(
"product_grid_item_image_center_center",
forEachProduct((product) => <Badge product={product} />),
);
},
});
}

Sin JSX, la factory devuelve un objeto de componente directamente:

import {
forEachProduct,
onPage,
setNubeInstance,
} from "@tiendanube/nube-sdk-helper";
import type { NubeSDK } from "@tiendanube/nube-sdk-types";

export function App(nube: NubeSDK) {
setNubeInstance(nube); // call this first, before any other helper

onPage({
home: () => {
nube.render(
"product_grid_item_image_bottom_right",
forEachProduct((product) => ({ type: "txt", children: product.name })),
);
},
});
}

Devolver null o undefined desde la factory omite el producto: esas entradas se filtran automáticamente.

Helpers de UI y eventos

ui agrupa las operaciones de vista más comunes, incluyendo renderizar el mismo componente en múltiples slots en una sola llamada:

import { setNubeInstance, ui } from "@tiendanube/nube-sdk-helper";
import type { NubeSDK } from "@tiendanube/nube-sdk-types";

export function App(nube: NubeSDK) {
setNubeInstance(nube); // call this first, before any other helper

ui.renderAll(["corner_top_left", "corner_top_right"], {
type: "txt",
children: "Hi",
});
ui.showToast("Done!", "success");
ui.clear("corner_top_right");
}

onEvent y toastOn reducen el patrón repetitivo de "escuchar y reaccionar" a una línea cada uno, ambos devolviendo una función de cancelación:

import { onEvent, setNubeInstance, toastOn } from "@tiendanube/nube-sdk-helper";
import type { NubeSDK } from "@tiendanube/nube-sdk-types";

export function App(nube: NubeSDK) {
setNubeInstance(nube); // call this first, before any other helper

const off = onEvent("cart:update", (state) => {
console.log("items:", state.cart.items.length);
});

// Call off() later, when you no longer need it.
void off;

toastOn("cart:add:success", "Added to cart", "success");
toastOn("cart:update", (state) => `Cart: ${state.cart.items.length} items`);
}

Referencia de la API

Referencia formal de cada símbolo exportado en la raíz del paquete (@tiendanube/nube-sdk-helper).

Instancia

Gestionan la instancia del SDK que usa el resto del helper.

setNubeInstance(nube)

Registra la instancia de NubeSDK para la app actual. Llámala una vez, al inicio de App(nube).

setNubeInstance(nube: Readonly<NubeSDK>): void

getNubeInstance()

Devuelve la instancia registrada. Si no se registró ninguna, recurre a self.__SDK_INSTANCE__ y, en ausencia de ambas, lanza un error descriptivo.

getNubeInstance(): Readonly<NubeSDK>

clearNubeInstance()

Limpia la instancia registrada. Útil en tests o al reinicializar la app.

clearNubeInstance(): void

Getters

Exponen el estado actual y los metadatos que el runtime inyecta sobre la app.

getCurrentState()

Devuelve el estado actual (readonly) del SDK.

getCurrentState(): Readonly<NubeSDKState>

getAppData()

Devuelve los datos de la app inyectados por el runtime: id y script.

getAppData(): Readonly<{ id: string; script: string }>

getScriptURL()

Devuelve la URL desde la que se cargó el script de la app, como una instancia URL congelada (cacheada en la primera llamada).

getScriptURL(): Readonly<URL>

getScriptSearchParams()

Devuelve los URLSearchParams (readonly) de la URL del script.

getScriptSearchParams(): Readonly<URLSearchParams>

getScriptParam(key)

Devuelve el valor de un query param específico de la URL del script, o null si no está presente. Es la forma idiomática de configurar una app desde la etiqueta de script, sin una petición adicional.

getScriptParam(key: string): Nullable<string>

Selectores de estado

Accesores enfocados en las porciones más leídas del estado. Todos aceptan un state opcional; cuando se omite, leen el estado actual de la instancia registrada (pasa un estado explícito para volverlos puros).

getCart(state?: NubeSDKState): Cart
getCartItems(state?: NubeSDKState): CartItem[]
getPageType(state?: NubeSDKState): Page["type"] // ej.: "home", "product", "checkout"
getCustomer(state?: NubeSDKState): Nullable<Customer> // null cuando no está disponible en la página

Guards

Los guards cumplen doble función: validan en runtime y estrechan el tipo para TypeScript. A diferencia de un cast (as ProductPage), verifican la estructura antes de estrechar — si la comprobación falla, el tipo no se expone.

import {
getCurrentState,
isProductPage,
setNubeInstance,
} from "@tiendanube/nube-sdk-helper";
import type { NubeSDK } from "@tiendanube/nube-sdk-types";

export function App(nube: NubeSDK) {
setNubeInstance(nube); // call this first, before any other helper

const { page } = getCurrentState().location;
if (isProductPage(page)) {
// `page` se estrechó a ProductPage, así que `page.data.product` está tipado.
console.log(page.data.product.name);
}
}

Páginas — reciben un Page y estrechan al tipo de página correspondiente:

GuardEstrecha a
isProductPageProductPage
isCategoryPageCategoryPage
isCheckoutPageCheckoutPage
isAllProductsPageAllProductsPage
isSearchPageSearchPage
isHomePageHomePage
isAccountPageAccountPage
isAccountLoginPageAccountLoginPage
isAccountRegisterPageAccountRegisterPage
isAccountInfoPageAccountInfoPage
isAccountResetPageAccountResetPage
isAccountNewPasswordPageAccountNewPasswordPage
isAccountOrdersPageAccountOrdersPage

Carrito — reciben unknown y validan la estructura:

GuardEstrecha a
isCartCart
isCartItemCartItem
isCartValidationSuccessvalidación de carrito exitosa
isCartValidationPendingvalidación de carrito pendiente
isCartValidationFailvalidación de carrito fallida

Dominio — reciben unknown y validan la estructura:

GuardEstrecha a
isStoreStore
isCustomerCustomer
isPaymentPayment
isShippingShipping
isShippingOptionShippingOption

Dirección — reciben unknown y validan la estructura:

GuardEstrecha a
isAddressAddress
isShippingAddressShippingAddress
isBillingAddressBillingAddress

Componentes y datos de página — útiles para comprobar el formato de page.data antes de acceder a él:

GuardEstrecha a
isNubeComponentNubeComponent
hasProductList{ products: ProductDetails[] }
hasSections{ sections: unknown[] }
isSectionWithProductsuna sección que contiene products
hasSingleProduct{ product: ProductDetails }

Page matching

pageMatch(state, handlers)

Despacha al handler correspondiente al tipo de página en el estado que le pases. Cada handler recibe el payload correctamente tipado para su página. Se ejecuta una vez.

pageMatch(state: NubeSDKState, handlers: PageHandlers): void

onPage(handlers)

Se suscribe al evento page:loaded y llama al handler correspondiente en cada navegación. Devuelve una función de cancelación.

onPage(handlers: PageHandlers): () => void

onCheckoutStep(handlers)

Escucha checkout:ready y, cuando la página actual es un checkout, invoca el handler registrado para el step actual. También se ejecuta de inmediato para el step corriente si ya está en el checkout. Devuelve una función de cancelación.

onCheckoutStep(handlers: CheckoutStepHandlers): () => void

Tipos relacionados: PageDataMap, PageHandlerFunction<T>, PageHandlers, CheckoutStepHandlers.

Render

getProductsFromState(state)

Extrae todos los productos del estado, sin importar el tipo de página (listas directas, productos dentro de secciones y el producto principal en páginas de detalle). Devuelve un array vacío si no hay productos.

getProductsFromState(state: NubeSDKState): ProductDetails[]

forEachProduct(renderFactory)

Crea una función de render que extrae los productos del estado, mapea cada uno con renderFactory, descarta los resultados null/undefined y asigna automáticamente una key única a partir del id del producto.

forEachProduct(
renderFactory: (product: ProductDetails) => NubeComponent | null | undefined,
): (state: NubeSDKState) => NubeComponent[]

UI

ui es un objeto congelado con cuatro helpers de vista.

ui.showToast(message: string, variant?: ToastVariant): void  // variant por defecto "info"
ui.clear(slot: UISlot): void
ui.render(slot: UISlot, component: RenderableComponent): void
ui.renderAll(slots: UISlot[], component: RenderableComponent): void
  • showToast — muestra un toast en la esquina superior derecha. variant es "success" | "error" | "warning" | "info".
  • clear — limpia un slot (nube.clearSlot).
  • render — renderiza un componente en un slot.
  • renderAll — renderiza el mismo componente en varios slots en una sola llamada.

Tipos relacionados: ToastVariant, RenderableComponent, UIHelper.

Eventos

Wrappers ergonómicos alrededor de nube.on que devuelven una función de cancelación.

onEvent(event, listener)

Equivalente a nube.on(event, listener), pero la función devuelta desregistra el listener vía nube.off — sin necesidad de guardar referencia a la instancia y al listener para limpiarlo.

onEvent<T extends NubeSDKListenableEvent>(
event: T,
listener: EventListenerMap[T],
): () => void

toastOn(event, message, variant?)

Muestra un toast cada vez que el evento se dispara. El mensaje puede ser una cadena estática o una función que lo deriva del estado. Devuelve una función de cancelación.

toastOn<T extends NubeSDKListenableEvent>(
event: T,
message: string | ((state: Readonly<NubeSDKState>) => string),
variant?: ToastVariant,
): () => void

Browser

Acceso a las Browser APIs (storage, navegación) a través de la instancia del SDK. Ver también Browser APIs .

browser

Objeto que expone las Browser APIs (asyncLocalStorage, asyncSessionStorage, navigate, ...). Se materializa de forma lazy en el primer acceso a una propiedad y se cachea.

import { browser, setNubeInstance } from "@tiendanube/nube-sdk-helper";
import type { NubeSDK } from "@tiendanube/nube-sdk-types";

export async function App(nube: NubeSDK) {
setNubeInstance(nube); // call this first, before any other helper

await browser.asyncLocalStorage.setItem("seen-banner", "true");
const seen = await browser.asyncLocalStorage.getItem("seen-banner");
}

Navega a una ruta dentro del dominio de la tienda. La ruta debe empezar con /.

navigate(route: `/${string}`): void

clearBrowserCache()

Limpia la caché interna de las Browser APIs, forzando una nueva instancia en el próximo acceso. Útil en tests.

clearBrowserCache(): void

Utilidades

Funciones de propósito general, independientes de la instancia del SDK.

deepClone(obj)

Clona un valor en profundidad. Usa structuredClone cuando está disponible (lo está, en el runtime del worker de NubeSDK), con fallback a serialización JSON.

deepClone<T>(obj: T): T

debounce(func, wait)

Devuelve una versión debounced de la función, que solo se ejecuta tras wait ms sin nuevas llamadas.

debounce<T extends (...args: never[]) => unknown>(
func: T,
wait: number,
): (...args: Parameters<T>) => void

throttle(func, limit)

Devuelve una versión throttled de la función, que se ejecuta como máximo una vez cada limit ms.

throttle<T extends (...args: never[]) => unknown>(
func: T,
limit: number,
): (...args: Parameters<T>) => void

Próximos pasos

  • Events — Lista completa de eventos disponibles en NubeSDK
  • State — Estructura de estado de NubeSDK
  • UI Slots — Slots disponibles para renderizado

Help us improve NubeSDK

Found an issue or have a suggestion? Let us know on GitHub.