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

@jabraf/app-config

v0.0.1-4113486.2

Published

Application configuration and feature flags management for web projects

Readme

@jabraf/app-config

Application configuration and feature flags management for web projects.

Installation

npm install @jabraf/app-config

react is an optional peer dependency. Install it alongside @jabraf/app-config only if you intend to use the useFeature hook.

Overview

@jabraf/app-config is a lightweight configuration and feature-flag layer for Node.js and React applications. It provides:

  • A universal runtime API (setConfig / getConfig) that works identically in browser and Node environments — the consumer statically imports the generated config/app-config.json and hands it to the library at bootstrap.
  • A Node-only buildConfig entrypoint (under the @jabraf/app-config/build subpath) that delegates to a project-owned config/make-config.ts so apps can produce their own configuration artifacts.
  • A React hook (useFeature) plus cookie helpers (setFeatureCookie, removeFeatureCookie) for toggling features at runtime with cookie-based overrides.
  • A jabraf-config CLI (scaffolded — the command set is not yet implemented).

Entry points

| Import | Environment | Exports | | ----------------------------------------- | --------------- | ------------------------------------------------------- | | @jabraf/app-config | browser + Node | setConfig, getConfig, resetConfig, types | | @jabraf/app-config/hooks/use-feature.js | browser (+ SSR) | useFeature, setFeatureCookie, removeFeatureCookie | | @jabraf/app-config/build | Node only | buildConfig, appDirectory, fromRoot |

The root entry point and the React hooks subpath never import node:* modules and are safe to bundle for the browser.

Project Layout

The package resolves paths relative to the nearest package.json of the consuming project and expects the following files under a config/ directory:

your-app/
└── config/
    ├── make-config.ts           # Authored: build-time script invoked by buildConfig
    └── app-config.json          # Generated: application configuration consumed by getConfig

make-config.ts must export an async buildAppConfig function that produces and persists the configuration. buildConfig simply imports this module and invokes that function:

// config/make-config.ts
export async function buildAppConfig(): Promise<void> {
  // Read environment, source files, etc., and write `config/app-config.json`
  // using your preferred strategy.
}

Because config/app-config.json is a build artifact rather than source, add it to your .gitignore:

# config build output from @jabraf/app-config
config/app-config.json

Feature Type

Features are tracked through a global FeatureMap interface. The Feature string-literal type is derived as keyof FeatureMap. Register your app's features by augmenting FeatureMap from a declaration file in your project — do not redeclare Feature directly, as that would clash with the type shipped by this package and produce a Duplicate identifier 'Feature' error.

// app/types/features.d.ts
declare global {
  interface FeatureMap {
    beta: true;
    'experimental-search': true;
    'new-checkout': true;
  }
}

export {};

After augmenting, Feature resolves to 'beta' | 'experimental-search' | 'new-checkout' everywhere the package is consumed. If you don't augment FeatureMap, Feature is never and calls like isFeatureEnabled(...) won't type-check.

Usage

Bootstrap: register the config once

Statically import the generated config/app-config.json and hand it to setConfig at app startup. The same snippet works in a browser entry, a Node script, or an SSR server — there is no node:fs involved.

// app/setup.ts
import appConfig from '../config/app-config.json' with { type: 'json' };
import { setConfig } from '@jabraf/app-config';

setConfig(appConfig);

TypeScript: make sure "resolveJsonModule": true is set in your tsconfig.json (it is by default in @jabraf/dev / Vite / Next.js).

CommonJS bundlers / older Node: drop the with { type: 'json' } assertion — import appConfig from '../config/app-config.json' is enough.

First-time checkouts: since config/app-config.json is git-ignored and generated by buildConfig, the import may not resolve on a fresh clone. Either commit a placeholder {}, run buildConfig before the type-checker, or annotate the import with // @ts-expect-error generated by buildConfig.

Read configuration

import { getConfig } from '@jabraf/app-config';

const config = getConfig();
console.log(config.env);
console.log(config.hostname);
console.log(config.features);

getConfig returns whatever object was last registered with setConfig. It throws Error: app-config not set. Call setConfig(config) with your imported config/app-config.json at app startup. when called before bootstrap.

resetConfig() clears the registered config — primarily useful in tests.

Build configuration (Node only)

import { buildConfig } from '@jabraf/app-config/build';

await buildConfig();

buildConfig dynamically imports your config/make-config.ts and invokes its buildAppConfig export. If that export is missing, buildConfig throws Error: buildAppConfig not found in config/make-config.ts.

React: useFeature

Once setConfig has run, the useFeature hook reads features directly from the registered config:

// app/components/beta-banner.tsx
import { useFeature } from '@jabraf/app-config/hooks/use-feature.js';

function BetaBanner() {
  const { isFeatureEnabled } = useFeature();
  if (!isFeatureEnabled('beta')) return null;
  return <div>Welcome to the beta!</div>;
}

Cookies named feature__{feature} take precedence over the registered features, which makes runtime overrides (e.g., for QA or beta testers) easy.

Toggling features via cookies

import { setFeatureCookie, removeFeatureCookie } from '@jabraf/app-config';

setFeatureCookie('beta', true);
setFeatureCookie('beta', false);
removeFeatureCookie('beta');

Both setFeatureCookie and removeFeatureCookie are no-ops in SSR environments where document is undefined.

API Reference

setConfig(config: AppConfig): void

Registers the application configuration. Call once at app bootstrap with the statically-imported config/app-config.json. Subsequent calls replace the registered config.

getConfig(): AppConfig

Returns the registered AppConfig reference. Throws Error: app-config not set. Call setConfig(config) with your imported config/app-config.json at app startup. when called before setConfig.

resetConfig(): void

Clears the registered config so that the next getConfig call throws again. Intended for tests.

buildConfig(): Promise<void>@jabraf/app-config/build

Node only. Dynamically imports config/make-config.ts from the project root and invokes its buildAppConfig export. Throws if the export is missing.

useFeature()@jabraf/app-config/hooks/use-feature.js

React hook. Returns { isFeatureEnabled: (feature: Feature) => boolean }. Resolves features from getConfig().features. The returned function checks a feature__{name} cookie first and falls back to the registered features. The function is memoized against the registered features reference.

setFeatureCookie(feature: Feature, enabled: boolean): void@jabraf/app-config/hooks/use-feature.js

Writes feature__{feature}={enabled} with a one-year expiry and path=/. No-op when document is undefined.

removeFeatureCookie(feature: Feature): void@jabraf/app-config/hooks/use-feature.js

Clears the cookie for feature by setting it with an expiry in the past. No-op when document is undefined.

Utilities — @jabraf/app-config/build (Node only)

  • appDirectory(): string — Resolves the directory of the nearest package.json to the current working directory. Memoized after the first call.
  • fromRoot(...segments: string[]): string — Joins path segments against appDirectory().

Types

type Environment = 'dev' | 'test' | 'staging' | 'production';

type EnvironmentConfig<T> = {
  [key in Environment]: T;
};

type FeatureConfig<T extends string = Feature> = {
  [key in T]: boolean;
};

type AppConfig = {
  env: Environment;
  hostname: string;
  features: FeatureConfig;
};

type BuildAppConfig = {
  buildAppConfig: () => Promise<void>;
};

CLI

The package ships a jabraf-config binary that is scaffolded but not yet implemented. Running it currently logs NOT IMPLEMENTED YET!!. Command support will land in a future release.

npx jabraf-config --version

License

MIT © Jabran Rafique