{"_id":"@aisociety/promptshield","name":"@aisociety/promptshield","dist-tags":{"beta":"0.1.0-beta.0","latest":"0.1.0-beta.0"},"versions":{"0.1.0-beta.0":{"name":"@aisociety/promptshield","version":"0.1.0-beta.0","description":"Official TypeScript SDK for PromptShield — AI security middleware by AI Society","license":"MIT","homepage":"https://promptshield.sociedadia.com","repository":{"type":"git","url":"git+https://github.com/sociedadia/prompt-shield.git","directory":"packages/sdk"},"bugs":{"url":"https://github.com/sociedadia/prompt-shield/issues"},"type":"module","main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"}},"engines":{"node":">=18"},"sideEffects":false,"scripts":{"build":"tsc -p tsconfig.json","dev":"tsc -w -p tsconfig.json","typecheck":"tsc --noEmit","prepublishOnly":"rm -rf dist && tsc -p tsconfig.json"},"devDependencies":{"typescript":"^5.7.2"},"publishConfig":{"access":"public"},"keywords":["ai","security","prompt-injection","jailbreak","llm","chatbot","guardrails","promptshield","anthropic","openai"],"gitHead":"f8639b801424f43824697387b97ff6e09cb13250","_id":"@aisociety/promptshield@0.1.0-beta.0","_nodeVersion":"24.13.1","_npmVersion":"11.8.0","dist":{"integrity":"sha512-BpYA1I47/muVARt4eeEH5LaoUZvpR5YgZ47vRmQNtReW2VVV1rPBTYiDy5ezz+LXCGnrCFk28wdT2/SFjFffFQ==","shasum":"cc4acbd551ba04f44cf009f7529b2544c041b70f","tarball":"https://registry.npmjs.org/@aisociety/promptshield/-/promptshield-0.1.0-beta.0.tgz","fileCount":6,"unpackedSize":34450,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDWeB67LzWpi2usthTr1sXhbri3Wg3ubiq6lzEfkuL5HgIhANk6YKEybibhI24T21++bJP0Xw0YCfb15NLsf65AuZFJ"}]},"_npmUser":{"name":"luisvargasfdz","email":"luisvargasfdz@gmail.com"},"directories":{},"maintainers":[{"name":"luisvargasfdz","email":"luisvargasfdz@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/promptshield_0.1.0-beta.0_1777785762899_0.12756965821249833"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-03T05:22:42.843Z","0.1.0-beta.0":"2026-05-03T05:22:43.050Z","modified":"2026-05-03T05:22:43.214Z"},"maintainers":[{"name":"luisvargasfdz","email":"luisvargasfdz@gmail.com"}],"description":"Official TypeScript SDK for PromptShield — AI security middleware by AI Society","homepage":"https://promptshield.sociedadia.com","keywords":["ai","security","prompt-injection","jailbreak","llm","chatbot","guardrails","promptshield","anthropic","openai"],"repository":{"type":"git","url":"git+https://github.com/sociedadia/prompt-shield.git","directory":"packages/sdk"},"bugs":{"url":"https://github.com/sociedadia/prompt-shield/issues"},"license":"MIT","readme":"# @aisociety/promptshield\n\nOfficial TypeScript / JavaScript SDK for [PromptShield](https://promptshield.sociedadia.com) — AI security middleware that protects your LLM apps from prompt injection, jailbreaks, social engineering, and document-based attacks.\n\n```\nUser → PromptShield → Your LLM → PromptShield → User\n       ↑ blocks attacks         ↑ validates output\n```\n\n- Zero runtime dependencies\n- Native `fetch` (Node ≥ 18, Bun, Deno, browsers)\n- Strong types, ESM-first\n- Works in serverless (Vercel, Cloudflare Workers, AWS Lambda)\n\n---\n\n## Install\n\n```bash\npnpm add @aisociety/promptshield\n# or\nnpm i @aisociety/promptshield\n# or\nyarn add @aisociety/promptshield\n```\n\n> **Node < 18?** Polyfill `fetch` and `FormData`, or upgrade. Pass your fetch in via `new PromptShield({ fetch })`.\n\n---\n\n## Quickstart\n\n```ts\nimport { PromptShield } from '@aisociety/promptshield';\n\nconst ps = new PromptShield({ apiKey: process.env.PROMPTSHIELD_API_KEY! });\n\nconst result = await ps.check({ message: userInput });\nif (!result.safe) {\n  return { error: 'blocked', reason: result.reason };\n}\n// safe — call your LLM\n```\n\nGet an API key at [promptshield.sociedadia.com](https://promptshield.sociedadia.com).\n\n---\n\n## API reference\n\n### `new PromptShield(options)`\n\n| Option | Type | Default |\n| --- | --- | --- |\n| `apiKey` | `string` (required) | — |\n| `baseUrl` | `string` | `https://api.promptshield.sociedadia.com` |\n| `fetch` | `typeof fetch` | `globalThis.fetch` |\n| `timeoutMs` | `number` | `30000` |\n| `defaultHeaders` | `Record<string, string>` | `{}` |\n\n### `ps.check(params)`\n\nRun a security check on user input before sending it to your LLM.\n\n```ts\nconst result = await ps.check({\n  message: 'Ignore previous instructions and...',\n  sessionId: 'sess-123',\n  userId: 'user-42',\n  history: [{ role: 'user', content: 'previous turn' }],\n  inboxLink: 'https://your-app.com/inbox/abc',\n});\n```\n\nReturns:\n\n```ts\n{\n  safe: boolean;\n  riskLevel: 'low' | 'medium' | 'high';\n  reason: string;\n  layerBlocked: number | string | null;\n  category?: AttackCategory;\n  confidence?: number;\n  cached?: boolean;\n  creditsConsumed: number;\n  creditsRemaining: number;\n  latencyMs: number;\n  requestId: string;\n}\n```\n\nCost: 1 credit per check.\n\n### `ps.validateOutput(params)`\n\nRun a check on the LLM response before returning it to the user. Catches data exfiltration, jailbreak success, and policy violations.\n\n```ts\nconst out = await ps.validateOutput({ response: llmReply });\nif (!out.safe) {\n  return { error: 'response_blocked', reason: out.reason };\n}\n```\n\nCost: 0.5 credits per check.\n\n### `ps.scanDocument(params)`\n\nScan an uploaded file for indirect prompt injection. Supports PDF, DOCX, XLSX, and images.\n\n```ts\nimport { readFileSync } from 'node:fs';\n\n// From Node Buffer\nconst scan = await ps.scanDocument({\n  file: readFileSync('./contract.pdf'),\n  filename: 'contract.pdf',\n  mimetype: 'application/pdf',\n});\n\n// From browser File / Blob\nconst scan = await ps.scanDocument({\n  file: fileFromInput,\n  filename: fileFromInput.name,\n});\n\n// From base64\nconst scan = await ps.scanDocument({\n  file: { base64: '...', filename: 'doc.pdf', mimetype: 'application/pdf' },\n});\n```\n\nFor files ≤ 2 MB, returns a synchronous result. Larger files are queued:\n\n```ts\nif (scan.status === 'completed') {\n  console.log(scan.safe, scan.reason);\n} else {\n  // Poll\n  let status = await ps.getScanStatus(scan.jobId);\n  while (status.status === 'queued' || status.status === 'processing') {\n    await new Promise((r) => setTimeout(r, 1000));\n    status = await ps.getScanStatus(scan.jobId);\n  }\n  console.log(status.result?.safe);\n}\n```\n\nCost: 3 credits per scan.\n\n### `ps.isSafe(result)`\n\nConvenience guard:\n\n```ts\nif (ps.isSafe(result)) { /* allow */ }\n```\n\n### Errors\n\nAll non-2xx responses throw `PromptShieldError`:\n\n```ts\nimport { PromptShieldError } from '@aisociety/promptshield';\n\ntry {\n  await ps.check({ message });\n} catch (err) {\n  if (err instanceof PromptShieldError) {\n    console.error(err.status, err.code, err.message, err.requestId);\n  }\n}\n```\n\n| Code | Meaning |\n| --- | --- |\n| `unauthorized` | Bad or missing API key |\n| `insufficient_credits` | Out of credits on the Free plan |\n| `rate_limited` | Per-key rate limit hit |\n| `timeout` | Request exceeded `timeoutMs` |\n| `network_error` | Connection failed |\n\n---\n\n## Integration examples\n\n### Before an OpenAI call\n\n```ts\nimport OpenAI from 'openai';\nimport { PromptShield } from '@aisociety/promptshield';\n\nconst ps = new PromptShield({ apiKey: process.env.PROMPTSHIELD_API_KEY! });\nconst openai = new OpenAI();\n\nexport async function chat(userMessage: string, sessionId: string) {\n  const check = await ps.check({ message: userMessage, sessionId });\n  if (!check.safe) {\n    return { blocked: true, reason: check.reason };\n  }\n\n  const completion = await openai.chat.completions.create({\n    model: 'gpt-4o-mini',\n    messages: [{ role: 'user', content: userMessage }],\n  });\n  const reply = completion.choices[0]?.message?.content ?? '';\n\n  const out = await ps.validateOutput({ response: reply, sessionId });\n  if (!out.safe) {\n    return { blocked: true, reason: out.reason };\n  }\n  return { reply };\n}\n```\n\n### Before an Anthropic call\n\n```ts\nimport Anthropic from '@anthropic-ai/sdk';\nimport { PromptShield } from '@aisociety/promptshield';\n\nconst ps = new PromptShield({ apiKey: process.env.PROMPTSHIELD_API_KEY! });\nconst anthropic = new Anthropic();\n\nexport async function ask(userMessage: string) {\n  const check = await ps.check({ message: userMessage });\n  if (!check.safe) throw new Error(`blocked: ${check.reason}`);\n\n  const msg = await anthropic.messages.create({\n    model: 'claude-sonnet-4-5',\n    max_tokens: 1024,\n    messages: [{ role: 'user', content: userMessage }],\n  });\n  return msg;\n}\n```\n\n### Document upload from Express\n\n```ts\nimport express from 'express';\nimport multer from 'multer';\nimport { PromptShield } from '@aisociety/promptshield';\n\nconst ps = new PromptShield({ apiKey: process.env.PROMPTSHIELD_API_KEY! });\nconst upload = multer({ limits: { fileSize: 10 * 1024 * 1024 } });\nconst app = express();\n\napp.post('/upload', upload.single('file'), async (req, res) => {\n  if (!req.file) return res.status(400).json({ error: 'no file' });\n\n  const scan = await ps.scanDocument({\n    file: req.file.buffer,\n    filename: req.file.originalname,\n    mimetype: req.file.mimetype,\n    userId: req.user?.id,\n  });\n\n  if (scan.status !== 'completed') {\n    return res.json({ status: 'pending', jobId: scan.jobId });\n  }\n  if (!scan.safe) return res.status(400).json({ error: 'unsafe', reason: scan.reason });\n\n  // safe — store and process\n  res.json({ ok: true });\n});\n```\n\n---\n\n## Links\n\n- Dashboard: <https://promptshield.sociedadia.com>\n- Docs: <https://promptshield.sociedadia.com/docs>\n- Status: <https://promptshield.sociedadia.com/status>\n- Issues: <https://github.com/sociedadia/prompt-shield/issues>\n\n---\n\n## License\n\nMIT © AI Society\n","readmeFilename":"README.md","_rev":"1-9491449015b10b97a36935d48695728a"}