Node.js SDK
| Field | Value |
|---|---|
| Document ID | ASCEND-SDK-010 |
| Version | 2.0.0 |
| Last Updated | December 19, 2025 |
| Author | Ascend Engineering Team |
| Publisher | OW-KAI Technologies Inc. |
| Classification | Enterprise Client Documentation |
| Compliance | SOC 2 CC6.1/CC6.2, PCI-DSS 7.1/8.3, HIPAA 164.312, NIST 800-53 AC-2/SI-4 |
Reading Time: 15 minutes | Skill Level: Intermediate
Overview
The ASCEND Node.js SDK (@ascend/sdk) provides enterprise-grade governance integration for TypeScript and JavaScript AI agents. It includes full TypeScript types, circuit breaker patterns, and fail mode configuration.
Installation
npm install @ascend/sdk
# or
yarn add @ascend/sdk
Requirements
- Node.js 16+
- TypeScript 4.5+ (optional but recommended)
Verify Installation
import { VERSION } from '@ascend/sdk';
console.log(`ASCEND SDK Version: ${VERSION}`);
Quick Start
// Source: sdk/nodejs/src/index.ts:22
import { AscendClient, FailMode, Decision } from '@ascend/sdk';
// Initialize client
const client = new AscendClient({
apiKey: process.env.ASCEND_API_KEY!,
agentId: 'my-agent-001',
agentName: 'My AI Agent',
environment: 'production',
failMode: FailMode.CLOSED
});
// Evaluate an action
const decision = await client.evaluateAction({
actionType: 'database.query',
resource: 'production_db',
parameters: { query: 'SELECT * FROM users' }
});
if (decision.decision === Decision.ALLOWED) {
console.log('Action approved!');
// Execute your action here
} else if (decision.decision === Decision.DENIED) {
console.log(`Denied: ${decision.reason}`);
} else if (decision.decision === Decision.PENDING) {
console.log('Awaiting human approval');
}
Client Configuration
Constructor Options
// Source: sdk/python/owkai_sdk/client.py:243 (same pattern in Node.js)
interface AscendClientOptions {
apiKey: string; // Required: Your API key
agentId?: string; // Agent identifier
agentName?: string; // Human-readable name
apiUrl?: string; // API endpoint URL
environment?: string; // production, staging, development
failMode?: FailMode; // CLOSED (block) or OPEN (allow)
timeout?: number; // Request timeout (seconds)
maxRetries?: number; // Max retry attempts
enableCircuitBreaker?: boolean; // Enable circuit breaker
circuitBreakerThreshold?: number; // Failures before opening
circuitBreakerTimeout?: number; // Recovery timeout
signingSecret?: string; // HMAC signing secret
debug?: boolean; // Enable debug logging
}
| Option | Type | Default | Description |
|---|---|---|---|
apiKey | string | Required | ASCEND API key |
agentId | string | - | Unique agent identifier |
agentName | string | - | Human-readable name |
apiUrl | string | https://pilot.owkai.app | API endpoint |
environment | string | production | Deployment environment |
failMode | FailMode | CLOSED | Behavior when unavailable |
timeout | number | 5 | Request timeout (seconds) |
maxRetries | number | 3 | Max retry attempts |
enableCircuitBreaker | boolean | true | Enable circuit breaker |
debug | boolean | false | Enable debug logging |
Environment Variables
export ASCEND_API_KEY="owkai_your_key_here"
export ASCEND_API_URL="https://pilot.owkai.app"
export ASCEND_AGENT_ID="my-agent-001"
export ASCEND_ENVIRONMENT="production"
Fail Mode Configuration
The SDK supports two fail modes for when ASCEND is unreachable:
import { AscendClient, FailMode } from '@ascend/sdk';
// CLOSED (default): Block actions when ASCEND is unavailable
// Recommended for high-security environments
const secureClient = new AscendClient({
apiKey: process.env.ASCEND_API_KEY!,
failMode: FailMode.CLOSED
});
// OPEN: Allow actions when ASCEND is unavailable
// Use only when availability is more important than security
const availableClient = new AscendClient({
apiKey: process.env.ASCEND_API_KEY!,
failMode: FailMode.OPEN
});
Agent Registration
// Source: sdk/python/owkai_sdk/client.py:570 (same pattern)
// Register agent with ASCEND
const registration = await client.register({
agentType: 'supervised',
capabilities: ['data_access', 'file_operations'],
allowedResources: ['production_db', 's3_bucket'],
metadata: {
version: '1.0.0',
team: 'data-engineering'
}
});
console.log(`Registered with trust level: ${registration.trust_level}`);
Evaluating Actions
Basic Evaluation
// Source: sdk/python/owkai_sdk/client.py:644 (same pattern)
const decision = await client.evaluateAction({
actionType: 'database.query',
resource: 'customer_db',
parameters: {
table: 'customers',
operation: 'SELECT',
columns: ['id', 'name', 'email']
},
context: {
sessionId: 'sess_123',
purpose: 'customer_support'
}
});
EvaluateAction Options
| Option | Type | Required | Description |
|---|---|---|---|
actionType | string | Yes | Category.action format |
resource | string | Yes | Resource being accessed |
parameters | object | No | Action-specific parameters |
context | object | No | Execution context |
resourceId | string | No | Specific resource ID |
riskIndicators | object | No | Pre-computed risk signals |
waitForDecision | boolean | No | Wait for approval (default: true) |
timeout | number | No | Wait timeout in seconds |
Decision Response
interface AuthorizationDecision {
actionId: string; // Unique action identifier
decision: Decision; // ALLOWED, DENIED, PENDING
riskScore: number; // 0-100 risk score
riskLevel: RiskLevel; // LOW, MEDIUM, HIGH, CRITICAL
reason: string; // Explanation
executionAllowed: boolean; // Can proceed
approvalRequestId?: string; // If pending
metadata: Record<string, any>;
}
// Decision enum
enum Decision {
ALLOWED = 'allowed',
DENIED = 'denied',
PENDING = 'pending_approval',
AUTO_APPROVED = 'auto_approved'
}
Waiting for Decisions
Async Wait
// Submit action that may need approval
const initialDecision = await client.evaluateAction({
actionType: 'financial.transfer',
resource: 'banking_api',
parameters: { amount: 50000 }
}, { waitForDecision: false });
if (initialDecision.decision === Decision.PENDING) {
// Wait for human approval
const finalDecision = await client.waitForDecision(
initialDecision.actionId,
60 // 60 second timeout
);
if (finalDecision.decision === Decision.ALLOWED) {
executeTransfer();
}
}
Check Approval Status
// Poll for approval status
const status = await client.checkApproval(approvalRequestId);
if (status.approved) {
console.log(`Approved by: ${status.approver}`);
} else if (status.denied) {
console.log(`Denied: ${status.comments}`);
} else {
console.log('Still pending...');
}
Action Logging
Log Successful Completion
// Source: sdk/python/owkai_sdk/client.py:802 (same pattern)
const decision = await client.evaluateAction({
actionType: 'database.query',
resource: 'customer_db'
});
if (decision.executionAllowed) {
const startTime = Date.now();
try {
const result = await executeQuery();
// Log success (required for SOC 2)
await client.logActionCompleted(decision.actionId, {
result: { rowCount: result.length },
durationMs: Date.now() - startTime
});
} catch (error) {
// Log failure
await client.logActionFailed(decision.actionId, {
error: { code: 'QUERY_ERROR', message: error.message },
durationMs: Date.now() - startTime
});
}
}
Webhook Configuration
// Source: sdk/python/owkai_sdk/client.py:984 (same pattern)
await client.configureWebhook({
url: 'https://your-app.com/webhooks/ascend',
events: [
'action.approved',
'action.denied',
'action.pending',
'policy.violation'
],
secret: 'whsec_your_secret'
});
Webhook Payload Format
{
"event": "action.approved",
"timestamp": "2025-12-16T10:00:00Z",
"data": {
"action_id": "act_123",
"agent_id": "my-agent-001",
"approver": "admin@company.com"
},
"signature": "v1=abc123..."
}
Verify Webhook Signature
import crypto from 'crypto';
function verifyWebhookSignature(
payload: string,
signature: string,
secret: string,
timestamp: string
): boolean {
const message = `${timestamp}.${payload}`;
const expected = crypto
.createHmac('sha256', secret)
.update(message)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(`v1=${expected}`),
Buffer.from(signature)
);
}
Circuit Breaker
The SDK includes a circuit breaker to prevent cascade failures:
// Source: sdk/python/owkai_sdk/client.py:62 (same pattern)
import { CircuitBreaker, CircuitState } from '@ascend/sdk';
const client = new AscendClient({
apiKey: process.env.ASCEND_API_KEY!,
enableCircuitBreaker: true,
circuitBreakerThreshold: 5, // Open after 5 failures
circuitBreakerTimeout: 30 // Try to recover after 30s
});
// Circuit breaker states:
// - CLOSED: Normal operation
// - OPEN: Failing, reject requests immediately
// - HALF_OPEN: Testing if service recovered
Error Handling
Exception Types
// Source: sdk/nodejs/src/errors.ts
import {
OWKAIError, // Base error
AuthenticationError, // Invalid API key
AuthorizationError, // Action denied
TimeoutError, // Request timeout
RateLimitError, // 429 response
ValidationError, // Invalid input
ConnectionError, // Network failure
CircuitBreakerOpenError // Circuit breaker open
} from '@ascend/sdk';
Production Error Handling
import {
AscendClient,
AuthenticationError,
ConnectionError,
CircuitBreakerOpenError,
TimeoutError
} from '@ascend/sdk';
async function executeWithGovernance() {
const client = new AscendClient({
apiKey: process.env.ASCEND_API_KEY!,
failMode: FailMode.CLOSED
});
try {
const decision = await client.evaluateAction({
actionType: 'data.access',
resource: 'customer_db'
});
if (decision.executionAllowed) {
return await executeBusinessLogic();
} else {
throw new Error(`Action not allowed: ${decision.reason}`);
}
} catch (error) {
if (error instanceof AuthenticationError) {
console.error('Invalid API key');
// Check ASCEND_API_KEY
} else if (error instanceof CircuitBreakerOpenError) {
console.error('ASCEND service appears down');
// Implement fallback
} else if (error instanceof TimeoutError) {
console.error('Request timed out');
// Consider queuing for retry
} else if (error instanceof ConnectionError) {
console.error('Network error');
// Check connectivity
}
throw error;
}
}
MCP Integration
Govern Model Context Protocol tools:
// Source: sdk/nodejs/src/mcp.ts
import { mcpGovernance, requireGovernance, highRiskAction } from '@ascend/sdk';
// Wrap MCP tool with governance
const governedTool = mcpGovernance({
actionType: 'database.query',
riskLevel: 'high'
})(originalTool);
// Decorator for high-risk actions
const tools = {
execute_sql: highRiskAction(async (params) => {
return await executeSql(params.query);
})
};
Metrics Collection
// Source: sdk/nodejs/src/metrics.ts
import { MetricsCollector } from '@ascend/sdk';
const metrics = new MetricsCollector();
// Get metrics snapshot
const snapshot = metrics.getSnapshot();
console.log(`Total requests: ${snapshot.totalRequests}`);
console.log(`Success rate: ${snapshot.successRate}%`);
console.log(`Avg latency: ${snapshot.avgLatencyMs}ms`);
// Subscribe to metrics
metrics.onMetric((event) => {
console.log(`${event.type}: ${event.duration}ms`);
});
Complete Example
// main.ts - Production ASCEND Integration
import { AscendClient, FailMode, Decision } from '@ascend/sdk';
const client = new AscendClient({
apiKey: process.env.ASCEND_API_KEY!,
agentId: 'production-agent',
agentName: 'Production Data Agent',
environment: 'production',
failMode: FailMode.CLOSED,
enableCircuitBreaker: true
});
async function processCustomerRequest(customerId: string) {
// Test connection
const status = await client.testConnection();
if (status.status !== 'connected') {
throw new Error(`Cannot connect: ${status.error}`);
}
// Evaluate action
const decision = await client.evaluateAction({
actionType: 'database.read',
resource: 'customer_database',
resourceId: customerId,
parameters: {
table: 'customers',
operation: 'SELECT',
dataClassification: 'pii'
}
});
if (decision.executionAllowed) {
const startTime = Date.now();
try {
const data = await fetchCustomerData(customerId);
await client.logActionCompleted(decision.actionId, {
result: { success: true },
durationMs: Date.now() - startTime
});
return data;
} catch (error) {
await client.logActionFailed(decision.actionId, {
error: { message: error.message }
});
throw error;
}
} else {
throw new Error(`Access denied: ${decision.reason}`);
}
}
Next Steps
- REST API — Direct HTTP API reference
- MCP Server Governance — MCP integration
- Python SDK — Python SDK reference
Document Version: 1.0.0 | Last Updated: December 2025