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

@bigin-io/site-contract

v1.0.1

Published

Single source of truth for site.config, content schemas, and the design-token spec

Readme

@bigin-io/site-contract

Single source of truth for site.config, the content/frontmatter schemas, and the design-token spec. Both renderers (ADR-1), the site Worker (ADR-5), and every pipeline skill read their shapes from here and nowhere else.

Framework-agnostic by construction: no renderer import, no Worker import, no host global. zod is the only runtime dependency.

Install

pnpm add @bigin-io/site-contract

Consumption modes (ADR-8)

| Consumer | How it resolves | | --- | --- | | A package inside this monorepo | "@bigin-io/site-contract": "workspace:^" | | A client site repo | a pinned semver range from npm (public since ADR-18; GitHub Packages before it) |

A site repo needs the scope mapped to the registry and a token:

# .npmrc
# Nothing. The @bigin-io scope publishes publicly to npm (ADR-18), so a
# site repo needs no registry mapping and no token at all. This block used
# to read:
#
#   # Not needed: the scope is public on npm (ADR-18).
#   //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}

Verified against a real install of 0.2.0 from the registry, from a repo outside this workspace (story 6.5, T6). Those two lines are the whole of it — nothing else is needed to resolve the package or any of its subpaths.

The token needs read:packages, and where it comes from differs.

| Where | The token | | --- | --- | | GitHub Actions, same org | the built-in GITHUB_TOKEN, with permissions: packages: read on the job | | A developer's machine | a PAT with read:packages, exported as GITHUB_TOKEN |

There is no ambient GITHUB_TOKEN outside Actions, so a local npm install fails without one. The failure is specific and worth recognising: a token carrying repo but not read:packages returns

403 Forbidden - Permission permission_denied: The token provided does not match expected scopes.

not a 404 or an auth prompt. gh auth refresh -h github.com -s read:packages adds the scope to an existing gh login.

Your tsconfig needs a URL global. zod's declaration files reference URL, so a consumer typechecking with skipLibCheck: false and a bare "lib": ["ES2022"], "types": [] fails in node_modules/zod, not in its own code. "types": ["node"] (or a DOM lib) resolves it. With that, the published declarations typecheck clean under strict, noUncheckedIndexedAccess and exactOptionalPropertyTypes.

Usage

import { defineSiteConfig, parseSiteConfig, SCHEMA_VERSION } from '@bigin-io/site-contract'

export default defineSiteConfig({
  schemaVersion: SCHEMA_VERSION,
  tier: 'content',
  renderer: 'nuxt',
  // ...
})
import { createContentSchemas } from '@bigin-io/site-contract/content'
import { toCssVars } from '@bigin-io/site-contract/tokens'
import { contentSiteConfig } from '@bigin-io/site-contract/fixtures'

const { page, post, section, collections } = createContentSchemas(config)
const cssVars = toCssVars(config.design.tokens)

Content schemas are a factory, not constants: tier and media zone decide what content is legal (ADR-11, ADR-12), so a simple-tier site rejects a media.<domain> image reference at parse time.

Two stages

| Schema | Gate | Allows | | --- | --- | --- | | siteConfigDraftSchema | G0 (sf-intake) | design.tokens, pages, collections, and cloudflare still absent | | siteConfigSchema | G4 (build) | everything present |

Anything that parses as complete also parses as draft — the cross-field rules are presence-guarded and shared between the two.

Versioning policy

schemaVersion is the contract's major line; CONTRACT_VERSION is the package semver, recorded in build manifests for NFR-6.

CONTRACT_VERSION always equals this package's package.json version. scripts/dist/bin/sync-versions.js rewrites it during changeset version, so the two move in one commit, and test/public-api.test.ts fails if they ever part company. Do not edit the literal by hand.

| Change | Release | | --- | --- | | Additive optional field | minor, no schemaVersion bump | | New required field | major + bump + migration | | Removed field or changed semantics | major + bump + migration | | A --sf-* CSS variable rename | major + bump + migration |

Migrations shipped

| To | Change | What a site repo does | | --- | --- | --- | | 2 | site.config.budgets removed (story 6.9) | Delete the budgets block and set schemaVersion: 2, or run migrateSiteConfig() |

schemaVersion: 2 is a breaking change from 0.4.0. A config that keeps the block is refused by name, not quietly stripped — so an upgrade cannot silently discard a budget a site meant to keep. NFR-1's budgets and the public/ image warning are repository constants in @bigin-io/site-tools now, and a site states neither. Note what that costs in both directions: a site can no longer ask to be faster than the platform floor either. That is a platform change, not a config field.

The --sf-* map and the leaf-key-name set are snapshot-locked in the test suite. A snapshot diff means a contract change, so it needs a PR — not a snapshot update.

After story 1.1 the contract is frozen: changes go through PR + review only, and every lane rebases on the merged change before continuing (CLAUDE.md § Workflow).

What this package does not do

It validates parsed objects. Loading site.config.ts (a TypeScript module) and reading markdown off disk are the renderer's and pipeline's job — a file-reading API here would be a contract-scope change.