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

@taraxvoid/voidflow

v0.11.1

Published

Shared workflows, actions and tooling for @taraxvoid sites

Readme

voidflow

Shared CI and deploy pipeline for a small fleet of Astro sites on Cloudflare Workers. One set of reusable GitHub Actions workflows and composite actions keeps lint, type checks, license policy, Playwright and axe-core accessibility tests, Unlighthouse budgets, and deploys identical across every site.

  • SHA-pinned. Every third-party action in this repo is pinned to a full commit SHA with a version comment.
  • Audited. Workflows are checked with zizmor, actionlint, check-jsonschema and shellcheck on every change (see Self-validation).
  • In production. It runs the pipelines for the sites listed under Used by, including the marketing site for RavenFlight Industries, LLC.

It is semi-opinionated: the defaults match how my own sites are built (bun, Astro, Playwright).

Used by

Usage

Point uses in your configuration at a workflow, e.g. in your .github/workflows/ci.yml. Pin to a release commit SHA with the version in a comment, the same way you would any third-party action (see Versioning).

name: CI
on:
  pull_request:
    branches: [main, next, live]
    types: [opened, synchronize, reopened, ready_for_review]
  workflow_dispatch:

jobs:
  validate:
    uses: taraxvoid/voidflow/.github/workflows/site-ci.yml@15caea203066d42cb7be021eedb6356fac6ffdec # v0.8.1

Non-GitHub / self-hosted runners

Pass runner (defaults to GitHub runner ubuntu-latest)

jobs:
  validate:
    uses: taraxvoid/voidflow/.github/workflows/site-ci.yml@15caea203066d42cb7be021eedb6356fac6ffdec # v0.8.1
    with:
      runner: my-hosted-runner

Single-environment sites

Sites with one production environment and no next/live branches (main deploys to prod, pull requests get previews) pass single-environment: true, the same flag resolve-env and branch-env-map take:

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
    types: [opened, synchronize, reopened, ready_for_review]
  workflow_dispatch:

jobs:
  validate:
    uses: taraxvoid/voidflow/.github/workflows/site-ci.yml@<sha> # <version>
    with:
      single-environment: true

main then gets the production test tier (test:e2e:all, test:e2e:a11y, test:e2e:lighthouse) instead of only test:e2e:full. Include the push trigger so a direct push to main is validated too; the e2e steps resolve the branch from the pushed ref.

pnpm sites, build env, extra e2e paths

jobs:
  validate:
    uses: taraxvoid/voidflow/.github/workflows/site-ci.yml@<sha> # <version>
    with:
      package-manager: pnpm # default: bun
      e2e-extra-paths: '["wrangler.jsonc", "site.vars.json"]' # JSON array of globs
      build-env: ${{ format('{{"PUBLIC_SITE_URL":"https://example.com","GIT_SHA":"{0}"}}', github.sha) }}

With pnpm, the pnpm version comes from packageManager and Node from volta or engines in package.json. The lockfile (bun.lock or pnpm-lock.yaml) follows the package manager. build-env is a JSON object, visible in logs, so no secrets.

Workflow Types

Validation / Checks

Runs lint, typecheck, check for GPL licenses, e2e with Playwright.

site-ci.yml runs these package.json scripts: lint, check, build, test:unit, check:licenses, test:e2e:full (PRs into main), test:e2e:all (PRs into next and live), test:e2e:a11y (next and live), and test:e2e:lighthouse (live). A script the site does not define is skipped with a notice, so none of them is required.

Unlighthouse (performance / SEO budgets)

site-ci.yml runs bun run test:e2e:lighthouse on PRs into live. Sites implement that script with the shared runner here, which serves the built static directory on a free port and runs Unlighthouse against it, reusing Playwright's Chromium. It exits non-zero if a category budget in the site's config fails.

In the site's package.json (pin the tag):

"test:e2e:lighthouse": "bun run build && bunx --package @taraxvoid/[email protected] unlighthouse-runner --dir dist"

Options: --dir (default dist, use dist/client for Cloudflare adapter builds), --config (default unlighthouse.config.ts), --version (pinned Unlighthouse version). Start from scripts/unlighthouse/unlighthouse.config.example.ts and add .unlighthouse/ to the site's .gitignore.

License policy

site-ci.yml runs bun run check:licenses when the lockfile or scripts/ change. Sites implement that script with the shared check, which runs license-checker in the site's repo root and fails on GPL, AGPL, SSPL and similar copyleft licenses (LGPL is allowed).

In the site's package.json (pin the tag):

"check:licenses": "bunx --package @taraxvoid/voidflow@<version> check-licenses"

Playwright preview config

Shared playwright.config for Astro sites that run e2e against astro preview. It picks a free port outside CI, sets ASTRO_PREVIEW_BACKGROUND=false (Astro backgrounds preview in agent environments, which makes Playwright think the server exited), and drops the webServer when PLAYWRIGHT_BASE_URL is set.

bun add -d @taraxvoid/voidflow   # or: pnpm add -D @taraxvoid/voidflow
// playwright.config.js
import { definePreviewConfig } from '@taraxvoid/voidflow/playwright'

export default definePreviewConfig({ ciPort: 4141 })

The same release is also published unscoped as voidflow (identical code and version, with a short pointer README), so bun add -d voidflow and import ... from 'voidflow/playwright' work too. @taraxvoid/voidflow is the canonical name.

Options: ciPort (required in CI), runner (default bun, e.g. pnpm), timeout (default 30000), projects (default Pixel 7 and Desktop Chrome), testDir (default ./test/e2e). Requires @playwright/test in the site.

Dependency updates (Renovate)

default.json is the shared Renovate preset. Sites add a renovate.json:

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": ["github>taraxvoid/voidflow"]
}

It builds on config:best-practices (which pins GitHub Action digests), holds updates for 3 days like minimumReleaseAge in bunfig.toml (except our own package and security alerts), uses chore(deps): Conventional Commits, groups actions, astro, biome and playwright, and runs on Monday mornings. Custom managers keep three things current that Dependabot cannot see: the @taraxvoid/[email protected] pin inside package.json scripts, a lefthook remote's ref tag, and tool versions in a justfile (annotate the line above with # renovate: datasource=... depName=...). Requires the Renovate GitHub App on the repo.

||||||| 4041a59

Git hooks (lefthook)

lefthook/site.yml is the shared hook set for the site stack, consumed as a lefthook remote. It calls the site's own package.json scripts (bun run --if-present, so a missing script is skipped):

  • pre-commit: dependency guard, format (formatted files are re-staged), lint:actions, check, test:unit, and check:licenses / audit when the lockfile changed.
  • commit-msg: advisory Conventional Commits hint (never blocks).
  • pre-push: bail if the remote branch is ahead, then test:push; skipped when there is nothing new to push.
# lefthook.yml in the site
remotes:
  - git_url: https://github.com/taraxvoid/voidflow
    ref: v0.10.0 # a tag or branch; lefthook passes it to `git clone --branch`
    configs:
      - lefthook/site.yml

Lefthook merges lefthook.yml, then remotes, then lefthook-local.yml, so a site's own lefthook.yml can add commands (for example image compression) but cannot override ones defined here. Differences go through package.json scripts: define test:unit:precommit (for example excluding tests that need a built dist/) and the pre-commit unit step runs it instead of test:unit.

Install the binary through mise (lefthook = "<version>" in mise.toml) and set "prepare": "lefthook install" so bun install wires the hooks. ref cannot be a commit SHA; pin a release tag.

Branch rulesets as code

Branch protection for the fleet lives in rulesets/index.ts: one canonical main / next / live definition (plus prerelease and maintenance tiers for repos with release channels) and a small per-repo table (Netlify or not, check names, CODEOWNERS, extra bypass actors). Hand-edited rulesets drift, and drift is how a next ruleset ends up requiring a check name that no workflow reports any more.

just rulesets-plan                  # read-only: diff every repo against the config
just rulesets-plan --repo soundry
just rulesets-plan --check          # exit 1 on drift, for CI
just rulesets-apply                 # create/update rulesets to match
just rulesets-apply --prune         # also delete rulesets a repo lists under `retire`

Single-environment sites (a stable main that deploys to prod) manage only the main tier; their old next/live rulesets are listed under retire. voidflow itself manages main, prerelease (next) and maintenance (release/*) and sets linearHistory: false so next can be promoted into main with a merge commit. Uses the gh CLI for auth (needs admin on the repos). Rulesets that are not in the config are reported and left alone; only retire entries are ever deleted, and only with --prune. It is repo tooling, not part of the published package.

Deployments

Example deployment job added to your workflow above. resolve-env maps the branch to dev/staging/prod once, up front, so its output can be used both to drive the deploy and to label the job (Deploy [dev], Deploy [staging], Deploy [prod]). A job's name: can reference needs.<job>.outputs.* but not a step output from within itself, hence the split:

jobs:
  resolve-env:
    needs: validate
    if: github.event_name == 'push'
    uses: taraxvoid/voidflow/.github/workflows/resolve-env.yml@15caea203066d42cb7be021eedb6356fac6ffdec # v0.8.1

  deploy:
    name: Deploy [${{ needs.resolve-env.outputs.env }}]
    needs: resolve-env
    if: github.event_name == 'push'
    environment: ${{ needs.resolve-env.outputs.env }}
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: taraxvoid/voidflow/actions/cloudflare-deploy@15caea203066d42cb7be021eedb6356fac6ffdec # v0.8.1
        with:
          env: ${{ needs.resolve-env.outputs.env }}
          cloudflare-api-token: ${{ secrets.CLOUDFLARE_API_TOKEN }}

Sites with a single production environment and per-PR previews (no next or live branch) pass with: { single-environment: true } to resolve-env.yml (or the same input on actions/branch-env-map). main then maps to prod and pull_request events map to preview; any other ref fails.

Versioning

Semver, released with release-please (release-please.yml) on three branch-based channels (full flow in RELEASING.md):

| Channel | Branch | Example | npm dist-tag | |---|---|---|---| | stable | main | 0.10.0 | latest | | prerelease | next | 0.10.0-next, 0.10.0-next.1 | next | | maintenance | release/N.x | 0.9.4 | release-N.x |

release-please keeps a standing release PR open on each channel's branch, updated as commits land. Merging it bumps package.json (and CHANGELOG.md on stable), tags vX.Y.Z, creates the GitHub release and publishes to npm and JSR under the channel's dist-tag. The PR is opened with the org's release-bot GitHub App token (RELEASE_BOT_CLIENT_ID / RELEASE_BOT_APP_PRIVATE_KEY) so CI runs on it.

Feature PRs target next; promotion to main is a merge-commit PR (just promote).

Commit messages should follow Conventional Commits, enforced loosely, as an advisory commit-msg hint (see scripts/check-commit-msg.sh), not a blocking check. They drive the version bump and generated changelog.

Ways to consume a release:

  • Floating major tag: @v0 follows the newest stable 0.x release. Easiest to track, and mutable like any floating tag.
  • SHA pin with a version comment, e.g. @15caea2... # v0.8.1: what I use. Same hardening as any third-party action, and Renovate or Dependabot can bump it.
  • Try unreleased changes: pin the commit SHA of a vX.Y.Z-next / vX.Y.Z-next.N prerelease tag.

Treat @main and @next as unstable.

Self-validation

This repo validates its own workflows and composite actions (.github/workflows/ci.yml):

  • actionlint: workflow schema/logic; also shellchecks run: steps in .github/workflows/*.yml automatically (shellcheck ships on ubuntu-latest)
  • check-jsonschema: schema-checks actions/**/action.yml and the workflow files against SchemaStore's github-action.json / github-workflow.json
  • shellcheck (scripts/shellcheck-actions.ts): checks run: steps inside actions/**/action.yml, which actionlint doesn't reach
  • zizmor: security audit (unpinned refs, script injection via ${{ }} in run:, excess permissions, etc.)

Local dev setup

brew install just lefthook actionlint shellcheck bun act uv
lefthook install
  • just validate: run everything CI runs, locally
  • just lint-workflows / lint-actions / lint-shell / security: run one check at a time
  • just dry-run: full local run of ci.yml via act (needs Docker running); pass extra args, e.g. just dry-run -j validation
  • lefthook runs the fast checks (lint-workflows, lint-actions, lint-shell) on pre-commit, and zizmor on pre-push

Colima users: .actrc already disables the docker-socket mount (--container-daemon-socket -). act binds /var/run/docker.sock by default, which doesn't exist under Colima and fails with operation not supported. None of these workflow steps need docker-in-docker, so this is safe.

Run just dry-run from a normal checkout, not a linked git worktree. act copies the working tree via docker cp rather than a real clone, so a worktree's .git pointer back to the parent repo doesn't resolve inside the container, so git ls-files-based steps (schema validation, scripts/shellcheck-actions.ts) silently see zero files instead of erroring. Verified clean end-to-end (🏁 Job succeeded) from a plain clone.

Provided as is under the MIT license. Issues and pull requests are welcome.