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

kq-config

v1.4.0

Published

Professional .kq config parser — server/client separation, AES-256 encryption, audit tools, CLI dashboard, 200-test suite, zero dependencies.

Downloads

260

Readme

kq-config

npm version CI License: MIT Node.js

A professional .kq config file parser for Node.js — server/client block separation, built-in .env support, AES-256-GCM encryption, audit tools, CLI dashboard, schema validation, and zero external dependencies.


What does kq mean?

kq stands for Konfig Query — and is also formed from the first and last letters of the author's name, Kanishq.

The .kq extension is a custom config format built from the ground up — purpose-built for projects that need clean separation between server and client configuration, with professional-grade security baked in.


Why kq-config?

Most config solutions give everyone access to everything. kq-config lets you define server and client blocks in a single file — your server only reads server values, your client only reads client values. Secrets never leak to the frontend.

config.kq
├── ::shared     → merged into both server and client
├── ::server     → server only (db passwords, jwt secrets, ports)
└── ::client     → client only (api urls, themes, timeouts)

Features

  • Block separation::server and ::client in one file; each side reads only its own
  • Shared values::shared block merged into both automatically
  • Built-in .env support — no dotenv needed; auto-loads .env from config folder
  • $ENV: injectiondb_pass = $ENV:DB_PASS — secrets never hardcoded
  • AES-256-GCM encryptionENC: syntax for encrypted values in config files
  • Secret masking.all(true) hides sensitive values in output/logs
  • Raw secret detection — warns when plain secrets found in config
  • Layered overrides — base + environment-specific override (dev → staging → prod)
  • Runtime overridesKQ_SERVER_PORT=9999 beats everything
  • Schema validation — required, type, min/max, pattern, enum, defaults
  • Auto type casting"3000"3000, "true"true
  • Audit methods — unused, missing, active, invalid env vars
  • Diff support — compare two configs, see what changed
  • Snapshot — point-in-time view of config
  • CLI toolnpx kq inspect opens browser dashboard
  • Pre-commit hook — blocks commits containing raw secrets
  • Example file generatornpx kq example generates .kq.example from your config (safe to commit)
  • Gitignore safety checknpx kq gitignore verifies sensitive files are in .gitignore
  • TypeScript support — full type definitions included
  • ESM + CJS — works with both import and require
  • Zero dependencies — nothing to install, nothing to audit

Install

npm install kq-config

Quick Start

config.kq:

::shared
  app_name = MyApp
  version  = 1.0
::end

::server
  host       = localhost
  port       = 3000
  db_pass    = $ENV:DB_PASS
  secret_key = $ENV:SECRET_KEY
  debug      = true
::end

::client
  api_url = http://localhost:3000
  theme   = dark
  timeout = 5000
::end

.env:

DB_PASS=supersecret
SECRET_KEY=myjwtsecret

Your code:

const { KQParser } = require("kq-config");
const path = require("path");

const server = new KQParser(path.join(__dirname, "config.kq"), "server").load();
console.log(server.get("port")); // 3000
console.log(server.get("db_pass")); // "supersecret" — from .env automatically

const client = new KQParser(path.join(__dirname, "config.kq"), "client").load();
console.log(client.get("api_url")); // "http://localhost:3000"
console.log(client.get("db_pass")); // undefined — client can NEVER see this ✅

Import Styles

// CommonJS
const { KQParser } = require("kq-config");

// ES Module
import { KQParser } from "kq-config";

// TypeScript
import { KQParser, KQSchema, KQOptions, KQAuditResult } from "kq-config";

Recommended Project Setup

your-project/
├── config.kq               ← base config         (commit ✅)
├── config.prod.kq          ← production overrides (DO NOT commit ❌)
├── config.prod.kq.example  ← prod template        (commit ✅)
├── .env                    ← your secrets         (DO NOT commit ❌)
├── .env.example            ← secrets template     (commit ✅)
└── server.js

.gitignore:

.env
config.prod.kq
config.staging.kq

Built-in .env Support

No need to install dotenv. kq-config auto-loads .env from the same folder as your config.kq:

// .env loaded automatically — nothing extra needed
const server = new KQParser("config.kq", "server").load();

Custom path:

new KQParser("config.kq", "server", null, { envFile: ".env.production" });

Disable:

new KQParser("config.kq", "server", null, { envFile: false });

Shell always wins over .env file:

.env file      ← lower priority
shell env var  ← wins if same key set in shell

Environment Overrides

config.prod.kq — only what changes in production:

::server
  host      = 0.0.0.0
  port      = 8080
  debug     = false
  log_level = warn
::end

::client
  api_url = https://api.example.com
::end

Load based on APP_ENV:

const env = process.env.APP_ENV || "development";

const overrides = {
  production: "config.prod.kq",
  staging: "config.staging.kq",
};

const overrideFile = overrides[env]
  ? path.join(__dirname, overrides[env])
  : null;

const server = new KQParser("config.kq", "server", overrideFile).load();

Run commands:

node server.js                      # development
APP_ENV=staging node server.js      # staging
APP_ENV=production node server.js   # production

# Windows CMD
set APP_ENV=production && node server.js

# Windows PowerShell
$env:APP_ENV="production"; node server.js

Schema Validation

const server = new KQParser("config.kq", "server").load().validate({
  host: { type: "string", required: true },
  port: { type: "number", required: true, min: 1, max: 65535 },
  secret_key: { type: "string", required: true },
  log_level: {
    type: "string",
    required: false,
    default: "info",
    enum: ["debug", "info", "warn", "error"],
  },
  debug: { type: "boolean", required: false, default: false },
});

Throws KQValidationError listing all errors at once:

KQValidationError: Config validation failed for role 'server':
  ✗ Required key 'secret_key' is missing
  ✗ 'port' — value 99999 is above maximum 65535

Runtime Overrides

KQ_SERVER_PORT=9999 node server.js
KQ_CLIENT_THEME=light node server.js
KQ_SERVER_DEBUG=false node server.js

Pattern: KQ_<ROLE>_<KEY>=value — values are automatically type-cast.


Override Priority

.env file
      ↓
config.kq (::shared)
      ↓
config.kq (::server or ::client)
      ↓
config.prod.kq (override file)
      ↓
shell environment variables
      ↓
KQ_SERVER_PORT=9999   ← always wins

Security Features

1. AES-256-GCM Encryption (ENC: syntax)

Store encrypted secrets directly in your .kq file:

Generate a master key:

node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
# 3a7bd3e2360a3d29eea436fcfb7e44c735d117c7888a8660b1e5c8c51b9ff59f

Add to .env:

KQ_MASTER_KEY=3a7bd3e2360a3d29eea436fcfb7e44c735d117c7888a8660b1e5c8c51b9ff59f

Encrypt a value:

process.env.KQ_MASTER_KEY = "3a7bd3e2...";
const enc = KQParser.encrypt("mysupersecretpassword");
// "ENC:aGVsbG8gd29ybGQ=:randomIV:authTag"

// Or generate a fresh key
const key = KQParser.generateKey(); // 64-char hex string

Put it in config.kq:

::server
  db_pass    = ENC:aGVsbG8gd29ybGQ=:randomIV:authTag
  secret_key = ENC:dGhpcyBpcyBhIHNlY3JldA==:iv2:tag2
::end

Load — decryption is automatic:

const server = new KQParser("config.kq", "server").load();
server.get("db_pass"); // "mysupersecretpassword" ✅

Decrypt manually:

const dec = KQParser.decrypt("ENC:aGVsbG8gd29ybGQ=:randomIV:authTag");

2. Secret masking

server.all(); // { port: 3000, db_pass: "supersecret" }
server.all(true); // { port: 3000, db_pass: "***MASKED***" } ✅

// Always mask
new KQParser("config.kq", "server", null, { mask: true });

Keys automatically masked: anything matching password, secret, token, api_key, jwt, auth, credential, signing, cipher, salt, hmac.


3. Raw secret detection

# config.kq — WARNING triggered
::server
  db_pass = ghp_abc123XYZ789realtoken   ← GitHub token detected
::end
# Warning: Key 'db_pass' looks like a secret with a raw value.
#          Use '$ENV:DB_PASS' or 'ENC:' instead.

4. All security protections

| Protection | What it blocks | | ------------------- | ----------------------------------------------------- | | Path traversal | ../../etc/passwd attacks | | Prototype pollution | __proto__, constructor, then etc. | | Nested blocks | ::server inside ::server | | Key format | Only [a-z_][a-z0-9_]* — hyphens/dots/spaces blocked | | ReDoS | Values over 10,000 characters | | Memory exhaustion | Files over 1MB | | Key length | Keys over 256 characters | | Null bytes | Null bytes in values | | Control characters | Control characters in values | | Env hijacking | .env cannot overwrite NODE_OPTIONS, PATH etc. | | Circular override | Base and override cannot be same file | | Symlink attack | Symlinks outside cwd blocked | | Supply chain | Zero external dependencies | | npm provenance | Every release cryptographically signed |


5. $ENV: vs ENC: — when to use which

| | $ENV:VAR | ENC:ciphertext | | ----------------- | -------------------- | ------------------------ | | Secret lives in | .env file or shell | inside config.kq | | Can commit to git | no | yes — encrypted | | Needs master key | no | yes — KQ_MASTER_KEY | | Best for | local dev, CI/CD | committing config safely |


Audit Methods

const server = new KQParser("config.kq", "server").load();

// All $ENV: vars that are set and working
server.activeEnv();
// [{ key: "DB_PASS", source: ".env file" }, { key: "SECRET_KEY", source: "shell environment" }]

// $ENV: vars referenced in config but not set anywhere
server.missingEnv();
// [{ key: "OLD_VAR", suggestion: "Add 'OLD_VAR=your_value' to your .env file" }]

// .env vars never referenced in any config file
server.unusedEnv();
// [{ key: "FORGOTTEN", suggestion: "Remove from .env — not referenced..." }]

// .env vars with empty or placeholder values
server.invalidEnv();
// [{ key: "API_KEY", value: "***", reason: "Looks like a placeholder" }]

// All four at once
server.audit();
// { active: [...], missing: [...], unused: [...], invalid: [...] }

// Warn automatically at load time
new KQParser("config.kq", "server", null, { warnUnused: true }).load();

Diff & Snapshot

const dev = new KQParser("config.kq", "server").load();
const prod = new KQParser("config.kq", "server", "config.prod.kq").load();

// Compare two configs
const diff = dev.diff(prod);
// {
//   added:   {},
//   removed: {},
//   changed: { port: { from: 3000, to: 8080 }, debug: { from: true, to: false } }
// }

// Point-in-time snapshot
const snap = server.snapshot();
// { role: "server", filepath: "...", loadedAt: "...", config: {...masked}, keyCount: 14 }

// Reload config (re-reads files)
server.reload();

CLI Tool

# Generate .kq.example file — safe to commit to GitHub
npx kq example

# Custom output path
npx kq example --file config.kq --output config.kq.example

# Check .gitignore covers all sensitive files
npx kq gitignore

# Open browser dashboard at http://localhost:3737
npx kq inspect

# Custom options
npx kq inspect --role server --port 4000
npx kq inspect --file config.kq --override config.prod.kq

# Terminal audit report
npx kq audit

# Encrypt / decrypt
npx kq encrypt "mysecret"
npx kq decrypt "ENC:..."

Generate Example File

generateExample() reads your .kq file and generates a .kq.example file where:

  • $ENV:DB_PASSYOUR_DB_PASS_HERE
  • ENC:abc:iv:tagYOUR_ENCRYPTED_SECRET_KEY_HERE
  • Plain values like port = 3000 → unchanged

The output file is safe to commit to GitHub. Share it with your team so they know what values to set.

# From CLI — generates config.kq.example automatically
npx kq example

# Custom output path
npx kq example --output config.kq.example
// From code
const result = KQParser.generateExample("config.kq");
// result.path         → "config.kq.example"
// result.replacements → [{ key: "db_pass", type: "env", was: "$ENV:DB_PASS" }, ...]

Example input (config.kq):

::server
  port       = 3000
  db_pass    = $ENV:DB_PASS
  secret_key = ENC:abc:iv:tag
::end

Generated output (config.kq.example):

# config.kq.example — safe to commit to GitHub
# Copy this file to config.kq and fill in the values.

::server
  port       = 3000
  db_pass    = YOUR_DB_PASS_HERE
  secret_key = YOUR_ENCRYPTED_SECRET_KEY_HERE
::end

Gitignore Safety Check

npx kq gitignore checks that all sensitive files are listed in .gitignore. Run it any time to verify you are not at risk of accidentally committing secrets.

npx kq gitignore

If files are missing:

MISSING  .env -- NOT in .gitignore (contains secrets)
         Fix: echo ".env" >> .gitignore
MISSING  config.prod.kq -- NOT in .gitignore (production config)
         Fix: echo "config.prod.kq" >> .gitignore

WARNING: 2 file(s) not in .gitignore -- risk of commit!

If all covered:

OK  .env (contains secrets)
OK  config.prod.kq (production config)

All 2 sensitive file(s) are in .gitignore -- safe!

kq-config also automatically emits a KQGitignoreWarning at .load() time if sensitive files are not in .gitignore — so you get warned even if you forget to run the command.


Pre-commit Hook

Blocks commits containing raw secrets:

# Install once
node scripts/pre-commit.js --install

# Blocks: .env files, config.prod.kq, AWS keys, GitHub tokens,
#         Stripe keys, Slack tokens, JWTs, raw passwords in .kq files

.kq File Syntax

# comment            → ignored entirely
@version = 1.0      → meta directive (ignored by parser)

::shared            → open shared block
  app_name = MyApp
::end               → close block

::server
  port       = 3000               integer — auto cast
  debug      = true               boolean — auto cast
  score      = 9.5                float   — auto cast
  nullable   = null               null    — auto cast
  greeting   = "hello world"      quoted string
  db_pass    = $ENV:DB_PASS       from environment
  secret_key = ENC:abc:iv:tag     encrypted value
  timeout    = 5000 # ms          inline comment
::end

Auto Type Casting

| File value | Parsed as | | ---------------- | --------------------------------- | | 3000 | 3000 (number) | | 3.14 | 3.14 (float) | | true / false | boolean | | null | null | | "hello world" | "hello world" (quotes stripped) | | anything else | string |

Key Rules

  • Keys must match [a-z_][a-z0-9_]* — only lowercase letters, numbers, underscores
  • Uppercase keys are automatically lowercased (MyPortmyport)
  • Hyphens, dots, spaces in keys are not allowed and throw KQParseError

Full API Reference

new KQParser(filepath, role, overrideFile?, options?)

| Parameter | Type | Description | | -------------------- | --------------- | ----------------------------------------- | | filepath | string | Path to your .kq file | | role | string | "server", "client", or any block name | | overrideFile | string\|null | Optional override file | | options.envFile | string\|false | Custom .env path or false to disable | | options.mask | boolean | Always mask secrets in .all() | | options.warnUnused | boolean | Warn at load for unused .env vars |

Methods

| Method | Returns | Description | | -------------------------------------- | ---------- | -------------------------------------- | | .load() | this | Load and merge all layers | | .reload() | this | Reload config again | | .validate(schema) | this | Validate against schema | | .get(key, fallback?) | value | Get single value | | .has(key) | boolean | Check if key exists | | .all(mask?) | object | All values (masked if true) | | .keys() | string[] | All keys | | .values() | array | All values | | .entries() | array | All [key, value] pairs | | .size() | number | Number of keys | | .snapshot() | object | Point-in-time config view | | .diff(other) | object | Compare two parsers | | .unusedEnv() | array | Unused .env vars | | .missingEnv() | array | Missing env vars | | .activeEnv() | array | Active env vars | | .invalidEnv() | array | Invalid .env values | | .audit() | object | All four audit categories | | KQParser.generateExample(file, out?) | object | Generate .kq.example with placeholders | | KQParser.encrypt(text) | string | Encrypt with AES-256-GCM | | KQParser.decrypt(enc) | string | Decrypt ENC: value | | KQParser.generateKey() | string | Generate 64-char hex key |


Error Types

| Error | When thrown | Extra properties | | --------------------- | --------------------------------- | ----------------------- | | KQError | Base class | — | | KQFileNotFoundError | Config file not found | .filepath | | KQEnvError | $ENV:VAR not set anywhere | .varName | | KQValidationError | Schema validation fails | — | | KQParseError | Invalid syntax or blocked content | .filepath, .lineNum |

import {
  KQParser,
  KQFileNotFoundError,
  KQEnvError,
  KQValidationError,
  KQParseError,
} from "kq-config";

try {
  const server = new KQParser("config.kq", "server").load().validate(schema);
} catch (e) {
  if (e.name === "KQFileNotFoundError")
    console.error("File not found:", e.filepath);
  else if (e.name === "KQEnvError")
    console.error("Missing env var:", e.varName);
  else if (e.name === "KQParseError")
    console.error(`Line ${e.lineNum}:`, e.message);
  else if (e.name === "KQValidationError") console.error(e.message);
  process.exit(1);
}

Reporting a Vulnerability

Please do not open a public GitHub issue for security vulnerabilities. See SECURITY.md for how to report privately.


License

MIT — © 2026 kanishq-9