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

@adaptive-ds/project-registry

v0.8.1

Published

Machine-wide Git-backed project registry with CLI and daemon entry points.

Readme

@adaptive-ds/project-registry

A project model for the machine-wide Adaptive Project Registry.

Package name follows the rest of the stack: @adaptive-ds/ plus the folder name.

Install

bun add @adaptive-ds/project-registry

Usage

import { projectList, projectNormalize } from "@adaptive-ds/project-registry"

const normalized = projectNormalize({
  owner: "david",
  name: "project-registry",
  description: "Adaptive project catalog",
})
if (!normalized.success) return normalized

console.log(projectList([normalized.data]).data.map((project) => project.name))

Project identity is the (owner, name) pair. Normalization validates the combined registry and Caddy model, and listing applies deterministic Software-compatible ordering. Fallible operations return a Result from @adaptive-ds/result.

Default user domains

Each owner can persist a default base domain in the Git-backed registry with the CLI:

project-registry user default-domain get
project-registry user default-domain set example.com
project-registry user default-domain unset

set is an upsert. unset persists an explicit unset decision, so it suppresses the environment fallback for that owner. Project defaults resolve in this order: explicit project domains, the persisted user decision, the environment fallback, and then no domain.

Repositories without a stored user decision can use the environment fallback, configured as JSON in PROJECT_REGISTRY_DEFAULT_USER_DOMAINS:

PROJECT_REGISTRY_DEFAULT_USER_DOMAINS='{"leo":"leonardomora.de"}'

Creating project api for leo without --domain assigns api.leonardomora.de. Explicit domains continue to override the configured default. The API equivalents are:

GET    /api/v1/users/:owner/default-domain
PUT    /api/v1/users/:owner/default-domain
DELETE /api/v1/users/:owner/default-domain

PUT accepts { "expectedRevision": "...", "domain": "example.com" }; DELETE accepts { "expectedRevision": "..." }. The GET response reports the effective domain, its source (explicit, environment, or none), and the registry revision. JSON CLI output preserves the complete response or mutation data, including the revision.

Cloudflare DNS credentials

When the daemon's Cloudflare DNS integration is enabled, it reads the credential for each project owner from:

/etc/project-registry/cloudflare/{owner}.env

Set PROJECT_REGISTRY_CLOUDFLARE_CREDENTIALS_DIR to use another absolute directory. Each file may contain CLOUDFLARE_API_TOKEN=value or the CF_API_TOKEN=value alias; the preferred name wins. Files are parsed as simple assignments and are never executed or sourced. A missing owner file defers that owner's DNS work for retry, and a global CLOUDFLARE_API_TOKEN or CF_API_TOKEN environment variable is not used as a fallback.

Set PROJECT_REGISTRY_CLOUDFLARE_DNS_ENABLED=false to disable DNS reconciliation explicitly. The default is enabled, but no DNS request is made until the relevant owner's credential is available.

Updating an owner token

The supported user workflow reads the token from stdin, so the secret is not placed in process arguments or shell history:

secret-manager cloudflare-token | project-registry user cloudflare-token set --token-stdin

Use --json for the safe response envelope or --socket <path> to select a daemon socket. Human output is updated cloudflare-token; JSON output is { "success": true, "data": { "updated": true } }.

The authenticated API operation is:

PUT /api/v1/users/{owner}/cloudflare-token
{ "token": "<token supplied in the request body>" }

It returns { "success": true, "data": { "updated": true } }. There is no token get/list endpoint. The owner is bound to the authenticated CLI socket user or HTTP session; a request cannot update another owner.

The library exports the privileged daemon-side filesystem component, not a general user credential client:

import {
  projectRegistryDaemonCloudflareCredentialsCreate,
  projectRegistryDaemonCloudflareCredentialsFilesystemDefault,
} from "@adaptive-ds/project-registry"

const credentialsR = projectRegistryDaemonCloudflareCredentialsCreate({
  directory: "/etc/project-registry/cloudflare",
  filesystem: projectRegistryDaemonCloudflareCredentialsFilesystemDefault(),
})
if (!credentialsR.success) return credentialsR
const updatedR = await credentialsR.data.tokenSet(owner, token)

Only the privileged daemon should construct this factory and call tokenSet; normal users should use the authenticated CLI or API. Updating a token does not immediately reconcile DNS. The next DNS operation reads the updated owner file.

Scripts

  • bun run dev watch tests
  • bun run test run tests once
  • bun run build emit dist/
  • bun run format biome format
  • bun run release version, changelog, GitHub release

License

MIT