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

@biks2013/config-service

v1.0.2

Published

Configuration service with multi-source fallback pattern

Readme

@biks2013/config-service

Configuration service with multi-source fallback pattern, type safety, and hot reload support.

Installation

npm install @biks2013/config-service

Features

  • 🔄 GitHub-first configuration with automatic database fallback
  • 📦 Support for GitHub (primary) and Database (fallback) sources
  • 🔒 Type-safe configuration with TypeScript generics
  • 💾 Automatic caching from GitHub to Database
  • 🏗️ Extensible architecture for custom configuration services
  • 🚫 Returns null when configuration not found in any source
  • 🛡️ Resilient operation when GitHub is unavailable

Usage

Basic Example

import { createConfigService } from '@biks2013/config-service';
import { GitHubAssetClient } from '@biks2013/github-asset-client';
import { AssetDatabaseService } from '@biks2013/asset-database';
import * as YAML from 'yaml';

interface AppConfig {
  database: {
    host: string;
    port: number;
  };
  features: {
    enableCache: boolean;
  };
}

const configService = createConfigService<AppConfig>({
  sources: [
    {
      type: 'github',
      priority: 1,  // Primary source - always tried first
      options: {
        client: new GitHubAssetClient({
          repo: 'org/config-repo',
          token: process.env.GITHUB_TOKEN!,
        }),
        assetKey: 'config/app.yaml',
      },
    },
    {
      type: 'database',
      priority: 2,  // Fallback - only used if GitHub fails
      options: {
        service: new AssetDatabaseService({
          connectionString: process.env.DATABASE_URL!,
          ownerCategory: 'app',
          ownerKey: 'my-app',
        }),
        assetKey: 'app-config',
      },
    },
  ],
  parser: async (content) => YAML.parse(content),
}, (service, data) => {
  // Process the parsed configuration
  // Note: configs is protected, processing handled internally
});

// Use the service
const service = configService();

// Get specific config values
const dbHost = await service.getConfig('database.host');
if (dbHost === null) {
  console.log('Configuration not found - GitHub unavailable and no cached version in database');
  return;
}

const cacheEnabled = await service.getConfig('features.enableCache');

// Get all configuration
const allConfig = await service.getAll();

// Reload configuration
await service.reload();

// Clean up
await service.destroy();

Custom Configuration Service

import { ConfigService, createConfigService } from '@biks2013/config-service';

interface UserPermissions {
  userId: string;
  permissions: string[];
}

class PermissionService extends ConfigService<UserPermissions[]> {
  private permissions = new Map<string, string[]>();

  protected processConfiguration(data: UserPermissions[]): void {
    this.permissions.clear();
    for (const user of data) {
      this.permissions.set(user.userId, user.permissions);
    }
  }

  async getUserPermissions(userId: string): Promise<string[]> {
    await this.ensureInitialized();
    return this.permissions.get(userId) || [];
  }

  async hasPermission(userId: string, permission: string): Promise<boolean> {
    const permissions = await this.getUserPermissions(userId);
    return permissions.includes(permission);
  }
}

Configuration Sources

GitHub Source

{
  type: 'github',
  priority: 1,
  options: {
    client: GitHubAssetClient,
    assetKey: 'path/to/config.yaml'
  }
}

Database Source

{
  type: 'database',
  priority: 2,
  options: {
    service: AssetDatabaseService,
    assetKey: 'config-key',
    category: 'optional-category'
  }
}

API

createConfigService<T>(options, processor)

Creates a singleton configuration service instance.

Options

interface ConfigServiceOptions<T> {
  sources: ConfigSource[];           // Configuration sources with priorities
  parser: (content: string) => T;    // Parser function (e.g., JSON.parse, YAML.parse)
  verbose?: boolean;                 // Enable detailed logging (default: false)
}

Processor Function

type ConfigProcessor<T> = (service: ConfigService<T>, data: T) => void;

ConfigService Methods

  • getConfig(key?: string): Promise<any> - Get configuration value by key (returns null if not found)
  • getAll(): Promise<Map<string, any>> - Get all configuration values
  • reload(): Promise<void> - Reload configuration from sources
  • destroy(): Promise<void> - Clean up resources

Configuration Loading Strategy

The service follows a GitHub-first approach with database fallback:

  1. Primary Source (GitHub): Always attempted first

    • Fetches latest configuration from GitHub repository
    • On success: Automatically caches to database for future fallback
    • On failure: Falls back to database cache
  2. Fallback Source (Database): Only used when GitHub is unavailable

    • Provides resilience during GitHub outages
    • Contains previously cached configurations
    • Never accessed directly unless GitHub fails
  3. Returns null: When configuration not found in any source

This ensures you always get the latest configuration when possible, with automatic failover for reliability.

Verbose Logging

Enable verbose mode to get detailed insights into the configuration loading process:

const configService = createConfigService<AppConfig>({
  sources: [...],
  parser: YAML.parse,
  verbose: true  // Enable verbose logging
}, processor);

When verbose mode is enabled, you'll see:

  1. GitHub Reads: Detailed information about assets read from GitHub

    • Asset path being read
    • File size and SHA
    • Content preview
  2. Database Operations:

    • Asset registration logs
    • Content length and creation timestamps
    • Difference Detection: Automatic comparison between GitHub and cached versions
  3. Fallback Behavior: Clear logs showing which source was attempted and why it failed

Example verbose output:

[ConfigService] Starting configuration reload...
[GitHub] Reading asset from path: config/app.yaml
[GitHub] Successfully read asset 'config/app.yaml':
[GitHub]   - Size: 1234 bytes
[GitHub]   - SHA: abc123def456...
[GitHub]   - Content preview: database:\n  host: localhost\n  port: 5432\n...
[Database] Registering asset 'app-config' in database
[Database] DIFFERENCE DETECTED: Content from GitHub differs from database cache
[Database]   - Previous length: 1200 bytes
[Database]   - New length: 1234 bytes
[Database] Successfully registered asset 'app-config' in database
[ConfigService] Configuration loaded successfully from github:config/app.yaml

This is especially useful for:

  • Debugging configuration issues
  • Monitoring configuration changes
  • Understanding fallback behavior
  • Tracking cache updates

License

MIT