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

@dashcommerce/core

v0.1.4

Published

DashCommerce — full WooCommerce-equivalent commerce plugin for EmDash CMS

Downloads

599

Readme

@dashcommerce/core

The e-commerce plugin for EmDash CMS.

Current npm version: 0.1.2. See the monorepo README for the full feature list and quick start, or dashcommerce.dev/docs for guides. Live demo: demo.dashcommerce.dev.

Package exports

| Entry | Context | Purpose | |---|---|---| | . | Vite / build time | Descriptor factory (dashcommerce()) — imported in astro.config.mjs. Side-effect-free. | | ./sandbox | Runtime server | definePlugin({ hooks, routes }) loaded by the emdash runtime. Sandbox-safe. | | ./admin | Browser | React admin pages + dashboard widgets + field widgets. | | ./astro | Host SSR | blockComponents registry for Portable Text block renderers. | | ./astro/components/* | Host SSR | Storefront Astro components (<ProductCard>, <CartSummary>, etc.). | | ./astro/islands/* | Host SSR + client | React islands (CartDrawerIsland, CheckoutIsland, etc.). |

Install

Four steps to add DashCommerce to an existing EmDash + Astro site:

bun add @dashcommerce/core

Register the plugin in astro.config.mjs:

import { dashcommerce } from "@dashcommerce/core";

emdash({ plugins: [dashcommerce()] });

Merge the products collection + taxonomies into your seed file, then re-apply:

bunx dashcommerce-merge-seed
bun emdash seed --on-conflict=update

Open /_emdash/admin/plugins/dashcommerce/settings and paste your Stripe test keys.

Want sample data? Add --with-demo-catalog to the merge step to seed six demo products (one per product type) plus product_category and product_tag terms, so the admin isn't empty on first boot:

bunx dashcommerce-merge-seed --with-demo-catalog
bun emdash seed --on-conflict=update

Re-running is safe — existing products with matching ids are preserved. Swap or delete the demo entries any time from the Products admin.

For a fully-wired reference setup (seed data, storefront pages, Stripe keys), see @dashcommerce/starter. Full walkthrough: dashcommerce.dev/docs/getting-started.

Seed merge CLI

@dashcommerce/core ships a dashcommerce-merge-seed binary (on your PATH via node_modules/.bin). It writes the products collection and product_category / product_tag taxonomies into your EmDash seed.json, replacing any prior DashCommerce entries by slug / name. Unrelated keys in the seed file (settings, content, menus, other collections) are left intact.

# Typical one-liner after emdash init (fresh DB)
bunx dashcommerce-merge-seed && bun emdash seed --on-conflict=update

Or add to package.json:

"scripts": {
  "bootstrap": "dashcommerce-merge-seed && bun emdash seed --on-conflict=update"
}

Why --on-conflict=update? On a first run it's a no-op, but subsequent runs (after a DashCommerce release that tweaks the products schema) need it to update the collection in place rather than skipping it.

Options: --seed <path> (override file), --cwd <dir>, --with-demo-catalog (append 6 demo products + curated taxonomy terms). When --seed is omitted the CLI uses the same default resolution as emdash seed: .emdash/seed.json if present, otherwise package.jsonemdash.seed.

Prefer to assemble the seed in TypeScript? Import mergeDashCommerceSeed(seedObject, { withDemoCatalog }) from the package root — same dedupe rules as the CLI. The demo catalog is also exported directly as DEMO_PRODUCTS, DEMO_PRODUCT_CATEGORY_TERMS, and DEMO_PRODUCT_TAG_TERMS for cherry-picking.

Runtime surface

Public routes (storefront)

All paths mount under /_emdash/api/plugins/dashcommerce/.

GET    /cart                              Current cart (creates if missing; re-runs recalculate)
POST   /cart/items                        Add line item
PATCH  /cart/item?lineId={id}             Update qty
DELETE /cart/item?lineId={id}             Remove line
DELETE /cart/clear                        Empty cart (keeps session)
POST   /cart/currency                     Switch currency (empty cart only)
POST   /cart/coupon                       Apply coupon
DELETE /cart/coupon/remove?code={code}    Remove coupon
POST   /cart/shipping-location            Set country + postal (hosted checkout pre-flight)
POST   /cart/shipping-address             Full address (embedded checkout)
POST   /cart/contact                      Email + billing address
POST   /cart/shipping-methods             List rates for current ship-to
POST   /cart/shipping-method              Choose method id
GET    /cart/restore?token={t}            Abandoned-cart recovery link

POST   /checkout/create-intent            Embedded Elements: create PaymentIntent
POST   /checkout/create-session           Hosted Checkout: create Checkout Session
GET    /checkout/mode                     Which mode is active (hosted | embedded)
POST   /checkout/webhook                  Stripe webhook sink (signature-verified)

GET    /orders/by-draft?id={draftId}      Poll order status after checkout

GET    /downloads/serve?token={t}         Signed-URL download delivery

GET    /reviews/list?productId={id}       Paginated reviews
POST   /reviews/item                      Submit a review (moderation queue)

GET    /config-check                      Read-only health check (Stripe keys present, etc.)

Admin-gated routes

Same prefix, gated by emdash's admin auth:

GET    /admin/settings                    Read all settings:* keys
POST   /admin/settings                    Write (validated via schema)
POST   /admin/stripe/ping                 Live-key sanity check
GET    /admin/orders, /admin/orders/:id   Order list + detail
POST   /admin/orders/:id/refund           Full or partial refund
PATCH  /admin/orders/:id/status           Transition order status (triggers review-request etc.)
GET    /admin/customers …                 Customer CRUD
GET    /admin/reports/revenue             Range-sliced revenue with comparison
GET    /admin/reports/top-products        Best sellers by qty or revenue
GET    /admin/reports/top-customers       Lifetime-value leaderboard
GET    /admin/reports/mrr                 Active subscription MRR by currency
… plus coupons, vendors, shipping zones/methods, tax rates, subscriptions, reviews moderation, menu, customer-portal-session

Hooks

  • content:beforeSave on the products collection — field validation (price map, variants, stock, shipping class)
  • cron — stock-lock sweep (5 min), abandoned-cart reminders (hourly), subscription renewals dry-check
  • plugin:install — seed default settings (taxMode=flat, currencies, download TTLs, etc.)
  • plugin:activate — assert Stripe keys present; emit config warnings if not

Plugin storage collections

19 collections declared in storage-collections.ts:

orders · order_items · order_refunds · customers · customer_addresses
product_variants · inventory_ledger · stock_locks
coupons · coupon_usages · shipping_zones · shipping_methods · shipping_classes
tax_rates · reviews · subscriptions · vendors · vendor_payouts · download_grants

Plus one content collection declared by the host via defineProductsCollection():

products  (lives on host content, not plugin storage — emdash restriction)

KV namespaces

Prefixes ctx.kv uses under the hood:

settings:*                  plugin configuration (tax mode, currencies, Stripe keys, etc.)
cart:{sessionId}            active carts (30-day TTL via cookie)
lock:{productId}:{variant}  stock soft-locks during checkout
abandoned:{sessionId}       abandoned-cart marker (sent / not sent)
email-throttle:{category}:* per-customer email de-duplication keys

Admin surface

React pages served at /_emdash/admin/plugins/dashcommerce/*:

  • Orders (list, detail, refund, status transitions)
  • Customers (list, detail, order history)
  • Coupons (CRUD + usage reports)
  • Shipping (zones + methods + classes)
  • Tax (mode + flat rate + rate table + Stripe Tax status)
  • Subscriptions (list, detail, pause/resume, invoice history)
  • Reviews (moderation queue, bulk approve/reject)
  • Vendors (invite, onboarding status, payout history)
  • Menus (storefront nav editor, nested up to 4 levels)
  • Reports (revenue + top products + top customers + MRR)
  • Settings (all settings:* keys with per-key validation)
  • Dashboard widgets: Revenue, Low Stock, Recent Orders, Pending Reviews, Failed Renewals

Field widgets (for use in any collection via widget: "dashcommerce:<name>"):

  • vendor-select — picks a vendor from vendors storage
  • price-map — multi-currency price input, respects settings:enabledCurrencies

Portable Text blocks (for any rich-text field):

  • product-embed — single product card by slug
  • product-grid — N products from a category slug
  • review-quote — inline quote of an approved review

Events & emails

The plugin sends these transactional emails via ctx.email.send (HTML + plain text):

| Event | Template | Triggered by | |---|---|---| | Order receipt | emails/receipt | Webhook charge.succeeded / checkout.session.completed | | Refund | emails/refund | Webhook charge.refunded or admin refund POST | | Subscription renewed | emails/subscription-renewed | Webhook invoice.payment_succeeded (cycle only) | | Dunning | emails/dunning | Webhook invoice.payment_failed | | Abandoned cart | emails/abandoned-cart | Hourly cron, per settings:abandonedCartDelayHours | | Review request | emails/review-request | Order status → completed on physical items | | Vendor invite | emails/vendor-onboarding | startOnboarding() in vendors/onboarding.ts | | Vendor activated | emails/vendor-onboarding | Webhook account.updated when chargesEnabled flips true | | Vendor payout | emails/vendor-payout | Webhook payout.paid |

All senders are idempotent via ctx.kv de-dup keys.

Development

bun install
bun run typecheck
bun run build          # tsdown bundles index + sandbox-entry + admin/entry
bun run dev            # tsdown --watch
bun test               # 66 tests across money / cart / coupons / webhook / tokens / split

src/astro/ is shipped as source — it is NOT bundled. It imports .astro components that rolldown can't compile; the host's Astro build resolves the imports at consumer build time.

License

MIT