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

@jfrader/observability

v0.4.0

Published

Strategy-based observability for small apps: error tracking (Sentry, pluggable) and analytics (PostHog, Plausible/Umami-style beacon, pluggable) behind one tiny API. Zero runtime dependencies.

Readme

@jfrader/observability

Strategy-based observability for small apps, one tiny API, zero runtime dependencies. Error tracking (Sentry by default) and analytics (PostHog by default) behind a strategy pattern, so you can switch providers — or drop them — by changing one import and one env var.

It is the shared observability layer used by all jfrader apps (MiFulbo, Huertoku, Civiku, Trucoshi, jfrader.com, Gurisitos). See changelog-lib for the sibling release-notes system.

Why a strategy pattern

Small apps have few users and little budget. The default choices here are free-tier-friendly and privacy-first:

| Concern | Default provider | Free tier | Alternative strategies | |---|---|---|---| | Errors | Sentry | 5k errors/mo | noop | | Analytics | PostHog | 1M events/mo | noop, custom beacon (Plausible/Umami-compatible) |

Both are behind interfaces (ErrorReporter, AnalyticsProvider), so any provider can be swapped without touching call sites. Provider SDKs are optional peer dependencies: install only what you actually use.

Install

npm install @jfrader/observability            # core (always)
npm install @sentry/react posthog-js          # only if you use those providers
# server-side: @sentry/node posthog-node

React (browser) quick start

// src/observability.ts
import { createBrowserObservability, readBrowserEnv } from "@jfrader/observability/browser";
import { createSentryBrowserErrorReporter } from "@jfrader/observability/providers/sentry-browser";
import { createPosthogBrowserAnalytics } from "@jfrader/observability/providers/posthog-browser";

const env = readBrowserEnv(import.meta.env); // VITE_SENTRY_DSN, VITE_PUBLIC_POSTHOG_KEY, ...

export const observability = createBrowserObservability({
  appName: "huertoku",
  environment: import.meta.env.MODE,
  errorReporter: env.sentryDsn
    ? createSentryBrowserErrorReporter({ dsn: env.sentryDsn, environment: import.meta.env.MODE })
    : undefined,
  analytics: env.posthogKey
    ? createPosthogBrowserAnalytics({ key: env.posthogKey, host: env.posthogHost ?? "https://us.i.posthog.com" })
    : undefined, // or createBeaconAnalytics({ endpoint: env.analyticsUrl })
});
// main.tsx
import { ObservabilityProvider, ObservabilityErrorBoundary } from "@jfrader/observability/browser";
import { observability } from "./observability";

createRoot(document.getElementById("root")!).render(
  <ObservabilityProvider value={observability}>
    <ObservabilityErrorBoundary fallback={<AppErrorScreen />}>
      <App />
    </ObservabilityErrorBoundary>
  </ObservabilityProvider>,
);
// anywhere
const track = useTrack();
track("game_completed", { score: 12 });

Version reload

New-deploy detection lives in @jfrader/pwa-updater. The deprecated re-export from observability was removed in 0.4.0 — import useVersionReload and isDynamicImportError from @jfrader/pwa-updater instead.

Node (server) quick start

// src/observability.ts
import { createNodeObservability, readNodeEnv } from "@jfrader/observability/node";
import { createSentryNodeErrorReporter } from "@jfrader/observability/providers/sentry-node";

const env = readNodeEnv(); // SENTRY_DSN, POSTHOG_KEY, ...

export const observability = createNodeObservability({
  appName: "mifulbo-api",
  environment: process.env.NODE_ENV ?? "development",
  errorReporter: env.sentryDsn ? createSentryNodeErrorReporter({ dsn: env.sentryDsn }) : undefined,
});

// Fastify:
app.setErrorHandler((error, request, reply) => {
  captureRequestError(observability, request, error);
  reply.send(error);
});

Switching providers

| Want | Change | |---|---| | No analytics (dev) | omit analytics (or set env vars empty) — noop fallback | | PostHog → Plausible/Umami/own endpoint | import createBeaconAnalytics instead of the PostHog adapter; set VITE_ANALYTICS_URL | | Sentry → nothing | omit errorReporter | | Any future provider | implement ErrorReporter / AnalyticsProvider (one file) |

Package entries

| Entry | Contents | Peer deps | |---|---|---| | @jfrader/observability | types, facade, noop, redaction utils, env readers | — | | @jfrader/observability/browser | facade + React (ObservabilityProvider, useTrack, ObservabilityErrorBoundary) | react (optional) | | @jfrader/observability/node | facade + captureRequestError | — | | @jfrader/observability/providers/sentry-browser | createSentryBrowserErrorReporter | @sentry/react | | @jfrader/observability/providers/sentry-node | createSentryNodeErrorReporter | @sentry/node | | @jfrader/observability/providers/posthog-browser | createPosthogBrowserAnalytics | posthog-js | | @jfrader/observability/providers/posthog-node | createPosthogNodeAnalytics | posthog-node |

Env conventions

Browser (readBrowserEnv(import.meta.env, prefix)):

  • VITE_SENTRY_DSN — enable Sentry
  • VITE_PUBLIC_POSTHOG_KEY (+ VITE_PUBLIC_POSTHOG_HOST, default https://us.i.posthog.com)
  • VITE_ANALYTICS_URL — custom beacon endpoint

Node (readNodeEnv()): same names without the VITE_ prefix.

Privacy defaults

  • Sentry adapters scrub credentials/tokens from URLs and breadcrumbs by default (redact option), send no PII, errors only (tracesSampleRate: 0).
  • PostHog browser adapter: autocapture off, session recording off, sensitive URL values scrubbed before send (redact accepts app-specific query keys).
  • Beacon adapter: sends { name, data, url, ts }, supports redactUrl to strip share codes; never throws.
  • Noop fallbacks: no provider configured → no network calls, no console noise.

Agent skill

The package ships skills/observability/SKILL.md, an agent-facing integration workflow covering browser and server setup, privacy and identity boundaries, event design, release/source-map conventions, and live verification. Agent clients that discover dependency skills can load it directly from the installed package; other clients can point their project skill configuration at that file.

Publishing

Primary flow (like changelog): push an annotated v<package-version> tag from main. The release workflow checks tag + lockfile, builds and tests once, packs one immutable tarball, then publishes or verifies that exact artifact on npmjs (trusted publisher) and GitHub Packages (scoped GITHUB_TOKEN). Retries are safe: an existing matching artifact is accepted, a different artifact at the same version fails.

Manual CLI fallback for npmjs (no tag needed): plain npm publish works because the repo .npmrc pins the @jfrader scope to npmjs (the user-level ~/.npmrc maps it to GitHub Packages).

History: 0.1.0 was CLI-published (its manifest carried publishConfig.registry, which overrides registry flags — incompatible with workflow republishing); 0.1.1+ go through the workflow. GitHub Packages packages are created public when published from a public repository.