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

@trudevlabs/storekit

v1.0.0

Published

Framework-agnostic e-commerce core: cart, pricing, promotions, checkout flow

Readme

@trudevlabs/storekit

Framework-agnostic e-commerce core: cart, pricing, promotions, checkout flow

Works with any frontend (React, Vue, Angular) and any backend (Node, Express, WordPress, Shopify, custom REST). No framework dependencies. All amounts in cents (integer) for precision.

Node < 18: createRestProvider requires fetch. Pass fetch in options or use node-fetch.

Install

npm install @trudevlabs/storekit

Quick Start

import { createCart, addItem, getCartSummary, createCheckout } from '@trudevlabs/storekit';

const cart = createCart({ currency: 'USD' });
addItem(cart, { id: 'prod123', name: 'Widget', price: 2999, qty: 2 });
const summary = getCartSummary(cart);
console.log(summary.total); // 5998 (cents)

const checkout = createCheckout(cart);
checkout.setShippingAddress({ city: 'NYC', country: 'US' });
checkout.setPaymentMethod('stripe');
const order = checkout.toOrder();

Cart

const { createCart, addItem, removeItem, updateQuantity, clearCart } = require('@trudevlabs/storekit');

const cart = createCart({ currency: 'USD' });

// Add items - price in cents (2999 = $29.99). Use priceInDollars: true for dollars
addItem(cart, { id: 'prod123', name: 'Widget', price: 2999, qty: 2 });
addItem(cart, { id: 'prod456', price: 1499 });

// Update
updateQuantity(cart, 'prod123', 1);

// Remove
removeItem(cart, 'prod456');

// Clear
clearCart(cart);

Pricing & Summary

const { getCartSummary, formatAmount } = require('@trudevlabs/storekit');

const summary = getCartSummary(cart, {
  taxRate: 0.08,
  shippingFlatRate: 599,
  shippingFreeAbove: 5000,
});

// summary: { subtotal, discount, tax, shipping, total, items, currency }
console.log(formatAmount(summary.total)); // "$64.99"

Promotions

const { createPromo, applyPromo, removePromo, PROMO_TYPES } = require('@trudevlabs/storekit');

// Create promo codes
const SAVE10 = createPromo({
  code: 'SAVE10',
  type: PROMO_TYPES.PERCENT,
  value: 10,
  minPurchase: 2000,
  maxDiscount: 5000,
});

const FLAT5 = createPromo({
  code: 'FLAT5',
  type: PROMO_TYPES.FIXED,
  value: 500,
});

const registry = { SAVE10, FLAT5 };

// Apply
applyPromo(cart, 'SAVE10', registry);
applyPromo(cart, SAVE10, registry);

// Remove
removePromo(cart, 'SAVE10');

Promo Types

| Type | Options | Description | |------|---------|-------------| | percent | value, minPurchase, maxDiscount | % off | | fixed | value | Fixed amount off | | bogo | buyQty, getQty | Buy X get Y free | | free_shipping | - | Waives shipping |

Checkout Flow

const { createCheckout, CHECKOUT_STEPS } = require('@trudevlabs/storekit');

const checkout = createCheckout(cart, {
  steps: [CHECKOUT_STEPS.CART, CHECKOUT_STEPS.SHIPPING, CHECKOUT_STEPS.PAYMENT, CHECKOUT_STEPS.REVIEW],
});

// Navigation
checkout.getStep();      // 'cart'
checkout.next();         // → shipping
checkout.prev();         // → cart
checkout.goToStep(2);    // → payment

// Data
checkout.setShippingAddress({ street: '123 Main', city: 'NYC', zip: '10001', country: 'US' });
checkout.setBillingAddress({ ... });
checkout.setPaymentMethod('stripe');

// Summary (includes promos, tax, shipping)
const summary = checkout.getSummary({
  taxRate: 0.08,
  shippingFlatRate: 599,
});

// Create order
const order = checkout.toOrder('ord_123');
// { id, cartId, items, subtotal, discount, tax, shipping, total, shippingAddress, ... }

Storage – persist cart (browser, Node)

const { createLocalStorageAdapter, createCommerce, loadCart } = require('@trudevlabs/storekit');

// localStorage (browser)
const storage = createLocalStorageAdapter('my_cart');

// Or custom adapter (React Native, AsyncStorage, etc.)
const customStorage = {
  get: () => AsyncStorage.getItem('cart').then(JSON.parse),
  set: (data) => AsyncStorage.setItem('cart', JSON.stringify(data)),
  remove: () => AsyncStorage.removeItem('cart'),
};

const session = createCommerce({ storage });
await session.loadFromStorage();  // restore (sync or async storage)
await session.addItem({ id: 'p1', name: 'Widget', price: 2999 });

Provider – connect to your backend

const { createRestProvider, createCommerce } = require('@trudevlabs/storekit');

// Custom REST API (Node, Express, etc.)
const provider = createRestProvider('https://api.yoursite.com', {
  headers: { Authorization: 'Bearer token' },
});

const session = createCommerce({ provider, storage });
await session.loadFromProvider(cartId);  // load cart from backend
await session.addItem({ id: 'prod1', price: 2999 });  // syncs to backend

Provider API contract

Your backend should expose:

| Endpoint | Method | Purpose | |----------|--------|---------| | /products | GET | List products | | /products/:id | GET | Single product | | /carts | GET/POST | Get/create cart | | /carts/:id | PUT | Update cart | | /orders | POST | Create order | | /promos | GET | Promo codes | | /shipping/rates | POST | Shipping rates |


Backend Examples

Node.js / Express

Backend – Express API that @trudevlabs/storekit calls:

// server.js
const express = require('express');

const app = express();
app.use(express.json());

const carts = new Map();  // or use a database

app.get('/api/products', (req, res) => {
  // Return products from DB: { id, name, price (cents), sku, images }
  res.json([{ id: '1', name: 'Widget', price: 2999, sku: 'WID-01', images: [] }]);
});

app.get('/api/carts/:id', (req, res) => {
  const cart = carts.get(req.params.id);
  res.json(cart ? { id: cart.id, items: cart.items, currency: 'USD', promoCodes: cart.promoCodes } : { items: [] });
});

app.post('/api/carts', (req, res) => {
  const cart = { id: `cart_${Date.now()}`, ...req.body, items: req.body.items || [], promoCodes: req.body.promoCodes || [] };
  carts.set(cart.id, cart);
  res.json(cart);
});

app.put('/api/carts/:id', (req, res) => {
  carts.set(req.params.id, req.body);
  res.json(req.body);
});

app.post('/api/orders', (req, res) => {
  const order = { id: `ord_${Date.now()}`, ...req.body, createdAt: new Date().toISOString() };
  // Save to DB, process payment, etc.
  res.json(order);
});

app.listen(3000);

Frontend – connect with createRestProvider:

const { createRestProvider, createCommerce, createLocalStorageAdapter } = require('@trudevlabs/storekit');

const provider = createRestProvider('http://localhost:3000/api');
const storage = createLocalStorageAdapter('cart');
const session = createCommerce({ provider, storage });

// Load products, add to cart
const products = await provider.getProducts();
await session.addItem({ id: products[0].id, name: products[0].name, price: products[0].price });

Custom REST API

Use createRestProvider with any API that matches the contract:

const { createRestProvider, createCommerce } = require('@trudevlabs/storekit');

const provider = createRestProvider('https://api.yoursite.com/v1', {
  headers: {
    Authorization: 'Bearer YOUR_API_KEY',
    'X-Store-Id': 'store_123',
  },
});

const session = createCommerce({ provider });

// Fetch products
const products = await provider.getProducts({ category: 'electronics', page: 1 });
const product = await provider.getProduct('prod_abc');

// Cart syncs to backend automatically
await session.addItem({ id: product.id, name: product.name, price: product.price, qty: 1 });
await session.loadFromProvider(session.cart.id);

// Create order
const checkout = require('@trudevlabs/storekit').createCheckout(session.cart);
checkout.setShippingAddress({ city: 'NYC', country: 'US', zip: '10001' });
const order = checkout.toOrder();
const created = await provider.createOrder(order);

WooCommerce

WooCommerce uses a different API shape. Create a provider adapter:

const { createProvider, normalizeProduct, createCommerce } = require('@trudevlabs/storekit');

const WOO_SITE = 'https://yoursite.com';
const WOO_KEY = 'ck_xxx';  // Consumer key
const WOO_SECRET = 'cs_xxx';  // Consumer secret
const auth = Buffer.from(`${WOO_KEY}:${WOO_SECRET}`).toString('base64');

async function request(path, options = {}) {
  const res = await fetch(`${WOO_SITE}/wp-json/wc/v3${path}`, {
    ...options,
    headers: { Authorization: `Basic ${auth}`, 'Content-Type': 'application/json', ...options.headers },
  });
  if (!res.ok) throw new Error(`WooCommerce: ${res.status}`);
  return res.json();
}

const woocommerceProvider = createProvider({
  getProducts: async (query = {}) => {
    const params = new URLSearchParams(query).toString();
    const data = await request(`/products${params ? '?' + params : ''}`);
    return Array.isArray(data) ? data.map((p) => normalizeProduct({
      id: String(p.id),
      name: p.name,
      price: parseFloat(p.price) * 100,
      sku: p.sku,
      images: p.images?.map((i) => i.src) || [],
    })) : [];
  },
  getProduct: async (id) => {
    const p = await request(`/products/${id}`);
    return normalizeProduct({ id: String(p.id), name: p.name, price: parseFloat(p.price) * 100, sku: p.sku, images: p.images?.map((i) => i.src) || [] });
  },
  getCart: async (cartId) => null,  // WooCommerce uses session cookies; implement if using headless
  saveCart: async (cart) => cart,   // Persist client-side or via custom endpoint
  createOrder: async (order) => {
    const payload = {
      line_items: order.items.map((i) => ({ product_id: parseInt(i.id), quantity: i.qty })),
      shipping: order.shippingAddress ? { address_1: order.shippingAddress.street, city: order.shippingAddress.city, state: order.shippingAddress.state, postcode: order.shippingAddress.zip, country: order.shippingAddress.country } : {},
    };
    return request('/orders', { method: 'POST', body: JSON.stringify(payload) });
  },
});

const session = createCommerce({ provider: woocommerceProvider });
const products = await woocommerceProvider.getProducts({ per_page: 10 });
await session.addItem({ id: products[0].id, name: products[0].name, price: products[0].price });

Shopify

Use Shopify Storefront API (GraphQL) or REST. Example with REST Admin API:

const { createProvider, normalizeProduct, createCommerce } = require('@trudevlabs/storekit');

const SHOP = 'your-store.myshopify.com';
const TOKEN = 'shpat_xxx';  // Storefront or Admin API token

async function shopifyRequest(path, options = {}) {
  const url = `https://${SHOP}/admin/api/2024-01${path}`;
  const res = await fetch(url, {
    ...options,
    headers: { 'X-Shopify-Access-Token': TOKEN, 'Content-Type': 'application/json', ...options.headers },
  });
  if (!res.ok) throw new Error(`Shopify: ${res.status}`);
  return res.json();
}

const shopifyProvider = createProvider({
  getProducts: async (query = {}) => {
    const limit = query.limit || 10;
    const data = await shopifyRequest(`/products.json?limit=${limit}`);
    const products = data.products || [];
    return products.map((p) => normalizeProduct({
      id: String(p.id),
      name: p.title,
      price: Math.round(parseFloat(p.variants?.[0]?.price || 0) * 100),
      sku: p.variants?.[0]?.sku,
      images: p.images?.map((i) => i.src) || [],
    }));
  },
  getProduct: async (id) => {
    const data = await shopifyRequest(`/products/${id}.json`);
    const p = data.product;
    return normalizeProduct({
      id: String(p.id),
      name: p.title,
      price: Math.round(parseFloat(p.variants?.[0]?.price || 0) * 100),
      sku: p.variants?.[0]?.sku,
      images: p.images?.map((i) => i.src) || [],
    });
  },
  getCart: async () => null,
  saveCart: async (cart) => cart,
  createOrder: async (order) => {
    // Shopify: create draft order or use Checkout API
    const lineItems = order.items.map((i) => ({ variant_id: parseInt(i.id), quantity: i.qty }));
    const data = await shopifyRequest('/draft_orders.json', {
      method: 'POST',
      body: JSON.stringify({ draft_order: { line_items: lineItems } }),
    });
    return data.draft_order;
  },
});

const session = createCommerce({ provider: shopifyProvider });
const products = await shopifyProvider.getProducts({ limit: 20 });
await session.addItem({ id: products[0].id, name: products[0].name, price: products[0].price, qty: 1 });

Shopify Storefront API: For public storefronts, use the Storefront API (/storefront-api) with a Storefront access token and adapt the GraphQL queries to fetch products and create checkouts.


Events – lifecycle hooks

const { on, createCommerce } = require('@trudevlabs/storekit');

on('cart:itemAdded', ({ cart, item }) => console.log('Added', item.name));
on('cart:itemRemoved', ({ itemId }) => {});
on('cart:updated', () => {});
on('cart:synced', ({ cart }) => {});
on('checkout:stepChange', ({ step, index }) => {});
on('checkout:completed', ({ order }) => {});
on('order:created', ({ order }) => analytics.track('purchase', order));

// Note: on/off use a global emitter (shared across sessions). Use createEventEmitter() for isolated listeners.

const session = createCommerce({ storage });
await session.addItem({ id: 'p1', name: 'Widget', price: 2999 });  // fires cart:itemAdded

Full Example (React/Vue/Angular + any backend)

const commerce = require('@trudevlabs/storekit');

// 1. Cart
const cart = commerce.createCart({ currency: 'USD' });
commerce.addItem(cart, { id: 'prod1', name: 'T-Shirt', price: 2500, qty: 2 });
commerce.addItem(cart, { id: 'prod2', name: 'Hat', price: 1500 });

// 2. Promo
const promo = commerce.createPromo({ code: 'SAVE10', type: 'percent', value: 10 });
commerce.applyPromo(cart, promo);

// 3. Summary
const summary = commerce.getCartSummary(cart, {
  taxRate: 0.08,
  shippingFlatRate: 599,
  shippingFreeAbove: 10000,
});
console.log(commerce.formatAmount(summary.total));

// 4. Checkout
const checkout = commerce.createCheckout(cart);
checkout.setShippingAddress({ city: 'NYC', country: 'US' });
checkout.setPaymentMethod('stripe');
const order = checkout.toOrder();

// 5. Send order to your backend / Stripe / etc.
fetch('/api/orders', { method: 'POST', body: JSON.stringify(order) });

Architecture

┌─────────────────────────────────────────────────────┐
│  React / Vue / Angular (any frontend)                │
└─────────────────────────────────────────────────────┘
                        │
┌─────────────────────────────────────────────────────┐
│  createCommerce({ storage, provider })               │
│  Events: cart:*, checkout:*, order:*                 │
└─────────────────────────────────────────────────────┘
                        │
        ┌───────────────┼───────────────┐
        ▼               ▼               ▼
   localStorage    Custom REST    Shopify/WooCommerce
   sessionStorage  (your API)     (future adapters)

API Reference

| Function | Description | |----------|-------------| | createCart(options) | Create empty cart (pure) | | addItem(cart, item) | Add product. price in cents (2999 = $29.99). Use priceInDollars: true for dollars | | createCommerce({ storage, provider }) | Integrated session with persist + sync | | loadCart(storage) | Load cart from storage adapter | | loadCartFromProvider(provider, cartId) | Load cart from backend | | createLocalStorageAdapter(key) | Browser localStorage | | createRestProvider(baseUrl, opts) | REST API adapter | | on(event, handler) | Subscribe to events | | createCheckout(cart, options) | Checkout flow | | formatAmount(cents, currency) | Format for display |

License

MIT