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

kainguru-sdk

v0.2.27

Published

Node.js / TypeScript SDK for the Kainguru ML platform — run models and fine-tune them.

Readme

kainguru-sdk

Node.js / TypeScript SDK for the Kainguru ML platform — run models and fine-tune them from any Node application.

  • TypeScript-first; ships compiled JS + .d.ts, dual ESM + CJS build
  • Node 18+
  • Promise-based, async/await friendly
  • Built-in polling with configurable timeout and backoff
  • Automatic retry on 429 / 5xx with exponential backoff (honors Retry-After)

Covers /v1/executions and /v1/fine-tuning.


Installation

npm install kainguru-sdk

Authentication

You must pass both an API key (issued from the Kainguru Dashboard, it begins with kg_) and the base URL (the full host including the /api context path):

import { KainguruClient } from 'kainguru-sdk';

const client = new KainguruClient({
  apiKey: 'kg_your_api_key',
  baseUrl: 'https://your-host.example.com/api',
});

Both fields are required. If either is missing or blank, the constructor throws KainguruConfigError (fail fast).


Quick start

import { KainguruClient } from 'kainguru-sdk';

const client = new KainguruClient({
  apiKey: 'kg_your_api_key',
  baseUrl: 'https://your-host.example.com/api',
});

// Submit a model run, then block until it finishes
const submitted = await client.executions.execute({
  mlFlowId: 'my-mlflow-id',
  input: { prompt: 'hello world' },
  outputFormat: 'json',
});

const done = await client.executions.awaitCompletion(submitted.id);

console.log(done.status);              // 'COMPLETED' | 'FAILED'
console.log(done.execution?.output);   // model output

mlFlowId is the model's MLflow id — the same identifier the Dashboard shows for the model you want to run.


Executions API

// Run a model (returns immediately, typically PENDING)
const pending = await client.executions.execute({
  mlFlowId,
  input,
  outputFormat,          // optional
  execId,                // optional pre-assigned execution id
});

// Poll the current status once
const current = await client.executions.get(id);

// Block until COMPLETED or FAILED (default: 2 s interval, 5 min timeout)
const done = await client.executions.awaitCompletion(id);

// Block with custom poll options
const done2 = await client.executions.awaitCompletion(id, {
  pollIntervalMs: 1_000,
  timeoutMs: 60_000,
});

Terminal statuses: COMPLETED, FAILED. REGISTERED is treated as non-terminal (still progressing). A FAILED job resolves awaitCompletion — inspect dto.status, it is not thrown.


Fine-Tuning API

// Start fine-tuning a model
const pending = await client.fineTuning.execute({
  modelId,
  name: 'my-fine-tuned-variant',
  input,
});

// Get status / poll until done
const current = await client.fineTuning.getStatus(id);
const done = await client.fineTuning.awaitCompletion(id);

Polling options

await client.executions.awaitCompletion(id, {
  pollIntervalMs: 2_000,   // base interval between polls (default 2 000)
  timeoutMs: 300_000,      // total wall-clock timeout (default 300 000)
  backoff: 1.5,            // multiply interval each attempt (default 1.0 = fixed)
  maxIntervalMs: 30_000,   // cap on interval after backoff (default 30 000)
  signal: ac.signal,       // optional AbortSignal to cancel the poll
});

On timeout, awaitCompletion rejects with KainguruTimeoutError, which carries the last DTO seen via error.lastDto.


Configuration

const client = new KainguruClient({
  apiKey: 'kg_...',                              // required
  baseUrl: 'https://your-host.example.com/api',  // required — full host incl. /api context path
  timeoutMs: 30_000,                             // per-request timeout (default 30 000)
  maxRetries: 3,                                 // retries on 429 / 5xx / network (default 3)
  debug: true,                                   // verbose request/response logging (default false)
});

Both apiKey and baseUrl are required. The base URL must be the full host including the dashboard's /api context path.

Every method also accepts a per-request apiKey to override the client key for a single call.

Debug logging

Set debug: true to log every request and response to the console via console.error (the X-API-Key header is redacted). Keep it off in production — request and response bodies are logged in full.


Error handling

All errors extend KainguruError and are exported from the package root, so instanceof works across the dual ESM/CJS build.

| Error | When | |---|---| | KainguruConfigError | Missing/invalid configuration (e.g. no API key) | | KainguruApiError | Non-2xx HTTP response, or success=false in the body. Has httpStatus, body, apiCode? | | KainguruAuthError | 401 / 403 (subclass of KainguruApiError) | | KainguruNotFoundError | 404 (subclass of KainguruApiError) | | KainguruRateLimitError | 429 (subclass of KainguruApiError); retryAfterMs? | | KainguruTimeoutError | awaitCompletion exceeded timeoutMs; carries lastDto | | KainguruConnectionError | Network failure / no response; underlying error on cause |

import {
  KainguruApiError,
  KainguruTimeoutError,
  KainguruConnectionError,
} from 'kainguru-sdk';

try {
  const result = await client.executions.awaitCompletion(id);
  if (result.status === 'FAILED') {
    // FAILED is returned, not thrown — inspect the result
  }
} catch (e) {
  if (e instanceof KainguruApiError) {
    console.error(`HTTP ${e.httpStatus}`, e.body);
  } else if (e instanceof KainguruTimeoutError) {
    console.error('Timed out; last status:', e.lastDto);
  } else if (e instanceof KainguruConnectionError) {
    console.error('Network error:', e.cause);
  }
}

The SDK automatically retries 429 and 5xx responses up to 3 times with exponential backoff (base 1 s, doubling per attempt); Retry-After headers are respected.


Limitations (v0.1.0)

  • Cancel endpoints are not exposed yet (they require JWT/Keycloak auth, not an API key).
  • input parameters are untyped (Record<string, unknown>).
  • outputFormat is a free string; allowed values are not yet enumerated by the backend.

Building or publishing the SDK yourself? See MAINTAINERS.md.