npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@baaskit/checkout-js

v0.1.6

Published

BaaskitCheckout SDK for embedding Baaskit card payments in merchant checkouts.

Readme

BaaskitCheckout JS

@baaskit/checkout-js permite embeber Baaskit Tarjetas dentro del checkout existente de un comercio mediante un iframe controlado por SDK.

La V1 no procesa pagos reales en este repositorio. Incluye SDK, protocolo postMessage, mock local, ejemplos y tests para validar la arquitectura.

🤖 Para agentes de IA: este SDK trae un Skill de integración

Este paquete incluye un Skill de integración para agentes de IA (Claude, Cursor, Kiro, OpenCode, Antigravity, Copilot, Gemini, …). Es un conjunto de instrucciones autocontenidas que le permite a un agente integrar el checkout embebido de Baaskit end-to-end y sin soporte humano, en cualquier stack de e-commerce (Next.js, Remix/React Router, Shopify, Vue, Angular, PHP, vanilla JS, …). Si descargas o instalas este SDK, el agente puede leer el skill y dejar la integración funcionando solo.

Cómo lo descubre cada agente

| Archivo | Para qué sirve | |---|---| | AGENTS.md | Punto de entrada estándar cross-agent (lo leen Cursor, OpenCode y otros). Redirige al skill. | | skills/baaskit-checkout-integration/SKILL.md | Skill canónico: mapa, reglas de oro, decisión de ui_mode, checklist y verificación. | | .cursor/rules/baaskit-checkout.mdc | Puntero nativo para Cursor (descubrimiento automático). | | .claude/skills/baaskit-checkout-integration/SKILL.md | Puntero nativo para Claude Code. |

Instalado como dependencia, el skill queda en node_modules/@baaskit/checkout-js/skills/baaskit-checkout-integration/ (se incluye en el paquete npm).

Qué cubre el skill

El skill (SKILL.md) más sus referencias en skills/baaskit-checkout-integration/references/:

| Referencia | Contenido | |---|---| | backend.md | OAuth2 client credentials, crear el OnlineCheckout (con ui_mode, cardholder, tokenization_enable), webhook y confirmación server-side, variables de entorno y ambientes. | | frontend.md | Montar el SDK, botón "Pagar" del comercio, eventos, estados de UI y auto-resize. | | security.md | PCI/SAQ A, CSP frame-ancestors, manejo de secretos, idempotencia. | | troubleshooting.md | Fallos comunes y su solución (iframe que no carga, X-Frame-Options, pantalla en blanco, el pago no se confirma, error 502, …). |

El skill instruye al agente a preguntar primero el ui_mode (embedded_page embebido, por defecto, o hosted_page con redirección) y a implementar la creación del OnlineCheckout en consecuencia.

Cómo usarlo (agente)

  1. Lee AGENTS.md.
  2. Sigue skills/baaskit-checkout-integration/SKILL.md y abre las referencias según cada paso.
  3. Pregunta el ui_mode, detecta el stack del proyecto y traduce los patrones a ese stack.

Flujo correcto

La sesion Baaskit debe crearse cuando el cliente selecciona Baaskit Tarjetas como metodo de pago.

No debe crearse al cargar el carrito. Tampoco debe esperarse hasta que el cliente presione Pagar, porque el iframe necesita una sesion valida para inicializarse.

  1. Cliente selecciona Baaskit Tarjetas.
  2. Frontend del comercio llama a su backend: POST /api/baaskit/session.
  3. Backend valida carrito, stock, descuentos, shipping, impuestos, moneda y orden.
  4. Backend crea una sesion en Baaskit usando clave secreta.
  5. Frontend recibe payment_link_url.
  6. Frontend monta BaaskitCheckout (el SDK inyecta el iframe con el formulario de tarjeta).
  7. El comercio renderiza su propio boton "Pagar" — el iframe no tiene boton de pago.
  8. Al presionar "Pagar", el comercio llama BaaskitCheckout.submit() → el iframe ejecuta el pago.
  9. El iframe emite estado visual por postMessage.
  10. La orden se marca como pagada solo por webhook firmado o verificacion server-side.

Instalacion

npm install @baaskit/checkout-js

Uso con bundler

import { BaaskitCheckout } from "@baaskit/checkout-js";

const checkout = await fetch("/api/baaskit/session", {
  method: "POST",
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    cartId: currentCart.id
  })
}).then((response) => response.json());

BaaskitCheckout.mount("#baaskit-payment-container", {
  paymentLinkUrl: checkout.payment_link_url,
  environment: "production",
  locale: "es-CL",
  appearance: {
    theme: "light",
    borderRadius: "8px",
    primaryColor: "#1155cc"
  },
  onReady: () => {
    setUiState("ready");
  },
  onProcessing: () => {
    setUiState("processing");
  },
  onSuccess: (payload) => {
    setUiState("succeeded_pending_confirmation");
    console.log("Pago aprobado visualmente", payload);
  },
  onError: (error) => {
    setUiState(error.errorCode === "session_expired" ? "expired" : "failed");
  },
  onCancel: () => {
    setUiState("failed");
  }
});

Uso con script

<script src="https://cdn.baaskit.com/checkout-js/v1/baaskit-checkout.umd.cjs"></script>
<script>
  window.BaaskitCheckout.BaaskitCheckout.mount("#baaskit-payment-container", {
    paymentLinkUrl: checkout.payment_link_url,
    environment: "production"
  });
</script>

API

BaaskitCheckout.mount(selector, options);
BaaskitCheckout.submit();
BaaskitCheckout.unmount();
BaaskitCheckout.destroy();
BaaskitCheckout.openRedirectFallback();

mount acepta un selector CSS o un HTMLElement. El SDK crea internamente el iframe; el comercio no debe insertarlo manualmente.

submit dispara el pago dentro del iframe. El iframe en modo embebido no tiene boton de pago propio — el comercio debe renderizar su propio boton "Pagar" y llamar a submit() al presionarlo. Esto le da al comercio control total sobre la UX del boton (posicion, estilo, texto, validaciones previas) mientras el iframe se encarga solo de la captura segura de datos y el procesamiento.

unmount remueve iframe, listeners y estado interno. Usalo en el cleanup de componentes, antes de montar una sesion nueva, o si necesitas que el iframe vuelva a leer el monto (ver el warning de abajo).

⚠️ Si tu carrito puede cambiar despues de crear la sesion, actualizar el monto es OBLIGATORIO.

El amount queda congelado al crear el OnlineCheckout, y Baaskit cobra siempre el monto persistido, nunca el que muestra tu frontend. Ante un cambio (cantidad, cupon, shipping, total, moneda) tu backend debe llamar PUT /onlinecheckout/{id} con el nuevo total antes de que el comprador pague — si no, se cobra el total viejo.

El SDK no expone ningun metodo para cambiar el monto, y es deliberado: es una llamada server-to-server con tus credenciales OAuth2. Nunca la expongas a tu propio frontend — si el navegador pudiera fijar el monto, un comprador podria pagar el total que quisiera.

El iframe puede seguir montado: mostrara el total anterior, pero el cobro sera el nuevo. Muestra tu propio total fuera del iframe, o unmount() + montar de nuevo si necesitas que la cifra coincida.

destroy hace lo mismo que unmount e invalida la instancia.

openRedirectFallback queda preparado para casos donde el flujo embebido no sea viable, por ejemplo 3DS bloqueado en iframe, WebView restrictiva o navegador incompatible.

Options

interface BaaskitCheckoutOptions {
  paymentLinkUrl: string;
  environment?: "development" | "production";
  locale?: "es-CL" | "en-US";
  appearance?: {
    theme?: "light" | "dark" | "auto";
    borderRadius?: string;
    primaryColor?: string;
  };
  allowedOrigins?: string[];
  embedBaseUrl?: string;
  onReady?: () => void;
  onProcessing?: (payload?: unknown) => void;
  onSuccess?: (payload: {
    paymentId: string;
    sessionId: string;
    orderId?: string;
    jwt?: string;
  }) => void;
  onError?: (error: {
    errorCode: string;
    message: string;
    recoverable: boolean;
  }) => void;
  onCancel?: () => void;
  onResize?: (height: number) => void;
}

embedBaseUrl existe para mocks locales y ambientes controlados. En integraciones reales se debe preferir environment.

Flujo POC /embebed

Para esta POC, el iframe se carga desde:

GET https://payment.dev.baaskit.com/embebed?id=JWT

El HTML del checkout se entrega y luego el JavaScript del iframe resuelve el OnlineCheckout llamando:

POST /onlinecheckout/token
Content-Type: application/json

{
  "token": "JWT"
}

Si /onlinecheckout/token responde correctamente, el iframe inicializa el formulario de tarjeta. Si falla, el iframe debe mostrar estado de checkout invalido, expirado o no disponible.

Esta decision es exclusiva de la POC. Para produccion, no recomiendo entregar el HTML completo antes de validar el JWT. El flujo productivo recomendado es:

GET /embebed?id=JWT
Backend valida el JWT con /onlinecheckout/token o validacion criptografica local
Si es valido, devuelve HTML del checkout
Si no es valido, devuelve error minimo sin cargar la superficie completa de pago

Estados sugeridos del comercio

type BaaskitUiState =
  | "not_selected"
  | "creating_session"
  | "ready"
  | "processing"
  | "succeeded_pending_confirmation"
  | "failed"
  | "expired";

succeeded_pending_confirmation significa exito preliminar en frontend. La orden real aun no debe considerarse pagada.

La pagina embebida debe ocultar los inputs de tarjeta al comenzar el procesamiento. Durante processing muestra un estado de espera y, tras baaskit.payment.succeeded, reemplaza el formulario por una confirmacion visual sin volver a exponer los datos ingresados. Si el pago falla y es recuperable, puede ofrecer volver al formulario para reintentar.

Backend de referencia del comercio

Crear sesion

POST /api/baaskit/session
Content-Type: application/json
{
  "cartId": "cart_123"
}

Responsabilidades del backend:

  • Buscar carrito server-side.
  • Validar stock, precios, descuentos, shipping, impuestos, total y moneda.
  • Crear o recuperar una orden pendiente.
  • Crear OnlineCheckout en Baaskit con clave secreta.
  • Retornar payment_link_url al frontend.

Respuesta:

{
  "session_id": "bsk_chk_123",
  "client_secret": "bsk_client_secret_xxx",
  "expires_at": "2026-06-18T20:00:00Z"
}

Webhook

POST /api/webhooks/baaskit

Responsabilidades:

  • Validar firma.
  • Validar event_id idempotente.
  • Validar order_id.
  • Validar monto y moneda contra la orden local.
  • Marcar la orden como pagada.
  • Responder 2xx rapido.
  • Ejecutar tareas largas en background.

API Baaskit conceptual

POST /v1/checkout/sessions
Authorization: Bearer sk_test_xxx
Idempotency-Key: UUID
{
  "order_id": "ORDER-10001",
  "amount": 16295,
  "currency": "CLP",
  "description": "Compra ecommerce",
  "customer": {
    "email": "[email protected]"
  },
  "metadata": {
    "cart_id": "cart_123",
    "merchant_reference": "commerce_abc"
  },
  "return_url": "https://commerce.cl/checkout/result",
  "webhook_url": "https://commerce.cl/api/webhooks/baaskit"
}

Desarrollo local

npm install
npm test
npm run build
npm run dev

Abre http://localhost:5173/examples/vanilla/ para probar el mock.

TODO V1 hacia produccion

  • Implementar /embebed real en payment.baaskit.com.
  • Reemplazar mock por integracion real con Payment API y 3DS.
  • Configurar CSP con frame-ancestors por comercio autorizado.
  • Implementar allowlist server-side de dominios merchant.
  • Implementar firma de webhooks y validacion de idempotencia.
  • Definir contrato final de errores recuperables y expiracion de sesion.
  • ~~Definir fallback redirect/modal para emisores o ACS que bloqueen iframe.~~ (resuelto en v0.1.5 con allow-popups en sandbox y openRedirectFallback()).

Changelog

v0.1.6

Solo documentacion — sin cambios de codigo ni de API del SDK.

  • Se documenta que actualizar el monto via PUT /onlinecheckout/{id} es OBLIGATORIO si el carrito puede cambiar despues de crear la sesion. Baaskit cobra el monto persistido, no el que muestra el frontend del comercio; sin ese PUT se cobra el total viejo. Hasta esta version el skill y los docs del paquete solo documentaban unmount() + crear sesion nueva, y no mencionaban el PUT en ninguna parte.
  • skills/.../references/backend.md: nueva seccion 4b con updateOnlineCheckoutAmount() y la tabla de errores del endpoint (LINE_ITEMS_AMOUNT_MISMATCH, CHECKOUT_NOT_UPDATABLE, EXPIRED_CHECKOUT, 403, 404).
  • SECURITY.md y skills/.../references/security.md: advertencia de no exponer ese PUT al frontend del comercio ni proxearlo reenviando el monto que llegue del browser.
  • skills/.../references/troubleshooting.md: se separa "se cobro el total viejo" (grave, falta el PUT) de "el iframe muestra otro total" (cosmetico, el cobro es correcto). La version anterior afirmaba que una sesion vieja "podria cobrar un monto incorrecto", lo que era enganoso.
  • Aclaracion de diseño: el SDK no expone ningun metodo para cambiar el monto, y es deliberado — es una llamada server-to-server del backend del comercio.

v0.1.5

  • Se agregó publickey-credentials-create * a la Permissions Policy del iframe (requerido por Mastercard CorePasskeys/FIDO).
  • Se agregó atributo sandbox explícito con allow-popups y allow-popups-to-escape-sandbox para permitir que el SDK de Mastercard abra ventanas de autenticación (window.open).
  • Flags de sandbox incluidos: allow-scripts, allow-same-origin, allow-forms, allow-popups, allow-popups-to-escape-sandbox, allow-top-navigation-by-user-activation, allow-modals.