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

picko-sdk

v1.2.2

Published

TypeScript SDK for the Picko Bear API – typed HTTP client for domain monitoring integrations

Readme

picko-sdk

TypeScript SDK for the Picko Bear API – a typed, ergonomic client for domain monitoring integrations.

Features

  • TypeScript-first – fully typed inputs, outputs, and errors
  • All Bear API routes – domains (CRUD + stats + webhooks) and quota
  • Robust error handling – typed error subclasses for every HTTP failure mode
  • Retries & timeouts – configurable, with exponential back-off
  • Response-signature verification – optional HMAC-SHA256 check on every response
  • ESM + CJS – works in Node.js 18+ with either module system
  • Tree-shakeable – import only what you use

Installation

npm install picko-sdk
# or
yarn add picko-sdk

Requires Node.js ≥ 18 (uses the native fetch API).


Quick start

import { PickoClient } from "picko-sdk";

const picko = new PickoClient({
  baseUrl: "https://api.picko.jeremiemeunier.dev",
  apiToken: "your-api-token",
});

// List all domains
const domains = await picko.domains.list();
console.log(domains);

// Get API quota
const quota = await picko.quota.get();
console.log(`Remaining: ${quota.rateLimit.remaining}/${quota.rateLimit.limit}`);

Authentication

All Bear API endpoints require an Authorization header:

Authorization: Bearer <api_token>

The SDK handles this automatically. Pass apiToken to PickoClient:

Legacy public/secret authentication is still accepted for migration, but deprecated.

const picko = new PickoClient({
  baseUrl: "https://api.picko.jeremiemeunier.dev",
  apiToken: process.env.PICKO_API_TOKEN!,
});

Configuration

const picko = new PickoClient({
  // Required
  baseUrl: "https://api.picko.jeremiemeunier.dev",
  apiToken: "your-api-token",

  // Optional
  timeout: 10_000, // ms before a request times out (default: 10 000)
  retries: 2, // retry attempts on network errors / 5xx (default: 2)
  retryDelay: 300, // ms before the first retry; doubles each attempt (default: 300)
  headers: {
    // extra headers sent with every request
    "X-Custom-Header": "value",
  },

  // Response-signature verification (Pro)
  verifySignature: true,
  signingSecret: process.env.PICKO_SIGNING_SECRET,
});

API Reference

Domains – picko.domains

list(): Promise<BearDomain[]>

List all domains accessible to the authenticated user.

const domains = await picko.domains.list();

get(id: string): Promise<BearDomain>

Fetch a single domain by ID.

const domain = await picko.domains.get("64a1b2c3d4e5f6a7b8c9d0e1");

getStats(domainIds: string[], format: StatsFormat): Promise<BearDomainStats[]>

Get statistics for one or more domains. format controls the shape of stats:

The SDK sends one domain query parameter per ID (for example: ?domain=id1&domain=id2&format=history).

| format | stats shape | Description | | ---------- | ---------------------------- | ------------------------------------ | | complete | { history, live, tracker } | All three datasets combined | | history | StatsHistory[] | Daily uptime % (up to 30 or 90 days) | | live | StatsSpark[] | Current-day ping-by-ping results | | tracker | StatsTracker[] | Colour-coded status indicators |

const stats = await picko.domains.getStats(
  ["64a1b2c3d4e5f6a7b8c9d0e1"],
  "complete",
);

create(input: CreateDomainInput): Promise<CreateDomainResponse>

Create a new monitored domain. Free accounts are limited to 3 domains.

const result = await picko.domains.create({
  name: "My API",
  endpoint: "https://api.example.com/health",
  mail: ["[email protected]"], // optional
});

console.log(result.data._id); // new domain ID
console.log(result.init_ping); // initial health-check result

update(id: string, input: UpdateDomainInput): Promise<BearDomain>

Update a domain's name, endpoint URL, or notification emails (owner only).

const updated = await picko.domains.update("64a1b2c3d4e5f6a7b8c9d0e1", {
  name: "Renamed API",
  endpoint: "https://api.example.com/v2/health",
});

setState(id: string, state: "active" | "inactive"): Promise<BearDomain>

Enable or disable monitoring for a domain (owner only).

await picko.domains.setState("64a1b2c3d4e5f6a7b8c9d0e1", "inactive");

setDiscordWebhook(id: string, discord: string | null): Promise<BearDomain>

Set or remove the Discord webhook URL for a domain (owner only).

// Set
await picko.domains.setDiscordWebhook(
  "64a1b2c3d4e5f6a7b8c9d0e1",
  "https://discord.com/api/webhooks/123/token",
);

// Remove
await picko.domains.setDiscordWebhook("64a1b2c3d4e5f6a7b8c9d0e1", null);

setWebhook(id: string, url: string | null): Promise<void> (Pro)

Set or remove an external webhook URL for a domain (owner only, Pro subscription required). The API sends a verification POST to the URL before saving it.

await picko.domains.setWebhook(
  "64a1b2c3d4e5f6a7b8c9d0e1",
  "https://example.com/picko-hook",
);

delete(id: string): Promise<void>

Permanently delete a domain (owner only).

await picko.domains.delete("64a1b2c3d4e5f6a7b8c9d0e1");

Quota – picko.quota

get(): Promise<BearQuota>

Get the current API rate-limit quota and usage.

const quota = await picko.quota.get();
console.log(quota.rateLimit);
// { limit: 100, remaining: 87, resetAt: "2024-01-15T10:30:00.000Z" }

Rate limits: 100 req/min (free) · 600 req/min (Pro).


Error handling

Every error thrown by the SDK is an instance of PickoError (or a subclass). Catch the base class to handle all SDK errors, or use subclasses for specific cases:

import {
  PickoClient,
  PickoAuthError,
  PickoNotFoundError,
  PickoRateLimitError,
  PickoValidationError,
  PickoServerError,
  PickoNetworkError,
} from "picko-sdk";

try {
  const domains = await picko.domains.list();
} catch (err) {
  if (err instanceof PickoAuthError) {
    console.error("Invalid or missing API credentials");
  } else if (err instanceof PickoRateLimitError) {
    console.error("Rate limit hit – back off and retry");
  } else if (err instanceof PickoNotFoundError) {
    console.error("Domain not found");
  } else if (err instanceof PickoValidationError) {
    console.error("Bad request:", err.fields);
  } else if (err instanceof PickoServerError) {
    console.error(`Server error ${err.statusCode}`);
  } else if (err instanceof PickoNetworkError) {
    console.error("Network problem:", err.cause);
  }
}

All error classes expose:

  • message – human-readable description
  • statusCode – HTTP status code (where applicable)
  • body – raw parsed response body (where applicable)

PickoValidationError additionally exposes fields – the array of field-level validation details returned by the API.


Response signature verification

When verifySignature: true is set, the client checks the X-Signature (HMAC-SHA256) header on every response against your signingSecret. A PickoSignatureError is thrown if the signature does not match.

import { PickoClient, PickoSignatureError } from "picko-sdk";

const picko = new PickoClient({
  baseUrl: "https://api.picko.jeremiemeunier.dev",
  apiToken: process.env.PICKO_API_TOKEN!,
  verifySignature: true,
  signingSecret: process.env.PICKO_SIGNING_SECRET,
});

TypeScript types

All public types are exported from the package root:

import type {
  // Domain
  BearDomain,
  BearDomainStats,
  StatsComplete,
  StatsHistory,
  StatsSpark,
  StatsTracker,
  CreateDomainInput,
  UpdateDomainInput,
  CreateDomainResponse,
  StatsFormat,
  DomainActiveState,
  // Quota
  BearQuota,
  RateLimitInfo,
  // Primitives
  PickoAPIState,
  TrackerColor,
  TrackerTooltip,
  // Config
  PickoClientConfig,
} from "picko-sdk";

Advanced usage

Tree-shaking – use route modules directly

import { PickoHttpClient, DomainRoutes } from "picko-sdk";

const http = new PickoHttpClient({
  baseUrl: "https://api.picko.jeremiemeunier.dev",
  apiToken: process.env.PICKO_API_TOKEN!,
});

const domains = new DomainRoutes(http);
const list = await domains.list();

Custom fetch (e.g. for testing or proxying)

The PickoClient constructor accepts an optional second argument – a fetch-compatible function. Use this to inject a mock in tests or route requests through a proxy:

import { PickoClient } from "picko-sdk";

const picko = new PickoClient(
  { baseUrl: "...", apiToken: process.env.PICKO_API_TOKEN! },
  myCustomFetch,
);

Release plan

| Version | Contents | | ------- | ------------------------------------------------- | | 1.0.0 | All Bear API routes, full TypeScript types, tests |

Versioning follows Semantic Versioning.
Changelogs are maintained in Git tags and GitHub Releases.

To publish:

cd sdk
npm run build
npm publish --access public

Development

# Install dependencies
npm install

# Run tests
npm test

# Run tests in watch mode
npm run test:watch

# Build (ESM + CJS + type declarations)
npm run build

# Coverage report
npm run test:coverage

License

MIT © Jeremie Meunier