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

@sentia-labs/cli

v0.1.1

Published

Sentia SDK and CLI for AI-native product research, evidence, decisions, and calibration.

Readme

sentia

The Sentia SDK + CLI. One package, three surfaces:

  • Browser SDK — capture real product usage (page views, clicks, rage/dead clicks, and your own exposure/outcome events) from your web app.
  • Server SDK — send the same events from a Node backend.
  • CLIsentia command for research, populations, and artifacts (needs a secret API key).
npm install sentia

Quick start (browser)

import { Sentia } from '@sentia-labs/cli/browser';

export const sentia = new Sentia({
  writeKey: process.env.NEXT_PUBLIC_SENTIA_WRITE_KEY, // public, write-only
});

Your write key is a public, write-only credential — safe to ship in a client bundle, exactly like a Stripe publishable key or a Segment write key. It can only send events; it cannot read or export anything. Generate one in Settings → Developer. Reading/exporting data uses a separate secret API key (see CLI & command APIs).

Autocapture (page views, clicks, rage-clicks, dead-clicks) starts automatically. Tag any element with data-sentia-id="checkout-button" to get stable component attribution in the friction reports.


Closing the calibration loop

This is the point of the SDK: tie a shipped decision back to the simulation that predicted it. When a real user is shown the shipped variant, record an exposure; when they hit the success metric, record an outcome.

// Decision key is minted per simulation. Copy it from the report's
// "Instrument this decision" panel.
sentia.exposure('dec_9f2a1c04b7e3', 'variant_a');

// Later, when the user completes the success action:
sentia.outcome('activation_rate', 1);

Sentia measures the real conversion rate for that decision and scores it against the simulation's forecast — your Decision Hit Rate.

Full event API

sentia.identify('user_123', { plan: 'pro' });
sentia.group('acct_42', { seats: 20 });
sentia.track('checkout_started', { cart_value: 129 });
sentia.exposure('dec_...', 'variant_b');
sentia.outcome('revenue', 129, { unit: 'usd' });
sentia.feedback('The date picker was confusing');
await sentia.flush(); // force-send the queue (also runs on page unload)

Consent & privacy

Consent controls (opt-out API):

sentia.optOut(); // stop all capture; clears the queue; persisted
sentia.optIn(); // resume; persisted across reloads
sentia.hasOptedOut(); // -> boolean
  • Global Privacy Control & Do Not Track are honored automatically. If the browser sets navigator.globalPrivacyControl (GPC, legally enforceable under CCPA/CPRA) or Do Not Track, the SDK starts opted out.
  • Consent-first ("no capture until you say so"): initialize with new Sentia({ writeKey, optOut: true }), then call sentia.optIn() once the user consents. A persisted user choice always wins over defaults.

Privacy properties of the transport:

  • No cookies are sent on ingest (the request is cross-origin and credential-less by design).
  • Client IP is never attached to events. Sentia does no IP-based geo-lookup; the raw IP is dropped at the edge (it survives only on the security audit trail, where an IP is defensible).
  • Events post as text/plain with the write key in the body — a CORS "simple request", so there's no preflight and it works from any customer domain.
  • On page unload, the queue is flushed via navigator.sendBeacon (hooked to visibilitychange/pagehide, never the bfcache-breaking beforeunload), so the last events before a user leaves aren't lost.

Server (Node) usage

import { Sentia } from '@sentia-labs/cli/node';

const sentia = new Sentia({ writeKey: process.env.SENTIA_WRITE_KEY });
sentia.exposure('dec_9f2a1c04b7e3', 'variant_a', {}, { userId: 'user_123' });
sentia.outcome('activation_rate', 1, {}, { userId: 'user_123' });
await sentia.close(); // flush before the process exits

The server SDK skips browser autocapture and never touches the DOM.


CLI & command APIs

The sentia CLI and the command methods (runResearch, createPopulation, …) require a secret API key (sk_...), never the public write key:

const sentia = new Sentia({ apiKey: process.env.SENTIA_API_KEY });
await sentia.runResearch({ question: 'Where will buyers hesitate?', sourceIds: [...] });

Passing an SDK write key to a command method throws — write keys can only send events.


Bundle size

The capture core is a thin fetch/sendBeacon client. The heavier autocapture engine (posthog-js, run capture-only and first-party) is lazy-loaded via a dynamic import(), so it lands in its own chunk and only when autocapture is on — your initial bundle stays small.

Configuration

| Option | Default | Notes | | ----------------- | --------------------------- | -------------------------------------------- | | writeKey | — | Public, write-only. Required to send events. | | apiKey | — | Secret. Required for CLI/command APIs only. | | baseUrl | https://api.sentialabs.ai | Ingest host. | | optOut | false | Start opted out (consent-first). | | flushAt | 10 | Flush after N queued events. | | flushIntervalMs | 10000 | Flush at least this often. | | autocapture | true | false to disable, or an options object. | | context | {} | Default context merged into every event. |