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

kvalita

v1.39.0

Published

Shared linter configurations for TypeScript projects.

Readme

Kvalita

npm version license

Shared linter configurations for TypeScript projects.

Kvalita provides reusable, opinionated configurations for maintaining consistent code quality across TypeScript projects.

Installation

bun add -d kvalita

This will automatically install all required dependencies.

[!NOTE] All tools are installed together for simplicity, even if you only use some of the configurations. This ensures all CLIs and configs work correctly and avoids resolution issues.

Usage

Biome Configuration

Create a biome.json file in your project root:

{
  "extends": ["kvalita/biome"]
}

On top of Biome's recommended rules, the config turns on more built-in rules and runs GritQL plugins, some only in *.test.ts files. All of it lives in configs/biome: shared.json lists the rules, each .grit file in plugins/ is one plugin with its message, and fixtures/ shows what each plugin flags. Rules waiting for the projects to be swept clean of them sit in upcoming.json, which no config extends.

The plugins load from node_modules/kvalita, so the config expects kvalita installed at the project root.

A project adds the configs that fit it after kvalita/biome:

  • kvalita/biome-trousse for a project that depends on trousse.
  • kvalita/biome-library for a published library, which declares its exports' return types and never logs or exits.
  • kvalita/biome-react for a React app's components.
  • kvalita/biome-drizzle for a project that queries through Drizzle.
  • kvalita/biome-locales for a project that keeps its error messages under errors in src/locales.json. It reports at info level for now, so it never fails a run.
{
  "extends": ["kvalita/biome", "kvalita/biome-trousse", "kvalita/biome-library"]
}

Commitlint Configuration

Create a commitlint.json file in your project root:

{
  "extends": ["./node_modules/kvalita/configs/commitlint.json"]
}

Semantic Release Configuration

Use the --extends flag in your CI workflow:

- name: Release
  run: bunx semantic-release --extends kvalita/semantic-release

This configuration includes:

  • Branches: main, rc (prerelease), beta (prerelease), alpha (prerelease), and maintenance branches named N.x or N.N.x, which publish to the release-N.x dist-tag
  • conventionalcommits preset with feat!: syntax for breaking changes
  • npm provenance (requires id-token: write permission)

Lefthook Configuration

Create a lefthook.json file in your project root and extend the hooks you need:

{
  "extends": [
    "node_modules/kvalita/configs/lefthook-biome.json",
    "node_modules/kvalita/configs/lefthook-typescript.json",
    "node_modules/kvalita/configs/lefthook-commitlint.json"
  ]
}

Available hooks:

  • lefthook-biome.json - Lints and formats staged files with Biome (pre-commit)
  • lefthook-typescript.json - Type checks TypeScript files (pre-commit)
  • lefthook-commitlint.json - Validates commit messages (commit-msg)

Shared Workflows

Call them instead of copying the job into every repo. secrets: inherit passes CODECOV_TOKEN and NPM_TOKEN through.

# .github/workflows/test.yml
name: Test
on:
  push:
    branches: [main, alpha, beta, rc]
  pull_request:
jobs:
  test:
    uses: macieklamberski/kvalita/.github/workflows/shared-test.yml@main
    secrets: inherit
# .github/workflows/release.yml
name: Release
on:
  workflow_dispatch:
    inputs:
      branch:
        description: Branch to release
        required: true
        default: main
        type: choice
        options: [main, rc, beta, alpha]
jobs:
  release:
    uses: macieklamberski/kvalita/.github/workflows/shared-release.yml@main
    with:
      branch: ${{ inputs.branch }}
      build: true
    secrets: inherit

shared-release takes branch, build, config and bun-version; shared-test takes bun-version and ref. Every one has a default, so a repo on the common setup passes nothing. Start the release from the branch it releases, and pass that branch as branch. npm's provenance names the branch the run started on, so a run started on main can't publish another branch. Pass the same branch as ref to any gate job, such as shared-test, so the gates check the code being released.

shared-package checks the package the way a consumer gets it. It builds the package, installs it into an empty project with npm install --install-links, so only the published files land there, and loads every entry point in exports: through import, and through require() where a require condition exists. It does that on every even Node.js major from the floor in engines.node, or 18 when it isn't set, up to the latest release. On the latest one, it also turns off syntax detection and require() of ESM files, which older versions don't have. Optional peers get installed too, since an entry point built on one needs it.

A second job checks the same entry points the way TypeScript and bundler users reach them. It type-checks them from an ESM and a CommonJS project under each module resolution (node10, node16, nodenext and bundler) with strict and skipLibCheck: false, and fails only on errors in the package's own types. It also bundles them with Vite as a server build. With browser: true, it bundles them for the browser as well. Every setup only imports what the package claims: CommonJS files only use entry points with a require condition, and node10 only checks the root entry, when the package has a top-level types.

It takes ref, bun-version and browser:

# .github/workflows/package.yml
name: Package
on:
  push:
    branches: [main, alpha, beta, rc]
  pull_request:
  workflow_call:
    inputs:
      ref:
        type: string
        default: ''
jobs:
  package:
    uses: macieklamberski/kvalita/.github/workflows/shared-package.yml@main
    with:
      ref: ${{ inputs.ref }}

The workflow_call trigger lets the release workflow run it as a gate with ref: ${{ inputs.branch }}, next to shared-test.

Dependabot Configuration

Dependabot can't share a config between repos, so kvalita generates each repo's .github/dependabot.yml from the files it tracks:

bun node_modules/kvalita/configs/dependabot/dependabot.ts --write

Every repo gets bun and github-actions. docker-compose and docker are added when the repo has a compose file or a Dockerfile, and they cover every directory through /**/*, so a new Docker directory needs no regeneration. All entries share one group that runs weekly and waits 7 days after a release, so each repo gets one PR a week with every update in it, majors included.

shared-lint runs the same script without --write and fails when the committed config differs.

Ignore File Templates

Copy the templates into your project root, then add whatever the project itself produces:

cp node_modules/kvalita/configs/gitignore .gitignore
cp node_modules/kvalita/configs/dockerignore .dockerignore

The Docker entries carry a **/ prefix because Docker matches from the build context root, not at any depth like git. ** also matches zero directories, so the one spelling works in a flat project and a monorepo alike.