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

@nytka/core

v0.1.0

Published

Project plumbing shared by nytka connectors: find the project root, load its .env, write a payload, register a dataset with provenance.

Readme

@nytka/core

Project plumbing shared by nytka connectors: find the project root, load its one .env, write a payload, register a dataset in datasets/index.json with provenance.

Zero runtime dependencies, and there will never be one. Every connector installs this, so a dependency here is a dependency in every project that collects anything.

What this is not

Not a plugin contract. There is no base class, no plugin registry, no connector abstraction. Two connectors proved they share file-and-registry plumbing; they have not yet proved what a connector is. That waits for a third connector on a third auth mechanism.

Install

npm install @nytka/core

You normally do not: @nytka/plugin-gsc and @nytka/plugin-ga4 depend on it and re-export the parts a caller needs. Install it directly only when writing a connector.

API

import {
  findProjectRoot, loadEnv, writePayload, registerDataset,
  fmtJson, isoDate, monthKey, monthPeriod,
} from '@nytka/core'

| | | |---|---| | findProjectRoot(start?) | Walks up at most 12 levels for project.yaml. Returns the directory or null. Existence check only — no YAML parsing, no dependency. | | loadEnv(root) | Loads <root>/.env via process.loadEnvFile. Returns the path or null. One .env per project; plugins read process.env and never learn where a value came from. | | writePayload(root, id, payload) | Writes datasets/payloads/<id>.json, creating the directory and its own .gitignore. Returns the project-relative path. | | registerDataset(root, entry) | Adds or replaces the entry with entry.id in datasets/index.json. Returns the path written. | | fmtJson(value, indent?, width?) | JSON with anything that fits on one line kept on one line. | | isoDate(date?) | The local calendar date as YYYY-MM-DD. | | monthKey(date) | 2026-07-25 → 2026-07. Throws on anything that is not a YYYY-MM-DD calendar date. | | monthPeriod(from, to) | 2025-04-01, 2026-07-25 → 2025-04-to-2026-07. The reporting-period fragment of a dataset id. |

Two things here are load-bearing

fmtJson's width of 150

It is calibrated against real registries, not principled, and it is shared state: every connector writes the same datasets/index.json. JSON.stringify(x, null, 2) explodes every short array onto its own set of lines, so appending one entry reformats every entry already there — a several-hundred-line diff for a one-line change, which is a diff nobody reviews.

Changing the width reformats every entry every other connector ever wrote. test/fmtjson.test.mjs holds it to a byte-identical round trip on a registry that already went through it.

isoDate is local, not UTC

new Date().toISOString().slice(0, 10) converts to UTC first, so anywhere west of Greenwich an evening run stamps tomorrow — a collection at 20:06 EDT on 2026-07-28 records collectedAt: 2026-07-29, a date in the future against every other date in the project, which are all local calendar dates.

Dataset id convention

Ids name the reporting period at month granularity:

<source>-<operation>-<property-slug>-<YYYY-MM>-to-<YYYY-MM>

The exact window a collection actually fetched stays in the entry's dateRange. That split is deliberate. Connectors fetch up to now - lag, so an id built from the exact window moves every day and registerDataset — which matches on id — appends instead of replacing. Running a monthly collection daily for a month would leave thirty near-identical entries describing one series.

At month granularity the same month collected twice replaces in place, a new month is a new entry, and no provenance is lost.

Tests

npm test

node --test. No dependency, no network, no credential.

License

MIT