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

raiplus-moderation

v1.1.4

Published

Official Node.js SDK for the Raiplus Engine — Hinglish + English content moderation API with 3-Tier AI pipeline.

Downloads

175

Readme

raiplus-moderation

Official Node.js SDK for the Raiplus Engine — Hinglish + English content moderation API with a 3-Tier AI pipeline.

npm version Node.js License: MIT


Table of Contents

  1. Requirements
  2. Installation
  3. Quick Start
  4. Authentication
  5. Methods
  6. Response Shapes
  7. Error Handling
  8. Rate Limits
  9. TypeScript
  10. Configuration Options
  11. How the Pipeline Works

Requirements

| Requirement | Version | |-------------|-----------| | Node.js | ≥ 18.0.0 | | npm | ≥ 8.0.0 |

Why Node 18+? The SDK uses the built-in fetch API (available since Node 18) and AbortSignal.timeout() — no extra dependencies needed.


Installation

npm install raiplus-moderation

That's it. No other dependencies are required.


Quick Start

const Raiplus = require('raiplus-moderation');

const client = new Raiplus('YOUR_API_KEY');

// Full mode — detect + rewrite toxic text (~300ms)
const result = await client.moderate('ye code ekdum bakwas hai bkl');
console.log(result.isToxic);    // true
console.log(result.cleanText);  // 'ye code thoda aur accha ho sakta hai yaar'
console.log(result.confidence); // 0.97

// Fast mode — detect only, no rewrite (<50ms)
const scan = await client.detect('bhai kya scene hai');
console.log(scan.isToxic);     // false
console.log(scan.confidence);  // 0.03

Authentication

API Key (recommended)

Get your key from the Raiplus Dashboard after registration.

const Raiplus = require('raiplus-moderation');
const client  = new Raiplus('rp_alpha_xxxxxxxxxxxxxxxx');

Keys look like rp_alpha_ followed by a random string. Keep them secret — don't commit them to git.

Best practice — use an environment variable:

# .env
RAIPLUS_API_KEY=rp_alpha_xxxxxxxxxxxxxxxx
require('dotenv').config();
const client = new Raiplus(process.env.RAIPLUS_API_KEY);

Email / Password login

If you don't have an API key yet, you can authenticate using your Raiplus account credentials. The SDK stores the session cookie internally after login.

const Raiplus = require('raiplus-moderation');
const client  = new Raiplus(); // no key needed

// Step 1: Register (skip if already registered)
await client.register('[email protected]', 'yourpassword', 'devbhai');

// Step 2: Verify the OTP sent to your email
await client.verifyOtp('[email protected]', '123456');

// Step 3: All subsequent requests are authenticated automatically
const result = await client.moderate('kya bakwas hai yaar');

If your account already exists:

await client.login('[email protected]', 'yourpassword');
// Now make requests normally
const result = await client.moderate('some text');

Methods

moderate(text)

Full moderation — detects toxicity and rewrites toxic text with polite replacements.

  • Routes to: Node-1 (primary) → Node-2 (fallback if Node-1 fails)
  • Latency: ~300ms average
  • Rate limit: 30 req/min (authenticated alpha) · 20 req/min (guest)
  • Data storage: Result saved to Training Data Lake
const result = await client.moderate('ye code bakwas hai bkl');

console.log(result.isToxic);      // true
console.log(result.confidence);   // 0.97
console.log(result.originalText); // 'ye code bakwas hai bkl'
console.log(result.cleanText);    // 'ye code thoda aur accha ho sakta hai yaar'
console.log(result.actionTaken);  // 'sanitized_by_node'
console.log(result.tags);         // { profanity: true, insult: false, threat: false }
console.log(result.telemetry);    // { total_latency_ms: 310, nodes_hit: ['Node-1'], ... }

Parameters:

| Parameter | Type | Required | Description | |-----------|--------|----------|---------------------------------| | text | string | Yes | Text to moderate (max 500 chars)|

Returns: ModerationResult


detect(text)

Fast detect-only scan — returns a boolean toxicity result without rewriting. Hits Node-3 directly, bypassing Node-1 and Node-2 entirely.

  • Routes to: Node-3 (Deep Scanner) directly
  • Latency: <50ms
  • Rate limit: 300 req/min (authenticated alpha)
  • Data storage: Toxic hits saved to FastScan Data Lake (90-day TTL)
const scan = await client.detect('ye code bakwas hai bkl');

console.log(scan.isToxic);      // true
console.log(scan.confidence);   // 0.95
console.log(scan.actionTaken);  // 'detection_only'
// Note: scan has no cleanText — Node-3 never rewrites

Parameters:

| Parameter | Type | Required | Description | |-----------|--------|----------|------------------------------| | text | string | Yes | Text to scan (max 500 chars) |

Returns: DetectResult


batch(texts, options)

Process multiple texts sequentially. Useful for scanning chat logs, comment feeds, or any bulk dataset.

const texts = [
  'ye code bakwas hai bkl',
  'nice work bhai, accha hai',
  'bsdk kya kar raha hai tu',
  'bhai meeting mein hoon',
];

// detect_only — fast, 300/min burst, no rewrites
const results = await client.batch(texts, { mode: 'detect_only' });

results.forEach((r, i) => {
  console.log(`[${i}] toxic: ${r.isToxic}, confidence: ${r.confidence}`);
});
// [0] toxic: true,  confidence: 0.97
// [1] toxic: false, confidence: 0.02
// [2] toxic: true,  confidence: 1.00
// [3] toxic: false, confidence: 0.01

// full mode — rewrites, 30/min burst
const rewrites = await client.batch(texts, { mode: 'full' });
rewrites.forEach(r => console.log(r.cleanText));

Parameters:

| Parameter | Type | Default | Description | |--------------------|----------|---------------|-------------------------------------------------| | texts | string[] | — | Array of texts to process (max 1000) | | options.mode | string | 'full' | 'full' or 'detect_only' | | options.delayMs | number | 0 | Optional delay between requests in ms |

Returns: Promise<Array<ModerationResult | DetectResult>>

Tip for large datasets: Use mode: 'detect_only' + delayMs: 0 for maximum throughput (300/min burst). Then use moderate() only on the texts flagged as toxic.


Auth Methods

| Method | Description | |-----------------------------------------|-----------------------------------------------------| | register(email, password, username) | Create a new account. Follow with verifyOtp(). | | verifyOtp(email, otp) | Verify OTP from email. Stores session cookie. | | login(email, password) | Login with credentials. Stores session cookie. | | logout() | Logout and clear the stored cookie. | | me() | Get your user profile (quota, role, etc.). |


Response Shapes

ModerationResult

Returned by moderate() and batch() with mode: 'full'.

{
  isToxic:      boolean   // whether text is toxic
  confidence:   number    // 0.0 – 1.0 severity score
  originalText: string    // sanitized input text
  cleanText:    string    // rewritten text (or original if not toxic)
  actionTaken:  string    // what the engine did (see table below)
  tags: {
    profanity:  boolean
    insult:     boolean
    threat:     boolean
  }
  telemetry: {
    node1_latency_ms:  number | null
    node2_latency_ms:  number | null
    total_latency_ms:  number
    nodes_hit:         string[]
    delayed_by:        string | null
    circuit_breaker:   'open' | 'closed'
    node1_source:      string
    mode_requested:    string
  }
  success:      boolean
}

DetectResult

Returned by detect() and batch() with mode: 'detect_only'.

{
  isToxic:      boolean
  confidence:   number
  originalText: string
  actionTaken:  string    // 'detection_only' or 'clean'
  telemetry:    object
  success:      boolean
  // Note: no cleanText — Node-3 never rewrites
}

actionTaken values

| Value | Meaning | |--------------------------|----------------------------------------------------------------| | clean | Text was not toxic — returned as-is | | sanitized_by_node | Node-1 or Node-2 rewrote the text contextually | | pure_abuse_refused | Short abuse (≤3 words), no context to rewrite — refused | | front_door_blocked | Instant keyword match — confidence 1.0, routed to Node-1/2 | | detection_only | detect_only mode — boolean result, no rewrite | | fallback_detection_only| Circuit breaker open or all nodes failed — Node-3 fallback | | obfuscation_blocked | Mixed-script injection detected in Layer 0 | | unsupported_language | Non-Latin/non-Hinglish script detected |


Error Handling

Every error thrown by the SDK is an instance of RaiplusError so you can use a single catch clause.

const { RateLimitError, AuthError, ValidationError, NetworkError } = require('raiplus-moderation');

try {
  const result = await client.moderate(text);
} catch (e) {
  if (e instanceof RateLimitError) {
    console.log(`Rate limited. Retry in ${e.retryAfter}s. Tier: ${e.tier}`);
    await sleep(e.retryAfter * 1000);
    // retry...

  } else if (e instanceof AuthError) {
    console.log('Auth failed. Check your API key or re-login.');

  } else if (e instanceof ValidationError) {
    console.log('Bad input:', e.message);

  } else if (e instanceof NetworkError) {
    console.log('Network error — server unreachable or timed out.');

  } else {
    throw e; // re-throw unexpected errors
  }
}

Error Classes

| Class | HTTP Status | When thrown | |-------------------|-------------|--------------------------------------------------| | RaiplusError | any | Base class — all SDK errors extend this | | RateLimitError | 429 | Rate limit hit. Has .retryAfter (seconds) and .tier | | AuthError | 401 / 403 | Invalid/missing API key or session | | ValidationError | 400 | Bad input (empty text, too long, invalid mode) | | NetworkError | — | Network failure or request timeout |

Automatic retry pattern

async function moderateWithRetry(client, text, maxAttempts = 3) {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await client.moderate(text);
    } catch (e) {
      if (e instanceof RateLimitError && attempt < maxAttempts) {
        console.log(`Attempt ${attempt}: rate limited. Waiting ${e.retryAfter}s...`);
        await new Promise(r => setTimeout(r, e.retryAfter * 1000));
        continue;
      }
      throw e;
    }
  }
}

Rate Limits

The API enforces dynamic, mode-based rate limits:

| Tier | Mode | Burst / min | Daily quota | |-----------------------|-----------------|-------------|-------------| | Guest (unauthenticated) | any | 20 req/min | 100 req/day | | Alpha (authenticated) | full | 30 req/min | 500 req/day | | Alpha (authenticated) | detect_only | 300 req/min | 5,000 req/day |

Why the difference? full mode runs Node-1/Node-2 — compute-heavy rewriting models. detect_only runs Node-3 only — a purpose-built boolean scanner that's ~6× cheaper per request.

The SDK surfaces rate limit info in the RateLimitError:

e.retryAfter  // seconds until the limit resets
e.tier        // 'guest' | 'full' | 'detect_only'
e.status      // 429

The last successful response's rate limit headers are also available:

result.telemetry.rate_limit
// { limit: 30, remaining: 28, reset: 1711245600 }

TypeScript

The SDK ships with full TypeScript declarations in src/index.d.ts. No @types/ package needed.

import Raiplus, { RaiplusClient, ModerationResult, DetectResult, RateLimitError } from 'raiplus-moderation';

const client: RaiplusClient = new Raiplus('rp_alpha_xxx');

const result: ModerationResult = await client.moderate('ye code bakwas hai bkl');
console.log(result.cleanText);

const scan: DetectResult = await client.detect('bhai kya scene hai');
console.log(scan.isToxic);

Configuration Options

const client = new Raiplus('YOUR_API_KEY', {
  // Override API base URL — useful for staging or self-hosted instances
  baseUrl: 'https://staging.raiplus.in',   // default: 'https://raiplus.in'

  // Request timeout in milliseconds
  timeout: 15000,                           // default: 30000 (30s)

  // Log all request/response details to console (development only)
  debug: true,                              // default: false
});

How the Pipeline Works

Client request
      │
      ▼
┌─────────────────────────────────────┐
│  LAYER 0 — V8 GATEWAY & ARMOR       │
│  • Language Gate (Latin/Hinglish)   │
│  • Mixed-script injection block     │
│  • Homoglyph sanitizer (Cyrillic→Latin) │
│  • Front-door regex (instant block) │
└────────────────┬────────────────────┘
                 │
     ┌───────────▼────────────┐
     │  mode === detect_only? │
     └───┬───────────┬────────┘
         │ YES       │ NO
         ▼           ▼
    [NODE-3]    [NODE-1] Primary Brain
    <50ms       ~300ms, context-aware rewrite
    boolean         │
    result          │ (if Node-1 fails)
         │          ▼
         │      [NODE-2] HA Fallback
         │      ~300-400ms
         │          │
         └──────────▼
              Response
  • Node-1 — Primary brain. Smart context-aware rewrite. Uses the most powerful internal models.
  • Node-2 — High-availability fallback. Takes over seamlessly if Node-1 times out.
  • Node-3 — Deep Scanner. Boolean only (is_toxic: true/false). No rewrites. Used exclusively for detect_only mode and as last-resort fallback.

License

MIT © 2026 Raiplus Engine — raiplus.in