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

@aranova/tracking-cli

v0.10.0

Published

CLI for the Aranova tracking package — generates typed service unions from your dashboard taxonomy

Readme

@aranova/tracking-cli

CLI for the Aranova tracking packages. Generates a typed service union from a business's dashboard-managed service taxonomy (so createSalesClient calls get compile-time-checked service values) plus the business's registered Google Ads / Meta tag IDs and R2 runtime config (ARANOVA_TRACKING_CONFIG) — ad-platform config stays backend-driven instead of hand-typed.

Install it as a devDependency alongside @aranova/tracking-react or @aranova/tracking-next:

npm install --save-dev @aranova/tracking-cli

gen

Fetches the active services, registered ad-platform IDs, and R2 tracking config reference for one site of your business and writes a typed module.

npx @aranova/tracking-cli gen [--dev] [--endpoint <url>] [--api-key <key>] [--site <hostname>] [--non-interactive] [--out <path>] [--check] [--env-file <path>]

| Flag | Default | Notes | | ------------------- | --------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | --dev | off | Use the local dev backend (http://localhost:6969). Pre-flights reachability and fails fast if it's down. | | --endpoint <url> | prod (https://aranovainternal-production.up.railway.app/tracking) | Overrides both --dev and the prod default. | | --api-key <key> | ARANOVA_TRACKING_SECRET_KEY (else ARANOVA_TRACKING_API_KEY) from .env | Use a secret key (aranv_sk_…). Public keys are Origin-enforced and will 403 from Node. | | --out <path> | src/aranova-services.ts | - writes to stdout. | | --check | off | Don't write — compare the existing --out file against the freshly generated module. Exits 1 with a line diff if it's stale or missing, 0 if up to date. Great for CI. | | --env-file <path> | — | Extra dotenv file to load (after .env and .env.local). | | --site <hostname> | ARANOVA_TRACKING_SITE, else inferred | Which of the business's sites to generate for. Inferred from the existing file's siteId, then from the repo's public key; on a TTY you get a picker. | | --non-interactive | off | Never prompt (CI / agents). A single site auto-resolves; an unconfirmed multi-site business exits 2 with the roster and a --site hint. |

Requires Node ≥ 20.

The key is read from .env via dotenv, so the typical invocation is just:

# .env  (never commit a secret key)
ARANOVA_TRACKING_SECRET_KEY=aranv_sk_xxxxxxxxxxxxxxxxxxxxxxxxxx

npx @aranova/tracking-cli gen --dev

Output

// AUTO-GENERATED by `@aranova/tracking-cli gen` — do not edit by hand.
// Re-run the command to refresh after changing services in the dashboard.

export const ARANOVA_SERVICES = [
  { key: "detail", label: "Detail" },
  { key: "oil", label: "Oil" },
  { key: "tires", label: "Tires" },
] as const;

export type AranovaService = (typeof ARANOVA_SERVICES)[number]["key"];

export const ARANOVA_SERVICE_LABELS: Record<AranovaService, string> = {
  detail: "Detail",
  oil: "Oil",
  tires: "Tires",
};

// Legacy compatibility export. New installs use ARANOVA_TRACKING_CONFIG.
export const ARANOVA_GTAG_IDS = {
  production: "AW-111111111",
  test: "AW-18151802025",
} as const;

export const ARANOVA_TRACKING_CONFIG = {
  businessId: "<business>",
  environment: "production",
  cdnBaseUrl: process.env.NEXT_PUBLIC_ARANOVA_CDN_BASE_URL || "https://demos.aranova.io",
} as const;

export const ARANOVA_CALENDARS = [
  { key: "consultations", label: "Consultations", timeZone: "America/Toronto" },
] as const;

export type AranovaCalendarKey = (typeof ARANOVA_CALENDARS)[number]["key"];

export const ARANOVA_CALENDAR_LABELS: Record<AranovaCalendarKey, string> = {
  consultations: "Consultations",
};

ARANOVA_SERVICES carries each service's human-readable label (handy for a dropdown), AranovaService is the union of keys, and ARANOVA_SERVICE_LABELS is a typed key→label lookup. ARANOVA_GTAG_IDS and ARANOVA_CONFIG_URL remain generated only so legacy imports keep compiling; do not wire them into new installs. Use ARANOVA_TRACKING_CONFIG with createTracking, createSalesClient (via getTrackingConfigRuntime), and <AdPlatformTracking> so R2 remains the live authority and dashboard tombstones clear old Google commands without a redeploy.

ARANOVA_TRACKING_CONFIG is environment-independent: it carries the business identity and reads its origin from an env var, defaulting to the production CDN. Generating against a local backend therefore cannot bake a localhost origin into this committed file, and gen --check compares dashboard content rather than whichever environment you last generated against. To point a local run at your own object storage, set the variable — no code change:

NEXT_PUBLIC_ARANOVA_CDN_BASE_URL=http://localhost:9100/aranova-demos

Leave it unset in production. The emitted variable name follows the SDK package found in your package.json (NEXT_PUBLIC_ for tracking-next, REACT_APP_ for tracking-react); the plain-script tracking-browser build has no bundler to inline a variable, so it gets the production origin and overrides via init({ trackingConfig: { …, cdnBaseUrl } }).

ARANOVA_CALENDARS lists the calendar syncs registered for the business, for createCalendarReadClient<AranovaCalendarKey>(). Appointment types are deliberately absent — those are your site's own vocabulary, not dashboard config. When a business has no calendars the union is never; leave the generic unbound (it defaults to string) until one exists.

Bind the generated union when constructing the sales client:

import { createSalesClient } from '@aranova/tracking-next';
import type { AranovaService } from './aranova-services';

const sales = createSalesClient<AranovaService>({
  apiKey: process.env.ARANOVA_TRACKING_SECRET_KEY!,
  endpoint: process.env.ARANOVA_TRACKING_ENDPOINT!,
});

await sales.record({ service: 'tires', /* 'tirez' is a compile error */ ... });

Generated types can lag the dashboard safely — the backend validates service on every write and returns 422 for an unknown key. Re-run gen to refresh.

A common setup is a package.json script:

"scripts": { "gen:services": "aranova-tracking gen --dev" }

See docs/tracking-package/sales-tracking.md for the full sales/conversions guide, and calendar.md for calendar bookings.

list

Print the active services to stdout — a quick way to see a business's taxonomy without generating a file.

npx @aranova/tracking-cli list [--dev] [--endpoint <url>] [--api-key <key>] [--json] [--env-file <path>]
KEY    LABEL
oil    Oil
tires  Tires

Pass --json for a machine-readable [{ "key", "label" }] array. list shares the --dev / --endpoint / --api-key / --env-file flags with gen.

gtags

Print the registered Google Ads tag IDs to stdout:

npx @aranova/tracking-cli gtags [--dev] [--endpoint <url>] [--api-key <key>] [--site <hostname>] [--json] [--env-file <path>]
LABEL       GTAG_ID
production  AW-111111111
test        AW-18151802025

list, gtags and meta-pixels resolve a site the same way gen does.

sites

Print the business's site roster (secret key) — the hostnames --site accepts:

npx @aranova/tracking-cli sites [--dev] [--endpoint <url>] [--api-key <key>] [--json] [--env-file <path>]
HOSTNAME          ROLE       PRIMARY  PUBLIC_KEY  GTAG_IDS                       GOALS  PUBLISHED
www.example.com   primary    yes      yes         production=AW-111,test=AW-222  3      7
shop.example.com  secondary  no       yes         -                              1      2

CI drift check

"scripts": { "gen:services:check": "aranova-tracking gen --check" }

gen --check regenerates in memory and compares against the committed file, exiting non-zero with a diff if they differ — so CI fails when the generated types lag the dashboard, without rewriting the file.

Exit codes

gen exits non-zero with a clear message on: missing/invalid key (401), a key not permitted for the business (403), an unreachable --dev backend, a network failure, or an unwritable --out path. It exits 2 — printing the site roster and a --site hint, writing nothing — when the site cannot be resolved (unknown --site, or a multi-site business with nothing to confirm the default in a non-interactive run). With --check it also exits non-zero when the --out file is stale or missing (it is never written in --check mode). An empty service list is not an error — it emits an empty array + empty labels map and warns. An empty/partial gtag map (or a backend without the /gtags route) is also not an error — it emits {} as const / the partial map with a note.