UNPKG

@simpleapps-com/augur-api

Version:

TypeScript client library for Augur microservices API endpoints

1,647 lines (1,322 loc) 108 kB
# 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 });