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

@marianmeres/ecsuite

v1.3.0

Published

[![NPM Version](https://img.shields.io/npm/v/@marianmeres/ecsuite)](https://www.npmjs.com/package/@marianmeres/ecsuite) [![JSR Version](https://img.shields.io/jsr/v/@marianmeres/ecsuite)](https://jsr.io/@marianmeres/ecsuite) [![License](https://img.shield

Readme

@marianmeres/ecsuite

NPM Version JSR Version License

E-commerce frontend UI helper library with optimistic updates, Svelte-compatible stores, and adapter-based server sync.

Features

  • Optimistic Updates: UI updates immediately, syncs with server asynchronously
  • Svelte-Compatible Stores: All domains expose a subscribe() method
  • Adapter Pattern: Pluggable server communication (REST, WebSocket, mock)
  • Event System: Subscribe to domain events for error handling and UI feedback
  • Local Persistence: Cart and wishlist are saved to localStorage

Installation

# Deno
deno add @marianmeres/ecsuite

# npm
npm install @marianmeres/ecsuite

Quick Start

import { createECSuite } from "@marianmeres/ecsuite";

// Create suite with your adapters
const suite = createECSuite({
	context: { customerId: "user-123" },
	adapters: {
		cart: myCartAdapter,
		wishlist: myWishlistAdapter,
		order: myOrderAdapter,
		customer: myCustomerAdapter,
	},
});

// Subscribe to cart state (Svelte-compatible)
suite.cart.subscribe((state) => {
	console.log(state.state, state.data);
	// state.state: "initializing" | "ready" | "syncing" | "error"
	// state.data: CartData | null
});

// Listen for errors
suite.on("domain:error", (event) => {
	showToast(event.error.message);
});

// Add item (optimistic update)
await suite.cart.addItem({ product_id: "prod-1", quantity: 2 });

Domains

| Domain | Persistence | Operations | | -------- | ------------ | ----------------------------------- | | Cart | localStorage | add, update, remove, clear | | Wishlist | localStorage | add, remove, toggle, clear | | Order | none | fetchAll, fetchOne, create | | Customer | none | fetch, refresh, update | | Payment | none | fetchForOrder, fetchOne (read-only) | | Product | cache only | getById, getByIds, prefetch |

State Machine

Each domain follows this state progression:

initializing → ready ↔ syncing → error
  • initializing: Fetching initial data
  • ready: Data loaded, idle
  • syncing: Operation in progress
  • error: Last operation failed (includes rollback)

Creating Adapters

Implement the adapter interface for your backend:

import type { CartAdapter } from "@marianmeres/ecsuite";
import { HTTP_ERROR } from "@marianmeres/http-utils";

const myCartAdapter: CartAdapter = {
	async fetch(ctx) {
		const res = await fetch(`/api/cart?customerId=${ctx.customerId}`);
		if (!res.ok) throw new HTTP_ERROR.BadRequest("Failed to fetch cart");
		return await res.json();
	},
	async addItem(item, ctx) {
		const res = await fetch("/api/cart/items", {
			method: "POST",
			body: JSON.stringify(item),
		});
		if (!res.ok) throw new HTTP_ERROR.BadRequest("Failed to add item");
		return await res.json();
	},
	// ... other methods
};

Testing with Mock Adapters

import { createECSuite, createMockCartAdapter } from "@marianmeres/ecsuite";

const suite = createECSuite({
	adapters: {
		cart: createMockCartAdapter({
			initialData: { items: [{ product_id: "p1", quantity: 2 }] },
			delay: 100,
		}),
	},
	storage: { type: "memory" },
});

Events

Subscribe to domain events:

suite.on("cart:item:added", (event) => {
	console.log(`Added ${event.quantity} of ${event.productId}`);
});

suite.onAny(({ event, data }) => {
	console.log(event, data);
});

suite.once("order:created", (event) => {
	redirectToConfirmation(event.orderId);
});

API Reference

For complete API documentation, see API.md.

License

MIT