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

@dispersed/sdk

v0.1.0

Published

Web-standards TypeScript SDK for the Dispersed Network compute API

Readme

@dispersed/sdk

TypeScript SDK for the Dispersed Network compute API. Built on Web Standards (fetch, URL, AbortSignal, crypto.subtle) - runs unchanged in Node.js, Bun, Deno, Cloudflare Workers, and modern browsers.

npm install @dispersed/sdk
# or: pnpm add @dispersed/sdk

Quick start

import { DispersedClient } from "@dispersed/sdk";

const client = new DispersedClient({
  publicKey: process.env.DISPERSED_PUBLIC_KEY!,
  secretKey: process.env.DISPERSED_SECRET_KEY!,
});

const jobs = await client.jobs.list({ limit: 10, "filter[status]": "RUNNING" });
console.log(`${jobs.total} running jobs`);

Get API keys at https://console.dispersed.com/keys.

Configuration

new DispersedClient({
  publicKey: string;            // required - your API public key
  secretKey: string;            // required - your API secret key (HMAC signing)
  baseUrl?: string;             // default: "https://api.dispersed.com"
  timeout?: number;             // default: 30_000 ms
  retry?: number;               // default: 2 (retries 5xx and 429 with exponential backoff)
  before?: BeforeHook[];        // observability hooks run before each request
  after?: AfterHook[];          // observability hooks run after each response
});

Auth is HMAC-SHA256 over a canonical request string - the SDK handles signing on every request.

Resources

client.accounts; // .getMe(), .getBalance(uuid), .getSpendSummary(uuid), .getConsumerSummary(uuid)
client.jobs; // .list(params?), .get(uuid), .create(input), .cancel(uuid, input?)
client.jobRuns; // .list(params?), .get(uuid), .cancel(uuid, input?), .getCostSummary(uuid)
client.jobRecipes; // .list(params?), .get(uuid), .create(input), .update(uuid, input),
// .delete(uuid), .fork(uuid), .cook(uuid, input?), .createFromJob(jobUuid)
client.gpuRegistry; // .list(params?)
client.compute; // .rewards(params?), .ledgerAuthorizations(params?), .ledgerTransactions(params?)
client.apiKeys; // .revoke(uuid)
client.sshPublicKeys; // .list(params?), .create(input), .update(uuid, input), .delete(uuid)

Method shape: positional args for IDs and required inputs, optional object for filters/params, and a trailing RequestOptions for per-call overrides.

RequestOptions - per-call overrides

Every resource method accepts an optional trailing RequestOptions argument:

interface RequestOptions {
  signal?: AbortSignal; // cancellation
  headers?: Record<string, string>; // additional request headers
  timeout?: number; // override the client default
  retry?: number; // override the client default
}

Cancellation - pass any AbortSignal. The SDK composes it with its own timeout via AbortSignal.any(), so a user signal never silently disables the timeout. Aborting mid-retry-backoff stops immediately rather than waiting out the delay.

const controller = new AbortController();
setTimeout(() => controller.abort(), 5_000);

await client.jobs.create(input, { signal: controller.signal });

Headers - merged into the outgoing request as a baseline. Useful for idempotency keys, request IDs, or trace context. The SDK's auth headers (X-API-Key, X-Time, X-Nonce, X-Signature) always overlay caller-supplied values, so you can't accidentally break signing.

await client.jobs.create(input, {
  headers: { "X-Idempotency-Key": "create-job-2026-04-21-abc" },
});

Timeout / retry - override the client defaults for a single call. Useful for slow operations or non-idempotent POSTs you don't want retried.

await client.jobs.create(input, { retry: 0 }); // never retry
await client.jobRuns.getCostSummary(uuid, { timeout: 60_000 }); // allow longer

Hooks

Hooks are arrays of plain functions, run for every request. Use them for cross-cutting observability (logging, correlation IDs, metrics) - not for control flow.

const client = new DispersedClient({
  publicKey,
  secretKey,
  before: [
    (req) => {
      req.headers["X-Request-Id"] = crypto.randomUUID();
    },
  ],
  after: [
    (res, req) => {
      console.log(`${req.method} ${req.url.pathname} → ${res.status}`);
    },
  ],
});

The SDK passes a cloned Response to after-hooks, so you can read the body without consuming it for the caller.

Error handling

Non-2xx responses throw an ApiError:

import { ApiError } from "@dispersed/sdk";

try {
  await client.jobs.get("missing-uuid");
} catch (err) {
  if (err instanceof ApiError) {
    if (err.isNotFound) {
      /* 404 */
    }
    if (err.isAuth) {
      /* 401 / 403 */
    }
    if (err.isRetryable) {
      /* 5xx / 429 - already retried per config.retry */
    }

    console.error(err.code, err.detail, err.details);
  }
}

ApiError exposes status, code, detail, details[], timestamp, and the convenience getters isAuth, isNotFound, isRetryable.

Web Standards

The SDK depends on no HTTP library and no runtime-specific APIs. It uses:

| Concern | API | | ------------ | ------------------------------------------------------------------------------------------------- | | HTTP | fetch, Request, Response, Headers | | Cancellation | AbortController, AbortSignal, AbortSignal.any(), AbortSignal.timeout() | | URLs | URL, URLSearchParams | | Crypto | crypto.subtle.importKey, crypto.subtle.sign, crypto.subtle.digest, crypto.getRandomValues | | Text | TextEncoder |

The same bundle runs in Node.js (≥20), Bun, Deno, Cloudflare Workers, Vercel Edge, and modern browsers - no polyfills, no platform-specific code paths.

Browser caveat: the User-Agent header is on the Fetch spec's forbidden header list, so browsers silently drop it. The SDK always sends X-Dispersed-Client: @dispersed/sdk/<version> as well, which works everywhere - server-side analytics should key off that header.

Version

import { VERSION } from "@dispersed/sdk";

A unit test asserts the exported VERSION stays in sync with package.json.

License

MIT