@simpleapps-com/augur-api
Version:
TypeScript client library for Augur microservices API endpoints
1,647 lines (1,322 loc) • 108 kB
Markdown
# The Augur Platform: Code That Almost Writes Itself
Transform enterprise API chaos into developer flow with intelligent client generation, context-aware discovery, and AI-powered development acceleration.
## Experience the Magic in 30 Seconds
```typescript
// Before: 35+ lines of authentication boilerplate
const userJwt = await getToken({ req: request });
if (!userJwt?.jwtToken) throw new Error('Authentication failed');
const api = new AugurAPI({ siteId: context.siteId, bearerToken: userJwt.jwtToken });
// After: Pure business intent ✨
const api = AugurAPI.fromContext(context);
// Ask for anything and find it instantly
const userOps = await api.findEndpoint('user management');
const inventory = await api.findEndpoint('stock levels');
const pricing = await api.findEndpoint('product pricing');
// Code that understands your business domain
const users = await api.joomla.users.list({ limit: 10, edgeCache: 2 });
const availability = await api.vmi.invProfileHdr.checkAvailability(warehouse);
const price = await api.pricing.getPrice({ customerId, itemId, quantity });
```
## Table of Contents
- [🚀 Quick Start Guide](./QUICKSTART.md) - **Experience the magic in under 5 minutes**
- [The Five Ideals in Action](#the-five-ideals-in-action)
- [🎯 AI-Powered Discovery System](#-ai-powered-discovery-system)
- [📖 API Discovery Guide](./API-DISCOVERY.md) - Natural language API navigation
- [Developer Experience Revolution](#developer-experience-revolution)
- [Context-Aware Architecture](#context-aware-architecture)
- [Prophet 21 Data Source Integration](#prophet-21-data-source-integration) - **ERP naming conventions and business context**
- [Installation & First Steps](#installation--first-steps)
- [Intelligent Discovery Examples](#intelligent-discovery-examples)
- [Cross-Service Intelligence](#cross-service-intelligence)
- [Advanced Capabilities](#advanced-capabilities)
- [Platform Integration](#platform-integration)
- [Performance & Caching](#performance--caching)
- [Troubleshooting & Support](#troubleshooting--support)
## The Five Ideals in Action
This platform embodies the Five Ideals from The Unicorn Project, transforming how developers interact with enterprise APIs:
### Locality and Simplicity ✨
**No more coordination across 13 different APIs.** One unified interface eliminates architectural complexity.
```typescript
// Instead of learning 13 different authentication patterns
await joomlaAPI.authenticate(token);
await commerceAPI.setAuth(bearer);
await pricingAPI.login(credentials);
// One pattern rules them all
const api = AugurAPI.fromContext(context);
```
### Focus, Flow, and Joy 🎯
**Zero context switching.** Intelligent discovery means never leaving your flow state.
```typescript
// No documentation hunting, no API reference browsing
const results = await api.findEndpoint('inventory management');
// Instantly find: api.vmi.warehouses.list, api.vmi.invProfileHdr.checkAvailability
// Your IDE becomes clairvoyant with comprehensive semantic JSDoc
api.vmi.invProfileHdr. // ← Auto-complete shows exactly what you need
```
### Improvement of Daily Work 🔄
**The platform learns your patterns** and suggests related operations across services.
```typescript
// When you work with users, it suggests related customer operations
const user = await api.joomla.users.get('123');
// Related suggestions: api.customers.customer.get, api.orders.salesRep.getOrders
```
### Psychological Safety 🛡️
**Fail fast with clear, actionable errors.** No more guessing what went wrong.
```typescript
try {
const api = AugurAPI.fromContext(context);
} catch (error) {
// Clear guidance: "Context missing siteId - check your context.siteId property"
// No blame, just solutions
}
```
### Customer Focus 📊
**Business context embedded** in every endpoint. Search by business intent, not technical implementation.
```typescript
// Search by what you're trying to accomplish
await api.findEndpoint('customer order history');
await api.findEndpoint('product recommendations');
await api.findEndpoint('inventory replenishment');
```
## AI-Powered Discovery System
**Never memorize API endpoints again.** The discovery system understands business context and finds functionality through natural language.
### Semantic Intelligence
Every endpoint includes AI-readable metadata:
```typescript
/**
* @searchTerms ["users", "authentication", "user management", "login"]
* @relatedEndpoints ["api.customers.customer.get", "api.joomla.userGroups.list"]
* @workflow ["user-onboarding", "authentication-flow", "user-administration"]
* @commonPatterns ["Get user profile", "List active users", "Create new account"]
*/
```
### Cross-Service Awareness
The system maps relationships between all 13 microservices:
```typescript
// Working with users? It knows you might need customers too
const userEndpoints = await api.findEndpoint('user management');
// Suggests: joomla.users.list, customers.customer.get, orders.salesRep.getOrders
// Working with inventory? It connects you to pricing
const inventoryOps = await api.findEndpoint('stock management');
// Suggests: vmi.warehouses.list, pricing.getPrice, items.products.get
```
## Developer Experience Revolution
### Context-Aware Creation
Eliminate 70% of setup boilerplate with intelligent context extraction:
```typescript
// Traditional enterprise pattern (35+ lines)
const authentication = await authenticateUser(request);
if (!authentication.success) {
return handleAuthFailure(authentication.error);
}
const siteContext = await resolveSiteContext(authentication.user);
const apiConfig = {
siteId: siteContext.siteId,
bearerToken: authentication.jwtToken,
timeout: getConfiguredTimeout(),
retries: getRetryPolicy()
};
const api = new AugurAPI(apiConfig);
// Context-aware magic (1 line)
const api = AugurAPI.fromContext(context);
```
### Intelligent Method Discovery
Every method includes rich semantic metadata for AI assistants:
```typescript
// Ask your AI assistant: "Help me manage warehouse inventory"
// It instantly finds and suggests:
await api.vmi.warehouses.list({ customerId: 12345 });
await api.vmi.invProfileHdr.checkAvailability(warehouseId);
await api.vmi.invProfileHdr.replenish(warehouseId, { items });
```
### Factory Pattern Excellence
Sophisticated factory patterns create consistent, discoverable APIs:
```typescript
// Auto-generated from OpenAPI specs with semantic enhancement
export class VMIClient extends BaseServiceClient {
get warehouses() { return this.createWarehouseOperations(); }
get inventory() { return this.createInventoryOperations(); }
get distributors() { return this.createDistributorOperations(); }
}
```
## Installation & First Steps
```bash
npm install @simpleapps-com/augur-api
```
### Immediate Value Demo
```typescript
import { AugurAPI } from '@simpleapps-com/augur-api';
// Create from context (eliminates boilerplate)
const api = AugurAPI.fromContext(context);
// Discover capabilities (no documentation needed)
const services = await api.discover();
console.log(`Connected to ${services.length} business services`);
// Find what you need (natural language)
const userStuff = await api.findEndpoint('user management');
const inventoryStuff = await api.findEndpoint('stock levels');
// Work with intelligent caching (sub-100ms responses)
const users = await api.joomla.users.list({
limit: 10,
edgeCache: 2 // Cloudflare edge caching
});
```
## Intelligent Discovery Examples
### Business Context Understanding
The platform knows your business domain and connects related operations:
```typescript
// Search by business intent, not technical endpoints
const userOps = await api.findEndpoint('customer account management');
// Returns:
// - api.joomla.users.list (user authentication)
// - api.customers.customer.get (customer profiles)
// - api.orders.salesRep.getOrders (order history)
const inventoryOps = await api.findEndpoint('stock replenishment');
// Returns:
// - api.vmi.invProfileHdr.checkAvailability (current levels)
// - api.vmi.invProfileHdr.replenish (automated ordering)
// - api.pricing.getPrice (cost calculations)
```
### Workflow-Aware Suggestions
Working on one task? The system suggests the next logical steps:
```typescript
// Create a user account
const newUser = await api.joomla.users.create({
username: 'john.doe',
email: 'john@company.com'
});
// System knows you might need to:
// 1. Set up customer profile: api.customers.customer.create()
// 2. Assign user groups: api.joomla.userGroups.createMapping()
// 3. Check permissions: api.joomla.users.groups.list()
```
### Cross-Service Intelligence
The discovery system maps business workflows across all 13 microservices:
```typescript
// E-commerce workflow discovery
const ecommerceFlow = await api.findEndpoint('online shopping');
// Suggests complete customer journey:
// - Product search: api.opensearch.itemSearch.search()
// - Pricing: api.pricing.getPrice()
// - Cart management: api.commerce.cartHeaders.lookup()
// - Checkout: api.commerce.checkout.get()
// - Payment: api.payments.unified.transactionSetup()
```
## Context-Aware Architecture
### Intelligent Context Extraction
The `fromContext()` method understands various context patterns:
```typescript
// Middleware context
const api = AugurAPI.fromContext({
siteId: req.headers['x-site-id'],
jwt: req.headers.authorization?.replace('Bearer ', ''),
userId: req.user.id
});
// Tool handler context
const api = AugurAPI.fromContext({
siteId: context.siteId,
bearerToken: context.authentication.token,
parameters: context.requestParams
});
// Next.js context
const api = AugurAPI.fromContext({
siteId: process.env.NEXT_PUBLIC_SITE_ID,
jwt: session.accessToken
});
```
### Factory Pattern Excellence
Each service client is lazily instantiated with sophisticated caching:
```typescript
// Clients are created on-demand and cached
const joomla1 = api.joomla; // Creates new instance
const joomla2 = api.joomla; // Returns cached instance
console.log(joomla1 === joomla2); // true
// Token changes invalidate all clients automatically
api.setAuthToken('new-token');
const joomla3 = api.joomla; // Creates fresh instance with new token
console.log(joomla1 === joomla3); // false
```
### Semantic Method Generation
Every endpoint includes rich semantic metadata for AI discovery:
```typescript
/**
* List site settings with intelligent filtering and caching
* @fullPath api.agrSite.settings.list
* @service agr-site
* @domain site-content-management
* @searchTerms ["settings", "configuration", "site management", "admin"]
* @relatedEndpoints ["api.agrSite.settings.get", "api.agrSite.settings.update"]
* @workflow ["site-administration", "configuration-management"]
* @commonPatterns ["Get all settings", "Filter by service", "Cache configuration"]
* @discoverable true
*/
async list(params?: SettingListParams): Promise<SettingListResponse> {
// Implementation uses sophisticated base class patterns
}
```
## Advanced Capabilities
### Intelligent Service Discovery
The discovery system provides both exploration and targeted search:
```typescript
// Comprehensive service topology
const services = await api.discover();
console.log(`Platform connected to ${services.length} business services`);
// Each service reveals its capabilities
services.forEach(service => {
console.log(`${service.serviceName}: ${service.endpointCount} operations available`);
console.log(`Business domain: ${service.description}`);
});
// Targeted functionality search with intelligent scoring
const results = await api.findEndpoint('inventory management', {
minScore: 0.1, // Relevance threshold
maxResults: 10, // Limit results
service: 'vmi', // Optional service filter
domain: 'inventory-management', // Business domain filter
readOnly: true // Only read operations
});
// Results include relevance scores and match reasoning
results.forEach(result => {
console.log(`${result.endpoint.fullPath} (score: ${result.score})`);
console.log(`Match reason: ${result.matchReason}`);
});
```
### Multi-Method Pattern Innovation
Every endpoint offers dual access patterns for maximum flexibility:
```typescript
// Full response with metadata (standard pattern)
const response = await api.joomla.users.list({ limit: 10 });
console.log(`Found ${response.data.length} users`);
console.log(`Total available: ${response.totalResults}`);
console.log(`Status: ${response.message}`);
// Data-only access (streamlined pattern)
const users = await api.joomla.users.listData({ limit: 10 });
console.log(users); // Direct array access, no wrapper
```
## Prophet 21 Data Source Integration
Many API endpoints reflect Prophet 21 ERP system naming conventions and table structures. This provides direct mapping from your business processes to API operations.
### Understanding Prophet 21 Naming Patterns
The Path-Function Alignment Pattern preserves Prophet 21 table naming for user recognition:
```typescript
// Prophet 21 Table → API Endpoint → Client Structure
// inv_mast table → /inv-mast → api.items.invMast
// oe_hdr table → /oe-hdr → api.orders.oeHdr
// job_price_hdr table → /job-price-hdr → api.pricing.jobPriceHdr
// restock_hdr table → /restock-hdr → api.vmi.restockHdr
// inv_profile_hdr table → /inv-profile-hdr → api.vmi.invProfileHdr
// Examples with Prophet 21 context:
const inventory = await api.items.invMast.get(12345); // Inventory master record
const order = await api.orders.oeHdr.get(67890); // Order entry header
const pricing = await api.pricing.jobPriceHdr.get(111); // Job pricing header
const restock = await api.vmi.restockHdr.get(222); // Restocking header
const profile = await api.vmi.invProfileHdr.get(333); // Inventory profile header
```
### Prophet 21 Business Context
Understanding the ERP context helps predict API behavior:
```typescript
// Inventory Management (Prophet 21 inv_mast context)
const itemDetails = await api.items.invMast.get(itemId);
const locations = await api.items.invMast.locations.list(itemId); // Physical locations
const alternates = await api.items.invMast.alternateCode.list(itemId); // Alternate part numbers
// Order Processing (Prophet 21 oe_hdr context)
const orderHeader = await api.orders.oeHdr.get(orderId);
const salesRep = await api.orders.oeHdrSalesrep.get(orderId); // Sales representative info
const lineItems = await api.orders.oeHdr.lines.list(orderId); // Order line details
// VMI Operations (Prophet 21 inventory management context)
const profileHeader = await api.vmi.invProfileHdr.get(profileId); // VMI profile setup
const restockInfo = await api.vmi.restockHdr.get(restockId); // Restocking instructions
const warehouseData = await api.vmi.warehouse.get(warehouseId); // Warehouse details
```
### Migration from Legacy Naming
If you're familiar with conceptual API naming, here's the Prophet 21 mapping:
```typescript
// Legacy Conceptual → Prophet 21 Aligned
client.inventory → client.invMast // Inventory master
client.categories → client.itemCategory // Item categories
client.orders → client.oeHdr // Order entry header
client.salesRep → client.oeHdrSalesrep // Order header sales rep
client.purchaseOrders → client.poHdr // Purchase order header
client.invoices → client.invoiceHdr // Invoice header
client.inventoryProfiles → client.invProfileHdr // Inventory profile header
client.restocking → client.restockHdr // Restock header
client.calculateTax → client.taxEngine.calculate // Tax calculation engine
client.jobPriceHeaders → client.jobPriceHdr // Job price header
```
This alignment ensures that developers familiar with Prophet 21 can immediately understand the API structure and predict endpoint behavior based on their ERP knowledge.
### Sophisticated Caching Architecture
Intelligent edge caching with business-aware TTL policies:
```typescript
// Cache strategy varies by data volatility
const categories = await api.items.categories.list({
edgeCache: 8 // Static reference data - 8 hours
});
const pricing = await api.pricing.getPrice({
customerId: 12345,
itemId: 'STANDARD-ITEM',
quantity: 10,
edgeCache: 3 // Standard pricing - 3 hours
});
const cart = await api.commerce.cartHeaders.list({
userId: 123,
edgeCache: 1 // Volatile user data - 1 hour only
});
// Real-time operations never cached
const auth = await api.joomla.users.verifyPassword({
username: 'user',
password: 'pass'
// No edgeCache - authentication must be real-time
});
```
## Power Features (Hidden Gems)
**Unlock the full potential** of the Augur API with these advanced features that dramatically improve your development experience:
### Data Methods Pattern ⭐ NEW!
Every endpoint provides both complete responses AND streamlined data-only access:
```typescript
// Standard pattern - full response with metadata
const response = await api.joomla.users.list({ limit: 10 });
console.log(`Found ${response.data.length} users`);
console.log(`Total available: ${response.totalResults}`);
console.log(`Response status: ${response.status}`);
// Data-only pattern - direct access to the data array ⚡
const users = await api.joomla.users.listData({ limit: 10 });
console.log(users); // Direct User[] array, no wrapper
// Single item data access
const user = await api.joomla.users.getData('123');
console.log(user); // Direct User object, no response wrapper
// Works across ALL services
const products = await api.opensearch.itemSearch.searchData({
q: 'electrical wire',
searchType: 'query',
size: 20
}); // Direct item array
const pricing = await api.pricing.getPriceData({
customerId: 12345,
itemId: 'WIRE-123',
quantity: 10
}); // Direct pricing object
```
**Benefits:**
- **50% less code** for data extraction
- **Cleaner business logic** without response unwrapping
- **Same caching and validation** as standard methods
- **Consistent pattern** across all 13 microservices
### Advanced Discovery Filtering
Go beyond basic search with sophisticated filtering options:
```typescript
// Precision search with advanced filtering
const endpoints = await api.findEndpoint('user management', {
// Relevance threshold (0.0 to 1.0)
minScore: 0.7, // Only highly relevant matches
// Limit results
maxResults: 5, // Top 5 matches only
// Service-specific filtering
service: 'joomla', // Only Joomla service endpoints
// Business domain filtering
domain: 'user-management', // Only user management domain
// Operation type filtering
readOnly: true, // Only read operations (GET requests)
writeOnly: false, // Exclude write operations
// Response format preferences
includeMetadata: true, // Include match reasoning and scores
sortBy: 'relevance' // Sort by relevance score (default: 'relevance' | 'alphabetical')
});
// Rich result information
endpoints.forEach(result => {
console.log(`🔍 ${result.endpoint.fullPath}`);
console.log(` Score: ${result.score} | Reason: ${result.matchReason}`);
console.log(` Domain: ${result.endpoint.domain} | Service: ${result.endpoint.service}`);
console.log(` Method: ${result.endpoint.method} | Read-only: ${result.endpoint.readOnly}`);
});
// Cross-service workflow discovery
const ecommerceFlow = await api.findEndpoint('complete customer order', {
domain: ['commerce', 'pricing', 'inventory'], // Multiple domains
includeWorkflow: true, // Include workflow relationships
minScore: 0.5
});
// Results include cross-service relationships
ecommerceFlow.forEach(result => {
console.log(`${result.endpoint.fullPath} → Related: ${result.relatedEndpoints?.join(', ')}`);
});
```
### Debug Utilities and Troubleshooting
Built-in debugging tools help you understand what's happening under the hood:
```typescript
// Create detailed debug information for any request
const debugInfo = api.joomla.users.createDebugInfo(
{ limit: 10, offset: 0 }, // Your parameters
{ edgeCache: 2 } // Request config
);
console.log('🔧 Debug Information:');
console.log('Expected Parameters:', debugInfo.expectedParams);
console.log('Provided Parameters:', debugInfo.providedParams);
console.log('Validation Results:', debugInfo.validation);
console.log('Cache Strategy:', debugInfo.cacheInfo);
console.log('Generated URL:', debugInfo.finalURL);
// Validate parameters before making requests
const validation = api.pricing.validatePriceParams({
customerId: 12345,
itemId: 'INVALID', // This might fail validation
quantity: -5 // Negative quantity should fail
});
if (!validation.isValid) {
console.log('❌ Parameter Validation Failed:');
validation.errors.forEach(error => {
console.log(` Field: ${error.field} | Issue: ${error.message}`);
console.log(` Expected: ${error.expected} | Received: ${error.received}`);
});
}
// Request tracing for performance analysis
api.enableRequestTracing(true);
const users = await api.joomla.users.list({ limit: 10 });
// Get trace information
const trace = api.getLastRequestTrace();
console.log('🚀 Performance Trace:');
console.log(` Total Time: ${trace.totalTime}ms`);
console.log(` Network Time: ${trace.networkTime}ms`);
console.log(` Validation Time: ${trace.validationTime}ms`);
console.log(` Cache Status: ${trace.cacheStatus}`);
console.log(` Request ID: ${trace.requestId}`);
```
### Automatic Parameter Extraction
The system intelligently maps URL templates to method parameters:
```typescript
// URL template: /bin-transfer/{binTransferHdrUid}
// Automatically creates: (id) => { binTransferHdrUid: id }
const binTransfer = await api.nexus.binTransfers.get(12345);
// Internally maps: 12345 → { binTransferHdrUid: 12345 }
// URL template: /customer/{customerId}/orders/{orderId}
// Automatically creates: (customerId, orderId) => { customerId, orderId }
const order = await api.customers.customer.orders.get(123, 456);
// Internally maps: (123, 456) → { customerId: 123, orderId: 456 }
// Complex URL templates with multiple parameters
// URL template: /pricing/job/{jobPriceHdrUid}/lines/{jobPriceLineUid}
const jobPriceLine = await api.pricing.jobPriceLines.get(123, 456);
// Internally maps: (123, 456) → { jobPriceHdrUid: 123, jobPriceLineUid: 456 }
// See the mapping for any endpoint
const mapping = api.nexus.binTransfers.getParameterMapping();
console.log('URL Template:', mapping.urlTemplate);
console.log('Parameter Map:', mapping.parameterMap);
console.log('Required Params:', mapping.requiredParams);
console.log('Optional Params:', mapping.optionalParams);
// Validate parameter mapping before calling
const isValid = api.nexus.binTransfers.validateParameterMapping(12345);
if (!isValid.valid) {
console.log('Parameter mapping issues:', isValid.errors);
}
```
### Smart Request Building
Advanced request construction with intelligent defaults:
```typescript
// Smart parameter inference
const smartRequest = api.commerce.cartHeaders.buildRequest({
userId: 123,
// System automatically infers common parameters:
// - siteId from API configuration
// - timestamp for cache busting
// - request ID for tracing
});
console.log('Generated request:', smartRequest);
// {
// userId: 123,
// siteId: 'your-site-id',
// _timestamp: 1693934400000,
// _requestId: 'req_abc123',
// _cacheKey: 'cart_headers_123_your-site-id'
// }
// Request templating for repeated operations
const userTemplate = api.joomla.users.createRequestTemplate({
limit: 50,
orderBy: 'username|ASC'
});
// Reuse template with variations
const activeUsers = await userTemplate.execute({ q: 'active' });
const adminUsers = await userTemplate.execute({ groupId: 1 });
const recentUsers = await userTemplate.execute({
createdSince: '2024-01-01',
limit: 20 // Override template default
});
```
## Platform Capabilities Matrix
| Capability | Impact | Technical Implementation |
|------------|--------|-------------------------|
| **Context-Aware Creation** | 70% boilerplate reduction | `AugurAPI.fromContext()` with intelligent field extraction |
| **Natural Language Discovery** | Zero API documentation hunting | Semantic JSDoc parsing with cross-service mapping |
| **Intelligent Caching** | Sub-100ms response times | Cloudflare edge integration with business-aware TTL |
| **Factory Pattern Excellence** | Consistent developer experience | Lazy instantiation with automatic cache invalidation |
| **Cross-Service Intelligence** | Business workflow awareness | Relationship mapping across 13 microservices |
| **AI Assistant Integration** | Code that almost writes itself | Rich semantic metadata in every endpoint |
| **Type Safety** | Runtime validation guarantee | Zod schema validation on all requests/responses |
| **Multi-Platform Support** | Universal JavaScript compatibility | React, React Native, Next.js, Node.js, Electron |
## Installation
```bash
npm install @simpleapps-com/augur-api
# or
yarn add @simpleapps-com/augur-api
# or
pnpm add @simpleapps-com/augur-api
```
### System Requirements
- Node.js >= 16.0.0
- TypeScript >= 4.5.0 (for TypeScript projects)
## Getting Started
### Basic Setup
```typescript
import { AugurAPI } from '@simpleapps-com/augur-api';
// Traditional approach - manual configuration
const api = new AugurAPI({
siteId: 'your-site-id', // Required for all endpoints
bearerToken: 'your-jwt-token', // Required except for health checks
});
// Context-aware approach (recommended) - eliminates boilerplate
const api = AugurAPI.fromContext(context);
// Make your first API call
const users = await api.joomla.users.list({
limit: 10,
edgeCache: 2 // Cache for 2 hours
});
console.log(`Found ${users.data.length} users`);
```
### Context-Aware Client Creation ⭐ NEW!
The `fromContext()` method dramatically simplifies API client initialization by automatically extracting authentication and site information from your context object:
```typescript
import { AugurAPI, type AugurContext } from '@simpleapps-com/augur-api';
// Your context object (common in tool handlers, middleware, etc.)
const context: AugurContext = {
siteId: 'my-site-123',
jwt: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
parameters: { limit: 10 },
filters: { search: 'electrical' },
userId: 456
};
// Before: 35+ lines of boilerplate
const userJwt = await getToken({ req: request });
if (!userJwt?.jwtToken) {
throw new Error('Authentication failed');
}
const api = new AugurAPI({
siteId: context.siteId,
bearerToken: userJwt.jwtToken
});
// After: 1 line of business intent ✨
const api = AugurAPI.fromContext(context);
// Optional configuration overrides
const api = AugurAPI.fromContext(context, {
timeout: 10000,
retries: 1
});
```
#### Context Interface
```typescript
interface AugurContext {
siteId: string; // Required: Site identifier
jwt?: string; // JWT token (preferred)
bearerToken?: string; // Alternative token field
parameters?: Record<string, unknown>; // Request parameters
filters?: Record<string, unknown>; // Filter parameters
userId?: string | number; // User identifier
}
```
#### Error Handling
The `fromContext()` method provides clear, actionable error messages:
```typescript
import { ContextCreationError } from '@simpleapps-com/augur-api';
try {
const api = AugurAPI.fromContext(context);
} catch (error) {
if (error instanceof ContextCreationError) {
console.error(`Context validation failed: ${error.message}`);
console.error(`Problem field: ${error.field}`);
// Handle specific issues
switch (error.field) {
case 'siteId':
// Handle missing site ID
break;
case 'bearerToken':
// Handle missing authentication
break;
}
}
}
```
### Environment Setup
```typescript
// .env file
AUGUR_SITE_ID=your-site-id
AUGUR_JWT_TOKEN=your-jwt-token
// app.ts
const api = new AugurAPI({
siteId: process.env.AUGUR_SITE_ID!,
bearerToken: process.env.AUGUR_JWT_TOKEN!,
});
```
### Quick Example: E-commerce Operations
```typescript
// Get product recommendations
const recommendations = await api.commerce.alsoBought.get({
itemId: 'WIRE-123',
customerId: 12345,
edgeCache: 4 // Cache recommendations for 4 hours
});
// Get real-time pricing
const pricing = await api.pricing.getPrice({
customerId: 12345,
itemId: 'WIRE-123',
quantity: 100,
edgeCache: 3 // Cache standard pricing for 3 hours
});
// Search for products
const searchResults = await api.opensearch.itemSearch.search({
q: 'electrical wire 12 AWG',
searchType: 'query',
size: 20,
edgeCache: 2 // Cache search results for 2 hours
});
```
## Authentication & Security
> 📋 **[Complete Authentication Guide](./AUTHENTICATION.md)** - Comprehensive guide including cross-site authentication for multi-tenant applications.
### Standard Authentication (Most Common)
The Augur API uses a dual authentication system:
1. **Site ID** (`x-site-id` header) - Required for ALL endpoints
2. **Bearer Token** (JWT) - Required for all endpoints EXCEPT health checks
```typescript
const api = new AugurAPI({
siteId: 'your-site-id', // Always required
bearerToken: 'your-jwt-token', // Required except for health checks
});
```
### Health Checks (No Authentication Required)
```typescript
// Health checks work without bearer token
const api = new AugurAPI({
siteId: 'your-site-id',
// No bearerToken needed
});
const health = await api.joomla.getHealthCheck();
const pricing = await api.pricing.getHealthCheck();
const vmiPing = await api.vmi.health.ping();
```
### Environment Variables Setup
```typescript
// .env file
AUGUR_SITE_ID=your-site-id
AUGUR_JWT_TOKEN=your-jwt-token
// app.ts
const api = new AugurAPI({
siteId: process.env.AUGUR_SITE_ID!,
bearerToken: process.env.AUGUR_JWT_TOKEN!,
});
```
### Dynamic Authentication Updates
```typescript
// Update credentials at runtime
api.setAuthToken('new-jwt-token');
api.setSiteId('new-site-id');
// Useful for token refresh scenarios
async function refreshTokenIfNeeded() {
try {
await api.joomla.users.list({ limit: 1 });
} catch (error) {
if (error instanceof AuthenticationError) {
const newToken = await refreshJWTToken();
api.setAuthToken(newToken);
}
}
}
```
### Advanced: Cross-Site Authentication
For multi-tenant applications that need to authenticate users across different sites:
```typescript
import { authenticateUserForSite } from '@simpleapps-com/augur-api';
const result = await authenticateUserForSite({
targetSiteId: 'tenant_site_1',
username: 'user@tenant.com',
password: 'user-password',
augurInfoToken: 'admin-jwt-token'
});
if (result.success) {
const userData = await result.targetSiteAPI!.joomla.users.get(result.userId!);
}
```
> ⚠️ **Cross-site authentication is an advanced feature.** See the [Complete Authentication Guide](./AUTHENTICATION.md) for detailed implementation patterns, security considerations, and troubleshooting.
## API Documentation
### Service Overview
| Service | Purpose | Key Features |
|---------|---------|--------------|
| **Joomla** | Content & User Management | Articles, users, groups, tags, menu items |
| **Commerce** | E-commerce Operations | Cart management, checkout, recommendations |
| **Pricing** | Dynamic Pricing | Price calculations, job pricing, tax engine |
| **VMI** | Inventory Management | Warehouses, stock levels, replenishment |
| **OpenSearch** | Product Search | Full-text search, faceting, similarity matching |
| **Items** | Product Catalog | Products, categories, attributes, brands |
| **Customers** | Customer Data | Customer profiles, contacts, addresses, orders |
| **Orders** | Order Management | Order lookup, documents, purchase orders |
| **Payments** | Payment Processing | Transaction setup, payment validation |
| **Legacy** | Legacy Systems | State data, inventory lookups |
| **Nexus** | Warehouse Operations | Bin transfers, receiving, shipping |
| **P21 PIM** | Product Information | Product data management, AI suggestions |
| **AGR Site** | Site Management | Settings, notifications, transcripts |
### Complete Endpoint Reference
#### Joomla Service
```typescript
// Content Management
const articles = await api.joomla.content.list({
categoryIdList: '1,2,3', // Filter by categories
tagsList: 'featured,new', // Filter by tags
limit: 20,
offset: 0,
orderBy: 'created|DESC',
q: 'search term',
edgeCache: 6 // Cache articles for 6 hours
});
const article = await api.joomla.content.get('123', {
alias: 'article-alias',
catid: 5,
edgeCache: 8 // Cache single articles for 8 hours
});
const articleDoc = await api.joomla.content.getDoc('123');
// User Management
const users = await api.joomla.users.list({
limit: 50,
offset: 0,
orderBy: 'username|ASC',
q: 'john',
edgeCache: 2 // Cache user lists for 2 hours
});
const user = await api.joomla.users.get('456');
const userDoc = await api.joomla.users.getDoc('456');
// Create new user
const newUser = await api.joomla.users.create({
username: 'newuser',
email: 'user@example.com',
name: 'New User',
password: 'securepassword'
});
// Update user
const updatedUser = await api.joomla.users.update('456', {
email: 'newemail@example.com'
});
// Block/unblock user
await api.joomla.users.block('456');
// User Groups
const userGroups = await api.joomla.users.groups.list('456', {
limit: 10,
edgeCache: 4 // Cache group memberships for 4 hours
});
const groupMapping = await api.joomla.users.groups.createMapping('456', {
groupId: 789
});
// System Groups
const allGroups = await api.joomla.userGroups.list({
orderBy: 'title|ASC',
parentIdList: '1,2',
edgeCache: 8 // Cache group hierarchy for 8 hours
});
const groupDetails = await api.joomla.userGroups.get('789');
// Tags
const tags = await api.joomla.tags.list({
categoryId: 1,
parentId: 0,
q: 'tech',
limit: 50,
edgeCache: 6 // Cache tags for 6 hours
});
// Authentication
const authResult = await api.joomla.users.verifyPassword({
username: 'user@example.com',
password: 'userpassword',
siteId: 'optional-cross-site-id' // For cross-site auth when using augur_info
});
if (authResult.data.isVerified) {
console.log('User authenticated:', authResult.data.username);
console.log('User ID:', authResult.data.id);
console.log('JWT Token:', authResult.data.token);
}
// Health Check
const health = await api.joomla.getHealthCheck();
```
#### Commerce Service
```typescript
// Cart Management
const carts = await api.commerce.cartHeaders.list({
userId: 123,
edgeCache: 1 // Cache cart data for 1 hour max
});
const cart = await api.commerce.cartHeaders.lookup({
userId: 123,
customerId: 456,
contactId: 789
});
const cartLines = await api.commerce.cartLines.get(cart.data.cart_hdr_uid);
// Product Recommendations
const alsoBought = await api.commerce.alsoBought.get({
itemId: 'WIRE-123',
customerId: 12345,
edgeCache: 6 // Cache recommendations for 6 hours
});
// Checkout Operations
const checkout = await api.commerce.checkout.get(checkoutUid, {
edgeCache: 2 // Cache checkout data for 2 hours
});
const checkoutDoc = await api.commerce.checkout.getDoc(checkoutUid, {
cartHdrUid: cart.data.cart_hdr_uid,
edgeCache: 4 // Cache checkout documents for 4 hours
});
// Health Check
const health = await api.commerce.getHealthCheck();
```
#### Pricing Service
```typescript
// Price Engine
const pricing = await api.pricing.getPrice({
customerId: 12345,
itemId: 'ITEM-001',
quantity: 10,
shipToId: 'SHIP-001', // Optional
unitOfMeasure: 'EA', // Optional
edgeCache: 3 // Cache standard pricing for 3 hours
});
// Job Price Management
const jobPriceHeaders = await api.pricing.jobPriceHeaders.list({
limit: 20,
orderBy: 'job_price_hdr_uid|DESC',
edgeCache: 4 // Cache job listings for 4 hours
});
const jobPriceHeader = await api.pricing.jobPriceHeaders.get(12345);
const jobPriceLines = await api.pricing.jobPriceLines.list(12345, {
limit: 50,
edgeCache: 4 // Cache price lines for 4 hours
});
const jobPriceLine = await api.pricing.jobPriceLines.get(12345, 67890);
// Tax Engine
const taxCalculation = await api.pricing.calculateTax({
customer_id: 12345,
ship_to_id: 'SHIP-001',
items: [
{
item_id: 'ITEM-001',
quantity: 10,
unit_price: 25.50,
extended_price: 255.00
}
],
addresses: {
origin: {
street: '123 Main St',
city: 'Anytown',
state: 'CA',
zip: '90210'
},
destination: {
street: '456 Oak Ave',
city: 'Other City',
state: 'NY',
zip: '10001'
}
},
edgeCache: 1 // Cache tax calculations for 1 hour
});
// Health Checks
const ping = await api.pricing.ping();
const health = await api.pricing.getHealthCheck();
```
#### VMI (Vendor Managed Inventory) Service
```typescript
// Warehouse Management
const warehouses = await api.vmi.warehouses.list({
customerId: 12345,
limit: 10,
q: 'distribution',
usersId: 456,
edgeCache: 4 // Cache warehouse data for 4 hours
});
const warehouse = await api.vmi.warehouses.get(123);
const newWarehouse = await api.vmi.warehouses.create({
warehouse_name: 'New Distribution Center',
warehouse_desc: 'Primary warehouse for west coast operations',
customer_id: 12345,
inv_profile_hdr_uid: 1
});
const updatedWarehouse = await api.vmi.warehouses.update(123, {
warehouse_name: 'Updated Warehouse Name'
});
// Enable/disable warehouse
await api.vmi.warehouses.enable(123, { status_cd: 704 }); // Enable
await api.vmi.warehouses.enable(123, { status_cd: 705 }); // Disable
// Inventory Operations
const availability = await api.vmi.invProfileHdr.checkAvailability(123, {
q: 'wire' // Search for items containing 'wire'
});
// Adjust inventory (sets absolute values)
await api.vmi.invProfileHdr.adjust(123, {
adjustments: [
{
inv_mast_uid: 456,
qty_on_hand: 200.0,
reason: 'Physical count adjustment'
}
]
});
// Receive inventory
await api.vmi.invProfileHdr.receive(123, {
receipts: [
{
inv_mast_uid: 456,
qty_received: 50.0,
po_number: 'PO-2024-001',
lot_number: 'LOT-456'
}
]
});
// Get replenishment information
const replenishment = await api.vmi.invProfileHdr.getReplenishmentInfo(123, {
distributorsUid: 789,
edgeCache: 2 // Cache replenishment info for 2 hours
});
// Execute replenishment
await api.vmi.invProfileHdr.replenish(123, {
distributor_uid: 789,
restock_items: [
{ inv_mast_uid: 456, qty_to_order: 100.0 }
]
});
// Transfer inventory between warehouses
await api.vmi.invProfileHdr.transfer(123, {
to_warehouse_uid: 124,
transfers: [
{
inv_mast_uid: 456,
qty_to_transfer: 25.0,
reason: 'Stock balancing'
}
]
});
// Record inventory usage (with warranty tracking)
await api.vmi.invProfileHdr.recordUsage(123, {
job_description: 'Office Renovation - Building A',
department: 'Facilities',
usage_items: [
{
inv_mast_uid: 456,
inv_profile_line_type: 'prophet21',
qty_used: 5.0
},
{
inv_mast_uid: 789,
inv_profile_line_type: 'products',
qty_used: 2.0,
warranty: {
model_no: 'MDL-123',
serial_no: 'SN-456789',
warranty_type: 'Standard',
notes: 'Installed in conference room'
}
}
]
});
// Distributor Management
const distributors = await api.vmi.distributors.list({
customerId: 12345,
statusCd: 704, // Active distributors only
edgeCache: 8 // Cache distributor data for 8 hours
});
const distributor = await api.vmi.distributors.get(789);
const newDistributor = await api.vmi.distributors.create({
distributor_name: 'ABC Supply Co',
distributor_desc: 'Primary electrical supplier',
customer_id: 12345,
contact_email: 'orders@abcsupply.com',
contact_phone: '555-1234'
});
// Product Management
const products = await api.vmi.products.find({
customerId: 12345,
prefix: 'WIRE',
edgeCache: 6 // Cache product catalogs for 6 hours
});
const productList = await api.vmi.products.list({
customerId: 12345,
distributorsUid: 789,
prefix: 'WIRE',
limit: 20,
edgeCache: 6
});
// Health Monitoring
const ping = await api.vmi.health.ping();
const health = await api.vmi.health.check();
```
#### OpenSearch Service
```typescript
// Item Search
const searchResults = await api.opensearch.itemSearch.search({
q: 'electrical wire 12 AWG',
searchType: 'query', // 'query' | 'similarity'
size: 20,
operator: 'AND', // 'AND' | 'OR'
itemCategoryUidList: '123,456,789',
filters: JSON.stringify([
{ attributeUid: 123, attributeValueUid: 456 }
]),
edgeCache: 2 // Cache search results for 2 hours
});
// Similarity search for recommendations
const similarItems = await api.opensearch.itemSearch.search({
q: 'CAT5e network cable 100ft blue',
searchType: 'similarity',
size: 15,
edgeCache: 4 // Cache similarity results for 4 hours
});
// Get search facets for filtering
const attributes = await api.opensearch.itemSearch.getAttributes({
q: 'LED bulbs',
searchType: 'query',
edgeCache: 6 // Cache facet structure for 6 hours
});
// Items Management
const items = await api.opensearch.items.list({
itemId: 'WIRE', // Prefix filter
online: 'Y', // Only online items
statusCd: 704, // Active items only
limit: 100,
offset: 0,
edgeCache: 3 // Cache item data for 3 hours
});
const itemDetail = await api.opensearch.items.get(123456);
// Index management operations (no caching for real-time operations)
const refreshResult = await api.opensearch.items.refresh(123456);
const updateResult = await api.opensearch.items.update(123456);
const batchRefresh = await api.opensearch.items.refreshAll();
// Health Monitoring
const ping = await api.opensearch.health.ping();
const health = await api.opensearch.health.check();
```
### Response Format
All Augur microservices follow a unified response pattern:
```typescript
interface BaseResponse<T> {
status: number; // HTTP status code (200 for success)
message?: string; // Status message (optional - omitted in health checks)
data: T; // Response data of type T
totalResults?: number; // Total count (optional - present in paginated responses)
count?: number; // Item count (optional - present in some responses)
options?: Array<Record<string, unknown>>; // Optional array of key-value pairs
}
// Example response
const usersResponse = await api.joomla.users.list({ limit: 10 });
// usersResponse = {
// status: 200,
// message: "Ok",
// data: [...users...],
// totalResults: 150
// }
// Access the actual data
const users = usersResponse.data;
const totalCount = usersResponse.totalResults;
```
#### Important: Query Parameter Handling
HTTP query parameters are always transmitted as strings. The library uses Zod's coercion to automatically handle numeric parameters:
```typescript
// You pass numbers
await api.customers.customer.orders.list(12345, {
limit: 10, // number
offset: 0 // number
});
// They become strings in the URL: ?limit=10&offset=0
// The API might echo them back as strings
// But Zod coercion handles this automatically!
```
### HTTP Methods and URL Patterns
| Method | Pattern | Client Method | Example |
|--------|---------|---------------|---------|
| GET | `/users` | `listUsers()` | List multiple resources |
| GET | `/user/{id}` | `getUser()` | Get single resource |
| POST | `/user` | `createUser()` | Create new resource |
| PUT | `/user/{id}` | `updateUser()` | Update existing resource |
| DELETE | `/user/{id}` | `deleteUser()` | Delete resource |
### Error Handling
```typescript
import {
AugurAPIError,
AuthenticationError,
ValidationError,
NotFoundError,
RateLimitError
} from '@simpleapps-com/augur-api';
try {
const user = await api.joomla.users.get('user-id');
} catch (error) {
if (error instanceof AuthenticationError) {
console.error('Authentication failed:', error.message);
// Handle auth error - refresh token or redirect to login
} else if (error instanceof ValidationError) {
console.error('Request validation failed:', error.validationErrors);
// Handle validation errors - check request parameters
} else if (error instanceof NotFoundError) {
console.error('Resource not found:', error.message);
// Handle not found - show user-friendly message
} else if (error instanceof RateLimitError) {
console.error('Rate limit exceeded:', error.message);
// Handle rate limiting - implement backoff strategy
} else if (error instanceof AugurAPIError) {
console.error('API error:', error.code, error.message);
// Handle other API errors
}
}
```
## Advanced Features
### Edge Caching with Cloudflare
The client provides built-in edge caching that dramatically improves performance by serving cached responses from Cloudflare's global edge network.
#### Supported Cache Durations
Only specific cache durations are supported and validated:
| Value | Duration | Best For |
|-------|----------|----------|
| `1` | 1 hour | Frequently changing data, cart contents |
| `2` | 2 hours | User lists, moderate volatility data |
| `3` | 3 hours | Standard pricing, product information |
| `4` | 4 hours | Recommendations, warehouse data |
| `5` | 5 hours | Tags, categories, reference data |
| `8` | 8 hours | Static content, distributor information |
#### Cache Implementation
```typescript
// How it works internally:
// edgeCache: 4 → adds URL parameter: cacheSiteId4=your-site-id
// This triggers Cloudflare cache rules for 4-hour TTL
const users = await api.joomla.users.list({
limit: 20,
edgeCache: 4 // Cached at edge for 4 hours
});
```
#### Caching Best Practices
```typescript
// ✅ Good: Cache stable reference data
const categories = await api.items.categories.list({
edgeCache: 8 // Categories rarely change
});
// ✅ Good: Cache with appropriate TTL
const pricing = await api.pricing.getPrice({
customerId: 12345,
itemId: 'STANDARD-ITEM',
quantity: 10,
edgeCache: 3 // Standard pricing changes infrequently
});
// ✅ Good: Short cache for volatile data
const cart = await api.commerce.cartHeaders.list({
userId: 123,
edgeCache: 1 // Cart data changes frequently
});
// ❌ Bad: Don't cache real-time operations
const auth = await api.joomla.users.verifyPassword({
username: 'user',
password: 'pass'
// No edgeCache - authentication must be real-time
});
// ❌ Bad: Don't cache user-specific data too long
const userSpecificData = await api.vmi.invProfileHdr.checkAvailability(warehouseId, {
q: 'search',
edgeCache: 8 // Too long for inventory data
});
```
### Request Cancellation
```typescript
const controller = new AbortController();
// Start a request
const usersPromise = api.joomla.users.list(
{ limit: 100 },
{ signal: controller.signal } // Pass abort signal
);
// Cancel the request if needed
setTimeout(() => {
controller.abort();
}, 5000);
try {
const users = await usersPromise;
} catch (error) {
if (error.name === 'AbortError') {
console.log('Request was cancelled');
}
}
```
### Custom Headers and Timeouts
```typescript
// Per-request configuration
const users = await api.joomla.users.list(
{ limit: 20 },
{
timeout: 10000, // 10 second timeout
headers: {
'X-Custom-Header': 'value',
'X-Request-ID': 'unique-id'
}
}
);
```
### Batch Operations
```typescript
// Execute multiple operations in parallel
const [users, articles, tags] = await Promise.all([
api.joomla.users.list({ limit: 10, edgeCache: 2 }),
api.joomla.content.list({ limit: 5, edgeCache: 6 }),
api.joomla.tags.list({ limit: 20, edgeCache: 8 })
]);
// Process results
console.log(`Found ${users.data.length} users`);
console.log(`Found ${articles.data.length} articles`);
console.log(`Found ${tags.data.length} tags`);
```
### Middleware Integration
```typescript
// Add global request/response interceptors
const api = new AugurAPI({
siteId: 'your-site-id',
bearerToken: 'your-token',
// Request interceptor
onRequest: (config) => {
console.log(`Making request to: ${config.url}`);
config.headers['X-Request-Timestamp'] = Date.now().toString();
return config;
},
// Response interceptor
onResponse: (response) => {
console.log(`Response status: ${response.status}`);
return response;
},
// Error interceptor
onError: (error) => {
console.error('API Error:', error.message);
// Custom error handling logic
throw error;
}
});
```
## Integration Guides
### React Integration
```tsx
import React, { useState, useEffect } from 'react';
import { AugurAPI, User, AugurAPIError, type AugurContext } from '@simpleapps-com/augur-api';
// Custom hook for Augur API - Context-aware approach
function useAugurAPI(context?: AugurContext) {
const [api] = useState(() => {
if (context) {
// Use context-aware creation (recommended)
return AugurAPI.fromContext(context);
}
// Fallback to manual configuration
return new AugurAPI({
siteId: process.env.REACT_APP_AUGUR_SITE_ID!,
bearerToken: getStoredToken()
});
});
return api;
}
// Component using the API
const UserList: React.FC = () => {
const api = useAugurAPI();
const [users, setUsers] = useState<User[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
async function fetchUsers() {
try {
setLoading(true);
setError(null);
const response = await api.joomla.users.list({
limit: 50,
edgeCache: 2 // Cache for 2 hours
});