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

@centaurisystems/launchpad-sdk

v1.1.2

Published

Launchpad component SDK: registerComponent, usePortalContext, and the locked component build toolchain. SDK v1 targets React 19.

Readme

@centaurisystems/launchpad-sdk

Build React components for Launchpad developer portals: register them, read portal data, and build them with the locked toolchain. Publish with one command via @centaurisystems/cli — versioned per environment, rolled back in seconds, disabled with one click.

Install

npm install --save-dev @centaurisystems/launchpad-sdk @centaurisystems/cli

Use

import { registerComponent, usePortalContext } from "@centaurisystems/launchpad-sdk";

function PricingCalculator() {
  const { environment, theme } = usePortalContext();
  return <div style={{ color: theme.colors.primary }}>Running in {environment}</div>;
}

registerComponent({
  name: "pricing-calculator",
  displayName: "Pricing Calculator",
  component: PricingCalculator,
  props: { title: { type: "string", label: "Title" } }
});

Local dev/testing: wrap with MockPortalProvider. At portal runtime this module is replaced by the portal's live implementation.

The manifest the platform stores comes from the "launchpad" field of your package.json (copied to dist/launchpad.json by centauri components build). Your code is never executed server-side.

Theming: follow the portal's light/dark toggle

usePortalContext().theme is live. On portals with light/dark support:

  • theme.colors.background_color / text_color / surface_color / border_color are mode-resolved: complete CSS color strings (e.g. hsl(211 100% 59%)) whose values flip — re-rendering your component — when the visitor toggles dark mode. Style your surfaces with these (backgrounds, text, cards, borders) so your component follows the toggle automatically. Any of the four may be absent (older portals, or a portal that can't resolve them), so always keep your own fallback.
  • theme.mode ("light" | "dark", optional) is for discrete switches the resolved colors can't express — picking a logo asset or a chart palette. Treat undefined as light.
  • Brand *_color keys (primary_color, secondary_color, key_color, …) are raw brand tokens and do not flip with the mode — use them for accents, never for surfaces.
function StatusCard() {
  const { theme } = usePortalContext();
  const { colors, mode } = theme;
  const style: React.CSSProperties = {
    // Mode-resolved keys with graceful fallbacks — flips live with the toggle.
    background: colors.surface_color ?? "#f8fafc",
    color: colors.text_color ?? "#0f172a",
    border: `1px solid ${colors.border_color ?? "#e2e8f0"}`,
    // Brand accent: intentionally NOT mode-resolved.
    borderTopColor: colors.primary_color ?? "#6366f1"
  };
  return (
    <div style={style}>
      <img src={mode === "dark" ? logoDark : logoLight} alt="" />
    </div>
  );
}

Site placement

By default a component is a block: something a portal admin drags onto a page in the page builder and configures per placement. Set "placement": "site" in the manifest instead to have the portal mount your component once on every portal page, rather than as a page-builder block. Omit the field (or set it to "block") for the default page-block behavior — the build never injects a default into dist/launchpad.json when it's absent from your source.

{
  "launchpad": {
    "name": "pageview-tracker",
    "displayName": "Pageview Tracker",
    "placement": "site",
    "description": "Site-wide, invisible pageview/click tracking."
  }
}

Site-placement components:

  • are excluded from the page builder's block palette — there's no page slot to drag them onto
  • are typically headless: render null always, since nothing anchors visible output for a component with no page slot
  • must clean up every listener, timer, and patch (e.g. a monkeypatched history.pushState) on unmount. The portal can mount and unmount a site component repeatedly — navigation-rule changes, a kill switch — so nothing it sets up may outlive one mount/unmount cycle, and it must never touch state after unmounting.

See examples/pageview-tracker for a full reference implementation (SPA navigation tracking via patched history methods, sampling, sendBeacon delivery).

Slot placement: replace the portal's built-in chrome

Set "placement" to "slot:header", "slot:footer", or "slot:menu" to have the portal render your component instead of its built-in chrome for that region. footer is the bottom chrome; header is the entire top chrome bar; menu is the primary navigation region inside the built-in header bar (a header replacement subsumes the menu — enable one or the other). Slot regions are a closed set defined by the portal layout: any other slot:* value is rejected by the build and by the platform at publish time.

{
  "launchpad": {
    "name": "custom-footer",
    "displayName": "Custom Footer",
    "placement": "slot:footer",
    "description": "Replaces the portal's built-in footer."
  }
}

What "replace" means for your component:

  • Render a complete region, not a fragment. The built-in chrome for that region is gone while your component is enabled and in scope — everything the region should show (navigation, copyright, links) is yours to render.
  • The portal fails safe, but don't rely on it. If your bundle fails to load, fails its integrity check, or your component throws (repeatedly — a circuit breaker stops re-mount attempts for the session), the portal falls back to its own built-in chrome for that region, and admin routes always keep built-in chrome. That fallback is a recovery mechanism, not a feature: a flickering half-replaced region is still a broken portal.
  • Keep it accessible. You are now the portal's chrome. Use the real landmarks (<footer role="contentinfo">, <header role="banner">, a <nav> with an aria-label for menus), real <a> elements for links (never click-handler divs), and visible focus states — keyboard and screen-reader users navigate portals by these landmarks.
  • Same settings surface as site components. Portal admins configure your manifest-declared props plus path (include/exclude prefixes) and audience (all/authenticated/anonymous) rules per environment; out of scope, the built-in chrome renders. Among several enabled components targeting the same slot, only one renders per page (admin-controlled ordering).
  • Same portal context. usePortalContext() works exactly as for blocks — including the live theme.mode and the mode-resolved background_color / text_color / surface_color / border_color keys (see "Theming" above), so your chrome follows the visitor's light/dark toggle.
  • Like site components, slot components are excluded from the page builder's block palette, and clean unmount rules apply: remove every listener and timer in effect cleanup.

See examples/custom-footer for a full reference implementation (complete accessible footer, defensive link-list parsing, live theme mapping).

Versioning and deprecation policy

The SDK major version pins to a React major version. SDK v1 → React 19 (peer dependency react@^19).

When Launchpad portals upgrade to a new React major, a new SDK major is released, and the previous SDK major remains supported in portals for a minimum of 6 months from the portal upgrade announcement. Rebuild and republish your components against the new SDK major within that window.

Node API

  • buildComponent(opts) from @centaurisystems/launchpad-sdk/build — the locked esbuild config used by centauri components build.
  • scaffoldComponent(opts) from @centaurisystems/launchpad-sdk/scaffold — the create-launchpad-component template used by centauri components init.