Pular para o conteúdo principal

SDK Helper

Apps NubeSDK rodam dentro de um web worker isolado, sem acesso direto ao DOM. Tudo que o app faz: ler o estado, renderizar componentes, navegar e armazenar dados passa pela instância do SDK que o runtime entrega ao ponto de entrada App(nube).

Na prática, essa instância nube acaba sendo passada por todas as funções e componentes do app, e alguns padrões se repetem em todo projeto: ler a página atual, estreitar tipos de página, renderizar um componente por produto, exibir um toast ao receber um evento.

@tiendanube/nube-sdk-helper concentra esses padrões em um conjunto de utilitários pequeno e fortemente tipado.

Instalação

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

@tiendanube/nube-sdk-types é uma peer dependency e deve ser instalada junto.

Registrando a instância

O runtime entrega a instância do SDK apenas como argumento do ponto de entrada. A ideia central do helper é simples: registre uma vez, e todos os outros helpers chegam até ela por conta própria, sem precisar passar nube por toda a árvore do 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`);
}

Três funções gerenciam a instância:

  • setNubeInstance(nube): registra a instância (chame uma vez no topo do App).
  • getNubeInstance(): retorna a instância registrada, lançando um erro descritivo se ela ainda não foi registrada.
  • clearNubeInstance(): limpa a instância (útil em testes).

Por que isso importa

Com a instância registrada globalmente, as ações mais comuns viram funções independentes que podem ser chamadas de qualquer lugar: um componente aninhado, um módulo utilitário, um event handler, sem precisar receber 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
}

// Em qualquer outro lugar do app, sem `nube` no escopo:
function onCheckoutClick() {
navigate("/checkout"); // routes to the path internally via the SDK instance
ui.showToast("Taking you to checkout...", "info");
}

Sem o helper, seria necessário ter uma referência a nube no escopo e chamar nube.getBrowserAPIs().navigate(...), além de construir o componente de toast manualmente. O helper reduz ambos a uma linha.

O mesmo se aplica ao armazenamento no 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");
}

Lendo o estado com seletores

Os seletores seguem um padrão consistente: chamados sem argumento, leem o estado atual do SDK; passando um estado explícito, tornam-se funções 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

// Sem argumento: lê o estado atual da instância do SDK.
const items = getCartItems();
const pageType = getPageType();
const customer = getCustomer();
}
Testabilidade

Passe um estado mock para qualquer seletor e ele se comporta como uma função pura: sem efeitos colaterais, sem depender da instância registrada. Esse padrão vale para toda a família de seletores.

Guards

Guards fazem dupla função: validam em runtime e estreitam o tipo para o TypeScript, desbloqueando os dados específicos da página tipados pelo 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);
}
}
Validação e tipagem juntos

Diferente de um cast (as ProductPage), os guards verificam a estrutura em runtime antes de estreitar o tipo. Se a condição não passar, o TypeScript não expõe page.data.product.

Há um guard para quase toda estrutura encontrada em um app NubeSDK:

  • Páginas: isProductPage, isCategoryPage, isCheckoutPage, isHomePage, isAllProductsPage, isSearchPage
  • Carrinho: isCart, isCartItem, isCartValidationSuccess, isCartValidationPending, isCartValidationFail
  • Domínio: isStore, isCustomer, isPayment, isShipping, isAddress, e mais
  • Componentes / dados de página: isNubeComponent, hasProductList, hasSections, hasSingleProduct, isSectionWithProducts

Getters

Além dos seletores de estado, os getters expõem os metadados injetados pelo runtime sobre o app. Um exemplo útil é getScriptURL, que analisa a URL de onde o script do app foi carregado (cacheada como uma 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
}

Essa é a forma idiomática de configurar um app a partir da tag de script, sem precisar de uma requisição adicional.

Page matching

pageMatch e onPage resolvem o mesmo problema de ângulos diferentes. pageMatch despacha uma vez contra um estado fornecido, e cada handler recebe o payload corretamente tipado para a sua página. onPage envolve pageMatch, mas subscreve à navegação, re-executando a cada mudança de página e retornando uma função de cancelamento.

Use pageMatch para uma decisão pontual com base no estado atual:

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),
});
}

Use onPage para reagir continuamente à navegação do usuário:

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 especificamente, onCheckoutStep permite reagir a um step específico:

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

Uma necessidade frequente é renderizar algo em um slot de grade de produto: um badge, um label, um ícone. forEachProduct extrai todos os produtos do estado atual (independentemente do tipo de página), mapeia cada um por uma factory de renderização, descarta resultados vazios e atribui automaticamente um key único a partir do id do produto.

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 um badge sobre cada imagem de produto na grade da home.
onPage({
home: () => {
nube.render(
"product_grid_item_image_center_center",
forEachProduct((product) => <Badge product={product} />),
);
},
});
}

Sem JSX, a factory retorna um objeto de componente diretamente:

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 })),
);
},
});
}

Retornar null ou undefined da factory pula o produto: essas entradas são filtradas automaticamente.

Helpers de UI e eventos

ui agrupa as operações de view mais comuns, incluindo renderizar o mesmo componente em múltiplos slots em uma chamada:

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 e toastOn reduzem o padrão repetitivo de "escutar e reagir" a uma linha cada, ambos retornando uma função de cancelamento:

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`);
}

Referência da API

Referência formal de cada símbolo exportado na raiz do pacote (@tiendanube/nube-sdk-helper).

Instância

Gerenciam a instância do SDK usada por todo o resto do helper.

setNubeInstance(nube)

Registra a instância do NubeSDK para o app atual. Chame uma vez, no início do App(nube).

setNubeInstance(nube: Readonly<NubeSDK>): void

getNubeInstance()

Retorna a instância registrada. Se nenhuma foi registrada, tenta o fallback self.__SDK_INSTANCE__ e, na ausência de ambos, lança um erro descritivo.

getNubeInstance(): Readonly<NubeSDK>

clearNubeInstance()

Limpa a instância registrada. Útil em testes ou ao reinicializar o app.

clearNubeInstance(): void

Getters

Expõem o estado atual e os metadados injetados pelo runtime sobre o app.

getCurrentState()

Retorna o estado atual (readonly) do SDK.

getCurrentState(): Readonly<NubeSDKState>

getAppData()

Retorna os dados do app injetados pelo runtime: id e script.

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

getScriptURL()

Retorna a URL de onde o script do app foi carregado, como uma instância URL congelada (cacheada na primeira chamada).

getScriptURL(): Readonly<URL>

getScriptSearchParams()

Retorna os URLSearchParams (readonly) da URL do script.

getScriptSearchParams(): Readonly<URLSearchParams>

getScriptParam(key)

Retorna o valor de um query param específico da URL do script, ou null se ausente. É a forma idiomática de configurar um app a partir da tag de script, sem uma requisição adicional.

getScriptParam(key: string): Nullable<string>

Seletores de estado

Acessores focados nas fatias mais lidas do estado. Todos aceitam um state opcional; quando omitido, leem o estado atual da instância registrada (passe um estado explícito para torná-los puros).

getCart(state?: NubeSDKState): Cart
getCartItems(state?: NubeSDKState): CartItem[]
getPageType(state?: NubeSDKState): Page["type"] // ex.: "home", "product", "checkout"
getCustomer(state?: NubeSDKState): Nullable<Customer> // null quando indisponível na página

Guards

Guards fazem dupla função: validam em runtime e estreitam o tipo para o TypeScript. Diferente de um cast (as ProductPage), verificam a estrutura antes de estreitar — se a checagem falhar, o tipo não é exposto.

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` foi estreitado para ProductPage, então `page.data.product` é tipado.
console.log(page.data.product.name);
}
}

Páginas — recebem um Page e estreitam para o tipo de página correspondente:

GuardEstreita para
isProductPageProductPage
isCategoryPageCategoryPage
isCheckoutPageCheckoutPage
isAllProductsPageAllProductsPage
isSearchPageSearchPage
isHomePageHomePage
isAccountPageAccountPage
isAccountLoginPageAccountLoginPage
isAccountRegisterPageAccountRegisterPage
isAccountInfoPageAccountInfoPage
isAccountResetPageAccountResetPage
isAccountNewPasswordPageAccountNewPasswordPage
isAccountOrdersPageAccountOrdersPage

Carrinho — recebem unknown e validam a estrutura:

GuardEstreita para
isCartCart
isCartItemCartItem
isCartValidationSuccessvalidação de carrinho com sucesso
isCartValidationPendingvalidação de carrinho pendente
isCartValidationFailvalidação de carrinho com falha

Domínio — recebem unknown e validam a estrutura:

GuardEstreita para
isStoreStore
isCustomerCustomer
isPaymentPayment
isShippingShipping
isShippingOptionShippingOption

Endereço — recebem unknown e validam a estrutura:

GuardEstreita para
isAddressAddress
isShippingAddressShippingAddress
isBillingAddressBillingAddress

Componentes e dados de página — úteis para checar o formato do page.data antes de acessá-lo:

GuardEstreita para
isNubeComponentNubeComponent
hasProductList{ products: ProductDetails[] }
hasSections{ sections: unknown[] }
isSectionWithProductsseção contendo products
hasSingleProduct{ product: ProductDetails }

Page matching

pageMatch(state, handlers)

Despacha para o handler correspondente ao tipo da página no estado fornecido. Cada handler recebe o payload corretamente tipado para a sua página. Executa uma vez.

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

onPage(handlers)

Subscreve ao evento page:loaded e chama o handler correspondente a cada navegação. Retorna uma função de cancelamento.

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

onCheckoutStep(handlers)

Escuta checkout:ready e, quando a página atual é um checkout, invoca o handler registrado para o step atual. Também executa imediatamente para o step corrente, se já estiver no checkout. Retorna uma função de cancelamento.

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

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

Render

getProductsFromState(state)

Extrai todos os produtos do estado, independentemente do tipo de página (listas diretas, produtos dentro de seções e o produto principal de páginas de detalhe). Retorna um array vazio se não houver produtos.

getProductsFromState(state: NubeSDKState): ProductDetails[]

forEachProduct(renderFactory)

Cria uma função de render que extrai os produtos do estado, mapeia cada um pela renderFactory, descarta resultados null/undefined e atribui automaticamente um key único a partir do id do produto.

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

UI

ui é um objeto congelado com quatro helpers de view.

ui.showToast(message: string, variant?: ToastVariant): void  // variant padrão "info"
ui.clear(slot: UISlot): void
ui.render(slot: UISlot, component: RenderableComponent): void
ui.renderAll(slots: UISlot[], component: RenderableComponent): void
  • showToast — exibe um toast no canto superior direito. variant é "success" | "error" | "warning" | "info".
  • clear — limpa um slot (nube.clearSlot).
  • render — renderiza um componente em um slot.
  • renderAll — renderiza o mesmo componente em múltiplos slots em uma chamada.

Tipos relacionados: ToastVariant, RenderableComponent, UIHelper.

Eventos

Wrappers ergonômicos em torno de nube.on que retornam uma função de cancelamento.

onEvent(event, listener)

Equivalente a nube.on(event, listener), mas a função retornada remove o listener via nube.off — sem precisar guardar referência à instância e ao listener para limpar.

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

toastOn(event, message, variant?)

Exibe um toast sempre que o evento dispara. A mensagem pode ser uma string estática ou uma função que a deriva do estado. Retorna uma função de cancelamento.

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

Browser

Acesso às Browser APIs (storage, navegação) através da instância do SDK. Veja também Browser APIs .

browser

Objeto que expõe as Browser APIs (asyncLocalStorage, asyncSessionStorage, navigate, ...). É materializado de forma lazy na primeira propriedade acessada e cacheado.

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 para uma rota dentro do domínio da loja. A rota deve começar com /.

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

clearBrowserCache()

Limpa o cache interno das Browser APIs, forçando uma nova instância no próximo acesso. Útil em testes.

clearBrowserCache(): void

Utilitários

Funções de propósito geral, independentes da instância do SDK.

deepClone(obj)

Clona um valor em profundidade. Usa structuredClone quando disponível (é o caso no runtime do NubeSDK), com fallback para serialização JSON.

deepClone<T>(obj: T): T

debounce(func, wait)

Retorna uma versão debounced da função, que só executa após wait ms sem novas chamadas.

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

throttle(func, limit)

Retorna uma versão throttled da função, que executa no máximo uma vez a cada limit ms.

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

Próximos passos

  • Events — Lista completa de eventos disponíveis no NubeSDK
  • State — Estrutura de estado do NubeSDK
  • UI Slots — Slots disponíveis para renderização

Help us improve NubeSDK

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