npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@felixgeelhaar/govee-api-client

v3.0.2

Published

Enterprise-grade TypeScript client library for the Govee Developer REST API

Readme

Govee API TypeScript Client

npm version License: MIT CI codecov

An enterprise-grade TypeScript client library for the Govee Developer REST API. Built with Domain-Driven Design (DDD) principles, comprehensive error handling, and production-ready rate limiting and retry capabilities.

Features

  • 🎯 Type-Safe: Full TypeScript support with comprehensive type definitions
  • 🏗️ Domain-Driven Design: Clean architecture following DDD principles
  • Runtime Validation: Zod-based API response validation for production safety
  • Rate Limiting: High-performance sliding window rate limiter with burst capability
  • 🔄 Retry Logic: Enterprise-grade retry with exponential backoff, jitter, and circuit breaker
  • 🛡️ Error Handling: Comprehensive error hierarchy with specific error types
  • 📊 Observability: Built-in metrics and monitoring for rate limiting and retries
  • 📝 Logging: Configurable logging with Pino integration
  • 🧪 Well Tested: >95% test coverage with unit and integration tests
  • 🚀 Production Ready: Enterprise-grade reliability and performance

Installation

npm install @felixgeelhaar/govee-api-client

Quick Start

import {
  GoveeClient,
  Brightness,
  ColorRgb,
  ColorTemperature,
} from '@felixgeelhaar/govee-api-client';

// Initialize the client (uses GOVEE_API_KEY environment variable)
const client = new GoveeClient();

// Or provide API key explicitly
// const client = new GoveeClient({ apiKey: 'your-govee-api-key' });

// Get all devices
const devices = await client.getDevices();
console.log(`Found ${devices.length} devices`);

// Find a specific device
const livingRoomLight = await client.findDeviceByName('Living Room');

if (livingRoomLight) {
  // Turn on the light with warm white and 75% brightness
  await client.turnOnWithColorTemperature(
    livingRoomLight.deviceId,
    livingRoomLight.model,
    ColorTemperature.warmWhite(),
    new Brightness(75)
  );
}

Configuration

API Key

The client reads the API key from the GOVEE_API_KEY environment variable by default:

# Set environment variable
export GOVEE_API_KEY=your-govee-api-key

# Or use a .env file
echo "GOVEE_API_KEY=your-govee-api-key" > .env
import { GoveeClient } from '@felixgeelhaar/govee-api-client';

// Uses GOVEE_API_KEY environment variable automatically
const client = new GoveeClient();

You can also provide the API key explicitly (not recommended for production):

const client = new GoveeClient({
  apiKey: 'your-govee-api-key', // Explicit API key (overrides environment variable)
});

Full Configuration

import pino from 'pino';
import { GoveeClient, RetryPolicy } from '@felixgeelhaar/govee-api-client';

const client = new GoveeClient({
  // apiKey is optional - uses GOVEE_API_KEY environment variable by default
  timeout: 30000, // Request timeout in milliseconds (default: 30000)
  rateLimit: 95, // Requests per minute (default: 95, with 5 buffer under Govee's limit)
  logger: pino({ level: 'info' }), // Optional logger (silent by default)
  enableRetries: true, // Enable retry functionality (default: false)
  retryPolicy: 'production', // Retry policy preset or custom RetryPolicy instance
});

API Reference

Device Management

// Get all devices
const devices = await client.getDevices();

// Get only controllable devices
const controllableDevices = await client.getControllableDevices();

// Find device by name (case-insensitive)
const device = await client.findDeviceByName('bedroom');

// Find devices by model
const devices = await client.findDevicesByModel('H6159');

// Get device state
const state = await client.getDeviceState(deviceId, model);
console.log(`Power: ${state.getPowerState()}`);
console.log(`Online: ${state.isOnline()}`);

Device Control

// Basic controls
await client.turnOn(deviceId, model);
await client.turnOff(deviceId, model);
await client.setBrightness(deviceId, model, new Brightness(75));

// Color control
const red = new ColorRgb(255, 0, 0);
await client.setColor(deviceId, model, red);

const coolWhite = new ColorTemperature(6500);
await client.setColorTemperature(deviceId, model, coolWhite);

// Convenience methods
await client.turnOnWithBrightness(deviceId, model, new Brightness(50));
await client.turnOnWithColor(deviceId, model, red, new Brightness(75));
await client.turnOnWithColorTemperature(deviceId, model, coolWhite, new Brightness(100));

Advanced Light Control

Dynamic Light Scenes

import { LightScene } from '@felixgeelhaar/govee-api-client';

// Get available dynamic scenes for a device
const scenes = await client.getDynamicScenes(deviceId, model);
console.log(`Available scenes: ${scenes.map(s => s.name).join(', ')}`);

// Use built-in factory methods for common scenes
await client.setLightScene(deviceId, model, LightScene.sunrise());
await client.setLightScene(deviceId, model, LightScene.sunset());
await client.setLightScene(deviceId, model, LightScene.rainbow());
await client.setLightScene(deviceId, model, LightScene.aurora());

// Or set a custom scene
const customScene = new LightScene(3853, 4280, 'My Scene');
await client.setLightScene(deviceId, model, customScene);

Segment Color Control (RGB IC Devices)

import { SegmentColor, ColorRgb } from '@felixgeelhaar/govee-api-client';

// Set color for individual segments
const segment1 = new SegmentColor(0, new ColorRgb(255, 0, 0)); // Red
const segment2 = new SegmentColor(1, new ColorRgb(0, 255, 0)); // Green
const segment3 = new SegmentColor(2, new ColorRgb(0, 0, 255)); // Blue

// Set multiple segments at once
await client.setSegmentColors(deviceId, model, [segment1, segment2, segment3]);

// Set brightness for individual segments
await client.setSegmentBrightness(deviceId, model, [
  { index: 0, brightness: new Brightness(100) },
  { index: 1, brightness: new Brightness(75) },
  { index: 2, brightness: new Brightness(50) },
]);

Music Mode

import { MusicMode } from '@felixgeelhaar/govee-api-client';

// Set music mode with sensitivity
const musicMode = new MusicMode(1, 75); // Mode 1, 75% sensitivity
await client.setMusicMode(deviceId, model, musicMode);

// Music mode without sensitivity (uses device default)
const basicMode = new MusicMode(2);
await client.setMusicMode(deviceId, model, basicMode);

Toggle and Mode Controls

// Nightlight toggle
await client.setNightlightToggle(deviceId, model, true); // Enable
await client.setNightlightToggle(deviceId, model, false); // Disable

// Gradient toggle
await client.setGradientToggle(deviceId, model, true);

// Preset scenes
await client.setNightlightScene(deviceId, model, 1); // Scene ID 1
await client.setPresetScene(deviceId, model, 'cozy'); // Named scene

Value Objects

ColorRgb

// Create RGB colors
const red = new ColorRgb(255, 0, 0);
const blue = ColorRgb.fromHex('#0000FF');
const green = ColorRgb.fromObject({ r: 0, g: 255, b: 0 });

console.log(red.toHex()); // "#ff0000"
console.log(blue.toString()); // "rgb(0, 0, 255)"

ColorTemperature

// Create color temperatures
const warm = ColorTemperature.warmWhite(); // 2700K
const cool = ColorTemperature.coolWhite(); // 6500K
const daylight = ColorTemperature.daylight(); // 5600K
const custom = new ColorTemperature(4000);

console.log(warm.isWarm()); // true
console.log(cool.isCool()); // true

Brightness

// Create brightness levels
const dim = Brightness.dim(); // 25%
const medium = Brightness.medium(); // 50%
const bright = Brightness.bright(); // 75%
const custom = new Brightness(85);

console.log(bright.asPercent()); // 0.75
console.log(custom.isDim()); // false

LightScene

import { LightScene } from '@felixgeelhaar/govee-api-client';

// Built-in factory methods for common dynamic scenes
const sunrise = LightScene.sunrise();
const sunset = LightScene.sunset();
const rainbow = LightScene.rainbow();
const aurora = LightScene.aurora();
const candlelight = LightScene.candlelight();
const nightlight = LightScene.nightlight();
const romantic = LightScene.romantic();
const blinking = LightScene.blinking();

// Custom scene
const custom = new LightScene(3853, 4280, 'My Custom Scene');

// Scene properties
console.log(sunrise.name); // "Sunrise"
console.log(sunrise.id); // 3853
console.log(sunrise.paramId); // 4280

SegmentColor

import { SegmentColor, ColorRgb, Brightness } from '@felixgeelhaar/govee-api-client';

// Color only for a segment
const segment1 = new SegmentColor(0, new ColorRgb(255, 0, 0));

// Color with brightness for a segment
const segment2 = new SegmentColor(
  1,
  new ColorRgb(0, 255, 0),
  new Brightness(75)
);

// Check if segment has brightness
console.log(segment1.hasBrightness()); // false
console.log(segment2.hasBrightness()); // true

// Access segment properties
console.log(segment2.index); // 1
console.log(segment2.color.toHex()); // "#00ff00"
console.log(segment2.brightness?.level); // 75

MusicMode

import { MusicMode } from '@felixgeelhaar/govee-api-client';

// Music mode with sensitivity (0-100)
const mode1 = new MusicMode(1, 75);

// Music mode without sensitivity
const mode2 = new MusicMode(2);

// Check if mode has sensitivity
console.log(mode1.hasSensitivity()); // true
console.log(mode2.hasSensitivity()); // false

// Access properties
console.log(mode1.modeId); // 1
console.log(mode1.sensitivity); // 75

Error Handling

The library provides a comprehensive error hierarchy for different types of failures:

import {
  GoveeApiError,
  InvalidApiKeyError,
  RateLimitError,
  NetworkError,
  ValidationError,
} from '@felixgeelhaar/govee-api-client';

try {
  await client.getDevices();
} catch (error) {
  if (error instanceof ValidationError) {
    // API returned malformed data that failed validation
    console.log('Validation error:', error.message);

    // Get detailed validation errors
    const details = error.getValidationDetails();
    details.forEach(detail => {
      console.log(`  ${detail.path}: ${detail.message}`);
      console.log(`  Received: ${JSON.stringify(detail.received)}`);
    });

    // Or get a summary string for logging
    console.log('Summary:', error.getValidationSummary());
  } else if (error instanceof InvalidApiKeyError) {
    console.log('API key is invalid or expired');
    console.log(error.getRecommendation());
  } else if (error instanceof RateLimitError) {
    console.log(`Rate limited. Retry after: ${error.getRetryAfterMs()}ms`);
  } else if (error instanceof GoveeApiError) {
    console.log(`API Error: ${error.message}`);
    if (error.isDeviceOffline()) {
      console.log('Device is currently offline');
    }
  } else if (error instanceof NetworkError) {
    console.log(`Network error: ${error.errorType}`);
    if (error.isRetryable()) {
      console.log('This error can be retried');
    }
  }
}

Runtime Validation

All API responses are validated at runtime using Zod schemas to ensure data integrity:

  • Automatic: All API calls are validated transparently
  • Type-safe: Catches malformed responses before they reach your code
  • Detailed errors: ValidationError provides specific information about what failed
  • Production-ready: Protects against unexpected API changes

If you need custom validation, the Zod schemas are exported:

import {
  GoveeDevicesResponseSchema,
  GoveeStateResponseSchema,
  GoveeCommandResponseSchema,
} from '@felixgeelhaar/govee-api-client';

// Use for custom validation scenarios
const result = GoveeDevicesResponseSchema.safeParse(rawApiData);
if (result.success) {
  console.log('Valid data:', result.data);
} else {
  console.log('Validation errors:', result.error);
}

Rate Limiting & Retry Features

The client includes enterprise-grade rate limiting and retry capabilities designed for production environments.

Rate Limiting

Uses a high-performance sliding window rate limiter that allows bursts up to the limit while maintaining the average rate over time:

const client = new GoveeClient({
  apiKey: 'your-api-key',
  rateLimit: 95, // Default: 95 req/min (5 request buffer under Govee's 100/min limit)
});

// Monitor rate limiter performance
const stats = client.getRateLimiterStats();
console.log(`Current utilization: ${stats.utilizationPercent}%`);
console.log(`Queue size: ${stats.queueSize}`);
console.log(`Can execute immediately: ${stats.canExecuteImmediately}`);

Retry Logic

Comprehensive retry functionality with exponential backoff, jitter, and circuit breaker:

const client = new GoveeClient({
  apiKey: 'your-api-key',
  enableRetries: true,
  retryPolicy: 'production', // 'development', 'testing', 'production'
});

// Monitor retry performance
const retryMetrics = client.getRetryMetrics();
if (retryMetrics) {
  console.log(`Total retry attempts: ${retryMetrics.totalAttempts}`);
  console.log(`Success rate: ${retryMetrics.successfulRetries}/${retryMetrics.totalAttempts}`);
  console.log(`Circuit breaker state: ${retryMetrics.circuitBreakerState}`);
}

Custom Retry Policies

Create custom retry policies for specific requirements:

import {
  GoveeClient,
  RetryPolicy,
  RateLimitError,
  NetworkError,
  GoveeApiError,
} from '@felixgeelhaar/govee-api-client';

const customRetryPolicy = new RetryPolicy({
  backoff: {
    type: 'exponential',
    initialDelayMs: 1000,
    maxDelayMs: 30000,
    multiplier: 2.0,
  },
  jitter: {
    type: 'equal',
    factor: 0.1,
  },
  condition: {
    maxAttempts: 3,
    maxTotalTimeMs: 60000,
    retryableStatusCodes: [408, 429, 502, 503, 504],
    retryableErrorTypes: [RateLimitError, NetworkError, GoveeApiError],
  },
  circuitBreaker: {
    enabled: true,
    failureThreshold: 5,
    recoveryTimeoutMs: 30000,
    halfOpenSuccessThreshold: 2,
  },
  enableMetrics: true,
});

const client = new GoveeClient({
  apiKey: 'your-api-key',
  enableRetries: true,
  retryPolicy: customRetryPolicy,
});

Monitoring & Observability

Get comprehensive metrics for monitoring and debugging:

// Get complete service statistics
const serviceStats = client.getServiceStats();
console.log('Rate Limiter:', serviceStats.rateLimiter);
console.log('Retry Metrics:', serviceStats.retries);
console.log('Configuration:', serviceStats.configuration);

// Rate limiter specific stats
const rateLimiterStats = client.getRateLimiterStats();
console.log({
  currentRequests: rateLimiterStats.currentRequests,
  maxRequests: rateLimiterStats.maxRequests,
  utilizationPercent: rateLimiterStats.utilizationPercent,
  queueSize: rateLimiterStats.queueSize,
  canExecuteImmediately: rateLimiterStats.canExecuteImmediately,
  nextAvailableSlot: rateLimiterStats.nextAvailableSlot,
});

// Retry metrics (when retries are enabled)
const retryMetrics = client.getRetryMetrics();
if (retryMetrics) {
  console.log({
    totalAttempts: retryMetrics.totalAttempts,
    successfulRetries: retryMetrics.successfulRetries,
    failedRetries: retryMetrics.failedRetries,
    totalRetryTimeMs: retryMetrics.totalRetryTimeMs,
    averageRetryDelayMs: retryMetrics.averageRetryDelayMs,
    circuitBreakerState: retryMetrics.circuitBreakerState,
    lastError: retryMetrics.lastError?.message,
    lastRetryTimestamp: retryMetrics.lastRetryTimestamp,
  });
}

// Reset metrics for clean monitoring periods
client.resetRetryMetrics();

Retry Policy Presets

The library includes three built-in retry policy presets optimized for different environments:

Production (Default)

  • Max attempts: 3
  • Backoff: Exponential with 1s initial delay, 30s max
  • Circuit breaker: Enabled (5 failures to open, 30s recovery)
  • Jitter: Equal jitter to prevent thundering herd

Development

  • Max attempts: 5
  • Backoff: Exponential with 500ms initial delay, 15s max
  • Circuit breaker: Disabled for easier debugging
  • Jitter: Full jitter for maximum randomization

Testing

  • Max attempts: 2
  • Backoff: Exponential with 2s initial delay, 60s max
  • Circuit breaker: Enabled with conservative settings
  • Jitter: Decorrelated jitter for sophisticated patterns

Performance Characteristics

  • Rate Limiter: High-performance sliding window allows concurrent execution within limits
  • Memory Efficient: Automatic cleanup of expired timestamps and bounded queue sizes
  • Production Ready: Circuit breaker prevents cascade failures
  • Observable: Comprehensive metrics for monitoring and alerting

Domain-Driven Design

The library follows DDD principles with clear separation of concerns:

  • Entities: GoveeDevice, DeviceState, Command
  • Value Objects: ColorRgb, ColorTemperature, Brightness
  • Repositories: IGoveeDeviceRepository, GoveeDeviceRepository
  • Services: GoveeControlService
  • Errors: Comprehensive error hierarchy

Advanced Usage

Custom Repository

import { GoveeControlService } from '@felixgeelhaar/govee-api-client';

// Use your own repository implementation
const service = new GoveeControlService({
  repository: new CustomGoveeRepository(),
  rateLimit: 120,
});

Command Pattern

import { CommandFactory } from '@felixgeelhaar/govee-api-client';

// Create commands manually
const powerOn = CommandFactory.powerOn();
const setBrightness = CommandFactory.brightness(new Brightness(75));

// Send custom commands
await client.sendCommand(deviceId, model, powerOn);
await client.sendCommand(deviceId, model, setBrightness);

Requirements

  • Node.js 20.0.0 or higher
  • Valid Govee Developer API key

Development

# Install dependencies
npm install

# Build the library
npm run build

# Run tests
npm test

# Run tests with coverage
npm run test:coverage

# Type checking
npm run lint

License

MIT © [Felix Geelhaar]

Contributing

Contributions are welcome! Please read our Contributing Guide for details on:

  • Code of conduct
  • Development workflow
  • Code standards and architecture
  • Testing requirements
  • Commit guidelines
  • Pull request process

For feature requests and discussions, visit our GitHub Discussions.

Roadmap

See our Product Roadmap for planned features and enhancements, including:

  • Short-term (1-3 months): Additional scene factory methods, animation utilities, performance optimizations
  • Medium-term (3-6 months): Device discovery, advanced scheduling, real-time monitoring
  • Long-term (6-12 months): Cloud integration, UI components, AI/ML features, ecosystem integrations

We welcome feedback and contributions for any roadmap items!

API Documentation

For more information about the Govee Developer API, visit: https://govee-public.s3.amazonaws.com/developer-docs/GoveeDeveloperAPIReference.pdf