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

@nextgen-composable/next-gen-composable

v1.0.5

Published

Reusable storefront composables (catalog / cart / shipping / billing / payment / configurator): executor-based transport behind a host facade

Readme

@nextgen-composable/next-gen-composable

Foundry-30846 — reusable catalog, cart, shipping, billing, payment and configurator composables on one executor-based RuntimeContext contract. Consumers: HMH (ship-to + bill-to), Homewater (install/service address across Retail, D2D, Direct).

v1.0 — the facade cutover (breaking). The packages no longer talk to Salesforce. Every adapter sends (method, payload) through a host-injected executor (context.executor); the host's server-side facade owns the org URL, the credential, the operation allow-list, and the account scoping. The old contract — context.security.{baseUrl, tokenProvider} with a browser-held Bearer token calling apexrest directly — is gone and can no longer be expressed. The reference facade lives in packages/facade/; the governing docs are Composable Drop-in Patterns v2.0 (the seam) and Genesis Platform API — Target Standard v1.0 §5 (sanctioned interfaces).

Workspace layout

The repo is an npm workspace organized by composable — each package is independently buildable/testable and designed to be extracted into its own repository later (see docs/extracting-a-package.md):

packages/
  composable-runtime/   @nextgen-composable/runtime — RuntimeContext contract (shim):
                        ComposableExecutor, executorOf/scopeOf, ServiceStatus/MutationResult,
                        framework-neutral store, formatPrice, createMockRuntimeContext,
                        and the shared address kernel (AddressDTO + normalize/validate)
  catalog/              @nextgen-composable/catalog  (owns CatalogCartGateway — its view of the cart)
  cart/                 @nextgen-composable/cart
  shipping/ billing/ payment/ configurator/
  facade/               @nextgen-composable/facade — HOST-OWNED, PUBLISHED: the
                        server-side facade kernel (per-family allow-list manifests,
                        org auth, scope stamping, Blink wire quirks) + the browser
                        executor. Imports no composable package; no composable
                        package imports it. Hosts install it from the root package
                        (`/facade`, `/facade/client`) and mount it in their own
                        server — see [packages/facade/README.md](./packages/facade/README.md)
src/                    the published package's compatibility facade + subpath entries

Every composable package has the same internal shape:

packages/<name>/src/
  core/                 DTOs, service ports, config, offline validation — provider-neutral
  controller/           framework-free state machine
  react/                <Name>Panel (provider-neutral, takes `service`) +
                        Connected<Name>Panel (batteries-included, executor-wired) + use<Name>Controller
  adapters/             create<Name>Service — payload building + response mapping; every
                        call goes through context.executor. NO fetch anywhere (guard-enforced).
  testing/              createMock*Service — complete in-memory services, run e2e with no backend
  styles.css            the composable's class-scoped --ec-* styles
  index.ts              the package's public API (nothing else is public)

Allowed dependencies between packages are documented in docs/dependency-boundaries.md and enforced by tests/architecture-guard.test.ts.

The transport contract (one law)

Browser                                  Host server                        Salesforce
ConnectedCatalogPanel
  └─ adapter: executor('retrieveCatalogNG', {…})
       └─ POST /api/composables ────────▶ facade
                                          ├─ allow-list the operation
                                          ├─ stamp the account scope
                                          ├─ mint/cache the org session
                                          └─▶ apexrest ────────────────────▶ org
  • The host builds ONE context: { runtime: 'custom', identity, session, executor }.
  • executor is a ten-line POST to the host's own backend (createFacadeExecutor in packages/facade/src/client.mjs).
  • No org URL, token, or credential exists in the browser. The facade's allow-list (packages/facade/src/ops.mjs, one manifest per family under ops/) is the entire reachable API.
  • Quote resolution stays host-owned: the host calls executor('getActiveQuote', …) itself and passes session.quoteId in.

Supported imports

// Historical surface (panels bind to the executor-wired Connected flavors):
import { CatalogPanel, CartPanel } from '@nextgen-composable/next-gen-composable'
import '@nextgen-composable/next-gen-composable/styles.css'

// Per-composable subpaths — pull in one composable only:
import { ConnectedCatalogPanel, CatalogPanel } from '@nextgen-composable/next-gen-composable/catalog'
import '@nextgen-composable/next-gen-composable/catalog/styles.css'
// (same for /cart, /shipping, /billing, /payment, /configurator — the panel-
//  shipping ones also expose the provider-neutral base panel, which takes an
//  explicit `service`)

// Inside this repo (and after extraction): the workspace packages themselves:
import { CartPanel } from '@nextgen-composable/cart'
import '@nextgen-composable/cart/styles.css'

Per-composable integration guides

Every composable carries its own INTEGRATION.md — the same eight sections in the same order, so an integrator opens any package and finds the wiring contract in the same place: install, runtime context (which fields this composable needs and why), config, events the host must handle, styling (tokens → theme → classes → replace), headless, zero-backend mocks, and a preflight checklist.

| Composable | Guide | Ships a panel? | | --- | --- | --- | | catalog | INTEGRATION.md · config reference | yes | | cart | INTEGRATION.md · config reference | yes | | configurator | INTEGRATION.md | yes, plus a <vue-expedite-configurator> custom element | | shipping | INTEGRATION.md | no — headless only | | billing | INTEGRATION.md | no — headless only | | payment | INTEGRATION.md | yes (PaymentPanel takes your controller) |

Family-wide headless answer, with the one packaging gap named: docs/headless-support.md.

Usage

For a client-shareable setup guide, see CLIENT-INTEGRATION.md.

Address capture

There is no address composable and no address panel. Capturing an address is always part of a step that owns it, so the address book, validation and save live in shipping (ship-to) and billing (bill-to) — both headless, so the host renders its own form:

import { useShippingController, createShippingService } from '@nextgen-composable/next-gen-composable/shipping'
// Shared address kernel — the DTO both steps speak, plus offline validation:
import { emptyAddress, validateAddressFormat, formatAddressLine } from '@nextgen-composable/next-gen-composable'

const shipping = useShippingController({
  context: runtimeContext,          // host supplies identity + executor (its facade)
  service: createShippingService({}),
  config: shippingConfig,
  quoteSource: { getShippingAddress: () => quote.shippingAddress ?? null, /* … */ },
  callbacks: { onAddressSaved: (address) => track(formatAddressLine(address)) },
})

See demos/demo/checkout for the reference form + address-book + modal built on that controller.

Checkout page

There is no checkout composable either — a checkout page is a host composition of shipping + billing + payment. Each composable owns one step and stays stateless about the quote; the host reads the quote and feeds each one through its quoteSource gateway. demos/demo/checkout is the reference composition, end to end.

Catalog page

import { CatalogPanel } from '@nextgen-composable/next-gen-composable'

<CatalogPanel
  context={runtimeContext}          // identity.accountId + executor drive every platform call
  onEvent={(event) => {             // one sink; switch on event.action.name
    if (event.action.name === 'addedToCart') rememberQuote(event.action.details.result.quoteId)
  }}
/>
  • Executor transport: panels read context.executor, context.identity.accountId, and context.session.quoteId; the host's facade makes the org call.
  • Look: replicates blink's catalog page 1:1 (MoleculeProductBlockMoleculeSearch / MoleculeProductItem / MoleculePagination): "Showing N results" header, bordered search bar, product cards with image · text · attribute fields · action button, numbered pagination.
  • Layouts: config.catalogDisplay.orientation'horizontal' (default) = blink's horizontal card orientation (full-width rows, image left); 'grid' = blink's vertical cards in a wrapping grid, on the corrected card design (fixed 4:3 media box, two-column meta grid, one primary action per card with an overflow menu); 'service' = the same card with no hero, for catalogs of software/services; also 'square' and 'table'.
  • Config-driven queries: CatalogConfig controls catalog source, inactive-item handling, fixed filters, multi-select left-rail facets, initial/two-level sorting, result counts, cart visibility, card fields, and paging. Existing Blink block JSON can be normalized with mapBlinkCatalogConfig.
  • Currency-aware: prices use each Salesforce record's CurrencyIsoCode, falling back to context.identity.currencyCode when the record omits it.
  • Real cart lifecycle: the add response's quote-line id is retained, so decrementing a quantity to zero sends deleteLineItems before the counter disappears.
  • Degraded, never blank: a provider outage keeps the last successful page on screen with a Retry action — an outage degrades browsing, it never empties the page.
  • Headless usage: createCatalogController (no React) or useCatalogController (React, custom UI).

Cart page

import { CartPanel } from '@nextgen-composable/next-gen-composable'

<CartPanel
  context={runtimeContext}          // session.quoteId identifies the active cart
  onEvent={(event) => {             // one sink; switch on event.action.name
    if (event.action.name === 'cartChanged') syncCartBadge(event.action.details.cart.lines.length)
  }}
/>
  • Cart operations: load cart lines, update quantity, remove lines, apply/remove promo code, and render quote totals.
  • Headless usage: createCartController (no React) or useCartController (React, custom UI).

Contract highlights (from the Foundry build notes)

  • Service port, RuntimeContext first: searchAddresses, resolveAddress, validateAddress, listSavedAddresses (account-scoped; empty for guests).
  • Host owns persistence — the composable emits a normalized DTO via callbacks, nothing more.
  • Google Places stays behind the host BFF (POST /api/v1/platform/address:search); no vendor SDK is embedded and no key ever reaches the client bundle.
  • Deterministic fallback: provider outage → manual entry with offline format validation (US ZIP / CA postal matrix). Never blocks checkout.
  • Mutations resolve to { status, errorMessage } — they never throw.
  • Controlled inputs only; class-scoped --ec-* tokens, dark theme via [data-ec-theme='dark']; no Shadow DOM. Peer React ^18 || ^19, ESM dist with ./styles.css export.
  • Architecture-guard test enforces composable boundaries, per-package layering, provider neutrality, bans direct transport everywhere (no fetch/XHR/axios in any package — adapters call the injected executor only), and keeps org coordinates and credentials out of the runtime contract (tests/architecture-guard.test.ts).

Running the demo

demos/demo/.env.local     SALESFORCE_BASE_URL + SALESFORCE_CLIENT_ID/SECRET (or SALESFORCE_TOKEN)
                          + EC_ACCOUNT_ID — server-side names, read only by the facade.
                          VITE_SF_* keeps only browser-visible identity/display facts.
npm run dev               vite dev server; @nextgen-composable/facade/vite hosts POST /api/composables

Scripts

  • npm run typecheck — strict TS for the facade + every workspace package
  • npm test — vitest (all package tests + the architecture guard + the facade tests); or per package: npm test -w @nextgen-composable/cart
  • npm run build — ESM bundle (root + per-composable entries), .d.ts tree (workspace specifiers rewritten so the tarball is self-contained), and dist/styles.css + dist/styles/<composable>.css

TODO before promotion

  • [ ] Swap packages/composable-runtime/src/runtime.ts shim for @expedite-commerce/composable-core once 30845 ships; replace the hand-rolled architecture guard with core's reusable helper.
  • [ ] Extract the architecture guard as a shared dev-dependency the sibling composable repos import (so the facade rule is not re-derived per repo).
  • [ ] Google Places key per environment (open item — who provisions).
  • [ ] Confirm the US-vs-Canada postal matrix with Homewater; extend core/validation.ts if more countries land.
  • [ ] Copy docs/promotion-pack.md + a typed client into ec-foundry-common/api-clients/address/.