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

@stealthscale/vite-plugin-sbom

v0.3.1

Published

Writes a CycloneDX bill of materials from the modules a build reached.

Readme

@stealthscale/vite-plugin-sbom

@stealthscale/vite-plugin-sbom writes a CycloneDX 1.7 bill of materials for a build. The component list is read from the finished module graph rather than from a manifest, so a package that is installed and never imported is absent from the document. A component is keyed by its package URL, and that same URL is its bom-ref, so a dependency edge points at the string an advisory database matches on.

Install

pnpm add -D @stealthscale/vite-plugin-sbom

The package peers on @stealthscale/vite-plugin-base, vite and vitest. Install all three beside it.

Usage

import { sbom } from "@stealthscale/vite-plugin-sbom";
import { defineConfig } from "vite";

export default defineConfig({
  plugins: [sbom()],
});

A task runner starts a build from the workspace root, so the package being described is taken from the bundler's resolved root rather than from the working directory. The plugin writes cyclonedx/bom.json into the output directory.

Every field is optional, and no field is read off another. An application build states all five:

sbom({
  paths: ["cyclonedx/bom.json", ".well-known/sbom"],
  serialNumber: mode === "production",
  supplier: { name: "Stealth Scale B.V.", url: ["https://stealthscale.io"] },
  timestamp: mode === "production",
  type: "application",
});

The build is serialised once and the same bytes go to each path, so a copy served from a deployment and a copy taken out of the output tree can never disagree.

Options

sbom and written both take a Described record.

| Option | Type | Default | Effect | | -------------- | ---------------------------- | ------------------------ | --------------------------------------------------------------- | | paths | readonly string[] | ["cyclonedx/bom.json"] | Where the document is emitted, relative to the output directory | | serialNumber | boolean | false | Writes a random URN naming this one build | | supplier | Supplier | None | Names the organisation that supplied the build | | timestamp | boolean | false | Records the moment the document was written | | type | "application" \| "library" | "library" | Whether the subject is deployed or installed |

Omit supplier and the document includes no supplier at all. Both fields of a stated supplier are required.

| Field | Type | Default | Effect | | ------ | ------------------- | -------- | ----------------------------------------------------------- | | name | string | Required | The organisation's name, written into the document as given | | url | readonly string[] | Required | Each address a consumer can reach the organisation at |

Note: serialNumber and timestamp are the only two fields that differ between two builds of the same source. Every list in the document is sorted, so leaving both off makes a build reproducible byte for byte.

Reference

| Export | Signature | What it returns | | --------- | --------------------------------------------------------------- | ----------------------------------------------------- | | sbom | (stated?: Described) => Plugin | A plugin that emits the document alongside the bundle | | written | (stated: Described, bundling: Bundling, at: string) => string | The serialised document for one build |

The bundler knows the plugin as stealth:sbom and calls it at generateBundle, after the module graph is complete and before the output is written. written does the same work without a bundler around it, taking the build context that hook receives as bundling and the directory of the package being described as at. Described and Supplier are exported as types, and the preceding tables list their fields.

The document

  • Components. Each installed package the build imported from appears once, typed as a library. The edges between them are drawn from the module graph the components themselves came from.
  • Metadata. The subject is built from the described package's manifest, under the build lifecycle phase. The tool list records the vite and rolldown versions read at run time, together with every devDependency of the described package that resolves.
  • Licence evidence. A licence or copying file in a package's top directory is attached to its component as base64 text, beside the expression its manifest declares. An expression SPDX does not define is recorded as a name instead.
  • Integrity and origin. A digest the lockfile pinned becomes the component's hash, and a source other than the default registry becomes a vcs_url or repository_url qualifier on the package URL. The search reads bun.lock first and pnpm-lock.yaml second, from the nearest directory above the package that has either one.

A missing manifest, an unreadable lockfile and a digest nothing can parse each cost the document detail rather than failing the build.

Licence

MIT. See LICENSE.