# JavaScript API Examples

Complete examples for integrating with the Tractatus Framework API using JavaScript (Node.js and Browser).

## Table of Contents

- [Authentication](#authentication)
- [Documents](#documents)
- [Governance Services](#governance-services)
- [Audit Logs](#audit-logs)
- [Error Handling](#error-handling)

---

## Authentication

### Login and Store Token (Node.js)

```javascript
const axios = require('axios');

const API_BASE = 'https://agenticgovernance.digital/api';
// For local development: const API_BASE = 'http://localhost:9000/api';

async function login(email, password) {
  try {
    const response = await axios.post(`${API_BASE}/auth/login`, {
      email,
      password
    });

    const { token, user } = response.data;

    // Store token for subsequent requests
    process.env.TRACTATUS_TOKEN = token;

    console.log('Login successful:', user);
    return { token, user };
  } catch (error) {
    if (error.response?.status === 429) {
      console.error('Too many login attempts. Please wait 15 minutes.');
    } else if (error.response?.status === 401) {
      console.error('Invalid credentials');
    } else {
      console.error('Login failed:', error.message);
    }
    throw error;
  }
}

// Usage
login('admin@tractatus.local', 'your_password')
  .then(({ token }) => {
    console.log('Token:', token);
  });
```

### Login and Store Token (Browser)

```javascript
async function login(email, password) {
  try {
    const response = await fetch('https://agenticgovernance.digital/api/auth/login', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ email, password })
    });

    if (!response.ok) {
      if (response.status === 429) {
        throw new Error('Too many login attempts. Please wait 15 minutes.');
      }
      throw new Error('Login failed');
    }

    const { token, user } = await response.json();

    // Store token in localStorage
    localStorage.setItem('tractatus_token', token);
    localStorage.setItem('tractatus_user', JSON.stringify(user));

    console.log('Login successful:', user);
    return { token, user };
  } catch (error) {
    console.error('Login error:', error);
    throw error;
  }
}

// Usage
login('admin@tractatus.local', 'your_password')
  .then(({ user }) => {
    console.log('Logged in as:', user.email);
  });
```

### Making Authenticated Requests (Node.js)

```javascript
const axios = require('axios');

// Create axios instance with authentication
function createAuthClient(token) {
  return axios.create({
    baseURL: 'https://agenticgovernance.digital/api',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    }
  });
}

// Usage
const token = process.env.TRACTATUS_TOKEN;
const client = createAuthClient(token);

// Now all requests include authentication
client.get('/governance/status')
  .then(response => console.log(response.data));
```

### Making Authenticated Requests (Browser)

```javascript
async function authenticatedFetch(endpoint, options = {}) {
  const token = localStorage.getItem('tractatus_token');

  if (!token) {
    throw new Error('Not authenticated. Please login first.');
  }

  const defaultOptions = {
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json',
      ...options.headers
    }
  };

  const response = await fetch(`https://agenticgovernance.digital/api${endpoint}`, {
    ...options,
    ...defaultOptions
  });

  if (response.status === 401) {
    // Token expired or invalid
    localStorage.removeItem('tractatus_token');
    localStorage.removeItem('tractatus_user');
    throw new Error('Session expired. Please login again.');
  }

  if (!response.ok) {
    throw new Error(`API error: ${response.statusText}`);
  }

  return response.json();
}

// Usage
authenticatedFetch('/governance/status')
  .then(data => console.log(data));
```

---

## Documents

### List All Documents

```javascript
async function listDocuments(options = {}) {
  const { page = 1, limit = 50, quadrant } = options;

  const params = new URLSearchParams({
    page: page.toString(),
    limit: limit.toString()
  });

  if (quadrant) {
    params.append('quadrant', quadrant);
  }

  const response = await fetch(
    `https://agenticgovernance.digital/api/documents?${params}`
  );

  if (!response.ok) {
    throw new Error('Failed to fetch documents');
  }

  return response.json();
}

// Usage
listDocuments({ page: 1, limit: 10, quadrant: 'STRATEGIC' })
  .then(data => {
    console.log(`Found ${data.pagination.total} documents`);
    data.documents.forEach(doc => {
      console.log(`- ${doc.title} (${doc.quadrant})`);
    });
  });
```

### Get Single Document

```javascript
async function getDocument(identifier) {
  const response = await fetch(
    `https://agenticgovernance.digital/api/documents/${identifier}`
  );

  if (response.status === 404) {
    throw new Error('Document not found');
  }

  if (!response.ok) {
    throw new Error('Failed to fetch document');
  }

  return response.json();
}

// Usage (by slug)
getDocument('introduction-to-tractatus')
  .then(data => {
    console.log('Title:', data.document.title);
    console.log('Quadrant:', data.document.quadrant);
    console.log('Content:', data.document.content_html.substring(0, 100) + '...');
  });

// Usage (by ID)
getDocument('672f821b6e820c0c7a0e0d55')
  .then(data => console.log(data.document));
```

### Search Documents

```javascript
async function searchDocuments(query) {
  const params = new URLSearchParams({ q: query });

  const response = await fetch(
    `https://agenticgovernance.digital/api/documents/search?${params}`
  );

  if (!response.ok) {
    throw new Error('Search failed');
  }

  return response.json();
}

// Usage
searchDocuments('boundary enforcement')
  .then(data => {
    console.log(`Found ${data.count} results`);
    data.results.forEach(result => {
      console.log(`- ${result.title} (score: ${result.score})`);
    });
  });
```

### Create Document (Admin Only)

```javascript
async function createDocument(token, documentData) {
  const client = createAuthClient(token);

  try {
    const response = await client.post('/documents', {
      title: documentData.title,
      slug: documentData.slug,
      quadrant: documentData.quadrant,
      content_markdown: documentData.content,
      status: documentData.status || 'published'
    });

    console.log('Document created:', response.data.document._id);
    return response.data.document;
  } catch (error) {
    if (error.response?.status === 403) {
      console.error('Admin role required');
    } else if (error.response?.status === 409) {
      console.error('Slug already exists');
    }
    throw error;
  }
}

// Usage
const newDocument = {
  title: 'Advanced Boundary Enforcement Patterns',
  slug: 'advanced-boundary-enforcement',
  quadrant: 'OPERATIONAL',
  content: '# Advanced Patterns\n\nThis document explores...',
  status: 'published'
};

createDocument(process.env.TRACTATUS_TOKEN, newDocument);
```

---

## Governance Services

### InstructionPersistenceClassifier

```javascript
async function classifyInstruction(token, text, context = {}) {
  const client = createAuthClient(token);

  const response = await client.post('/governance/classify', {
    text,
    context: {
      source: context.source || 'user',
      session_id: context.session_id || 'default',
      ...context
    }
  });

  return response.data.classification;
}

// Usage
classifyInstruction(
  process.env.TRACTATUS_TOKEN,
  'Always use MongoDB on port 27027',
  { source: 'user', session_id: 'sess_123' }
).then(classification => {
  console.log('Quadrant:', classification.quadrant);
  console.log('Persistence:', classification.persistence);
  console.log('Temporal Scope:', classification.temporal_scope);
  console.log('Confidence:', classification.confidence);
  console.log('Reasoning:', classification.reasoning);
});
```

### CrossReferenceValidator

```javascript
async function validateAction(token, action, context = {}) {
  const client = createAuthClient(token);

  const response = await client.post('/governance/validate', {
    action,
    context: {
      messages: context.messages || [],
      session_id: context.session_id || 'default',
      ...context
    }
  });

  return response.data.validation;
}

// Usage
const action = {
  type: 'database_config',
  target: 'MongoDB',
  parameters: { port: 27017 }
};

validateAction(process.env.TRACTATUS_TOKEN, action)
  .then(validation => {
    if (validation.status === 'REJECTED') {
      console.error('❌ Action rejected');
      console.error('Reason:', validation.reason);
      validation.conflicts.forEach(conflict => {
        console.error(`  Conflicts with: ${conflict.text} (${conflict.instruction_id})`);
      });
      console.log('Recommendation:', validation.recommendation);
    } else if (validation.status === 'APPROVED') {
      console.log('✅ Action approved');
    }
  });
```

### BoundaryEnforcer

```javascript
async function enforceBounda ry(token, action, context = {}) {
  const client = createAuthClient(token);

  const response = await client.post('/governance/enforce', {
    action,
    context
  });

  return response.data.enforcement;
}

// Usage
const action = {
  type: 'policy_change',
  description: 'Update privacy policy to enable more tracking',
  impact: 'user_privacy'
};

enforceBoundary(process.env.TRACTATUS_TOKEN, action)
  .then(enforcement => {
    if (enforcement.decision === 'BLOCK') {
      console.error('🚫 Action blocked - crosses values boundary');
      console.error('Boundary:', enforcement.boundary_crossed);
      console.error('Reason:', enforcement.reason);
      console.log('\nAlternatives:');
      enforcement.alternatives.forEach((alt, i) => {
        console.log(`${i + 1}. ${alt}`);
      });
    } else {
      console.log('✅ Action allowed');
    }
  });
```

### ContextPressureMonitor

```javascript
async function analyzePressure(token, context) {
  const client = createAuthClient(token);

  const response = await client.post('/governance/pressure', {
    context: {
      tokenUsage: context.tokenUsage || 50000,
      tokenBudget: context.tokenBudget || 200000,
      messageCount: context.messageCount || 20,
      errorCount: context.errorCount || 0,
      complexOperations: context.complexOperations || 0,
      sessionDuration: context.sessionDuration || 1800
    }
  });

  return response.data.pressure;
}

// Usage
analyzePressure(process.env.TRACTATUS_TOKEN, {
  tokenUsage: 120000,
  tokenBudget: 200000,
  messageCount: 45,
  errorCount: 3,
  complexOperations: 8,
  sessionDuration: 3600
}).then(pressure => {
  console.log('Pressure Level:', pressure.level);
  console.log('Score:', pressure.score + '%');
  console.log('\nFactors:');
  Object.entries(pressure.factors).forEach(([factor, data]) => {
    console.log(`  ${factor}: ${data.value} (${data.status})`);
  });
  console.log('\nRecommendation:', pressure.recommendation);

  if (pressure.triggerHandoff) {
    console.warn('⚠️ Session handoff recommended');
  }
});
```

### MetacognitiveVerifier

```javascript
async function verifyAction(token, action, reasoning, context = {}) {
  const client = createAuthClient(token);

  const response = await client.post('/governance/verify', {
    action,
    reasoning,
    context
  });

  return response.data.verification;
}

// Usage
const action = {
  type: 'refactor',
  scope: 'Refactor 47 files across 5 system areas',
  complexity: 'high'
};

const reasoning = {
  intent: 'Improve code organization',
  approach: 'Extract shared utilities, consolidate duplicates',
  risks: 'Potential breaking changes'
};

const context = {
  requested: 'Refactor authentication module',
  original_scope: 'single module'
};

verifyAction(process.env.TRACTATUS_TOKEN, action, reasoning, context)
  .then(verification => {
    console.log('Decision:', verification.decision);
    console.log('Confidence:', verification.confidence);

    if (verification.concerns.length > 0) {
      console.log('\n⚠️  Concerns:');
      verification.concerns.forEach(concern => {
        console.log(`  [${concern.severity}] ${concern.type}: ${concern.detail}`);
      });
    }

    if (verification.scopeCreep) {
      console.warn('\n🔴 Scope creep detected');
    }

    console.log('\nCriteria Scores:');
    Object.entries(verification.criteria).forEach(([criterion, score]) => {
      console.log(`  ${criterion}: ${(score * 100).toFixed(0)}%`);
    });

    if (verification.alternatives.length > 0) {
      console.log('\nAlternatives:');
      verification.alternatives.forEach((alt, i) => {
        console.log(`${i + 1}. ${alt}`);
      });
    }
  });
```

---

## Audit Logs

### Get Audit Logs with Filtering

```javascript
async function getAuditLogs(token, options = {}) {
  const client = createAuthClient(token);

  const params = {
    page: options.page || 1,
    limit: options.limit || 50
  };

  if (options.action) params.action = options.action;
  if (options.userId) params.userId = options.userId;
  if (options.startDate) params.startDate = options.startDate;
  if (options.endDate) params.endDate = options.endDate;

  const response = await client.get('/audit/audit-logs', { params });
  return response.data;
}

// Usage
getAuditLogs(process.env.TRACTATUS_TOKEN, {
  page: 1,
  limit: 20,
  action: 'validate_action',
  startDate: '2025-10-01T00:00:00Z'
}).then(data => {
  console.log(`Total logs: ${data.total}`);
  data.logs.forEach(log => {
    console.log(`[${log.timestamp}] ${log.service}: ${log.action} - ${log.status}`);
    if (log.details) {
      console.log('  Details:', JSON.stringify(log.details, null, 2));
    }
  });
});
```

### Get Audit Analytics

```javascript
async function getAuditAnalytics(token, startDate, endDate) {
  const client = createAuthClient(token);

  const params = {};
  if (startDate) params.startDate = startDate;
  if (endDate) params.endDate = endDate;

  const response = await client.get('/audit/audit-analytics', { params });
  return response.data.analytics;
}

// Usage
getAuditAnalytics(
  process.env.TRACTATUS_TOKEN,
  '2025-10-01T00:00:00Z',
  '2025-10-12T23:59:59Z'
).then(analytics => {
  console.log('Total Events:', analytics.total_events);
  console.log('\nBreakdown by Service:');
  Object.entries(analytics.by_service).forEach(([service, count]) => {
    console.log(`  ${service}: ${count}`);
  });
  console.log('\nBreakdown by Status:');
  Object.entries(analytics.by_status).forEach(([status, count]) => {
    console.log(`  ${status}: ${count}`);
  });
  console.log('\nRejection Rate:', analytics.rejection_rate + '%');
});
```

---

## Error Handling

### Comprehensive Error Handler

```javascript
async function handleApiRequest(requestFn) {
  try {
    return await requestFn();
  } catch (error) {
    // Axios error structure
    if (error.response) {
      const { status, data } = error.response;

      switch (status) {
        case 400:
          console.error('Bad Request:', data.message);
          console.error('Details:', data.details);
          break;
        case 401:
          console.error('Unauthorized: Please login');
          // Clear stored token
          localStorage.removeItem('tractatus_token');
          break;
        case 403:
          console.error('Forbidden: Insufficient permissions');
          console.error('Required role:', data.required_role || 'admin');
          break;
        case 404:
          console.error('Not Found:', data.message);
          break;
        case 409:
          console.error('Conflict:', data.message);
          console.error('Conflicting resource:', data.conflict);
          break;
        case 429:
          console.error('Rate Limit Exceeded:', data.message);
          console.error('Retry after:', error.response.headers['retry-after']);
          break;
        case 500:
          console.error('Internal Server Error');
          console.error('Error ID:', data.errorId);
          break;
        default:
          console.error('API Error:', status, data.message);
      }
    } else if (error.request) {
      console.error('Network Error: No response received');
      console.error('Check your internet connection');
    } else {
      console.error('Error:', error.message);
    }

    throw error;
  }
}

// Usage
handleApiRequest(async () => {
  return await classifyInstruction(token, 'Test instruction');
})
  .then(result => console.log('Success:', result))
  .catch(error => console.log('Handled error'));
```

### Retry Logic with Exponential Backoff

```javascript
async function retryWithBackoff(fn, maxRetries = 3, baseDelay = 1000) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await fn();
    } catch (error) {
      if (attempt === maxRetries) {
        throw error;
      }

      // Don't retry on client errors (4xx except 429)
      if (error.response?.status >= 400 &&
          error.response?.status < 500 &&
          error.response?.status !== 429) {
        throw error;
      }

      const delay = baseDelay * Math.pow(2, attempt - 1);
      console.log(`Attempt ${attempt} failed. Retrying in ${delay}ms...`);
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}

// Usage
retryWithBackoff(async () => {
  return await getDocument('some-slug');
}, 3, 1000)
  .then(doc => console.log('Document:', doc))
  .catch(error => console.error('All retries failed:', error));
```

---

## Complete Example: Full Integration

```javascript
const axios = require('axios');

class TractatusClient {
  constructor(baseURL = 'https://agenticgovernance.digital/api') {
    this.baseURL = baseURL;
    this.token = null;
    this.client = axios.create({ baseURL });
  }

  async login(email, password) {
    const response = await this.client.post('/auth/login', { email, password });
    this.token = response.data.token;
    this.client.defaults.headers.common['Authorization'] = `Bearer ${this.token}`;
    return response.data;
  }

  async classifyInstruction(text, context = {}) {
    const response = await this.client.post('/governance/classify', { text, context });
    return response.data.classification;
  }

  async validateAction(action, context = {}) {
    const response = await this.client.post('/governance/validate', { action, context });
    return response.data.validation;
  }

  async getDocuments(options = {}) {
    const response = await this.client.get('/documents', { params: options });
    return response.data;
  }
}

// Usage
const tractatus = new TractatusClient();

async function main() {
  await tractatus.login('admin@tractatus.local', 'password');

  const classification = await tractatus.classifyInstruction(
    'Always use MongoDB on port 27027'
  );
  console.log('Classification:', classification);

  const docs = await tractatus.getDocuments({ limit: 5 });
  console.log(`Found ${docs.total} documents`);
}

main().catch(console.error);
```

---

## Rate Limiting

The Tractatus API implements rate limiting:

- **Login endpoint**: 5 attempts per 15 minutes per IP
- **General API**: 100 requests per 15 minutes per IP

Handle rate limiting:

```javascript
async function apiCallWithRateLimit(fn) {
  try {
    return await fn();
  } catch (error) {
    if (error.response?.status === 429) {
      const retryAfter = error.response.headers['retry-after'];
      console.warn(`Rate limited. Retry after ${retryAfter} seconds`);

      // Wait and retry
      await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
      return await fn();
    }
    throw error;
  }
}
```

---

For more information, see the [API Reference](https://agenticgovernance.digital/api-reference.html) and [OpenAPI Specification](https://agenticgovernance.digital/docs/api/openapi.yaml).
