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

rsflowhub

v1.0.0

Published

Official JavaScript & TypeScript SDK for the RSFlowHub AI API: sentiment analysis, translation, chat, PII redaction, review and ticket AI, knowledge bases (RAG) and chatbots. Works in Node.js, Next.js, React, Vue, Bun, Deno and edge runtimes. New APIs wor

Readme

RSFlowHub JavaScript & TypeScript SDK

npm Tests Types License: MIT

The official JavaScript / TypeScript library for the RSFlowHub AI API. Add sentiment analysis, translation, AI chat, PII redaction, spam and comment moderation, review and support-ticket AI, knowledge-base search (RAG) and chatbots to Node.js, Next.js, React, Vue, Nuxt, SvelteKit, Express, NestJS, Bun, Deno, Cloudflare Workers and Vercel Edge with one API key.

  • Never out of date. Methods are not hard-coded. A new RSFlowHub API works the day it ships: client.ai.newEndpointName({...}). No SDK upgrade needed.
  • Zero dependencies. Uses the built-in fetch. ESM and CommonJS builds, full TypeScript types.
  • Typed everything. Every method has typed parameters with limits in the JSDoc, generated from the RSFlowHub OpenAPI spec.
  • Typed errors. ValidationError, InsufficientCreditsError, RateLimitError and more, each with the API's error code, message and request id.
  • Retries and timeouts. 429 and temporary 5xx answers are retried with backoff, respecting Retry-After (they never charge credits). AbortSignal support.

Other languages: PHP · Python · Examples

Install

npm install rsflowhub

yarn add rsflowhub · pnpm add rsflowhub · bun add rsflowhub · Deno: import { RSFlowHub } from 'npm:rsflowhub'

Get an API key from the RSFlowHub dashboard (free credits included). Node.js 18 or newer.

Quick start

import { RSFlowHub } from 'rsflowhub';

const client = new RSFlowHub({ apiKey: process.env.RSFLOWHUB_API_KEY }); // apiKey defaults to that env var

const res = await client.ai.sentimentAnalysis({
  text: 'Setup took two minutes and support answered right away.',
});

console.log(res.result.sentiment); // "positive"
console.log(res.requestId);        // "req_..." quote it when you contact support

CommonJS: const { RSFlowHub } = require('rsflowhub');

Every API answer is the envelope { success, request_id, data, meta }; AI endpoints put their output in data.result. A call returns an RSFlowHubResponse:

| | | | --- | --- | | res.result | the AI output (data.result), or data when there is none | | res.data | everything under data | | res.get('result.aspects.0.name') | dot-path read with an optional fallback | | res.requestId, res.meta, res.status, res.headers | envelope and HTTP details | | res.rateLimit | { limit, remaining, reset } from the X-RateLimit-* headers |

React, Next.js, Vue: keep the key on the server

Your API key spends your credits, and anything in browser code is public. The client refuses to start in a browser unless you pass dangerouslyAllowBrowser: true. Call RSFlowHub from your server and fetch that from your components:

// app/api/sentiment/route.ts (Next.js App Router)
import { RSFlowHub } from 'rsflowhub';

const client = new RSFlowHub();

export async function POST(request: Request) {
  const { text } = await request.json();
  const res = await client.ai.sentimentAnalysis({ text });
  return Response.json(res.result);
}
// any React component
const res = await fetch('/api/sentiment', { method: 'POST', body: JSON.stringify({ text }) });
const { sentiment } = await res.json();

Server actions, Remix loaders, Nuxt server routes, SvelteKit +server.ts, Express and NestJS work the same way. Full examples: Next.js, Express, React + Vite, Edge / Workers.

Calling any API

The method name is the endpoint slug in camelCase:

| API | Call | | --- | --- | | POST /ai/sentiment-analysis | client.ai.sentimentAnalysis({ text }) | | POST /ai/translation | client.ai.translation({ text: 'Hello', target_language: 'French' }) | | POST /ai/chat | client.ai.chat({ message: 'Hi!' }) | | POST /ai/pii-redaction | client.ai.piiRedaction({ text: 'Call me on 555-0100' }) | | POST /ai/ticket-analyze | client.ai.ticketAnalyze({ ticket: 'My order never arrived' }) | | POST /ai/any-new-api | client.ai.anyNewApi({...}) (works without an SDK update) |

All methods with their parameters: docs/ENDPOINTS.md. API docs: rsflowhub.com/docs.

Using noUncheckedIndexedAccess? A method newer than your installed types is client.ai.newApi!({...}) or client.call('ai', 'newApi', {...}).

Knowledge bases (RAG) and chatbots

Ids in the URL come first, then the body, then per-call options:

const kb = await client.knowledgeBases.create({ name: 'Help center' });
const kbId = kb.get('knowledge_base.id');

await client.knowledgeBases.createDocument(kbId, {
  file: await fs.openAsBlob('refund-policy.pdf'), // Node 20+; or a File from an <input>, or a Uint8Array
});

const answer = await client.knowledgeBases.ask(kbId, { question: 'Can I get a refund after 30 days?' });

const reply = await client.chatbots.sendMessage(chatbotId, { message: 'Where is my order?' });

A Blob, File, Uint8Array/Buffer or ArrayBuffer value turns the request into a file upload.

Any route

const usage = await client.request('GET', '/account/usage', undefined, { page: 2 });

Errors

import { APIError, ConnectionError, InsufficientCreditsError, RateLimitError, ValidationError } from 'rsflowhub';

try {
  await client.ai.textSummarize({ text: article });
} catch (error) {
  if (error instanceof ValidationError) console.log(error.errors);          // { text: ['The text field is required.'] }
  else if (error instanceof InsufficientCreditsError) console.log(error.requiredCredits, error.availableCredits);
  else if (error instanceof RateLimitError) console.log(error.retryAfter);   // already retried maxRetries times
  else if (error instanceof APIError) console.log(error.status, error.code, error.message, error.requestId);
  else if (error instanceof ConnectionError) console.log('network problem or timeout');
  else throw error;
}

| Error | When | Error codes | | --- | --- | --- | | AuthenticationError | 401 | API_KEY_MISSING, INVALID_API_KEY | | InsufficientCreditsError | 402 | INSUFFICIENT_CREDITS | | PermissionDeniedError | 403 | SPENDING_LIMIT_REACHED, USER_INACTIVE | | NotFoundError | 404 | ENDPOINT_NOT_FOUND | | ValidationError | 422 | VALIDATION_ERROR | | RateLimitError | 429 | RATE_LIMIT_EXCEEDED | | InternalServerError | 500 | INTERNAL_SERVER_ERROR | | ServiceUnavailableError | 502 / 503 | PROVIDER_UNAVAILABLE, AI_PROVIDER_ERROR | | ConnectionError | no answer / timeout | | | AbortError | your AbortSignal fired | |

All of them extend RSFlowHubError.

Options

const client = new RSFlowHub({
  apiKey: 'rfh_...',                       // default: process.env.RSFLOWHUB_API_KEY
  baseURL: 'https://rsflowhub.com/api/v1', // default: process.env.RSFLOWHUB_BASE_URL
  timeout: 60_000,                         // ms per attempt
  maxRetries: 2,                           // for 429, 502, 503, 504 and network errors
  headers: {},                             // extra headers on every request
  fetch: customFetch,                      // proxies, logging, tests, older runtimes
  liveSpec: true,                          // look up unknown non-AI methods in the live OpenAPI spec
});

// per call: last argument
const controller = new AbortController();
await client.ai.chat({ message: 'Hi' }, { signal: controller.signal, timeout: 10_000, maxRetries: 0 });
await client.knowledgeBases.get(12, { signal: controller.signal });

How it stays up to date

RSFlowHub publishes a machine-readable OpenAPI document generated from the API's own routes and validation rules. This SDK uses it in three ways:

  1. AI endpoints are called by name, so new ones work at once.
  2. Other new routes (for example a new knowledge-base action) are looked up in the live document the first time you call them.
  3. Types and docs (src/generated, docs/ENDPOINTS.md) are regenerated every week by a GitHub workflow that opens a pull request when the API changed.

To regenerate by hand: npm run generate (or node scripts/generate.mjs <url-or-file>).

Contributing

Issues and pull requests are welcome: npm install, npm test, npm run typecheck, npm run build. Do not edit generated files (src/generated, docs/ENDPOINTS.md); change scripts/generate.mjs instead.

License

MIT. See LICENSE.