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

@postinger/api-client

v0.2.1

Published

Typed client for the Postinger public API

Readme

@postinger/api-client

Typed Node.js client for Postinger's project-scoped public API. Requires Node.js >=24.15.0.

Published as @postinger/api-client; version 0.2.0 adds renewable CLI device credentials.

Version 0.2.1 defaults new connections to the production API at https://api.postinger.dev. Existing saved server URLs remain unchanged.

import { PostingerClient } from '@postinger/api-client';

const api = new PostingerClient({
  baseUrl: process.env.POSTINGER_API_URL!,
  apiKey: process.env.POSTINGER_API_KEY!,
});
const accounts = await api.listAccounts();
const session = await api.session();
const capabilities = await api.publishingCapabilities(accounts.data[0].id);
const draft = await api.createDraft({ content: 'Hello', targets: [], mediaIds: [] }, 'my-logical-draft-1');
const report = await api.analyticsReport({ from: '2026-09-01', to: '2026-09-13' });

baseUrl is the backend origin or its /public/v1 URL. HTTPS is required except on localhost. There is no implicit production destination. Redirects are rejected to keep credentials on the configured API. Use a customer pst_... key, not an Unkey root key.

Methods cover session verification, account publishing capabilities, post creation/editing/scheduling/publishing/deletion, signed media upload operations, and all five analytics endpoints. session() verifies any active key without requiring resource permissions and returns project, expiry and effective permissions. publishingCapabilities(accountId) needs accounts-read and returns rules shared with backend validation; check available before publishing. createDraft rejects scheduling fields; use createPost to schedule. Post updates preserve omitted fields. The PostingerClient upload methods return signed URLs; they do not read files or upload bytes themselves. Never attach the customer API key when sending bytes to storage.

Each result contains { data, meta: { requestId } }. Creation and publication also return idempotencyKey. Pass a stable key for a logical operation; reuse it and the same body for manual retries within the API's 24-hour window. Generated keys are reused within automatic retries. A new method call with no supplied key is a new operation.

Requests time out after 30 seconds. Up to two retries are attempted only for GET and writes with server-supported idempotency, on transport failures, 429, 502/503/504 or idempotency_in_progress. Long Retry-After values (>2s) are returned to the caller instead of holding the process. PATCH, DELETE and upload mutations are not automatically retried. An uncertain write may have succeeded; inspect its state and use the returned idempotency key where applicable.

PostingerError includes code, status, requestId, retryAfterSeconds and idempotencyKey when available. errorDetails() provides a serializable, sanitized error. Inputs are validated locally and authoritatively again by the API. Session responses are validated at runtime and unknown fields are removed; other response types describe the API contract without runtime validation.

listPosts returns one page. Use iteratePosts for async iteration; analytics pagination uses postAnalytics({ cursor }). Keep filters stable between pages. Analytics metrics retain decimal strings, nulls, freshness, and coverage fields without numeric coercion.

From the repository root: pnpm build:tools and pnpm test:tools.

Shared CLI/MCP helpers

The Node-only subpaths keep authentication and local uploads consistent between both tools:

import { resolveCredentials } from '@postinger/api-client/credentials';
import { uploadFile } from '@postinger/api-client/upload';

const api = new PostingerClient(await resolveCredentials());
const media = await uploadFile(api, '/absolute/path/photo.jpg');

resolveCredentials(apiUrl?, env?) uses environment credentials first, then the owner-readable CLI config, enforcing saved API origin binding and refusing unconfirmed device logins. It defaults to DEFAULT_API_URL (https://api.postinger.dev) when no explicit or saved URL applies. An environment key ignores the saved credential file; pair it with POSTINGER_API_URL for a custom server. The credentials subpath also exports configPath, readConfig, saveConfig and logout for CLI use. For a saved device session, resolution may call /cli/auth/refresh and returns a getApiKey callback. Pass the whole resolved object to PostingerClient so long-running clients renew the same device session before requests. Refreshed access tokens are cached in memory, without overwriting another process's saved login. The refresh secret is stable until session expiry/disconnect, making concurrent commands and uncertain refresh responses safe. Explicit API keys are never refreshed. Resolution does not open a browser.

uploadFile(api, path, onProgress?, { signal }?) streams a local JPEG/PNG/MP4/MOV through reservation, transfer and validation. Large videos use up to three concurrent parts. Unlike the low-level client methods, this helper retries idempotent transfer/completion steps with bounded backoff, including rate-limit waits. Reservation creation is not retried. It returns the final ApiResult<Media>, never publishes, and never sends API credentials to storage. The caller must authorize filesystem access; the MCP wrapper enforces its configured media directory. Cancellation aborts transfers/backoff and stops subsequent steps, but an in-flight API request may already have completed.