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 🙏

© 2025 – Pkg Stats / Ryan Hefner

cpconfig

v1.4.4

Published

A simple zero dependency utility to manage configuration files for node projects across your organization

Readme

cpconfig

cpconfig is a tiny toolkit that keeps project-specific configuration files in sync with disk. Give it the list of files you care about, and it will write them, ensure parent directories exist, and maintain a clearly marked block inside .gitignore.

The goal is to provide the ergonomic bootstrap experience of tools like coconfig without any custom module loading or complicated configuration layering—just code.

Features

  • Deterministic sync – Declare files and their contents, cpconfig handles creation and updates.
  • Managed .gitignore block – Automatically keeps tracked configs out of git with a dedicated annotated section.
  • Safe by default – No implicit imports or magic; works with plain TypeScript/JavaScript data.
  • Dry runs – Compute what would change without touching the file system.

Installation

yarn add @sesamecare-oss/cpconfig
# or
npm install @sesamecare-oss/cpconfig

Programmatic usage

import { syncConfigs } from '@sesamecare-oss/cpconfig';

await syncConfigs(
  {
    'config/.env.local': {
      contents: 'API_TOKEN=abc123',
    },
    '.secrets.json': {
      contents: () => JSON.stringify({ key: 'value' }, null, 2),
    },
  },
  {
    rootDir: process.cwd(), // optional, defaults to process.cwd()
  },
);

The call above writes the files if necessary and maintains this .gitignore block:

# Managed by cpconfig
config/.env.local
.secrets.json

Run the function as many times as you like—it is idempotent and only touches files when their content changes.

Package-driven configuration

Most projects keep their file definitions in a dedicated module and call the bundled CLI as part of postinstall:

{
  "name": "my-project",
  "scripts": {
    "postinstall": "cpconfig"
  },
  "config": {
    "cpconfig": "./cpconfig.config.mjs"
  }
}

The CLI walks up from the current working directory, finds the nearest package.json, and reads the config.cpconfig entry. The value must be a string pointing at a module—top-level cpconfig keys or inline objects are rejected. cpconfig resolves the module using standard Node.js rules and expects it to export one of:

  • a default or named config object with { files, options };
  • a plain object map of files;
  • a factory function (sync or async) returning either of the above.

Factory functions receive two arguments: the entire package.json config object (so you can read sibling settings) and the raw CLI argument array (e.g. ['--json']). Use them to branch on runtime options or shared configurations.

For example, cpconfig.config.mjs might look like:

export default {
  files: {
    'config/.env.local': { contents: 'API_TOKEN=abc123' },
    '.secrets.json': { contents: '{\n  "key": "value"\n}' },
  },
};
  • Run npx cpconfig manually whenever you need to refresh files.
  • Add cpconfig to postinstall to keep developer machines in sync automatically.

Options

| Option | Type | Default | Description | | --- | --- | --- | --- | | rootDir | string | process.cwd() | Base directory used to resolve all config paths. | | dryRun | boolean | false | When true, compute the diff without writing to disk. | | encoding | BufferEncoding | 'utf8' | Encoding used when reading and writing files. | | gitignorePath | string | <rootDir>/.gitignore | Custom location for the managed gitignore file. |

Each config file can optionally set gitignore: false to opt out of the managed block, or provide a mode (integer) that is applied when the file is first created. Add a sentinel string to embed your own marker inside the file (for example // @cpconfig or <!-- cpconfig -->). cpconfig only rewrites files that include their sentinel, so you never clobber hand-crafted files. Make sure the string appears in the requested contents. When an existing file is missing its sentinel, cpconfig leaves it untouched and prints a warning explaining why.

Result object

syncConfigs resolves with a structured result describing what happened:

const result = await syncConfigs(files);

result.files; // [{ path: 'config/.env.local', managed: true, action: 'created', gitignored: true }, ...]
result.gitignore; // { updated: true, added: ['config/.env.local'], removed: [] }

Use this information to log progress, emit metrics, or drive prompts.

CLI options

cpconfig --help

Options:
  --dry-run             Compute changes without writing files
  --json                Print the sync result as JSON
  --root <path>         Override the root directory used for file writes
  --gitignore <path>    Override the gitignore file path
  --config <path>       Load configuration from an explicit JSON file
  --help, -h            Show this message

Dry runs

Combine dryRun: true with the result payload to surface pending configuration changes without touching disk:

const preview = await syncConfigs(files, { dryRun: true });

if (preview.gitignore.updated || preview.files.some((file) => file.action !== 'unchanged')) {
  console.log('Configuration out of date. Run cpconfig to apply changes.');
}

License

UNLICENSED – tailor to your organisation’s distribution policy before publishing.