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

@misael703/bsale-sdk

v0.1.0

Published

TypeScript SDK for the Bsale REST API. Supports Chile, Peru, and Mexico.

Readme

@misael703/bsale-sdk

SDK en TypeScript para la API REST de Bsale. Compatible con Chile, Perú y México. Zero dependencies — solo usa fetch nativo de Node 20+.

Instalación

pnpm add @misael703/bsale-sdk

Quick Start

import { BsaleClient } from '@misael703/bsale-sdk';

const bsale = new BsaleClient({
  accessToken: 'tu-access-token',
});

// Listar productos
const products = await bsale.products.list({ limit: 10 });
console.log(products.items);

// Obtener un producto por ID
const product = await bsale.products.getById(123);

// Obtener TODOS los productos (paginación automática)
const allProducts = await bsale.products.listAll();

Recursos

Productos

// Listar
const products = await bsale.products.list({ state: 0 });

// Obtener variantes de un producto
const variants = await bsale.products.getVariants(123);

// Crear
const newProduct = await bsale.products.create({ name: 'Nuevo Producto' });

// Actualizar
const updated = await bsale.products.update(123, { name: 'Nombre Actualizado' });

// Contar
const { count } = await bsale.products.count();

Variantes

const variants = await bsale.variants.list({ state: 0 });
const variant = await bsale.variants.getById(456);
const costs = await bsale.variants.getCosts(456);

Documentos

// Listar por rango de fechas (Unix timestamps en segundos)
const docs = await bsale.documents.getByDateRange(1388545200, 1391223600);

// Crear documento
const doc = await bsale.documents.create({
  documentTypeId: 1,
  officeId: 1,
  details: [
    { variantId: 123, quantity: 2, netUnitValue: 1000 },
  ],
  payments: [
    { paymentTypeId: 1, amount: 2380 },
  ],
});

// Obtener detalles de un documento
const details = await bsale.documents.getDetails(789);

Clientes

const clients = await bsale.clients.list();
const client = await bsale.clients.create({
  firstName: 'Juan',
  lastName: 'Pérez',
  email: '[email protected]',
});

Listas de Precio

const priceLists = await bsale.priceLists.list();
const details = await bsale.priceLists.getDetails(1);

// Actualizar precio de una variante en una lista
await bsale.priceLists.updateDetail(1, 100, {
  variantValue: 5000,
  variantValueWithTaxes: 5950,
});

Stock

const stocks = await bsale.stocks.list();
const variantStock = await bsale.stocks.getByVariantAndOffice(456, 1);

Tipos de Documento

const types = await bsale.documentTypes.list();
const type = await bsale.documentTypes.getById(1);

Sucursales (Offices)

const offices = await bsale.offices.list();
const office = await bsale.offices.getById(1);

Despachos (Shippings)

const shippings = await bsale.shippings.list();
await bsale.shippings.create({ shippingDate: 1705276800, address: 'Av. Principal 123', officeId: 1 });
await bsale.shippings.update(1, { address: 'Av. Nueva 456' });

Formas de Pago

const paymentTypes = await bsale.paymentTypes.list();

Recepciones de Stock

const receptions = await bsale.stockReceptions.list();
await bsale.stockReceptions.create({
  officeId: 1,
  note: 'Ingreso de mercadería',
  details: [
    { variantId: 456, quantity: 100, cost: 500 },
  ],
});

Consumos de Stock

const consumptions = await bsale.stockConsumptions.list();
await bsale.stockConsumptions.create({
  officeId: 1,
  note: 'Merma de inventario',
  details: [
    { variantId: 456, quantity: 5 },
  ],
});

Devoluciones (Returns)

const returns = await bsale.returns.list();
const ret = await bsale.returns.getById(1);
const details = await bsale.returns.getDetails(1);

// Crear devolución (nota de crédito)
await bsale.returns.create({
  documentTypeId: 6,
  officeId: 1,
  referenceDocumentId: 100,
  details: [{ documentDetailId: 200, quantity: 1 }],
});

// Anular devolución (nota de débito)
await bsale.returns.annul({
  documentTypeId: 7,
  referenceDocumentId: 300,
});

Documentos de Terceros

const thirdPartyDocs = await bsale.thirdPartyDocuments.list();
const doc = await bsale.thirdPartyDocuments.getById(1);
const { count } = await bsale.thirdPartyDocuments.count();

Tipos de Producto

const productTypes = await bsale.productTypes.list();
const pt = await bsale.productTypes.getById(1);
const products = await bsale.productTypes.getProducts(1);
const attrs = await bsale.productTypes.getAttributes(1);

// Crear
await bsale.productTypes.create({ name: 'Electrónica', attributes: [{ name: 'Marca' }] });

// Actualizar
await bsale.productTypes.update(1, { name: 'Electrónica Actualizada' });

// Eliminar
await bsale.productTypes.delete(1);

Usuarios

const users = await bsale.users.list();
const user = await bsale.users.getById(1);
const summary = await bsale.users.getSalesSummary({ userid: 1 });
const sales = await bsale.users.getSales(1);
const returns = await bsale.users.getReturns(1);

Tipos de Despacho

const shippingTypes = await bsale.shippingTypes.list();
const st = await bsale.shippingTypes.getById(1);

Configuración

import { BsaleClient } from '@misael703/bsale-sdk';

const bsale = new BsaleClient({
  // Requerido: token de acceso a la API de Bsale
  accessToken: 'tu-access-token',

  // Opcional: URL base (default: https://api.bsale.io/v1)
  baseUrl: 'https://api.bsale.io/v1',

  // Opcional: timeout en ms (default: 15000)
  timeout: 15000,

  // Opcional: reintentos máximos para errores 5xx y de red (default: 3)
  maxRetries: 3,

  // Opcional: TTL del cache en ms (default: 60000)
  cacheTtlMs: 60000,

  // Opcional: callback para logging
  logger: (message, data) => console.log(`[bsale] ${message}`, data),
});

Multi-país

El SDK es compatible con todas las instancias regionales de Bsale. Cambia la baseUrl según el país:

| País | Base URL | |-------|----------| | Chile (default) | https://api.bsale.io/v1 | | Perú | https://api.bsale.com.pe/v1 | | México | https://api.bsale.com.mx/v1 |

// Ejemplo: Perú
const bsalePeru = new BsaleClient({
  accessToken: 'tu-token-peru',
  baseUrl: 'https://api.bsale.com.pe/v1',
});

// Ejemplo: México
const bsaleMexico = new BsaleClient({
  accessToken: 'tu-token-mexico',
  baseUrl: 'https://api.bsale.com.mx/v1',
});

Cache

El SDK incluye un cache en memoria para requests GET:

  • El cache tiene un TTL configurable (default: 60 segundos)
  • Las operaciones de escritura (POST/PUT/DELETE) invalidan automáticamente el cache del recurso afectado
  • Se puede limpiar manualmente:
// Limpiar todo el cache
bsale.clearCache();

// Limpiar cache de un recurso específico
bsale.clearResourceCache('products');

Webhooks

El método handleWebhook invalida automáticamente el cache cuando Bsale notifica cambios:

import { BsaleClient, BsaleWebhookPayload } from '@misael703/bsale-sdk';

const bsale = new BsaleClient({ accessToken: '...' });

// En tu endpoint de webhook
app.post('/webhooks/bsale', (req, res) => {
  const payload: BsaleWebhookPayload = req.body;
  bsale.handleWebhook(payload);
  res.sendStatus(200);
});

Topics soportados: product, variant, document, price, stock.

Agregar un nuevo Resource

  1. Crear tipo en src/types/{resource}.types.ts
  2. Exportar desde src/types/index.ts
  3. Crear src/resources/{resource}.resource.ts extendiendo BaseResource<T>
  4. Exportar desde src/resources/index.ts
  5. Agregar propiedad en BsaleClient
  6. Instanciar en el constructor de BsaleClient

Patrón:

import { BaseResource } from './base.resource';
import { BsaleFoo } from '../types';

export class FooResource extends BaseResource<BsaleFoo> {
  protected readonly path = 'foo';

  async customMethod(id: number) {
    return this.http.get(`/foo/${id}/bar.json`);
  }
}

Utilidades de Fecha

Bsale usa Unix timestamps en segundos (no milisegundos):

import { toBsaleTimestamp, fromBsaleTimestamp, formatBsaleDate, todayBsaleTimestamp } from '@misael703/bsale-sdk';

// Date &rarr; Unix seconds
const ts = toBsaleTimestamp(new Date());

// Unix seconds &rarr; Date
const date = fromBsaleTimestamp(1388545200);

// Unix seconds &rarr; string formateado
const str = formatBsaleDate(1388545200); // "01-01-2014"

// Hoy a las 00:00 como Unix seconds
const today = todayBsaleTimestamp();

Desarrollo

pnpm install        # Instalar dependencias
pnpm dev            # Build en watch mode
pnpm build          # Build de producci&oacute;n (CJS + ESM + types)
pnpm test           # Correr tests
pnpm test:watch     # Tests en watch mode
pnpm lint           # Linting
pnpm format         # Formatear c&oacute;digo

Licencia

MIT