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

@wtfalch/providers

v0.3.0

Published

Typed clients for Coolify, Cloudflare, GitHub and ZITADEL. Every client takes its credential as an argument; none of them reads env or a secrets file.

Readme

@wtfalch/providers

Typed clients for the systems the estate runs on: Coolify, Cloudflare, GitHub and ZITADEL. Every client takes its credential as a constructor argument — none of them reads an environment variable or a secrets file.

Status

Published: yes, v0.1.0, 2026-09-22.

See the repo README for why this package exists and what still needs deciding.

Usage

import { CoolifyClient } from '@wtfalch/providers/coolify';

const coolify = new CoolifyClient('https://coolify.example.com', token);
const projects = await coolify.listProjects();
import { CloudflareClient } from '@wtfalch/providers/cloudflare';

const cloudflare = new CloudflareClient(token, accountId);
const zones = await cloudflare.listZones();
import { GitHubClient } from '@wtfalch/providers/github';

const github = new GitHubClient();
const exists = await github.repoExists('wtfalch/providers');
import { ZitadelClient } from '@wtfalch/providers/zitadel';

const zitadel = new ZitadelClient('https://auth.wtfalch.dev', token);
const { org, created } = await zitadel.findOrCreateOrg('acme');
const { project } = await zitadel.findOrCreateProject(org.id, 'app-one');
const { appId, clientId } = await zitadel.createOidcApp(org.id, project.id, {
  name: 'web',
  appType: 'web',
  redirectUris: ['https://app-one.example.com/auth/callback'],
  postLogoutRedirectUris: ['https://app-one.example.com/'],
});

listResources

Coolify, Cloudflare and ZITADEL each expose listResources(scope), returning LiveResource[] (@wtfalch/providers/resource) — everything this package can see in that scope, for a plan to diff against. scope is that provider's own natural key (a Coolify project uuid, a Cloudflare zone id, a ZITADEL org id), not an estate-wide org id: resolving an estate org to a provider's scope is foundry's job, not this package's (see ADR 0002).

  • Coolify (projectUuid): environment (keyed by uuid), application and database (both keyed by uuid, scoped to the project's environments).
  • Cloudflare (zoneId): zone (keyed by the zone's name), dns_record (keyed by record id), email_routing (keyed by the zone id), and tunnel (keyed by tunnel id) — every non-deleted tunnel in the zone's owning account, not filtered to ones that route a hostname in this zone.
  • ZITADEL (orgId): project (keyed by id), project_grant (keyed by grant id), and app (keyed by the app's own ZITADEL id, since a name is only unique within one project) — one app per OIDC or API application in each project, config carrying name, projectId and appType (one of 'web', 'native' or 'api').

GitHub has no listResources: nothing in the estate declares a reader for it yet.

ZITADEL app creation

ZitadelClient can create the resources foundry's step executor needs, all find-or-create except apps (see below): findOrCreateOrg, findOrCreateProject, createOidcApp and createApiApp.

  • createOidcApp(orgId, projectId, { name, appType, redirectUris, postLogoutRedirectUris }) — appType is 'web' or 'native'. Both use the authorization-code grant with PKCE and no client secret (OIDC_AUTH_METHOD_TYPE_NONE); native here is a redirect-based public client (a loopback or custom-scheme URI), not the device-code flow auth/scripts/provision.mjs's own native app kind uses. Returns { appId, clientId } — no secret, since none is ever issued.
  • createApiApp(orgId, projectId, { name }) — API_AUTH_METHOD_TYPE_BASIC, matching provision.mjs. Returns { appId, clientId, clientSecret }: ZITADEL hands back the secret once, on creation, and never shows it again, so the caller must store it immediately. Never put a secret in a log line or an error.
  • deleteApp(orgId, projectId, appId) — an app's OIDC/API config cannot be converted in place, so a kind change deletes and recreates it under the same name. There is no findOrCreateApp: apps are looked up through listApps and recreated on a mismatch, not matched by name alone.

None of this is verified against a live ZITADEL instance (see ADR 0004).