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

@dbx-tools/projen

v0.6.211

Published

Downloads

6,966

Readme

@dbx-tools/projen

Projen engine for dbx-tools pnpm workspaces.

Import this package from .projenrc.ts when a repository should discover packages from the filesystem and generate manifests, tsconfigs, barrels, OpenAPI clients, codegen outputs, and release tasks.

Key features:

  • Filesystem package discovery: every src-bearing folder under configured workspace roots becomes a TypeScript package.
  • Tag-driven runtime defaults for shared libraries, Node packages, CLIs, servers, OpenAPI clients, and React/Vite UI packages.
  • Generated package manifests, tsconfigs, package-root barrels, Vite configs, pnpm workspace/catalog files, and VS Code settings.
  • Extensible mixin system so repositories can add deps, tasks, or generated files based on package predicates.
  • OpenAPI client generation from tsoa controllers and zod schema generation from .d.ts inputs.
  • Read-only generated-file stamping, cleanup, and watch-loop helpers.

Define A Workspace Root

import { project as projenProject } from "@dbx-tools/projen";

const project = new projenProject.DBXToolsNodeProject({
  name: "my-apps",
  scope: "my-apps",
  packageRoots: ["packages", "examples"],
});

project.synth();

Every src-bearing folder under the configured roots becomes a DBXToolsTypeScriptProject. Folder path drives package name and runtime tags.

Dependency installation runs once from this root. The default-on ROOT_INSTALL_ONLY_MIXIN clears child install / install:ci task steps during root pre-synthesis, including packages attached after root construction. Set rootInstallOnly: false only when a repository intentionally wants projen's per-project installation behavior.

The engine treats generated barrels, tests, declaration files, and folders without exported source modules as implementation details. They do not create new package membership.

Add A Python uv Workspace

DBXToolsPythonWorkspace attaches Python packaging to an existing projen root without turning Python packages into JavaScript workspace projects. It generates the root and member pyproject.toml files, standard py:* tasks, the VS Code interpreter setting, and an optional manual PyPI trusted-publishing workflow. Every generated TOML file is parsed and reserialized with smol-toml, so nested tables and arrays use consistent formatting instead of projen's indented table headers.

import { project, projectPy } from "@dbx-tools/projen";

const root = new project.DBXToolsNodeProject({ name: "my-apps" });

new projectPy.DBXToolsPythonWorkspace(root, {
  root: "python/packages",
  packages: [
    {
      directory: "core",
      description: "Shared Python helpers",
    },
    {
      directory: "service",
      description: "Python service",
      internalDependencies: ["core"],
    },
  ],
  release: true,
});

Distribution names and modules come from the parent scope plus each package directory. The repository comes from the parent project metadata or Git remote. internalDependencies renders standalone Git #subdirectory= requirements without repeating repository coordinates. Pass repository, name, or module only to override those conventions. root.vscode is projen's existing VS Code component; dbx-tools reuses it rather than constructing a second .vscode/settings.json owner.

Add A Rust Workspace

DBXToolsRustWorkspace discovers every source-bearing folder under its configurable root (default packages/rs), generates its Cargo manifest, and derives the crate name and repository from the parent project. A crate containing uniffi::setup_scaffolding!() automatically wires matching public Node and Python binding packages using the <name>-rs folder suffix. Node packages are named @<scope>/<name>-rs; Python distributions are named <scope>-<name>-rs and import generated values from <scope>.<name>_rs.bindings. Binding packages are always dedicated and never merge generated code into handwritten Node or Python packages. Repository-specific dependencies and features remain declarative options in .projenrc.ts; generated bindings are built separately from projen synthesis. Target-independent Node binding TypeScript is committed and remains generated/read-only, while native libraries stay ignored. Node facades compile to lib/ and publish JavaScript entry points that plain Node can load from node_modules. A complete bindings.ts / _bindings.ts / _bindings-ffi.ts triplet is exported directly from the generated package barrel. Python keeps bindings.py as the generated implementation and leaves __init__.py empty. Node generation fails when direct binding names conflict. Do not create a nodeExports binding subpath or a handwritten type facade.

Rust dependencies between binding-enabled workspace crates become Node workspace:* and Python internalDependencies automatically. Python generation selects the owning crate and supplies external_packages imports. UBRN currently emits every linked component; the generation task discards dependency outputs and rewrites their imports to the owning package root, including its generated uniffiModule converter table. It never copies a dependency's records or enums. Foreign callback adapters must first be wrapped in an object created by their own native library (createStorageHandle for auth), because callback registries are library-local. Release wheels replace sibling Git requirements with matching native-wheel versions, and dependent publishers wait for their dependencies. Each crate builds its own <crate>-uniffi-bindgen executable so a workspace build has no colliding binary outputs. Packaging runs that prebuilt executable.

sync --watch runs a focused Rust watcher beside the OpenAPI watcher. Changes inside an existing UniFFI crate regenerate that crate and its dependent bindings in dependency order; adding or removing a crate or setup_scaffolding!() marker triggers a full synth. Repos without Rust crates start no Rust watcher. When Rust projects are detected, Cargo is required and the focused task fails immediately if it is unavailable. rs:bindings is explicit rather than part of root pre-compile, so ordinary JavaScript PR builds type-check committed generated bindings without performing a host Rust build. Regenerate bindings through the focused watcher or explicit task while changing a UniFFI API. Release preparation runs Cargo workspace tests without invoking UBRN.

The workspace generates one release.yml workflow for every ecosystem. A push to the configured release branch starts it only when VERSION changed. The context job requires the version to differ from its parent and exceed the latest tag, creates the corresponding annotated v* tag, and exposes the verified tag, commit, and version to every source job. If the tag already exists, it must be annotated and reference the same commit. A manual run accepts that same tag and commit but requires dry-run mode, so it builds and validates without publishing packages or deploying documentation. One non-cancelling release concurrency group serializes publication.

Release generation writes release.yml without scanning for or removing other workflow files. Consumers explicitly delete exact workflow files they no longer want.

Failed-job reruns consume successful Rust artifacts from the same workflow run. For a separate recovery run, choose node, python, or docs instead of all. Node and Python recovery can supply the prior release.yml run ID; the workflow verifies that run used the commit selected by the annotated release tag before downloading its artifacts. Dispatch the workflow with the release tag as its Git ref so recovery checks out the immutable release boundary. Manual recovery defaults to dry-run and publishes only when dry_run is cleared. npm retries skip an exact version only after the local archive integrity and repository identity match registry metadata. PyPI retries enable Twine's hash-aware existing-file behavior, which skips matching files and fails when an existing filename has different content.

The Rust matrix has one row per target. Each row installs native dependencies, builds the Cargo workspace once, then packages every discovered output from that shared build. Set a source-only crate's or release-enabled binary's releaseExcludeOs package option to omit it from incompatible rows through Cargo --exclude. Release binary packaging and artifact upload are skipped in those rows. UniFFI crates cannot use this option because every configured target must produce their artifacts. Set a release binary's cli package option and the workspace cliRegistryPath to generate a typed dbx command registry from the same selected targets. The generated entries carry only the archives that the release matrix publishes, so an excluded operating system fails locally before any download is attempted. The runtime command uses @dbx-tools/core bin.ensure; the core installer itself contains no product registry. Rust rows prepare native npm archives and Python wheels; they do not install Bun or UBRN and do not build Node facades. A binary-only row therefore installs no language package tool. rustVersion remains the MSRV recorded in package manifests, while releaseRustVersion independently defaults release compilation to stable. Stable Windows rows verify and use the hosted runner's installed Rust toolchain and select rust-lld for the workspace build. Rust release rows restore and update dependency-only Cargo caches in the release branch's cache scope. The cache key excludes workspace version changes, and manual tag recovery restores without saving a tag-scoped copy. There is no separate cache workflow or sccache layer. Phase timings are written to each build log. Python generation executes the already-built target/<triple>/release/<crate>-uniffi-bindgen directly. Artifact packaging therefore does no Rust compilation after the main workspace build.

Artifacts identify their crate, target, and type. Rust jobs publish non-private Cargo crates with cargo publish --no-verify and upload requested binary assets to the GitHub release. Rust jobs never publish npm or PyPI packages.

Set LOCAL_CARGO_REGISTRY to a named Cargo registry such as a loopback Kellnr instance and provide LOCAL_CARGO_TOKEN. Public Cargo crates also publish directly to crates.io with CARGO_REGISTRY_TOKEN. Override releaseTargets only when a consumer has additional native runners; ordinary projects inherit the maintained matrix automatically. bun run release also accepts repeatable --os and --arch selectors; every selected operating system is crossed with every selected architecture. Omit both filters to regenerate the complete maintained matrix. DBX_TOOLS_RELEASE_PLATFORMS can select the generated matrix without repeating environment parsing in a consumer.

Public UniFFI facades are marked with dbxToolsConfig.uniffi = true in Node manifests and [tool.dbx_tools.config] uniffi = true in Python manifests. The Node jobs consume same-run artifacts, publish native archives first with npm provenance, compile and publish normal workspace packages including the Projen engine, then build facades from committed generated TypeScript without UBRN and publish them in binding dependency order. Local Verdaccio publication does not enable provenance. Set the UNIFFI_FACADE_SMOKE repository variable to true to run the optional nonblocking registry install and import check after facade publication. Python combines same-run platform wheels with standard wheel and source builds, then publishes each distribution through its own PyPI trusted-publisher environment. Binding publishers wait for their dependencies. Trusted-publisher instructions name release.yml and the release branch policy. The docs jobs generate README and TypeScript API content and deploy GitHub Pages from the same workflow. When a conventional Node binding path already belongs to a root subproject, Rust mapping reuses that project and adds binding dependencies and metadata to its existing manifest.

Customize Packages With Mixins

import { project as projenProject } from "@dbx-tools/projen";

const project = new projenProject.DBXToolsNodeProject();

projenProject.applyToProjects(project, { tags: "shared" }, (pkg) => {
  pkg.addDeps("zod@catalog:");
});

project.synth();

Use projectJs.addOptionalPeer(pkg, specifier) for an optional peer that must also resolve during local development. It writes the peer metadata and matching development dependency without turning the peer into a runtime dependency.

applyToProjects AND-s its globs (prefix a glob with ! to negate) into one predicate over the DBXTools child packages, then applies it as a constructs mixin across the subtree. Filter on the folder (path), the tags (tags), or the name from whichever angle fits: name matches the raw projen name verbatim, while identifierPackageName, identifierScope, and identifierName match the parsed @scope/name, its scope, and its unscoped half. Two flags widen the selection past DBXTools children - includeRoots for the tree root and includeNonDBXToolsProjects for plain projen projects (which widens the callback parameter to Project). Drop to mixin.create(predicate, fn) + project.with(...) only when you need a predicate the filters cannot express.

Built-in tag mixins set runtime defaults for shared, node, cli, server, ui, and openapi. Repo-specific mixins layer package-specific dependencies, scripts, and generated files on top.

A tag layers over a shared compiler floor every package gets at construction: ES2022 plus the web-platform globals available in every runtime, and deliberately no DOM lib and no Node types, so agnostic code stays isomorphic. The tags are what add an environment on top - node adds Node types, ui adds the DOM lib. That floor is also where jsx lives, for a reason worth knowing before moving it: packages resolve each other to SOURCE, so a consumer type-checks its dependency's files under its own tsconfig. The moment any package re-exports a .tsx module, every package that imports it - however far down the graph, whatever its tag - fails with TS6142: ... but '--jsx' is not set. Setting jsx per consumer is the wrong fix, since the consumer authors no JSX and cannot know a transitive dependency started to. The option is inert without JSX in the graph: it selects how JSX syntax compiles and adds no lib, global, or type dependency.

Work With Package Discovery

import { packages } from "@dbx-tools/projen";

const discovered = packages.scanPackages(process.cwd(), ["packages"]);
const recorded = packages.recordedPackages();

scanPackages() reads the filesystem during synth. recordedPackages() reads the generated pnpm-workspace.yaml plus package manifests for post-synth tools. Use the latter for docs, linting, and release checks that should match the recorded workspace.

Generate Barrels And Codegen

import { barrels, codegen } from "@dbx-tools/projen";

codegen.generateCodegen();
barrels.generateBarrels();

generateCodegen() reads package.json codegen.inputs and writes generated schema modules. They are written read-only, and the root ESLint task runs with --fix (which fails on a read-only file), so each generated module is added to ignorePatterns at synth - named individually via codegen.codegenModulePaths(), never as a blanket <package>/src/**. A codegen package may hold hand-written modules beside its generated ones, and those must stay linted.

generateBarrels() writes package-root index.ts barrels with module namespaces, flat unique type exports, PACKAGE_IDENTIFIER, and PACKAGE_VERSION, returning the number that actually changed. A name two modules both declare is ambiguous and stays namespace-only — except when one of them is generated: the hand-written module is the curated view of the generated shape (shared-genie's genie-model.ts extends its own codegen'd dashboards.ts), so it owns the name and stays hoisted. A barrel whose export surface is unchanged is left untouched, read-only bit included, so concurrent writers never collide over it. Every package is attempted even if one fails; the failures are re-thrown together as an AggregateError naming each package, rather than the first one abandoning the rest of the sweep.

Generate OpenAPI Clients

import { openapi } from "@dbx-tools/projen";

const packages = await openapi.generateOpenapi();

OpenAPI generation scans packages for tsoa controllers, emits openapi.json, generates TypeScript schemas, and adds an openapi-fetch client.

Configure pnpm Catalogs

project.pnpmWorkspace?.addCatalog("react", "^19");
project.pnpmWorkspace?.allowBuild("esbuild");

projen's native javascript.PnpmWorkspaceYaml writes pnpm-workspace.yaml; pnpmWorkspace.PnpmWorkspaceState supplies the options it renders and tracks package members, catalog entries, and build-script allowances. Any other pnpm setting goes through the root's workspaceYaml option, which is projen's typed PnpmWorkspaceYamlOptions:

new DBXToolsNodeProject({ workspaceYaml: { overrides: { glob: "^13.0.0" } } });

allowBuild writes pnpm's allowBuilds map rather than projen's own allowScripts option, which for pnpm renders onlyBuiltDependencies - a key current pnpm does not read, so the list would leave every build script skipped. Only allowances are declared; a dependency that is never allowed needs no entry, because pnpm warns and moves on.

The engine also applies catalogMode: manual (keeps pnpm add out of the generated catalog) and verifyDepsBeforeRun: warn. The file is emitted for the tree ROOT only; a member package never gets a nested one.

Clean And Watch Generated Files

import { clean, watch } from "@dbx-tools/projen";

const generated = clean.listGeneratedFiles();
watch.watchLoop({
  roots: watch.watchRoots(),
  onChange: async (files) => console.log(files),
});

Use these modules for maintenance tasks that should follow the same generated file contract as the CLI.

Modules

  • project - DBXToolsNodeProject, DBXToolsTypeScriptProject, package naming, compiler/task helpers.
  • mixin / projectPredicate - constructs mixin factory and package predicates.
  • tags - built-in runtime tag mixins and compiler floors.
  • packages - filesystem discovery and recorded package metadata.
  • pnpmWorkspace - generated pnpm workspace file and catalog model.
  • barrels / moduleExports - public entrypoint generation.
  • codegen - .d.ts to zod schema generation.
  • openapi - tsoa/OpenAPI package generation.
  • bunApp / tsconfig / vscode - generated support files/components.
  • generated / clean / watch / scaffold - read-only file stamping, cleanup, watchers, and synth orchestration.
  • publish - packaging and tag-based release helpers.
  • engineRoot - engine package root resolution for bootstrapped repos.

The engine registers its commands as projen tasks on the workspace root, so run them with bun run <task> - sync (add --watch), barrels, openapi, and clean. @dbx-tools/cli is only needed to bootstrap a folder that has no .projenrc.ts or toolchain yet.

Run Tasks From The ROOT

Every repo-wide task lives on the root, and the root's compile / test delegate with bun run --filter '*' rather than emitting a step per member - so a new package is covered without a re-synth. Work from the root:

| Task | What it does | | ----------------------- | ------------------------------------------------------- | | bun run build | synth + workspace compile and tests | | bun run compile | tsc --build in each member, in parallel | | bun run test | eslint once, then each member's tests | | bun run sync | re-synth (--watch to keep synthing) | | bun run barrels | regenerate the read-only index.ts barrels | | bun run bump | increment VERSION and synchronize generated versions | | bun run version:check | verify every version surface matches VERSION | | bun run release | run full local preflight and open a reviewed release PR |

release commits pending work on the current branch, merges the latest remote release branch when needed, and pushes it. It prepares the dedicated release/v<version> branch inside .worktrees/<tag>, leaving the source checkout on its current branch throughout validation, local publication, and PR creation. Failed preparation can resume from that worktree; success removes it. --message sets the source commit message. The task never merges the PR unless --approve is passed; that option merges the release branch directly through GitHub's merge API so no PR checks are created. A repository that blocks direct merges falls back to an immediate admin-merged PR. The task then fast-forwards the still-active source branch to the release commit. npm uses npm config get registry and publishes to a local Verdaccio automatically. Publishable JavaScript members compile once from the root in parallel, then upload through a bounded pool without rerunning their prepack tasks. Python prefers uv's default index and only treats a loopback .../+simple/ URL as writable devpi; a read-only cache such as proxpi (.../index/) is deliberately ignored. The task stamps every Python member and its sibling dependencies to the release version, builds the workspace with uv, then runs devpi upload --from-dir against the derived writable index. The npm and Python mirrors run concurrently because they touch disjoint package trees. Devpi client authentication remains in its normal ~/.devpi state.

Use --local-registry false or --local-pypi false to disable either local publish. An explicit --local-pypi http://localhost:3141/user/index/ overrides auto-detection; --python-root defaults to packages/py.

The GitHub PR workflow runs synth plus the workspace TypeScript compile rather than the complete root build. Release preparation has already run Rust tests, workspace type-checking, and local package preflight before opening the PR. JavaScript behavior tests remain an explicit developer task.

The configured release branch publishes only when a reviewed PR changes VERSION. Its workflow creates the annotated v* public release boundary. Available workflow stages form the generated chain Rust -> Python -> Node -> docs: Rust builds and publishes native artifacts and Cargo crates, Python publishes standard distributions, Node publishes standard workspace packages, and docs deploys after publication. A stage with no corresponding outputs is omitted.

Members intentionally keep only the tasks that something OTHER than a human invokes, so there is no second place to run the same thing:

  • compile / test - what the root's --filter '*' delegation calls.
  • prepack - standalone-publish safety that compiles one package before packing (27 of 33 members; the workspace release driver compiles them from the root and publishes with lifecycle scripts disabled).
  • watch - a single-package tsc --build -w, for narrowing a long edit/compile loop to one package.
  • build / package - a complete compile/test/pack lifecycle when invoked in one package. Release preparation validates through the root's filtered tasks, and publication uses concurrent bun publish --ignore-scripts. The package phase also packs with --ignore-scripts because its build already compiled; prepack remains available for a standalone publish that did not run build first.
  • install / install:ci / default / pre-compile / post-compile - projen's lifecycle scaffolding, emitted for every member because its task model expects them.

Do NOT run projen default (or bunx projen) from inside a member. Synth is a whole-tree operation driven by the ROOT .projenrc.ts, so a member-level run re-synths the entire workspace from the member's directory. Run bun run sync from the root instead.

Versioning

The whole repo shares ONE version, stored in the root VERSION file (a plain x.y.z string; a fresh tree with no file defaults to 0.0.1). Synth COPIES that value into every generated manifest - the root and projen/ package.json, every JS member, every Python pyproject.toml, the generated openapi packages, and the example apps - so the packages, the engine, and the examples always match. src/workspace-version.ts owns reading and writing it. Synth only ever reads it; it never resets, upgrades, or downgrades a version on its own.

bun run bump is the only command that changes the number: it fetches remote tags once, takes the highest v* tag as the base, increments by --level, writes VERSION, then synths so every manifest copies it. It has no git or publication side effects. bun run release invokes it while preparing the reviewed release PR. The remote is consulted only on bump and on one-time creation of a missing VERSION file, never on an ordinary synth.