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 🙏

© 2024 – Pkg Stats / Ryan Hefner

conffi

v1.0.2

Published

A schema-based configuration loader

Downloads

71

Readme

Conffi: A Modern Configuration Library

Conffi is a TypeScript library designed to simplify and streamline the process of creating configuration objects for your applications. It offers a flexible and type-safe approach for managing both global configurations and smaller, application-specific configurations.

Core Principles

Conffi prioritizes type enforcement throughout its design. This ensures type safety not only through a typed code but also through the runtime API itself. Additionally, the library provides convenient tools for manipulating values during configuration loading.

Getting Started

npm install conffi

Conffi's functional style allows for flexible usage. However, to get you started, here's a basic example:

  1. createConfig: This function is the heart of Conffi. It generates a function that ultimately resolves your configuration object. Importantly, createConfig is asynchronous to accommodate both runtime and load-time configuration creation.
import {createConfig} from 'conffi'

type Config = {
  host: string
}

const createMainConfig = createConfig<Config>(({env}) => ({
  host: env('host')
}))

const config = await createMainConfig() // {host}

Here, we define a configuration type (Config) and provide a callback function to createConfig. This callback receives an object containing helper functions for building the configuration. In this example, we utilize the env function to retrieve a value from the environment variables.

  1. Alternative Approach: While the callback provides access to helper functions, you can alternatively define the configuration directly:
import {createConfig, env} from 'conffi'

type Config = {
  host: string,
  port: number
}

const createMainConfig = createConfig<Config>({
  host: env('host'),
  port: env('port').number()
})

const config = await createMainConfig() // {host, port}

Runtime Support

Conffi extends its functionality to runtime environments, allowing you to pass parameters during configuration creation. These parameters can serve as fallbacks if environment variables are unavailable.

type Config = {host: string}

// let's assume that there is no environment variable of host
delete process.env['host']

const createMainConfig = createConfig<Config>(({env}) => ({
  host: env('host')
}))

// This function will throw an error, since host doesn't exist
const config = await createMainConfig()

// This however will used as fallback:
const config = await createMainConfig({host: 'google.com'}) // {host: 'google.com}

Preferably, configuration values can be entirely derived from runtime logic:

const createMainConfig = createConfig(({runtime}) => ({
  host: runtime()
}))

const config = await createConfig({host: 'google.com'}) // {host: 'google.com'}

The idea behind it is to let us mix between environment variable and runtime properties that could (if configured) override them.

Getters

Conffi provides various getter functions that introduce new values and manipulation capabilities to the configuration provider. Here are a few examples:

  • env(variableName: string): Retrieves a value from environment variables.
  • runtime(): Retrieves a value from the runtime environment (useful for dynamic configuration).
  • or(...getters: Getter<any>[]): Combines multiple getters, using the first non-null value as the fallback.
  • get(callback: <T>() => T | Promise<T>): Allows incorporating any function that returns a promise or a direct value.
import {createConfig} from 'conffi'

const createMainConfig = createConfig(({env, runtime, or, get}) => ({
  fromEnvironment: env('{env name}'),
  fromRuntimeValue: runtime(), // based on the given key
  conjunction: or(env('var'), env('another var')) // accepts different getters to fallback to
  anyValue: get(() => getValue().then((val) => val)) // accepts any callback that returns a promise or a value
}))

Manipulators

Conffi offers manipulators to transform retrieved values. These manipulators provide a chainable API for easy manipulation:

  • string(): Converts the value to a string.
  • number(): Converts the value to an integer.
  • boolean(): Converts the value to a boolean.
  • test(customTest: (value: any) => boolean | Promise<boolean>): Performs a custom test on the value, throwing an error with a provided message if the test fails. Supports asynchronous tests.
  • parse(customParser: <T>(value: any) => T | Promise<T>): Allows custom parsing logic for transforming the value.

By leveraging getters and manipulators, you can ensure your configuration values are in the desired format and meet any necessary validation requirements.

import {createConfig} from 'conffi'

const createMainConfig = createConfig(({env, runtime, or, get}) => ({
  text: env('textual').string(),
  number: env('numeric').number(), // translates to an integer
  bool: env('boolean').boolean(),
  customTest: env('custom').number().test((value) => value > 5, 'Value should be bigger'), // Custom tests, supports promises
  customValue: env('custom').parse((value) => Number.parseInt(value, 10)) // Translating to int ourselves
}))