@enforly/sdk
v0.3.0
Published
Server-side JavaScript and TypeScript client for the Enforly guardrails API
Readme
@enforly/sdk
Server-side JavaScript and TypeScript client for the Enforly guardrails API. Use it before executing an action that a policy may restrict.
Install
Requires Node.js 20 or newer and an Enforly API key. Create a key in the Enforly console, then set it as ENFORLY_API_KEY in your server environment. Keep the key on your server; do not put it in browser code or a public environment variable.
npm install @enforly/sdkimport { Enforly } from '@enforly/sdk'
const guard = new Enforly({ apiKey: process.env.ENFORLY_API_KEY })The default API origin is https://api.enforly.com. Set baseUrl in the constructor if your API runs at another origin.
Check an action
Pass exactly one of policy, policyId, or policyIds. Put the action and any evidence needed to judge it in the single JSON data field.
const result = await guard.check({
policy: 'Never run destructive database operations without explicit confirmation.',
data: {
action: { tool: 'database.execute_sql', query: 'DROP TABLE customers' },
userConfirmed: false,
},
})
if (result.allowed) {
// Execute the checked action here.
} else {
// Stop the action. A review decision needs a human or more evidence.
}Use a saved policy ID to evaluate its active version (set in the dashboard or with policies.activate):
const result = await guard.check({
policyId: '70fa6222-b16b-48b8-a137-c6f278503a91',
data: { tool: 'database.execute_sql', query: 'SELECT count(*) FROM customers' },
})Evaluate distinct saved policies in one request. The maximum depends on the tenant's plan (Free: 10, Basic: 25, Pro: 50 by default):
const result = await guard.check({
policyIds: [
'70fa6222-b16b-48b8-a137-c6f278503a91',
'00000000-0000-4000-8000-000000000001',
],
data: { tool: 'database.execute_sql', query: 'DROP TABLE customers' },
})
console.log(result.decision, result.allowed, result.results)Pin an exact version so a later edit or preset update cannot change the check. A version that does not exist fails with POLICY_VERSION_NOT_FOUND:
await guard.check({ policyId: '70fa6222-b16b-48b8-a137-c6f278503a91', policyVersion: 3, data })
await guard.check({
policyIds: [{ id: '70fa6222-b16b-48b8-a137-c6f278503a91', version: 3 }, '00000000-0000-4000-8000-000000000001'],
data,
})Single-policy results include decision, allowed, violationProbability, reviewProbability, policyId, policyVersion, and requestId. Multi-policy results include the overall decision, allowed, results (one decision and both probabilities per policy), and requestId. decision is allow, deny, or review. review means a person should decide: either the policy hands this case to a person (for example "refunds above 200 USD need manager approval") and that approval is missing from data, or the evidence is not clear enough to allow or deny. allowed is true only for allow; a model probability is an estimate, not proof. If any policy denies, the overall decision denies; otherwise any review makes the overall decision review.
Manage saved policies
const { policies } = await guard.policies.list()
const { id } = await guard.policies.create({
slug: 'database-safety',
title: 'Database safety',
body: 'Never run destructive database operations without explicit confirmation.',
})
const { policy } = await guard.policies.get(id)
const { version } = await guard.policies.update(id, {
body: 'Never run destructive database operations without explicit confirmation from the user.',
})
await guard.policies.activate(id, 1) // Roll back: unpinned checks use version 1 again.
await guard.policies.delete(id) // Deactivates the policy: { id, deactivated: true, requestId }.Updates create a new immutable version and make it active. In the dashboard you can also save a rule change as a draft and activate it later, or rename a policy without creating a version (checks never read the title). After delete, checks that use the ID fail with POLICY_NOT_FOUND; the dashboard keeps the policy listed read-only with its versions. version in listing and detail results is the active version and latest_version the newest; a preset stays on the version current when your workspace was created until you activate a newer one. The API returns policy listing and detail fields in snake_case, such as tenant_id and created_at. A key can read platform policies and policies owned by its tenant; only its own policies can be changed.
Handle errors safely
HTTP errors, network failures, timeouts, and invalid responses reject the call. Do not execute the checked action when a call throws.
import { EnforlyError } from '@enforly/sdk'
try {
const action = { tool: 'database.execute_sql', query: 'SELECT 1' }
const result = await guard.check({ policy: 'Do not delete data.', data: action })
if (result.allowed) {
// Execute the action here.
} else {
console.log('Action stopped:', result.decision)
}
} catch (error) {
if (error instanceof EnforlyError) {
console.error(error.code, error.status, error.requestId)
}
// Stop the action and surface the failure to your application.
}EnforlyError has code, status (HTTP status or null), and requestId (when available). Authentication, validation, missing-policy, rate-limit, context-limit, and service errors retain the API's error code. A request that exceeds 32,768 characters in the complete Jev payload returns 413 CONTEXT_LIMIT_EXCEEDED without consuming a monthly check. The client uses a 30-second timeout by default; change it with new Enforly({ apiKey, timeoutMs: 45000 }).
