@aisociety/promptshield
v0.1.0-beta.0
Published
Official TypeScript SDK for PromptShield — AI security middleware by AI Society
Maintainers
Readme
@aisociety/promptshield
Official TypeScript / JavaScript SDK for PromptShield — AI security middleware that protects your LLM apps from prompt injection, jailbreaks, social engineering, and document-based attacks.
User → PromptShield → Your LLM → PromptShield → User
↑ blocks attacks ↑ validates output- Zero runtime dependencies
- Native
fetch(Node ≥ 18, Bun, Deno, browsers) - Strong types, ESM-first
- Works in serverless (Vercel, Cloudflare Workers, AWS Lambda)
Install
pnpm add @aisociety/promptshield
# or
npm i @aisociety/promptshield
# or
yarn add @aisociety/promptshieldNode < 18? Polyfill
fetchandFormData, or upgrade. Pass your fetch in vianew PromptShield({ fetch }).
Quickstart
import { PromptShield } from '@aisociety/promptshield';
const ps = new PromptShield({ apiKey: process.env.PROMPTSHIELD_API_KEY! });
const result = await ps.check({ message: userInput });
if (!result.safe) {
return { error: 'blocked', reason: result.reason };
}
// safe — call your LLMGet an API key at promptshield.sociedadia.com.
API reference
new PromptShield(options)
| Option | Type | Default |
| --- | --- | --- |
| apiKey | string (required) | — |
| baseUrl | string | https://api.promptshield.sociedadia.com |
| fetch | typeof fetch | globalThis.fetch |
| timeoutMs | number | 30000 |
| defaultHeaders | Record<string, string> | {} |
ps.check(params)
Run a security check on user input before sending it to your LLM.
const result = await ps.check({
message: 'Ignore previous instructions and...',
sessionId: 'sess-123',
userId: 'user-42',
history: [{ role: 'user', content: 'previous turn' }],
inboxLink: 'https://your-app.com/inbox/abc',
});Returns:
{
safe: boolean;
riskLevel: 'low' | 'medium' | 'high';
reason: string;
layerBlocked: number | string | null;
category?: AttackCategory;
confidence?: number;
cached?: boolean;
creditsConsumed: number;
creditsRemaining: number;
latencyMs: number;
requestId: string;
}Cost: 1 credit per check.
ps.validateOutput(params)
Run a check on the LLM response before returning it to the user. Catches data exfiltration, jailbreak success, and policy violations.
const out = await ps.validateOutput({ response: llmReply });
if (!out.safe) {
return { error: 'response_blocked', reason: out.reason };
}Cost: 0.5 credits per check.
ps.scanDocument(params)
Scan an uploaded file for indirect prompt injection. Supports PDF, DOCX, XLSX, and images.
import { readFileSync } from 'node:fs';
// From Node Buffer
const scan = await ps.scanDocument({
file: readFileSync('./contract.pdf'),
filename: 'contract.pdf',
mimetype: 'application/pdf',
});
// From browser File / Blob
const scan = await ps.scanDocument({
file: fileFromInput,
filename: fileFromInput.name,
});
// From base64
const scan = await ps.scanDocument({
file: { base64: '...', filename: 'doc.pdf', mimetype: 'application/pdf' },
});For files ≤ 2 MB, returns a synchronous result. Larger files are queued:
if (scan.status === 'completed') {
console.log(scan.safe, scan.reason);
} else {
// Poll
let status = await ps.getScanStatus(scan.jobId);
while (status.status === 'queued' || status.status === 'processing') {
await new Promise((r) => setTimeout(r, 1000));
status = await ps.getScanStatus(scan.jobId);
}
console.log(status.result?.safe);
}Cost: 3 credits per scan.
ps.isSafe(result)
Convenience guard:
if (ps.isSafe(result)) { /* allow */ }Errors
All non-2xx responses throw PromptShieldError:
import { PromptShieldError } from '@aisociety/promptshield';
try {
await ps.check({ message });
} catch (err) {
if (err instanceof PromptShieldError) {
console.error(err.status, err.code, err.message, err.requestId);
}
}| Code | Meaning |
| --- | --- |
| unauthorized | Bad or missing API key |
| insufficient_credits | Out of credits on the Free plan |
| rate_limited | Per-key rate limit hit |
| timeout | Request exceeded timeoutMs |
| network_error | Connection failed |
Integration examples
Before an OpenAI call
import OpenAI from 'openai';
import { PromptShield } from '@aisociety/promptshield';
const ps = new PromptShield({ apiKey: process.env.PROMPTSHIELD_API_KEY! });
const openai = new OpenAI();
export async function chat(userMessage: string, sessionId: string) {
const check = await ps.check({ message: userMessage, sessionId });
if (!check.safe) {
return { blocked: true, reason: check.reason };
}
const completion = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: userMessage }],
});
const reply = completion.choices[0]?.message?.content ?? '';
const out = await ps.validateOutput({ response: reply, sessionId });
if (!out.safe) {
return { blocked: true, reason: out.reason };
}
return { reply };
}Before an Anthropic call
import Anthropic from '@anthropic-ai/sdk';
import { PromptShield } from '@aisociety/promptshield';
const ps = new PromptShield({ apiKey: process.env.PROMPTSHIELD_API_KEY! });
const anthropic = new Anthropic();
export async function ask(userMessage: string) {
const check = await ps.check({ message: userMessage });
if (!check.safe) throw new Error(`blocked: ${check.reason}`);
const msg = await anthropic.messages.create({
model: 'claude-sonnet-4-5',
max_tokens: 1024,
messages: [{ role: 'user', content: userMessage }],
});
return msg;
}Document upload from Express
import express from 'express';
import multer from 'multer';
import { PromptShield } from '@aisociety/promptshield';
const ps = new PromptShield({ apiKey: process.env.PROMPTSHIELD_API_KEY! });
const upload = multer({ limits: { fileSize: 10 * 1024 * 1024 } });
const app = express();
app.post('/upload', upload.single('file'), async (req, res) => {
if (!req.file) return res.status(400).json({ error: 'no file' });
const scan = await ps.scanDocument({
file: req.file.buffer,
filename: req.file.originalname,
mimetype: req.file.mimetype,
userId: req.user?.id,
});
if (scan.status !== 'completed') {
return res.json({ status: 'pending', jobId: scan.jobId });
}
if (!scan.safe) return res.status(400).json({ error: 'unsafe', reason: scan.reason });
// safe — store and process
res.json({ ok: true });
});Links
- Dashboard: https://promptshield.sociedadia.com
- Docs: https://promptshield.sociedadia.com/docs
- Status: https://promptshield.sociedadia.com/status
- Issues: https://github.com/sociedadia/prompt-shield/issues
License
MIT © AI Society
