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

@planetdataset/sdk-core

v0.2.4

Published

Vanilla-JS SDK for embedding Planet widgets (BOGO, Bundle, Upsell, Smart-cart) on any storefront. Sets up window.PlanetWidgets with init() and triggerAddToCart().

Readme

@planetdataset/sdk-core

Vanilla-JS SDK for embedding Planet widgets on any storefront — Shopify Hydrogen, custom Next.js, plain HTML, etc.

The package ships a single UMD bundle (planet-sdk.umd.js, ~460 KB minified / ~117 KB gzipped) that attaches window.PlanetWidgets on load. After calling init(config) once on the client, drop the planet-* web components into your markup.

For React/Hydrogen merchants, use @planetdataset/sdk-hydrogen instead — it provides typed React wrappers, a Hydrogen cart adapter, and SSR-safe loading on top of this package.

Install

npm install @planetdataset/sdk-core

Initialize

import "@planetdataset/sdk-core";
import "@planetdataset/sdk-core/style.css";

window.PlanetWidgets.init({
  // Required
  storeDomain: "my-store.myshopify.com",
  publicAccessToken: "<Storefront API public access token>",
  shopId: "gid://shopify/Shop/12345",
  localization: { country: "US", language: "EN" },
  moneyFormat: "${{amount}}", // Shopify money format string — see "Money format" below

  // Customer-targeting context for widget visibility rules
  advancedOptionsValues: {
    "customer.has_account": false,
    "customer.total_spent": 0,
    "customer.tags": [],
    "customer.orders_count": 0,
    "localization.market.handle": "us",
    "product.selling_plan_groups": false,
  },

  // Cart callbacks (Liquid `/cart.js` shape — see below)
  cart: {
    get: async () => /* fetch current cart */,
    add: async (items) => /* add lines, return updated cart */,
    update: async (updates) => /* bulk update line quantities, return cart */,
    change: async (lineKey, quantity) => /* change single line, return cart */,
  },

  // Optional: smart-cart drawer configuration
  smartCart: {
    cartUrl: "/cart",         // form action for the checkout button
    customSlots: { /* ... */ },
    hooks: {
      transformLineItems: (items) => items,
      afterCartChange: (cart, refetch) => { /* ... */ },
    },
  },
});

init() is synchronous and idempotent. Call window.PlanetWidgets.isInitialized() to check, or onReady(cb) to register a callback that fires once the SDK is ready (useful when widgets are rendered before init resolves).

Money format

Every price the widgets render — BOGO / Bundle / Upsell prices, Smart Cart totals, discount amounts, free-gift thresholds — is formatted with moneyFormat. It's the Shopify money format string, the exact same value a theme uses for shop.money_format: a template with one {{ amount }}-style placeholder plus whatever literal currency symbol or code the merchant puts around it (e.g. ${{amount}}, €{{amount_with_comma_separator}}, {{ amount }} USD, {{ amount_no_decimals }} kr).

Pass the merchant's real format — it's not decoration. The placeholder token selects the thousands/decimal separators and the number of decimals, and the surrounding text is the currency symbol. The default "${{amount}}" renders US-style $1,134.65; a EUR store that leaves it unset shows a $ instead of with the separators swapped. Omit it and prices are wrong for every non-USD merchant.

Supported placeholder tokens

The token drives separators and decimals (example amount: 1134.65):

| Token | Renders | |---|---| | {{amount}} | 1,134.65 | | {{amount_no_decimals}} | 1,135 | | {{amount_with_comma_separator}} | 1.134,65 | | {{amount_no_decimals_with_comma_separator}} | 1.135 | | {{amount_with_apostrophe_separator}} | 1'134.65 | | {{amount_with_space_separator}} | 1 134,65 | | {{amount_no_decimals_with_space_separator}} | 1 135 | | {{amount_with_period_and_space_separator}} | 1 134.65 |

Any literal characters around the token are kept verbatim, so ${{amount}}$1,134.65 and {{amount}} USD1,134.65 USD.

Where to get it

Read the format from whatever host renders the page — all three sources return the same string:

  • Shopify Liquid theme{{ shop.money_format }} (or {{ shop.money_with_currency_format }} to include the ISO code):
    window.PlanetWidgets.init({ /* … */ moneyFormat: {{ shop.money_format | json }} });
  • Storefront API (Hydrogen, custom React/Next.js, any headless storefront) — the Shop.moneyFormat field:
    query { shop { moneyFormat } }
  • Admin API (server side) — shop.currencyFormats.moneyFormat (and moneyWithCurrencyFormat for the currency-code variant).

For Hydrogen, @planetdataset/sdk-hydrogen wires shop.moneyFormat through the root loader for you — see its README.

Storefront API token scopes

The publicAccessToken must grant these unauthenticated Storefront API scopes:

| Scope | Why | |---|---| | unauthenticated_read_product_listings | Products & recommendations | | unauthenticated_read_product_inventory | Required — the recommendations widget filters on availableForSale; without this scope products read as unavailable and nothing renders | | unauthenticated_read_metaobjects | Smart Cart / cart-recommendations config (settings). The metaobject definitions must also expose Storefront access (PUBLIC_READ). | | unauthenticated_read_selling_plans | Only if you use subscriptions / selling plans |

Web components

After init, place these tags in your markup. They accept Shopify numeric IDs (not GIDs):

| Tag | Purpose | Attributes | |---|---|---| | <planet-bogo> | Buy-One-Get-One offers | product-id, variant-id | | <planet-bundle> | Multi-product bundles | product-id, variant-id | | <planet-upsell> | Recommended products with checkbox/radio selection | product-id, variant-id | | <planet-cart-recommendations> | Cart recommendations — the Smart Cart upsell as a standalone widget | none required (see note) | | <planet-smart-cart> | Drawer body — usually mounted inside planet-smart-cart-modal | none | | <planet-smart-cart-modal> | Slide-in drawer wrapper. Mounts once at the root of your app, listens for ATC events, registers window.PlanetDataset.SmartCart.methods.openDrawer | none |

Example product page:

<planet-bogo product-id="1234567890" variant-id="9876543210"></planet-bogo>
<planet-bundle product-id="1234567890" variant-id="9876543210"></planet-bundle>
<planet-upsell product-id="1234567890" variant-id="9876543210"></planet-upsell>

Example root layout (drop once globally):

<planet-smart-cart-modal></planet-smart-cart-modal>

<planet-cart-recommendations>

The Smart Cart product-recommendation upsell, usable on its own (cart page, custom drawer, etc.). It pulls its settings from the same Smart Cart metaobject config as <planet-smart-cart> (via the Storefront API — see Smart-cart configuration), so it needs no settings attribute.

Requires the cart API you pass to init() (see Cart API contract). The widget reads the cart via cart.get() to compute recommendations from the products in it — without a working cart API it can't render.

It self-syncs on the SDK's own cart-change events: it refetches via the cart API from init() after its own add-to-cart, an add via PlanetWidgets.triggerAddToCart, or a Smart Cart drawer op. It does not see cart mutations you make outside the SDK — for those, push the current cart as a cart JS property (Liquid /cart.js shape) whenever your cart changes (set it as a property, not an attribute, since it's an object):

const el = document.querySelector("planet-cart-recommendations");
el.cart = currentCart; // ICart, Liquid /cart.js shape

In React/Hydrogen, @planetdataset/sdk-hydrogen's <PlanetCartRecommendations cart={...} /> handles this for you.

Cart API contract

The cart callbacks must return data in the Liquid /cart.js shape:

interface ICart {
  token: string;
  items: Array<{
    key: string;
    id: string;           // variant numeric ID
    variant_id: string;
    product_id: string;
    quantity: number;
    title: string;
    product_title: string;
    variant_title: string;
    vendor: string;
    url: string;          // "/products/<handle>?variant=<id>"
    image: string;        // URL
    featured_image: { url: string; alt: string; aspect_ratio: number | null } | null;
    price: number;        // cents
    final_price: number;
    line_price: number;
    final_line_price: number;
    properties: Record<string, string>;
    selling_plan_allocation: object | null;
    line_level_discount_allocations: Array<{ amount: number; discount_application: { title: string } }>;
    parent_relationship: object | null;
  }>;
  item_count: number;
  total_price: number;       // cents
  total_discount: number;
  currency: string;          // "USD"
  note: string | null;
  cart_level_discount_applications: Array<object>;
}

The add(items) callback receives AddToCartItem[]:

interface AddToCartItem {
  id: string;              // variant numeric ID
  quantity: number;
  properties?: Record<string, string>;
  selling_plan?: string;
  parent_id?: string;
}

update(updates) receives a Record<lineKey, quantity>. change(lineKey, quantity) mutates a single line (quantity 0 = remove).

All four return Promise<ICart>.

Trigger add-to-cart programmatically

await window.PlanetWidgets.triggerAddToCart([
  { id: "9876543210", quantity: 1 },
]);

This dispatches BEFORE_ADD_TO_CART on the internal AsyncEventBus (so the smart-cart drawer opens) and routes through cart.add().

Coordination model

When ATC fires from any widget (BOGO, Bundle, Upsell, native form, programmatic call), the SDK dispatches planet:add-to-cart:before on an internal AsyncEventBus. Smart-cart-modal listens, performs the add via cart.add(), and opens the drawer. If smart-cart is not mounted, the widget's own cart.add() call still runs.

The drawer also exposes window.PlanetDataset.SmartCart.methods.openDrawer(open, refetch) once <planet-smart-cart-modal> has mounted, so you can open/close it from your own UI (e.g. a cart icon button).

Smart-cart configuration

Smart-cart pulls its display configuration (cart title, slot text, free-gift rules, recommendation algorithm, etc.) from Shopify metaobjects via the Storefront API:

  • planet_smart_cart_config — main config (cart enabled, position, theme)
  • planet_smart_cart_general_content — generic UI strings
  • planet_smart_cart_modules_content — per-module strings (free-gift, recommendations, etc.)

These metaobjects are managed in the Planet admin app. If a merchant hasn't configured them, smart-cart renders nothing (graceful degradation).

Build target

  • Output: UMD, single file, all dependencies (SolidJS, corvu, storefront-api-client) bundled
  • Target: ES2022
  • CSS: ships as a sibling planet-sdk.css — import via @planetdataset/sdk-core/style.css

Versioning

0.x.y — pre-1.0. Web component tag names, JS API and metaobject contract may evolve until 1.0.