Developer documentation
TypeScript SDK
Last reviewed 31 August 2026
TypeScript SDK
npm install @cain/sdk
Node 18+. No runtime dependencies -- it uses global fetch, so it will not drag
a transitive tree into a project that is already fighting its own.
Mirrors the Python SDK deliberately: same canonical decision, same five verdicts,
same invariant. Two SDKs that disagreed about what UNKNOWN means would be worse
than having one.
Declarative: trust
import { trust } from "@cain/sdk";
export const sendEmail = trust(
{ action: "send_email", resource: "customer_inbox" },
async (to: string, subject: string, body: string) => {
... // unchanged
},
);
Throws NotAuthorized before the body runs unless the verdict is ALLOW.
Imperative: verify
import { verify } from "@cain/sdk";
const decision = await verify({
action: "delete_customer",
resource: customerId,
});
if (decision.allowed) {
await deleteCustomer(customerId);
} else {
console.warn("refused:", decision.explain());
}
verify() never rejects. Timeout, DNS failure and non-2xx all resolve to a
decision with verdict ERROR.
guard() is the same call but throws unless ALLOW.
The Decision
decision.verdict // "ALLOW" | "DENY" | "REQUIRE_APPROVAL" | "UNKNOWN" | "ERROR" decision.allowed // true only for ALLOW decision.determinate // false for UNKNOWN and ERROR decision.deniedBy // string[] -- stages that refused and were enforcing decision.shadowDenials // string[] -- refused but not enforcing decision.policyVersion decision.explain()
There is deliberately no decision.denied. if (!decision.denied) would treat
UNKNOWN as permission.
Options
trust(
{
action: "refund",
resource: "billing",
includeArgs: false, // default: do not ship arguments
onUnauthorized: "throw", // or "returnUndefined". No "proceed".
},
fn,
);
Configuration
Reads CAIN_ENDPOINT, CAIN_API_KEY, CAIN_AGENT and CAIN_STRICT from the
environment -- which is what cain run sets, so a wrapped program needs no code
change. Or in code:
import { configure } from "@cain/sdk";
configure({ endpoint: "https://fabric.internal", strict: true });