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

@pipelex/sdk

v0.34.1

Published

TypeScript SDK for the Pipelex hosted API — execute methods, manage runs, and call the product surface.

Readme

@pipelex/sdk

TypeScript SDK for the Pipelex hosted API — execute MTHDS methods, manage runs, and call the product surface (methods catalog, organizations, billing, API keys, storage) from Node.

Pipelex is the runtime/product. MTHDS is the open standard it implements. This SDK speaks to the hosted Pipelex API; the pure protocol wire types it builds on come from the mthds package via its mthds/protocol subpath.

Status

Early. PipelexApiClient implements the MTHDS protocol-execution routes (execute / start / validate / models / version), the crate routes (resolve / codegen / pipeIo), the model reference check (checkModelReference), the durable run lifecycle (start → poll → result), and the Pipelex product routes (user profile, methods catalog, organizations, billing, API keys, onboarding, storage, runs list/update).

Besides the client, the package exports runCodegenCheck — a pure offline check that verifies a committed codegen() tree still matches its codegen.lock. It needs no server, no key, and no client instance, so it fits a CI job. See docs/crate-routes.md.

It also exports summarizeUsage, which folds a completed run's usage records into one null-aware summary — total cost, input and output tokens, and a per-pipe rollup — without any I/O. See docs/run-usage.md.

Install

npm install @pipelex/sdk

Run a method from the command line

The package publishes one command, pipelex-sdk, so a method runs with nothing installed but Node 22.12 or later and a key in PIPELEX_API_KEY:

npx @pipelex/sdk run --method github.com/acme/methods/[email protected] --inputs-template > inputs.json
npx @pipelex/sdk run --method github.com/acme/methods/[email protected] --inputs inputs.json

--method takes a published address, a catalog id (mt_…) or a local .mthds file or bundle directory. The run's main output is printed on stdout as JSON, and the run id, each uploaded file and every error on stderr. script writes a method its own command, a shell script pinned to this SDK's version:

npx @pipelex/sdk script --method github.com/acme/methods/[email protected]
./receipt-review --inputs inputs.json

See docs/cli.md for every flag, the output, the exit codes and Ctrl-C.

Usage

import { PipelexApiClient } from "@pipelex/sdk";

// Base URL + key from PIPELEX_BASE_URL / PIPELEX_API_KEY, or pass them explicitly.
const client = new PipelexApiClient({
  baseUrl: "https://api.pipelex.com",
  apiKey: process.env.PIPELEX_API_KEY,
});

// Validate an MTHDS bundle (a 200-diagnostic verdict, discriminated on `is_valid`).
const report = await client.validate(["domain = 'demo'"]);
if (report.is_valid) {
  // Run it and wait for the result (durable start + poll on the hosted API).
  const result = await client.startAndWaitForResult({ pipe_code: "demo.greet" });
  // Every completed run delivers a resolved `main_stuff`, and every named stuff of
  // the run in `working_memory`.
  console.log(result.main_stuff);
}

// Or run a published method by address — resolved server-side (fetch at tag,
// commit SHA recorded as provenance on the start ack). Requires pipelex-api >= 0.21.0;
// on api.pipelex.com, availability follows the platform deploy that forwards it.
const ack = await client.start({
  method_ref: "github.com/Pipelex/methods/[email protected]",
  inputs: { document: { url: "https://example.com/report.pdf" } },
});
console.log(ack.method_provenance); // { address, tag, commit_sha }

Checking a model reference

checkModelReference asks the runner whether a reference a method's model field could name resolves, as what kind and to which model (GET /v1/models/check, served by pipelex-api from pipelex 0.78.0). A reference that resolves nowhere is a verdict, not an error, and narrowing on kind types its matches:

const verdict = await client.checkModelReference("$writing-factual", "llm");
if (verdict.resolution === "resolved") {
  for (const match of verdict.matches) {
    // `resolves_to` is null when the name exists but a run through it would reach no model.
    console.log(match.category, match.resolves_to ?? "warning: no model the runner can call");
  }
  if (verdict.kind === "preset") console.log(verdict.matches[0]?.description);
} else {
  console.log(verdict.other_kinds, verdict.suggestions); // what the caller may have meant
}

A reference the runner cannot read at all (blank, a sigil alone, too long) or an unknown category throws ApiResponseError, a 422 whose errorType is InvalidModelReference or InvalidModelCategory.

Product routes

The hosted management surface (catalog, account, billing) hangs off the same client. Every route maps a non-2xx problem+json to a typed ApiResponseError (see Errors for how to branch on it):

import { PipelexApiClient, ApiResponseError } from "@pipelex/sdk";

const client = new PipelexApiClient({ apiKey: process.env.PIPELEX_API_KEY });

const me = await client.getMe(); // GET /v1/me
const page = await client.listMethods(); // GET /v1/methods — one page: { items, nextCursor }
for await (const method of client.iterateMethods()) {
  // follows the cursor for callers that genuinely want the whole catalog
}
const created = await client.createMethod({ name: "Greeter", mthds: "domain = 'demo'" });

try {
  const { portal_url } = await client.getBillingPortal();
  // open portal_url ...
} catch (err) {
  if (err instanceof ApiResponseError && err.type === "https://pipelex.com/errors/conflict") {
    // no subscription yet — start one via createCheckout(...)
  }
}

Errors

Every error the SDK throws carries a verdict: retryable, whether asking again can succeed, and errorDomain, who can fix the failure (input for the caller, config for a change to the environment such as the credential, the plan or the base URL, runtime for nobody beforehand). Both are always decided, and errorVerdictOf reads them from anything a catch holds, returning undefined for what is not an SDK error, such as a bug in the calling code or your own abort. "Retryable" means a retry can succeed, not that it is safe: a start answered with a 500 may already have created a run.

import { errorVerdictOf } from "@pipelex/sdk";

try {
  await client.startAndWaitForResult({ method_id: "mt_abc123", inputs });
} catch (err) {
  const verdict = errorVerdictOf(err);
  if (verdict === undefined) throw err; // not an SDK error: a bug, or the caller's own abort
  if (verdict.retryable) return scheduleRetry();
  if (verdict.errorDomain === "input") return askTheUserToFix(err);
  return reportToOperator(err);
}

A refused request throws an ApiResponseError carrying every member of the server's RFC 9457 problem document. Branch on errorDomain and type, as the hosted-envelope spec says, never on the HTTP status or the message: errorDomain is the verdict's domain and type is the stable URI of the error class, the same on every occurrence. The verdict is the server's when it sent a valid one, and otherwise the SDK's fallback, read from the status, except that an input or config domain the server sent without retryable is not retryable; problemDocument keeps what the server sent. userAction gives the next step, and requestId — from the body, or the X-Request-ID header — is the id to hand to support. code (the platform's native code, one-to-one with type) and errorType (the runner's exception class name) stay available as each surface's finer code, and errors carries the platform's field-level failures.

On the hosted API, a run that ends without completing throws a RunFailedError from waitForResult, startAndWaitForResult and downloadArtifacts, and comes back as the failed arm of getRunResult. (Against a bare pipelex-api runner, startAndWaitForResult runs the method with the blocking execute, so a failed run there throws the runner's ApiResponseError, whose problem members carry the same classification.) Its status is the run's terminal status and its error is the run's stored error report, checked field by field and typed as RunErrorReport: the reason in message, error_domain, type_uri and retryable to branch on, user_action as the next step, and the inference details. It is null when the run ended without a report, and the error's own verdict comes from it: the report's domain, and retryable only when the report says so. The report is the runner's VERBOSE one, provider text included, so what a person sees is your presentation:

import { RunFailedError } from "@pipelex/sdk";

try {
  await client.waitForResult(runId);
} catch (err) {
  if (err instanceof RunFailedError) {
    console.error(err.message); // "Run finished with status FAILED: <the reason>"
    console.error(err.error?.user_action?.detail ?? "No next step was given.");
  }
}

docs/errors.md gives each class's verdict, the fallback table, and every field of both.

Client identification

Every request to the API carries a User-Agent such as pipelex-sdk-js/0.21.0 node/22.4.0 (darwin; arm64), which the hosted platform reads to attribute traffic to a client surface in its analytics. A program built on the SDK can put its own name in front with appInfo, shaped like Stripe's option of that name; an invalid field is refused at construction with a TypeError. In a browser the SDK sets no User-Agent. A program that also calls the API with its own fetch gets the same value from the exported buildUserAgent(appInfo). The convention is the spec conformance/specs/client-identification.md, in the conformance repository, where the cross-repo specs sit beside the tests that verify them, and docs/client-identification.md describes this SDK's side of it.

const client = new PipelexApiClient({ appInfo: { name: "acme-invoicer", version: "1.4.0" } });
// User-Agent: acme-invoicer/1.4.0 pipelex-sdk-js/<version> node/<version> (<os>; <arch>)

Uploading from a browser

A browser page that holds a file but not the API key can still store it: the server that holds the key asks for an upload grant, and the page sends the file straight to storage with it. The file never crosses your server or the API gateway, so it can be as large as the service's own limit. The page imports @pipelex/sdk/upload, the browser-safe entry, which bundles with no Node builtin to mark external; the main @pipelex/sdk entry is Node-first.

// On the server, which holds the key:
const grant = await client.requestUploadGrant({
  filename: "report.pdf",
  content_type: "application/pdf",
  size: 48213,
});

// In the page, which holds the file:
import { uploadWithGrant } from "@pipelex/sdk/upload";
const { uri } = await uploadWithGrant(grant, file); // pipelex-storage://…

The full client surface is documented in docs/architecture.md.

Documentation

These pages ship inside the published package, so a reader who has only installed it opens them under node_modules/@pipelex/sdk/docs/ — at the version being called, rather than whatever the repository's default branch says today. They are also browsable at Pipelex/pipelex-sdk/tree/main/js/docs, which is the address to give someone who has not installed the package.

| Page | What it covers | | --- | --- | | docs/architecture.md | The whole client surface: the request pipeline, every route, the typed errors | | docs/cli.md | The pipelex-sdk command: run and script, the environment it reads, what it prints, its exit codes, how it reads a bundle, and the case table it shares with the Python SDK | | docs/run-results.md | Every field of RunResults — the run id as a durable handle, main_stuff, working_memory, graph_spec, the usage pair, produced files | | docs/run-usage.md | What a run consumed, record by record, and summarizeUsage which folds them into one reading | | docs/artifact-download.md | Turning the pipelex-storage:// references a run produced back into bytes: locateArtifacts, collectArtifacts, resolveArtifacts, fetchArtifact, downloadArtifacts, and how a saved file is named after the field it fills | | docs/input-preparation.md | The other direction — uploadFile and prepareInputs, which turn local files into references a run can take, and the upload grant a browser page sends a file with | | docs/crate-routes.md | resolve, codegen and pipeIo — the normalized crate, the stamped types, and a method's I/O artifacts without a validation — and the offline runCodegenCheck that guards a committed tree | | docs/client-identification.md | The User-Agent every API request carries, and appInfo, the option that puts your program's name in front of it | | docs/errors.md | The verdict every error carries (retryable, errorDomain, errorVerdictOf), a failed run's stored error report on RunFailedError and RunRead, and every member of a refused request's ApiResponseError, with the fields to branch on |

Develop

make install    # Install dependencies
make check      # Lint + format check + typecheck + build + depcruise (alias: make c)
make test       # Run the test suite (alias: make t)
make all        # Clean, check, and test

Always run make check before committing.

License

MIT