guardian-safety-sdk
v1.0.0
Published
Guardian SDK - Safe execution of irreversible actions with policy enforcement and approvals
Maintainers
Readme
@guardian/sdk
Guardian SDK for safe execution of irreversible actions with policy enforcement and approvals.
Installation
npm install @guardian/sdkQuick Start
import { Guardian } from '@guardian/sdk';
const guardian = new Guardian({
apiKey: 'gk_your_api_key',
baseUrl: 'http://localhost:3001',
});
const result = await guardian.run({
actionType: 'payment.send',
payload: { amount: 1000, recipient: '[email protected]' },
});
console.log(result.status); // 'EXECUTED'API
new Guardian(config)
Create a new Guardian client.
const guardian = new Guardian({
apiKey: string, // Required: Your Guardian API key
baseUrl: string, // Required: Guardian API URL
timeoutMs?: number, // Optional: Request timeout (default: 30000)
pollIntervalMs?: number, // Optional: Approval poll interval (default: 2000)
maxWaitMs?: number, // Optional: Max wait for approval (default: 900000)
});guardian.run(input)
Execute an action through Guardian.
const result = await guardian.run({
actionType: string, // Required: Action type identifier
payload: Record<string, any>, // Required: Action payload
idempotencyKey?: string, // Optional: Idempotency key (auto-generated if not provided)
waitForApproval?: boolean, // Optional: Wait for approval (default: true)
});
// Returns:
{
intentRunId: string,
status: 'ALLOW' | 'REQUIRE_APPROVAL' | 'DENY' | 'EXECUTED',
decision?: string,
reason?: string,
}Examples
Hello World (5 lines)
import { Guardian } from '@guardian/sdk';
const guardian = new Guardian({ apiKey: 'gk_xxx', baseUrl: 'http://localhost:3001' });
const result = await guardian.run({ actionType: 'hello.world', payload: { message: 'Hello!' } });
console.log(result.status);Retry-Safe Execution
The SDK automatically generates idempotency keys, making retries safe:
import { Guardian, GuardianNetworkError } from '@guardian/sdk';
const guardian = new Guardian({
apiKey: 'gk_your_api_key',
baseUrl: 'http://localhost:3001',
});
// Use a fixed idempotency key for retry safety
const idempotencyKey = `payment-${orderId}`;
async function sendPaymentWithRetry(orderId: string, amount: number) {
for (let attempt = 1; attempt <= 3; attempt++) {
try {
const result = await guardian.run({
actionType: 'payment.send',
payload: { orderId, amount },
idempotencyKey: `payment-${orderId}`,
});
return result;
} catch (error) {
if (error instanceof GuardianNetworkError && attempt < 3) {
console.log(`Attempt ${attempt} failed, retrying...`);
await new Promise(r => setTimeout(r, 1000 * attempt));
continue;
}
throw error;
}
}
}Approval-Required Action
import { Guardian, GuardianApprovalRejectedError } from '@guardian/sdk';
const guardian = new Guardian({
apiKey: 'gk_your_api_key',
baseUrl: 'http://localhost:3001',
maxWaitMs: 300000, // Wait up to 5 minutes for approval
});
try {
// This will block until approved (or rejected/timeout)
const result = await guardian.run({
actionType: 'payment.send',
payload: { amount: 50000, recipient: '[email protected]' },
});
console.log('Payment executed:', result.intentRunId);
} catch (error) {
if (error instanceof GuardianApprovalRejectedError) {
console.log('Payment rejected by:', error.rejectedBy);
console.log('Reason:', error.rejectionReason);
}
throw error;
}Non-Blocking Approval
import { Guardian } from '@guardian/sdk';
const guardian = new Guardian({
apiKey: 'gk_your_api_key',
baseUrl: 'http://localhost:3001',
});
// Don't wait for approval - return immediately
const result = await guardian.run({
actionType: 'payment.send',
payload: { amount: 50000, recipient: '[email protected]' },
waitForApproval: false,
});
if (result.status === 'REQUIRE_APPROVAL') {
console.log('Approval required. Intent ID:', result.intentRunId);
// Store intentRunId and handle approval asynchronously
}Error Handling
The SDK exports typed errors for precise error handling:
import {
Guardian,
GuardianDeniedError,
GuardianApprovalRejectedError,
GuardianIntegrityError,
GuardianNetworkError,
GuardianTimeoutError,
} from '@guardian/sdk';
try {
await guardian.run({ actionType: 'payment.send', payload: { amount: 1000000 } });
} catch (error) {
if (error instanceof GuardianDeniedError) {
// Action denied by policy
console.log('Denied:', error.reason);
} else if (error instanceof GuardianApprovalRejectedError) {
// Human reviewer rejected the action
console.log('Rejected by:', error.rejectedBy);
} else if (error instanceof GuardianIntegrityError) {
// Payload was modified after approval (tampering detected)
console.log('Integrity error - possible tampering');
} else if (error instanceof GuardianTimeoutError) {
// Approval timed out
console.log('Approval timed out');
} else if (error instanceof GuardianNetworkError) {
// Network/API error
console.log('Network error:', error.statusCode);
}
}How It Works
- Intent Check: SDK calls Guardian's
/v1/intents/checkendpoint with your action - Policy Evaluation: Guardian evaluates the action against configured policies
- Decision Handling:
ALLOW: SDK immediately executes the actionDENY: SDK throwsGuardianDeniedErrorREQUIRE_APPROVAL: SDK waits for human approval (ifwaitForApproval: true)
- Execution: Once approved, SDK calls
/v1/intents/:id/execute - Safety: SDK handles idempotency, payload integrity, and replay protection
Requirements
- Node.js 18+ (uses native
fetch) - Guardian backend running and accessible
License
MIT
