{"_id":"@canary-ops/sdk","_rev":"7-ab64ee71172bc38e259e88c4b18d3bba","name":"@canary-ops/sdk","dist-tags":{"latest":"0.6.0"},"versions":{"0.1.0":{"name":"@canary-ops/sdk","version":"0.1.0","keywords":["canary","ai-security","llm","observability","telemetry","ai-firewall","prompt-injection","agent-monitoring","llmops"],"author":{"name":"Canary"},"license":"MIT","_id":"@canary-ops/sdk@0.1.0","maintainers":[{"name":"cryptosuess","email":"cryptosuess@gmail.com"}],"homepage":"https://canary-ops.base44.app","bugs":{"url":"https://github.com/CryptoSuess/canary-sdk/issues"},"dist":{"shasum":"ceef48676aaaa1e19afdf11201c4f66cb91d8b12","tarball":"https://registry.npmjs.org/@canary-ops/sdk/-/sdk-0.1.0.tgz","fileCount":9,"integrity":"sha512-rPC41AhjwUMmy23+uWAZYIDfSuSvIPLI3nRe6GxHqfCxwmalL/HF4Rf82nlR27ffiutgnH+/IP5BVt9AUp+sIQ==","signatures":[{"sig":"MEYCIQC99Mz94s4KOHQPZS6M9h+4tLhAHkwfzHH7Udc14B49BwIhAPRn94o9h2672NjGpMCBXVENrlbUus99fV5OJXHUERZL","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":85804},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./package.json":"./package.json"},"gitHead":"3b0139d17c93649cf2c8008d15443d0f5054f326","scripts":{"dev":"tsup --watch","build":"tsup","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"cryptosuess","email":"cryptosuess@gmail.com"},"repository":{"url":"git+https://github.com/CryptoSuess/canary-sdk.git","type":"git"},"_npmVersion":"11.15.0","description":"The Operating System for AI Security — monitor, secure, and audit every AI agent and LLM application in production. Zero-dependency telemetry + firewall SDK for Canary.","directories":{},"sideEffects":false,"_nodeVersion":"24.15.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.5","typescript":"^5.8.2"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.1.0_1780536913317_0.36018942702062584","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@canary-ops/sdk","version":"0.2.0","keywords":["canary","ai-security","llm","observability","telemetry","ai-firewall","prompt-injection","agent-monitoring","llmops"],"author":{"name":"Canary"},"license":"MIT","_id":"@canary-ops/sdk@0.2.0","maintainers":[{"name":"cryptosuess","email":"cryptosuess@gmail.com"}],"homepage":"https://canary-ops.base44.app","bugs":{"url":"https://github.com/CryptoSuess/canary-sdk/issues"},"dist":{"shasum":"dbbe065924c2aabd42a60c81796e054a39d16f22","tarball":"https://registry.npmjs.org/@canary-ops/sdk/-/sdk-0.2.0.tgz","fileCount":10,"integrity":"sha512-AIO6dzxh1CwVQ//3clpdxMCbO31t6pKV9EvFerAW1O2VcAYD5xeRc4JdvyAV1Y1RQ5oGcMCHq9fWvZnwbPN3XQ==","signatures":[{"sig":"MEQCIHkufKZT3SSQf7YBzE3yFVn+oQWjtkjMe2EB3vhFpF9lAiAPeUaP34X4NLS8zGWU0z2QnaZtiDD9b/0AY2cShB/1CA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":269571},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./package.json":"./package.json"},"gitHead":"3fec4a51b7333ebc979d7663df63405f4e14e105","scripts":{"dev":"tsup --watch","lint":"eslint .","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run typecheck && npm run lint && npm run test && npm run build"},"_npmUser":{"name":"cryptosuess","email":"cryptosuess@gmail.com"},"repository":{"url":"git+https://github.com/CryptoSuess/canary-sdk.git","type":"git"},"_npmVersion":"11.15.0","description":"The Operating System for AI Security — monitor, secure, and audit every AI agent and LLM application in production. Zero-dependency telemetry, redaction, and firewall SDK for Canary.","directories":{},"sideEffects":false,"_nodeVersion":"24.15.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.5","eslint":"^9.39.4","vitest":"^2.1.9","globals":"^15.15.0","@eslint/js":"^9.39.4","typescript":"^5.8.2","typescript-eslint":"^8.60.1","@vitest/coverage-v8":"^2.1.9"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.2.0_1780707728760_0.9063539987415918","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@canary-ops/sdk","version":"0.3.0","keywords":["canary","ai-security","llm","observability","telemetry","ai-firewall","prompt-injection","agent-monitoring","llmops"],"author":{"name":"CryptoSuess & Txnchi"},"license":"MIT","_id":"@canary-ops/sdk@0.3.0","maintainers":[{"name":"cryptosuess","email":"cryptosuess@gmail.com"}],"homepage":"https://canary-ops.base44.app","bugs":{"url":"https://github.com/CryptoSuess/canary-sdk/issues"},"dist":{"shasum":"eae6b37a25d823d59e490cfedec8c77cabb75100","tarball":"https://registry.npmjs.org/@canary-ops/sdk/-/sdk-0.3.0.tgz","fileCount":10,"integrity":"sha512-XqtmhmdXKfInBs29YBV+EVsc4lSJkCqwtflujCkmE7B3mwNvjeNLS5NUl9RenLefIwXERiuKtEkDN98OX4UT6A==","signatures":[{"sig":"MEYCIQCtTesXFntgBvA5pyGPwd0ckdYd4qQ//maSlSZX1Jyx7wIhAO69qg5B48JG013kjx+zzsh1hpDg8s1Uo6NQo1XRgSrm","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":318054},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./package.json":"./package.json"},"gitHead":"add17d6738d090fa5bdcf68d1902d9d6464bc96b","scripts":{"dev":"tsup --watch","lint":"eslint .","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run typecheck && npm run lint && npm run test && npm run build"},"_npmUser":{"name":"cryptosuess","email":"cryptosuess@gmail.com"},"repository":{"url":"git+https://github.com/CryptoSuess/canary-sdk.git","type":"git"},"_npmVersion":"11.15.0","description":"The Operating System for AI Security — monitor, secure, and audit every AI agent and LLM application in production. Zero-dependency telemetry, redaction, and firewall SDK for Canary.","directories":{},"sideEffects":false,"_nodeVersion":"24.15.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.5","eslint":"^9.39.4","vitest":"^2.1.9","globals":"^15.15.0","@eslint/js":"^9.39.4","typescript":"^5.8.2","typescript-eslint":"^8.60.1","@vitest/coverage-v8":"^2.1.9"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.3.0_1781154034376_0.3878022924542679","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@canary-ops/sdk","version":"0.4.0","keywords":["canary","ai-security","llm","observability","telemetry","ai-firewall","prompt-injection","agent-monitoring","llmops"],"author":{"name":"CryptoSuess & Txnchi"},"license":"MIT","_id":"@canary-ops/sdk@0.4.0","maintainers":[{"name":"cryptosuess","email":"cryptosuess@gmail.com"}],"homepage":"https://canary-ops.base44.app","bugs":{"url":"https://github.com/CryptoSuess/canary-sdk/issues"},"dist":{"shasum":"8bf8aff986f5c8ed45838ce989399fd7cc73c331","tarball":"https://registry.npmjs.org/@canary-ops/sdk/-/sdk-0.4.0.tgz","fileCount":10,"integrity":"sha512-ax7v4jSMgBJ/06tCVKA2dm6leBrIQ904ziiG71eEjI5e3rhpP4w4KbHpFLRk2dUAmI1VsPbE7Ihiy0g53qL0ug==","signatures":[{"sig":"MEQCIGNoemPzF+Oko4OigiaiTGwhzLqf7vHEehOE1mPDpQBpAiB0bydPHVfLpexQPlPvYzxnBgcDNWFEHZ1ikiZYModQmA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":435230},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./package.json":"./package.json"},"gitHead":"ed2d651c9839d00a9244386d616f248bb384da0c","scripts":{"dev":"tsup --watch","lint":"eslint .","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run typecheck && npm run lint && npm run test && npm run build"},"_npmUser":{"name":"cryptosuess","email":"cryptosuess@gmail.com"},"repository":{"url":"git+https://github.com/CryptoSuess/canary-sdk.git","type":"git"},"_npmVersion":"11.15.0","description":"The Operating System for AI Security — monitor, secure, and audit every AI agent and LLM application in production. Zero-dependency telemetry, redaction, and firewall SDK for Canary.","directories":{},"sideEffects":false,"_nodeVersion":"24.15.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.5","eslint":"^9.39.4","vitest":"^2.1.9","globals":"^15.15.0","@eslint/js":"^9.39.4","typescript":"^5.8.2","typescript-eslint":"^8.60.1","@vitest/coverage-v8":"^2.1.9"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.4.0_1781191575813_0.23557233127962718","host":"s3://npm-registry-packages-npm-production"}},"0.4.1":{"name":"@canary-ops/sdk","version":"0.4.1","keywords":["canary","ai-security","llm","observability","telemetry","ai-firewall","prompt-injection","agent-monitoring","llmops"],"author":{"name":"CryptoSuess & Txnchi"},"license":"MIT","_id":"@canary-ops/sdk@0.4.1","maintainers":[{"name":"cryptosuess","email":"cryptosuess@gmail.com"}],"homepage":"https://canary-ops.base44.app","bugs":{"url":"https://github.com/CryptoSuess/canary-sdk/issues"},"dist":{"shasum":"14abb8e4501fdde262b72349e8d2564b7f3cc3d1","tarball":"https://registry.npmjs.org/@canary-ops/sdk/-/sdk-0.4.1.tgz","fileCount":10,"integrity":"sha512-RKs4qo6iKwjKumKbTSTL/eF+LxPzzdLlxmOX0pwiiDr3TrHZiAjdcMfTHKwjDa60Wo67tzT4Hvi8U8MuSGzg2Q==","signatures":[{"sig":"MEUCIQDXpZ1MCyRmte03n6OKU4GH6UwkrC6Ntc5+L4oSCP42ZgIgEbMudaKTJnfoKHQPU73RC8xKgpXgDx/8TfNzHlQZQJM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":439665},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./package.json":"./package.json"},"gitHead":"5efed7752ac81e7ff749aac7e960ce837dc0476e","scripts":{"dev":"tsup --watch","lint":"eslint .","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run typecheck && npm run lint && npm run test && npm run build"},"_npmUser":{"name":"cryptosuess","email":"cryptosuess@gmail.com"},"repository":{"url":"git+https://github.com/CryptoSuess/canary-sdk.git","type":"git"},"_npmVersion":"11.15.0","description":"The Operating System for AI Security — monitor, secure, and audit every AI agent and LLM application in production. Zero-dependency telemetry, redaction, and firewall SDK for Canary.","directories":{},"sideEffects":false,"_nodeVersion":"24.15.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.5","eslint":"^9.39.4","vitest":"^2.1.9","globals":"^15.15.0","@eslint/js":"^9.39.4","typescript":"^5.8.2","typescript-eslint":"^8.60.1","@vitest/coverage-v8":"^2.1.9"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.4.1_1781193536819_0.9024730453938847","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@canary-ops/sdk","version":"0.5.0","keywords":["canary","ai-security","llm","observability","telemetry","ai-firewall","prompt-injection","agent-monitoring","llmops"],"author":{"name":"CryptoSuess & Txnchi"},"license":"MIT","_id":"@canary-ops/sdk@0.5.0","maintainers":[{"name":"cryptosuess","email":"cryptosuess@gmail.com"}],"homepage":"https://canary-ops.base44.app","bugs":{"url":"https://github.com/CryptoSuess/canary-sdk/issues"},"dist":{"shasum":"8079bd90846a342d3442ef1a49b6fe2dac8900df","tarball":"https://registry.npmjs.org/@canary-ops/sdk/-/sdk-0.5.0.tgz","fileCount":10,"integrity":"sha512-4ZqkcI4zh/e2+qtfE9Wvi07VtpvetbY4uhNG5aVKMKMWMVFKHDlY74ucJ0d2eGNNbxvR9v99rKT/fGRXDsGFAQ==","signatures":[{"sig":"MEQCIE4tB8wJk8DypKpg5ka7kfoGrEN5yIfwYxyz2YJrWv0bAiA/aVI24JxmFPMe860djEqYf1tLEjt3qW4+chcRjciibA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":455145},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=24"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./package.json":"./package.json"},"gitHead":"5efed7752ac81e7ff749aac7e960ce837dc0476e","scripts":{"dev":"tsup --watch","lint":"eslint .","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run typecheck && npm run lint && npm run test && npm run build"},"_npmUser":{"name":"cryptosuess","email":"cryptosuess@gmail.com"},"repository":{"url":"git+https://github.com/CryptoSuess/canary-sdk.git","type":"git"},"_npmVersion":"11.15.0","description":"The Operating System for AI Security — monitor, secure, and audit every AI agent and LLM application in production. Zero-dependency telemetry, redaction, and firewall SDK for Canary.","directories":{},"sideEffects":false,"_nodeVersion":"24.15.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.5","eslint":"^9.39.4","vitest":"^2.1.9","globals":"^15.15.0","@eslint/js":"^9.39.4","typescript":"^5.8.2","@types/node":"^25.9.3","typescript-eslint":"^8.60.1","@vitest/coverage-v8":"^2.1.9"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.5.0_1781300815946_0.2072516401769242","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"@canary-ops/sdk","version":"0.6.0","description":"The Operating System for AI Security — monitor, secure, and audit every AI agent and LLM application in production. Zero-dependency telemetry, redaction, and firewall SDK for Canary.","type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./package.json":"./package.json"},"sideEffects":false,"scripts":{"build":"tsup","dev":"tsup --watch","typecheck":"tsc --noEmit","lint":"eslint .","test":"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run typecheck && npm run lint && npm run test && npm run build"},"keywords":["canary","ai-security","llm","observability","telemetry","ai-firewall","prompt-injection","agent-monitoring","llmops"],"author":{"name":"CryptoSuess & Txnchi"},"license":"MIT","homepage":"https://canary-ops.base44.app","repository":{"type":"git","url":"git+https://github.com/CryptoSuess/canary-sdk.git"},"bugs":{"url":"https://github.com/CryptoSuess/canary-sdk/issues"},"engines":{"node":">=24"},"publishConfig":{"access":"public"},"devDependencies":{"@eslint/js":"^9.39.4","@types/node":"^25.9.3","@vitest/coverage-v8":"^2.1.9","eslint":"^9.39.4","globals":"^15.15.0","tsup":"^8.3.5","typescript":"^5.8.2","typescript-eslint":"^8.60.1","vitest":"^2.1.9"},"gitHead":"c0f170ebbdb8abcd8e35c8808ee79d559e130aa9","_id":"@canary-ops/sdk@0.6.0","_nodeVersion":"24.15.0","_npmVersion":"11.15.0","dist":{"integrity":"sha512-KXAV0UD7iuD7YS5njWfWY58CpoG3m3kIG5/60NSrPYbslzxlA42Fo2nRJdGDiYG/WdkKPvRuTxeBhWPRjrgMBA==","shasum":"cd5f12f84c6dea5c17e115044122f20e3de0f6e4","tarball":"https://registry.npmjs.org/@canary-ops/sdk/-/sdk-0.6.0.tgz","fileCount":10,"unpackedSize":455145,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDhz4pjrDG+fKIReEdCcAHQiuFfg4PPFh5oONR3bY4oxgIhAKI0//Xve1V9/iqE+ShYTnvwv4PEvoUbjAvL3y8VQW4Y"}]},"_npmUser":{"name":"cryptosuess","email":"cryptosuess@gmail.com"},"directories":{},"maintainers":[{"name":"cryptosuess","email":"cryptosuess@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sdk_0.6.0_1781752658187_0.09393216238766189"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-04T01:35:13.106Z","modified":"2026-06-18T03:17:38.501Z","0.1.0":"2026-06-04T01:35:13.459Z","0.2.0":"2026-06-06T01:02:08.917Z","0.3.0":"2026-06-11T05:00:34.535Z","0.4.0":"2026-06-11T15:26:16.135Z","0.4.1":"2026-06-11T15:58:56.970Z","0.5.0":"2026-06-12T21:46:56.092Z","0.6.0":"2026-06-18T03:17:38.373Z"},"bugs":{"url":"https://github.com/CryptoSuess/canary-sdk/issues"},"author":{"name":"CryptoSuess & Txnchi"},"license":"MIT","homepage":"https://canary-ops.base44.app","keywords":["canary","ai-security","llm","observability","telemetry","ai-firewall","prompt-injection","agent-monitoring","llmops"],"repository":{"type":"git","url":"git+https://github.com/CryptoSuess/canary-sdk.git"},"description":"The Operating System for AI Security — monitor, secure, and audit every AI agent and LLM application in production. Zero-dependency telemetry, redaction, and firewall SDK for Canary.","maintainers":[{"name":"cryptosuess","email":"cryptosuess@gmail.com"}],"readme":"# @canary-ops/sdk\n\n**The Operating System for AI Security.** Monitor, secure, and audit every AI\nagent and LLM application in production — in under five minutes, with one\nzero-dependency package.\n\n```bash\nnpm install @canary-ops/sdk\n```\n\n```js\nimport canary from '@canary-ops/sdk';\n\ncanary.init({ apiKey: 'sk-canary-...', agentId: 'agt_...' });\n\n// All telemetry now flowing to Canary ✓\n```\n\n## Why\n\nYou can't secure what you can't see. Canary captures every prompt, response,\ntool call, token, cost, and latency from your agents, blocks prompt injections\nand jailbreaks **before** they reach your model, scans LLM outputs for leaked\nsecrets and PII **before they reach your users**, and **redacts sensitive data\nbefore any content leaves your process** — so the thing watching your agents\nnever becomes the thing that leaks your data.\n\n- 🔌 **Plugs in** — wrap your OpenAI, Anthropic, Gemini, or Bedrock client, use the LangChain callback handler, or integrate via the Vercel AI SDK telemetry hook. Streaming included.\n- 🛡️ **Input firewall** — injection/jailbreak heuristics run in-process at zero latency, with optional remote deep-scan.\n- 🔍 **Output scanning** — `scanResponse()` checks LLM outputs for secrets, PII, harmful content, and canary token exfiltration.\n- 🪤 **Canary tokens** — plant synthetic decoy credentials; get a critical alert the instant they appear in a response.\n- 🔒 **Redaction built in** — API keys, JWTs, private keys stripped by default; PII opt-in.\n- 🪶 **Zero dependencies** — isomorphic across Node 18+, browsers, Deno, Bun, edge.\n- 🧱 **Production-safe** — timeouts, retries with backoff, a circuit breaker, and **fail-open** by default so it never takes your app down.\n\n## Quickstart\n\n```js\nimport canary from '@canary-ops/sdk';\n\ncanary.init({\n  apiKey: process.env.CANARY_API_KEY, // sk-canary-...\n  agentId: process.env.CANARY_AGENT_ID,\n});\n\n// 1. Block malicious prompts (local heuristics + remote scan)\nawait canary.guard(userPrompt); // throws CanaryBlockedError if blocked\n\n// 2. Track model calls (cost auto-computed from model + tokens)\ncanary.trackPrompt({\n  content: userPrompt,\n  model: 'gpt-4o',\n  tokens_in: 42,\n  tokens_out: 128,\n  latency_ms: 340,\n});\n\n// 3. Scan the response before returning it to the user\nawait canary.scanResponse(responseText, { throwOnUnsafe: true });\n```\n\nEvents are **batched and flushed in the background** (every 5s or 20 events),\nso tracking never blocks your request path.\n\n## Auto-instrumentation\n\nWrap your existing client and Canary captures every call — **streaming and\nnon-streaming** — automatically.\n\n```js\nimport OpenAI from 'openai';\nimport canary from '@canary-ops/sdk';\n\ncanary.init({\n  apiKey: 'sk-canary-...', agentId: 'agt_...',\n  guard: { responses: true }, // auto-scan every response for secrets/PII/harmful content\n});\nconst openai = canary.wrapOpenAI(new OpenAI());\n\n// tokens, cost, latency, prompt + response all captured — even when streaming\n// responses are scanned automatically; CanaryBlockedError thrown if unsafe\nconst stream = await openai.chat.completions.create({\n  model: 'gpt-4o', stream: true, messages,\n});\nfor await (const chunk of stream) { /* your normal loop, untouched */ }\n```\n\n```js\nimport Anthropic from '@anthropic-ai/sdk';\nconst anthropic = canary.wrapAnthropic(new Anthropic());\nawait anthropic.messages.create({ model: 'claude-opus-4-8', messages, max_tokens: 1024 });\n```\n\n**Google Gemini:**\n\n```js\nimport { GoogleGenerativeAI } from '@google/generative-ai';\nconst genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);\nconst model = canary.wrapGemini(genAI.getGenerativeModel({ model: 'gemini-1.5-pro' }));\n// generateContent + generateContentStream both captured\nconst result = await model.generateContent('Hello');\n```\n\n**AWS Bedrock:**\n\n```js\nimport { BedrockRuntimeClient, InvokeModelCommand } from '@aws-sdk/client-bedrock-runtime';\nconst client = canary.wrapBedrock(new BedrockRuntimeClient({ region: 'us-east-1' }));\n// InvokeModelCommand + InvokeModelWithResponseStreamCommand captured\n// supports Claude, Titan, Llama 3, and Mistral model families\n```\n\n**LangChain (any version):**\n\n```js\nimport { ChatOpenAI } from '@langchain/openai';\nconst llm = new ChatOpenAI({ callbacks: [canary.callbackHandler()] });\n// LLM start/end/error + chain + tool events all captured\n```\n\n**Vercel AI SDK:**\n\n```js\nimport { generateText } from 'ai';\nconst result = await generateText({\n  model: openai('gpt-4o'),\n  prompt: 'Hello',\n  experimental_telemetry: canary.vercelTelemetry(),\n  // compatible with AI SDK v3 (ai.*) and v4+ (gen_ai.*) attribute names\n});\n```\n\nInstrument your tool/HTTP calls too:\n\n```js\nconst fetch = canary.wrapFetch(globalThis.fetch, { match: 'api.weather.com' });\n// latency, status, and errors for matching requests are now recorded\n```\n\n## Tracing\n\nWrap any async step to record its latency (and errors) as a span:\n\n```js\nconst docs = await canary.trace('retrieve_docs', () => vectorStore.search(query));\n```\n\n## Firewall\n\n```js\nconst verdict = await canary.scan(userPrompt);\n// { allowed, action, threats: [...], degraded? }\nif (!verdict.allowed) return refuse(verdict.threats);\n```\n\n- **Local heuristics** (in-process, no network) catch instruction-override,\n  DAN/jailbreak, system-prompt extraction, exfiltration, and embedded secrets.\n- **Remote deep-scan** adds semantic classification and your custom firewall rules.\n- A high-confidence local block **short-circuits** the network call.\n- If the remote scanner is down, behaviour follows `failOpen` (default `true` —\n  the local verdict stands and `degraded: true` is set).\n\n**Covered threat categories** (v0.3.0): prompt injection (direct + indirect tool\ninjection), jailbreaks (DAN, persona, hypothetical framing), system-prompt\nextraction (verbatim dump, context echo), data exfiltration (URL send, markdown\nlink, webhook instructions), adversarial encoding (base64/rot13/hex decode-and-run,\nleet-speak), and embedded secrets.\n\n## Output scanning\n\nScan an LLM response **before** returning it to the user:\n\n```js\nconst result = await canary.scanResponse(responseText);\nif (!result.allowed) {\n  return refuse(result.threats); // PII, secret, harmful content, or canary token\n}\n\n// Or throw on the spot\nawait canary.scanResponse(responseText, { throwOnUnsafe: true });\n```\n\nChecks for: leaked secrets and API keys, PII (SSNs, credit cards, emails,\nphones), canary token exfiltration, harmful content (LLM-as-judge), and\noff-topic responses (when `agent.purpose` is configured on the dashboard).\n\nEnable automatic output scanning for every completion:\n\n```js\ncanary.init({\n  apiKey, agentId,\n  guard: { responses: true }, // scan every wrapOpenAI / wrapAnthropic response\n});\n```\n\n## Canary tokens\n\nPlant synthetic decoy credentials in your agent's context or system prompt. If\na response ever includes one, Canary fires a critical `data_exfiltration` alert\n— catching exfiltration attacks the instant they succeed.\n\n```js\n// Plant a fake API key in the system prompt\nconst { token_value } = await canary.plantToken({ tokenType: 'api_key' });\nconst systemPrompt = `You are a helpful assistant.\\n\\nInternal ref: ${token_value}`;\n\n// scanResponse() (or guard.responses: true) catches it automatically if leaked\n```\n\nToken types: `api_key`, `email`, `ssn`, `credit_card`. All tokens are prefixed\n(`sk-canary-trap-`, `0000-` Luhn-valid cards, etc.) to distinguish them from\nreal credentials with zero false positives.\n\n## RAG / context scanning\n\nScan retrieved documents for **embedded injection attacks** before injecting\nthem into a prompt (OWASP LLM04 — indirect prompt injection via context):\n\n```js\nconst docs = await vectorStore.search(query);\n\n// Scan all chunks — up to 5 in parallel by default\nconst results = await canary.scanContext(docs.map(d => d.text));\n\n// Drop poisoned documents before sending to the model\nconst safeDocs = docs.filter((_, i) => results[i].allowed);\n```\n\nThreats found in context documents are re-typed as `context_poisoning` and\ntagged `LLM04` in the dashboard, so you can track RAG-specific attacks\nseparately from direct user input.\n\n## Redaction & privacy\n\nSensitive data is stripped **before it ever leaves the process**:\n\n```js\ncanary.init({\n  apiKey, agentId,\n  redaction: { secrets: true, pii: true, mode: 'mask' }, // secrets default on\n  captureContent: true,   // set false for metadata-only mode (no prompt text)\n  maxContentLength: 10000, // truncate long content\n  sampleRate: 1.0,         // 0–1; errors always kept\n  beforeSend: (e) => e,    // inspect / mutate / drop (return null) each event\n});\n```\n\nDetected out of the box: OpenAI/AWS/GitHub/Slack/Google keys, bearer tokens,\nJWTs, private keys (secrets); emails, phones, SSNs, credit cards (Luhn-checked),\nIPs (PII). Add your own with `redaction.customPatterns`.\n\n## API\n\n### `canary.init(config)`\n\n| Option            | Type                    | Default          | Description                                              |\n| ----------------- | ----------------------- | ---------------- | -------------------------------------------------------- |\n| `apiKey`          | `string`                | —                | **Required.** `sk-canary-...`                            |\n| `agentId`         | `string`                | —                | **Required.** Agent these events belong to.              |\n| `baseUrl`         | `string`                | Canary functions | Override the API host.                                   |\n| `flushIntervalMs` | `number`                | `5000`           | Background flush cadence.                                |\n| `maxBatchSize`    | `number`                | `20`             | Flush early once this many events queue.                 |\n| `sessionId`       | `string`                | server-assigned  | Group related events into a session.                     |\n| `sampleRate`      | `number`                | `1`              | Keep this fraction of events (errors exempt).            |\n| `captureContent`  | `boolean`               | `true`           | `false` = metadata-only, no prompt text sent.            |\n| `maxContentLength`| `number`                | `10000`          | Truncate captured content.                               |\n| `redaction`       | `RedactionConfig\\|bool` | secrets on       | Strip secrets/PII before sending.                        |\n| `beforeSend`      | `function`              | —                | Inspect/mutate/drop each event.                          |\n| `guard`           | `GuardConfig`           | local+remote     | Firewall behaviour (see below).                          |\n| `failOpen`        | `boolean`               | `true`           | Allow on remote-scan failure (vs block).                 |\n| `timeoutMs`       | `number`                | `10000`          | Per-request timeout.                                     |\n| `retry`           | `RetryConfig`           | 3 / 250ms        | Retry attempts + backoff for transient errors.           |\n| `environment`     | `string`                | —                | Tag events (e.g. `production`).                          |\n| `release`         | `string`                | —                | Tag events with your app version.                        |\n| `flushOnExit`     | `boolean`               | `true`           | Flush on process exit / page unload.                     |\n| `debug`           | `boolean`               | `false`          | Log SDK internals.                                       |\n| `onError`         | `function`              | warn-on-debug    | Handle background flush/scan failures.                   |\n\n**`guard` options:**\n\n| Option          | Type      | Default | Description                                                                     |\n| --------------- | --------- | ------- | ------------------------------------------------------------------------------- |\n| `local`         | `boolean` | `true`  | Run in-process heuristics on each `scan()` call.                               |\n| `remote`        | `boolean` | `true`  | Run the remote deep-scan.                                                       |\n| `blockOnLocal`  | `boolean` | `true`  | Short-circuit to block on a high-confidence local hit (skips network round-trip). |\n| `responses`     | `boolean` | `false` | Auto-scan every LLM response via `wrapOpenAI` / `wrapAnthropic`.               |\n\n### Methods\n\n**Telemetry**\n- `track(event)` / `trackPrompt` / `trackResponse` / `trackToolCall` / `trackError(err, extra?)`\n- `flush()` — send queued events now\n- `shutdown()` — flush and stop\n\n**Firewall (input)**\n- `scan(prompt, opts?)` → `ScanResult` — check a prompt; never throws on a verdict\n- `guard(prompt, opts?)` → `ScanResult` — like `scan()` but throws `CanaryBlockedError` if blocked\n\n**Output scanning**\n- `scanResponse(text, opts?)` → `ScanResult` — scan an LLM response for PII, secrets, harmful content, and canary tokens; set `throwOnUnsafe: true` to throw `CanaryBlockedError` instead of returning\n\n**Canary tokens**\n- `plantToken(opts?)` → `CanaryToken` — plant a synthetic decoy credential; returns `{ token_id, token_value, token_type }`\n\n**RAG / context**\n- `scanContext(docs[], opts?)` → `ScanResult[]` — scan an array of retrieved documents; returns one result per document in order\n\n**Instrumentation**\n- `trace(name, fn, opts?)` → result of `fn`, recorded as a span\n- `wrapOpenAI(client)` / `wrapAnthropic(client)` / `wrapFetch(fetch, opts?)`\n\n### Also exported\n\n`Canary` (class for multiple instances), `computeCost`, `hasPricing`,\n`localScan`, `newSessionId`, `CanaryBlockedError`, `CanaryNotInitializedError`,\nand all TypeScript types (`ScanResult`, `ScanOptions`, `ScanResponseOptions`,\n`PlantTokenOptions`, `CanaryToken`, `ScanContextOptions`, `TelemetryEvent`, …).\n\n## Error reference\n\n### `CanaryNotInitializedError`\n\n**When:** Any SDK method is called before `canary.init(...)`.\n\n```\nCanaryNotInitializedError: Canary SDK is not initialized. Call canary.init(...) first.\n```\n\n**Fix:** Call `canary.init({ apiKey, agentId })` once at app startup, before any `track*`, `scan`, `guard`, or `wrap*` calls.\n\n---\n\n### `CanaryBlockedError`\n\n**When:** `canary.guard(prompt)` is called and the firewall verdict blocks the prompt, **or** `canary.scanResponse(text, { throwOnUnsafe: true })` detects a threat.\n\n```js\ntry {\n  await canary.guard(userPrompt);\n} catch (err) {\n  if (err instanceof CanaryBlockedError) {\n    console.log(err.action);  // 'block' | 'quarantine' | …\n    console.log(err.threats); // DetectedThreat[]\n  }\n}\n```\n\n**Properties:** `action` (the highest-severity verdict), `threats` (array of `DetectedThreat`).\n\n**Note:** `canary.scan()` never throws — use it when you want to inspect the verdict without blocking execution.\n\n---\n\n### `CanaryApiError`\n\n**When:** The Canary API returns a non-2xx response that exhausts all retries.\n\n```\nCanaryApiError: POST /ingestEvents failed with status 401\n```\n\n**Common causes:**\n\n| Status | Cause | Fix |\n|---|---|---|\n| 401 | Invalid or missing API key | Check `apiKey` in `init()` |\n| 403 | Key lacks the required scope | Create a key with `telemetry` and `scan` scopes |\n| 404 | `agentId` not found | Verify the agent ID on the Agents page |\n| 500 | Server error | Check [status.canary-ops.com] or contact support |\n\nBy default the SDK **fails open** (`failOpen: true`) on API errors — it logs via `onError` and continues. Set `failOpen: false` to block on remote-scan failures.\n\n---\n\n## Troubleshooting\n\n**No events appearing in the dashboard**\n\n1. Confirm `canary.init()` was called before any `track*` call.\n2. Enable `debug: true` in `init()` — the SDK logs every flush to the console.\n3. Check that the API key has `telemetry` scope and the agent ID matches an existing agent.\n4. Events are batched and flushed every 5 seconds (or at 20 events). Call `await canary.flush()` to send immediately.\n\n**`wrapOpenAI` / `wrapAnthropic` not recording anything**\n\n- Make sure you call `canary.init(...)` before `canary.wrapOpenAI(client)`.\n- The wrapper patches the client in-place — if you create the client before wrapping, the patched version is the same object, so no re-assignment is needed.\n- Streaming responses record on the final chunk. If you break out of the `for await` loop early (e.g. an error), the `onFinalize` still fires.\n\n**`guard()` blocking legitimate prompts (false positives)**\n\n- Use `canary.scan(prompt)` first to inspect the `threats` array and see which rule matched.\n- Tune the local guard: set `guard: { blockOnLocal: false }` to let local hits through to the remote deep-scan for a second opinion.\n- The `score` field on each `DetectedThreat` indicates confidence (0–100). Local patterns with score < 80 warn but don't hard-block unless `blockOnLocal: true`.\n\n**Content appearing redacted when you don't want it to**\n\n- Secrets redaction (`redaction.secrets`) is **on by default**. If your prompts contain intentional API key patterns for testing, set `redaction: { secrets: false }`.\n- Check the `mode`: `'mask'` replaces with `[REDACTED]`, `'hash'` with an FNV-1a hex digest, `'remove'` deletes the field entirely.\n- PII redaction is **off by default**. It only activates if you set `redaction: { pii: true }`.\n\n**Cost shows as `undefined`**\n\n- `computeCost` returns `undefined` when the model string isn't in the built-in pricing table. Pass `cost_usd` explicitly to your `track*` calls, or ensure `model` matches a known model name (e.g. `'gpt-4o'`, `'claude-opus-4-8'`).\n- Call `hasPricing('your-model')` to check coverage.\n\n**Process exits before all events are flushed**\n\n- The SDK attaches a `beforeExit` handler automatically (`flushOnExit: true`). For short-lived scripts that exit via `process.exit()` (which skips `beforeExit`), call `await canary.shutdown()` before exiting.\n\n## Environments\n\nWorks anywhere with a global `fetch` + `AbortController`: **Node 18+**, modern\nbrowsers, Deno, Bun, and edge runtimes. Ships ESM + CommonJS + TypeScript types.\nZero runtime dependencies.\n\n## Authors\n\nBuilt by [CryptoSuess](https://github.com/CryptoSuess) & Txnchi.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}