# Lexicon Client TypeScript Library The official TypeScript-first client library for Lexicon DJ's local REST API. This library provides comprehensive type safety, unified control interfaces, and professional developer experience for building DJ software and music applications. ## API Overview ### Library Structure - **Client**: `createClient()` - Main entry point with configurable base URL and logging - **Tracks**: Full CRUD operations, advanced filtering, search, and metadata management - **Playlists**: Hierarchical playlist management with smart list support and track operations - **Tags**: Tag and category management with validation and assignment workflows - **Control**: Unified player control interface with state management and playback operations ### Core Types ```typescript // Main client interface interface LexiconClient { tracks: TracksAPI playlists: PlaylistsAPI tags: TagsAPI control: ControlAPI } // Result handling with neverthrow pattern type Result = Ok | Err // Core entities interface Track { id: number title: string artist: string bpm: number genre: string rating: number // ... additional metadata fields } interface Playlist { id: number name: string type: 'folder' | 'smart' | 'static' trackIds?: number[] playlists?: Playlist[] // recursive nesting support } interface Tag { id: number label: string categoryId: string // ... additional tag properties } ``` ### Usage Patterns #### Basic Client Setup ```typescript import { createClient } from '@juanpprieto/lexicon-client' // Connect to default local Lexicon DJ instance (localhost:48624) const client = createClient() // Or configure custom connection const client = createClient({ baseUrl: 'http://localhost:8080', logger: customLogger }) ``` #### Error Handling with Result Pattern ```typescript // All API methods return Result for safe error handling const tracksResult = await client.tracks.list({ limit: 50 }) if (tracksResult.isOk()) { const tracks = tracksResult.value.tracks console.log(`Found ${tracks.length} tracks`) } else { console.error('API Error:', tracksResult.error.message) } ``` #### Track Operations ```typescript // List tracks with pagination and filtering const tracks = await client.tracks.list({ limit: 100, offset: 0, sort: 'bpm', order: 'desc' }) // Advanced search with filters const filteredTracks = await client.tracks.search({ query: 'house music', filter: { genre: 'house', bpm: '>=120', rating: '>=4' }, limit: 25 }) // Get single track by ID const track = await client.tracks.get({ id: 1234 }) // Batch operations const trackIds = [1, 2, 3, 4, 5] const batchResult = await client.tracks.getBatch({ ids: trackIds }) ``` #### Playlist Management ```typescript // List all playlists const playlists = await client.playlists.list() // Get playlist with tracks const playlist = await client.playlists.get({ id: 1, includeTracks: true }) // Navigate hierarchical playlists const playlist = await client.playlists.get({ id: 1 }) if (playlist.isOk() && playlist.value.playlists) { // Handle nested playlists for (const subPlaylist of playlist.value.playlists) { console.log(`Sub-playlist: ${subPlaylist.name}`) } } ``` #### Tag and Category Operations ```typescript // List tags and categories const tagsResult = await client.tags.list() if (tagsResult.isOk()) { const { tags, categories } = tagsResult.value console.log(`Found ${tags.length} tags in ${categories.length} categories`) } // Get specific tag const tag = await client.tags.get({ id: 1 }) // Work with categories categories.forEach(category => { console.log(`Category: ${category.name} (${category.id})`) }) ``` #### Player Control and State Management ```typescript // Get current player state const stateResult = await client.control.player.getCurrentState() if (stateResult.isOk()) { const state = stateResult.value console.log(`Playing: ${state.currentTrack?.title}`) console.log(`Progress: ${Math.round(state.progress * 100)}%`) } // Basic player controls await client.control.player.play() await client.control.player.pause() await client.control.player.stop() // Advanced controls await client.control.player.seek({ progress: 0.5 }) // Seek to 50% await client.control.player.setVolume({ level: 0.8 }) // Set volume to 80% // Load tracks await client.control.player.loadTrack({ id: 1234 }) await client.control.player.loadPlaylist({ id: 5678 }) ``` ### Module Formats and Build Outputs The library is built with optimal production artifacts: - **ESM**: `dist/index.mjs` - Modern ES modules for bundlers and modern Node.js - **CommonJS**: `dist/index.js` - Compatible with older Node.js and require() patterns - **TypeScript**: `dist/index.d.ts` - Full type definitions for TypeScript projects - **Minified**: Tree-shaken and optimized for production (~105KB total) ### Dependencies - **zod**: Runtime schema validation and TypeScript inference - **neverthrow**: Functional error handling with Result pattern - **undici**: Modern HTTP client for Node.js - **ts-pattern**: Pattern matching for complex type operations - **pino**: High-performance structured logging - **p-queue**: Concurrent request management - **qs**: URL query string handling ### Common Use Cases #### DJ Application Development - Real-time track browsing and search - Playlist creation and management - Player state synchronization - Metadata editing and organization #### Music Library Tools - Bulk track analysis and processing - Automated playlist generation - Library statistics and reporting - Duplicate detection and cleanup #### Integration and Automation - External service synchronization - Automated DJ workflow scripting - Music data pipelines - Performance analytics ### Error Handling Patterns All API methods use the Result pattern for explicit error handling: ```typescript // Type-safe error handling const result = await client.tracks.search({ query: 'invalid' }) result.match( (success) => { // Handle successful response console.log(`Found ${success.tracks.length} tracks`) }, (error) => { // Handle API errors if (error.code === 'CONNECTION_ERROR') { console.log('Lexicon DJ is not running') } else if (error.code === 'VALIDATION_ERROR') { console.log('Invalid search parameters') } } ) ``` ### TypeScript Integration The library provides full TypeScript support with: - Comprehensive type definitions for all API responses - Generic type parameters for custom filtering - Recursive schema validation with Zod - Automatic type inference for API results - IntelliSense support for all methods and properties ### Prerequisites To use this library with a running Lexicon DJ instance: 1. Install and run Lexicon DJ 2. Enable "Local API" in Settings → Integrations 3. Confirm API is accessible at localhost:48624 (default) ### Installation ```bash npm install @juanpprieto/lexicon-client ``` ### Demo Applications The library includes demo applications to validate functionality: - **React + Vite**: ESM build validation with interactive UI - **Node.js Script**: CommonJS build validation with console output Both demos provide getting started examples and comprehensive API testing.