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
Maintainers
Readme
raiplus-moderation
Official Node.js SDK for the Raiplus Engine — Hinglish + English content moderation API with a 3-Tier AI pipeline.
Table of Contents
- Requirements
- Installation
- Quick Start
- Authentication
- Methods
- Response Shapes
- Error Handling
- Rate Limits
- TypeScript
- Configuration Options
- 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
fetchAPI (available since Node 18) andAbortSignal.timeout()— no extra dependencies needed.
Installation
npm install raiplus-moderationThat'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.03Authentication
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_xxxxxxxxxxxxxxxxrequire('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 rewritesParameters:
| 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: 0for maximum throughput (300/min burst). Then usemoderate()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 // 429The 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 fordetect_onlymode and as last-resort fallback.
License
MIT © 2026 Raiplus Engine — raiplus.in
