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

pmdash-connectors

v0.1.0

Published

The PMDash connector manifest format and validator — the minimum-requirements gate for open, installable integrations.

Readme

pmdash-connectors

The connector format for PMDash, and the validator that gates it.

A connector teaches PMDash how to turn data from some tool into dashboard metrics. Anyone can author one. A connector can only be installed once it passes the minimum requirements in this package, which is what makes it safe to install a connector written by someone else, or by an AI agent.

The core idea

A connector is a declarative manifest (JSON). It is pure data: it describes where a metric's value comes from and how to read it. It contains:

  • no executable code, and
  • no secret values.

Those two rules are the whole safety model. A manifest can be read, diffed, and reasoned about by a human or an agent, and installing one can never run arbitrary code or leak a credential.

Two directions

| Direction | Who moves the data | Credential | |-----------|--------------------|------------| | push | Your tool (or a Zapier/Make zap, a cron job, pmdash push) posts to a PMDash webhook | None stored by PMDash | | pull | PMDash polls the tool's API on a schedule | Entered once in the PMDash UI, encrypted at rest |

A credential is never written into a manifest. A pull manifest says where the credential goes (which header or query param) using the placeholder {{credential}}; PMDash injects the real value at run time.

Manifest shape

{
  "manifestVersion": "1",
  "id": "acme-crm",
  "name": "Acme CRM",
  "description": "What this connector does.",
  "maintainer": "[email protected]",
  "version": "0.1.0",
  "homepage": "https://developer.acme.com",
  "category": "leads",
  "direction": "pull",
  "auth": { "type": "api_key", "in": "header", "name": "Authorization", "scheme": "Bearer" },
  "source": {
    "baseUrl": "https://api.acme.com",
    "request": { "method": "GET", "path": "/v1/summary", "headers": { "Authorization": "Bearer {{credential}}" } },
    "cadence": "daily"
  },
  "metrics": [
    { "name": "New Leads (30d)", "metricType": "trend", "aggregation": "sum", "valuePath": "$.leads.last30Days", "displayFormat": "number" }
  ]
}

push connectors omit auth and source; their valuePath reads from the webhook payload instead of an API response. See examples/.

Fields

  • metricType: trend or countdown
  • aggregation (optional): sum count average percentage. Omit it when the field already holds the final number (push metrics, countdown metrics, or a pre-computed pull field).
  • displayFormat: number currency percentage
  • valuePath: a JSONPath (starts with $) into the API response (pull) or the posted payload (push)
  • benchmark (optional): { type: count|days|percentage|rating, value, warning, critical }
  • cadence (pull): every_run hourly daily

Minimum requirements (the install gate)

validateManifest(manifest) returns { valid, errors, warnings }. A connector is installable only when valid is true. It enforces:

  • Declarative only. No code/script/eval/function/exec/… keys anywhere.
  • No secret literals. Bearer tokens, sk_…/pmd_…-style keys, AWS/GitHub tokens, etc. are rejected. Use {{credential}}.
  • Only {{credential}}. No other template placeholder is allowed.
  • HTTPS + no internal targets. A pull baseUrl (and any URL in the request) must be https:// and must not point at localhost, loopback, private ranges, or cloud-metadata (169.254.169.254). This blocks server-side request forgery.
  • Well-formed. Valid slug id, semver version, a maintainer, a known direction, at least one metric, and a valid vocabulary for every metric field.
  • Direction integrity. push must not declare a source; pull must declare source + auth + cadence.

The gate is static. At install time PMDash also runs a live dry-run against your credential to confirm the connector actually returns the metrics it declares. That step lives in the app, not this package.

Executing a connector

The same core powers the install-time dry-run and the scheduled runner:

import { executeConnector, extractMetrics } from 'pmdash-connectors';

// pull: fetch the source once with the user's credential and read the metrics
const result = await executeConnector(manifest, credential, { fetchImpl, maxBytes, timeoutMs });
// { ok: true, metrics: [{ name, value, found, ... }] }  or  { ok: false, code, error }

// push: given a sample/real payload, show what would be extracted
const rows = extractMetrics(manifest, payload);

executeConnector re-applies the SSRF gate on the resolved URL, refuses redirects, injects the credential only at request time, times out the whole request (headers and body), and rejects an over-budget response by byte length after reading it. It never returns or logs the credential (error messages are scrubbed of it). A true streaming size cap that stops the download mid-flight is the runner's job (below). readPath resolves a metric's valuePath over own properties only (no prototype traversal). The remaining defenses below still belong to the deployment that calls it.

Required runtime-runner controls

The static gate cannot cover threats that only exist at fetch time. The engine that executes a pull connector must also:

  • Re-resolve DNS and block private IPs on the resolved address, and pin that IP for the actual request (a hostname like 127.0.0.1.nip.io passes the static gate but resolves to loopback; guards against DNS rebinding).
  • Not follow redirects blindly — re-run the host check on every hop, or disable redirects (a clean host can 302 to an internal one).
  • Cap response size and wall-clock time on every poll.
  • Evaluate valuePath with a non-eval JSONPath reader (no vm/script expressions).
  • Parse/merge the manifest with a null-prototype object so a hostile key can't pollute prototypes.
  • Never log the full request URL when auth.in is query (the credential rides in the query string) — prefer header auth.
  • Inject the credential only at request time, never by templating it into the stored manifest.

Usage

import { validateManifest } from 'pmdash-connectors';

const result = validateManifest(manifest);
if (!result.valid) {
  for (const e of result.errors) console.error(`${e.path}: ${e.message} (${e.code})`);
}

License

MIT