@juanpprieto/lexicon-client
v1.0.2
Published
TypeScript-first client for Lexicon DJ's local REST API with comprehensive type safety and unified control interface
Maintainers
Readme
@juanpprieto/lexicon-client
TypeScript-first client for Lexicon DJ's REST API with comprehensive type safety and unified control interface
Build professional DJ applications with confidence. This library provides complete type-safe access to Lexicon DJ's local API, with automatic validation, intelligent error handling, and a unified control interface for all DJ operations.
What is Lexicon DJ?
Lexicon DJ is professional DJ software for managing music libraries, creating playlists, and performing live DJ sets. It provides a built-in REST API that allows developers to programmatically control the software, access music metadata, and integrate DJ functionality into custom applications.
Perfect for building:
- 🎛️ Custom DJ controllers and interfaces
- 📊 Music library analysis and management tools
- 🤖 Automated playlist generation and DJ workflows
- 📱 Mobile DJ applications and remote controls
✨ Key Features
- 🔒 Complete Type Safety - Full TypeScript support with automatic type inference
- ⚡ Zero Configuration - Works out of the box with sensible defaults
- 🎛️ Unified Control API - 128+ DJ operations under
client.control.* - 📊 Comprehensive Library Management - Tracks, playlists, tags with full CRUD operations
- 🚀 Modern Architecture - Built with Zod validation, neverthrow error handling, and undici HTTP client
- 🧪 Production Ready - Extensive test suite with both unit and integration tests
⚡ Requirements
This library requires Lexicon DJ to be installed and running with the Local API enabled.
1. Install Lexicon DJ
Download and install Lexicon DJ - professional DJ software with local API support.
2. Enable the Local API
⚠️ CRITICAL: The Lexicon Local API is disabled by default and must be enabled manually:
- Open Lexicon DJ
- Go to Settings → Integrations
- Enable "Local API"
- Verify it's running on
localhost:48624
The Local API is a REST API that you can send requests to as long as Lexicon is running. See the official API documentation for complete details.
3. Verify Connection
# Test if the API is accessible
curl http://localhost:48624/api/tracks?limit=1🚀 Quick Start
Installation
npm install @juanpprieto/lexicon-clientBasic Usage
import { createClient } from '@juanpprieto/lexicon-client'
// Connect to Lexicon DJ (localhost:48624)
const client = createClient()
// List tracks from your library
const tracks = await client.tracks.list({ limit: 10 })
if (tracks.isOk()) {
console.log(`Found ${tracks.value.tracks.length} tracks`)
tracks.value.tracks.forEach(track => {
console.log(`${track.artist} - ${track.title}`)
})
}
// Control playback
await client.control.player.play()
await client.control.player.pause()⚠️ Important: This library uses functional error handling. API methods return
Result<T, E>instead of throwing errors. Always check.isOk()before accessing data.
🎮 Try the Demos
Learn by example with interactive demos that show exactly how to use the library:
React + Vite Demo (Web Applications)
cd demo/react-vite
npm install && npm run demoPerfect for building web DJ applications with modern React.
Node.js Demo (Scripts & Backend)
cd demo/node-script
npm install && npm run demoPerfect for automation scripts and backend DJ tools.
Both demos include:
- 🔌 Connection testing
- 📚 API examples for all namespaces
- 🎛️ Player control demonstrations
- 📋 AI documentation access examples
📚 API Documentation
Library Management
Tracks API
// List tracks with pagination
const tracks = await client.tracks.list({ limit: 25 })
if (tracks.isOk()) {
console.log(`Found ${tracks.value.tracks.length} tracks`)
}
// Search tracks by genre
const houseTracks = await client.tracks.search({
filter: { genre: 'house' },
limit: 10,
})
// Get a specific track
const track = await client.tracks.get({ id: 123 })
if (track.isOk()) {
console.log(`${track.value.artist} - ${track.value.title}`)
}Playlists API
// List all playlists
const playlists = await client.playlists.list()
if (playlists.isOk()) {
console.log(`Found ${playlists.value.playlists.length} playlists`)
}
// Get a specific playlist
const playlist = await client.playlists.get({ id: 1 })
if (playlist.isOk()) {
console.log(`Playlist: ${playlist.value.name}`)
console.log(`Tracks: ${playlist.value.trackIds?.length || 0}`)
}Tags API
// List all 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 a specific tag
const tag = await client.tags.get({ id: 1 })
if (tag.isOk()) {
console.log(`Tag: ${tag.value.label}`)
}Player Control API
// Basic playback control
await client.control.player.play()
await client.control.player.pause()
await client.control.player.stop()
// Get current player state
const state = await client.control.player.getCurrentState()
if (state.isOk()) {
console.log(`Playing: ${state.value.currentTrack?.title}`)
console.log(`Progress: ${Math.round(state.value.progress * 100)}%`)
}
// Seek to position
await client.control.player.seek({ progress: 0.5 }) // 50% through track🔧 Advanced Usage
Advanced Track Operations
// Search tracks with complex filters
const tracks = await client.tracks.search({
genre: ['house', 'techno'],
bpmMin: 120,
bpmMax: 140,
rating: { min: 4 },
limit: 50,
})
// Update track metadata
await client.tracks.update({
id: 123,
edits: {
rating: 5,
energy: '+1',
tags: [1, 2, 3],
},
})
// Memory-efficient iteration over large libraries
for await (const track of client.tracks.iterate({ genre: 'house' })) {
console.log(`${track.artist} - ${track.title}`)
}Advanced Playlist Management
// Create smart playlists with rules
const smartPlaylist = await client.playlists.create({
name: 'High Energy House',
type: 'smart',
smartlist: {
rules: [
{ field: 'genre', operator: 'is', value: 'house' },
{ field: 'energy', operator: 'greater_than', value: 7 },
],
},
})
// Add tracks to existing playlist
if (playlist.isOk()) {
await client.playlists.addTracks({
id: playlist.value.id,
trackIds: [1, 2, 3],
index: 0, // Insert at beginning
})
}Advanced Player Control
// Advanced DJ features
await client.control.player.hotcue.trigger({ index: 1 })
await client.control.player.loop.create({ amount: 4 })
await client.control.player.jump.beats({ beats: 16 })
await client.control.player.tempomarker.doubleBpm()
// Interface control
await client.control.appearance.toggleTheme()
await client.control.navigation.toggleSidebar()
await client.control.trackBrowser.analyze()Advanced Tag Management
// Create tag categories with colors
const category = await client.tagCategories.create({
name: 'Mood',
color: '#FF6B6B',
})
// Create tags within categories
const tag = await client.tags.create({
label: 'Energetic',
categoryId: category.value.id,
position: 0,
})Error Handling with neverthrow
import { match } from 'ts-pattern'
const result = await client.tracks.get({ id: 1 })
match(result)
.with({ isOk: () => true }, ({ value: track }) => {
console.log(`Found: ${track.artist} - ${track.title}`)
})
.with({ isErr: () => true }, ({ error }) => {
match(error)
.with({ type: 'NotFound' }, () => {
console.log('Track not found')
})
.with({ type: 'NetworkError' }, () => {
console.log('Connection failed - is Lexicon DJ running?')
})
.with({ type: 'ValidationError' }, err => {
console.log(`Invalid request: ${err.message}`)
})
.otherwise(() => {
console.log(`Unexpected error: ${error.message}`)
})
})Batch Operations with Queue Management
import PQueue from 'p-queue'
// Built-in concurrency management prevents API overload
const queue = new PQueue({ concurrency: 5 })
// Process large track collections efficiently
const trackIds = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
const tracks = await Promise.all(
trackIds.map(id => queue.add(() => client.tracks.get({ id })))
)
// Filter successful results
const validTracks = tracks
.filter(result => result.isOk())
.map(result => result.value)
console.log(
`Successfully loaded ${validTracks.length}/${trackIds.length} tracks`
)Custom Configuration
import { createClient } from '@juanpprieto/lexicon-client'
const client = createClient({
baseUrl: 'http://localhost:48624', // Custom Lexicon API URL
timeout: 30000, // 30 second timeout
retries: 3, // Retry failed requests
logger: {
level: 'debug', // Enable debug logging
pretty: true, // Pretty-print logs
},
})🏗️ TypeScript Integration
Automatic Type Inference
// No manual type annotations needed
const client = createClient() // → LexiconClient
const tracks = await client.tracks.search({
genre: 'house',
bpmMin: 128,
}) // → Result<PaginatedTracksResponse, ApiError>
if (tracks.isOk()) {
tracks.value.tracks.forEach(track => {
// track is automatically inferred as Track
console.log(track.artist) // Full IntelliSense support
})
}Custom Type Guards
import { type Track } from '@juanpprieto/lexicon-client'
function isHighEnergyTrack(track: Track): boolean {
return track.energy >= 8 && track.bpm >= 128
}
const tracks = await client.tracks.list()
if (tracks.isOk()) {
const highEnergyTracks = tracks.value.tracks.filter(isHighEnergyTrack)
console.log(`Found ${highEnergyTracks.length} high-energy tracks`)
}🤖 AI-Friendly Documentation
For AI Tools and Development
# Copy AI documentation to your project
npx @juanpprieto/lexicon-client copy-ai-docsThis creates:
docs/lexicon-client-llms.txt- Comprehensive API documentation for AI promptsdocs/lexicon-client-claude.md- Development context for Claude Code sessions
Usage with AI tools:
"Please read docs/lexicon-client-llms.txt for complete API context and examples"Alternative: Point AI directly to node_modules:
"Reference node_modules/@juanpprieto/lexicon-client/llms.txt for API documentation"🧪 Testing
Running Tests
# All tests
npm test
# Unit tests only
npm run test:unit
# Integration tests (requires running Lexicon DJ)
npm run test:integration
# Coverage report
npm run test:coverage
# Watch mode for development
npm run test:watchIntegration Test Requirements
Integration tests require a running Lexicon DJ instance with the Local API enabled:
- Open Lexicon DJ
- Go to Settings → Integrations
- Enable "Local API"
- Run
npm run lexicon:checkto verify connection
📦 Publishing & Releases
This package uses Changesets for version management:
# Add a changeset for your changes
npm run changeset
# Release (maintainers only)
npm run releaseAutomated Releases
- GitHub Actions handle automated testing and publishing
- Semantic versioning based on changeset types
- NPM provenance for supply chain security
- GitHub releases with automatically generated changelogs
🛡️ Security
Vulnerability Reporting
If you discover a security vulnerability, please report it privately via Security Advisories.
Supply Chain Security
- NPM Provenance - All published packages include build provenance
- SLSA Level 3 - Supply chain security attestation
- Dependency Scanning - Automated vulnerability detection
- CodeQL Analysis - Static security analysis
🤝 Contributing
We welcome contributions! Please see CONTRIBUTING.md for detailed guidelines.
Development Setup
# Clone and install
git clone https://github.com/juanpprieto/lexicon-client.git
cd lexicon-client
npm install
# Run quality checks
npm run validate
# Start development
npm run devProject Structure
src/
├── client/ # HTTP client and namespace implementations
├── schemas/ # Zod validation schemas (modular structure)
├── types/ # TypeScript type definitions
├── utils/ # Shared utilities
└── __tests__/ # Comprehensive test suite📋 API Reference
| Namespace | Methods | Description |
| ---------------- | ------- | ------------------------------------------------------------ |
| tracks | 7 | Track library management (CRUD, search, iteration) |
| playlists | 9 | Playlist operations (create, manage tracks, smart playlists) |
| tags | 4 | Tag management and assignment |
| tagCategories | 3 | Tag category organization with colors |
| control.player | 49 | Complete music player control and state |
| control.* | 79 | DJ interface control (navigation, appearance, analysis) |
Total: 151+ methods providing comprehensive Lexicon DJ integration.
🔗 Related Projects
- Lexicon DJ - Professional DJ software and music library management
- Lexicon DJ API Documentation - Official REST API reference
- OpenAPI Specification - Lexicon's API schema
📄 License
MIT © Juan Pablo Prieto
🎧 Ready to build amazing DJ applications? Get started now →
