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

@ticatec/consul-client

v1.0.0

Published

A lightweight, robust TypeScript client for HashiCorp Consul HTTP API, featuring comprehensive KV store management, connection pooling, and dual ESM/CommonJS builds.

Downloads

181

Readme

Ticatec Consul Client

中文 | English

Version License: MIT

A lightweight, high-performance TypeScript client for the HashiCorp Consul HTTP API, featuring comprehensive Key-Value (KV) management, native HTTP Blocking Query change monitoring (watch), automatic Base64 decoding, HTTP/HTTPS connection pooling, and built-in safe console logging.

Features

  • ✅ Dual Module Support: Full ES Module (ESM) and CommonJS (CJS) dual build with cross-module singleton state.
  • ✅ Zero Runtime Dependencies: Powered entirely by Node.js built-in networking (node:http, node:https), no external dependencies.
  • ✅ KV Store Management: Intuitive API for get, getValue, getWithMeta, set, delete/del, and keys.
  • ✅ Automatic Base64 Decoding: Decodes Consul's Base64 Value into UTF-8 strings or Buffer objects automatically.
  • ✅ Real-Time Watch: Native long-polling (Blocking Query) change watcher with exponential backoff retry and rate limiting protection against caching proxies.
  • ✅ Connection Pooling: Built-in HTTP and HTTPS agents with keep-alive enabled by default for high-throughput internal network access.
  • ✅ Singleton & Multi-Instance Registry: Named singletons (ConsulClient.getInstance('app')) or independent instances (new ConsulClient()).
  • ✅ Built-in Safe Console Logging: Standard zero-dependency console output filtered by LOG_LEVEL. ACL tokens are strictly kept out of logs.
  • ✅ Environment Variables Ready: Automatically resolves CONSUL_HTTP_ADDR, CONSUL_HOST, CONSUL_PORT, CONSUL_HTTP_SSL, and CONSUL_HTTP_TOKEN.

Installation

pnpm add @ticatec/consul-client
# or npm
npm install @ticatec/consul-client

This package is 100% self-contained with zero runtime external dependencies. Because application logging configurations (e.g. Pino) are often loaded from Consul at bootstrap, consul-client only relies on Node.js built-in console output (filtered by process.env.LOG_LEVEL), avoiding chicken-and-egg startup dependencies. You may also supply an optional custom logger via options.logger.


Quick Start

Basic Usage

Named import (recommended):

import { ConsulClient } from '@ticatec/consul-client';

CommonJS (CJS):

const { ConsulClient } = require('@ticatec/consul-client');

Initialize Client

// Uses default host (127.0.0.1:8500) or env variables (CONSUL_HTTP_ADDR, etc.)
const consul = new ConsulClient();

// Or explicit configuration:
const consul = new ConsulClient({
    host: 'consul.service.internal',
    port: 8500,
    token: 'my-acl-token',
    timeout: 10000
});

Key-Value (KV) Operations

Read Values (get & getValue)

// 1. Get KV item with metadata (automatically Base64 decoded)
const item = await consul.kv.get('config/app.yaml');
if (item) {
    console.log(item.Key);         // 'config/app.yaml'
    console.log(item.Value);       // 'port: 8080\nname: demo'
    console.log(item.ModifyIndex); // 1024
}

// 2. Convenience helper: retrieve only the value
const yamlStr = await consul.kv.getValue('config/app.yaml');

// 3. Retrieve and parse JSON directly
const config = await consul.kv.getValue<{ port: number }>('config/app.json', {
    json: true,
    defaultValue: { port: 3000 }
});

// 4. Retrieve binary data as Buffer
const bin = await consul.kv.get('certs/server.crt', { buffer: true });

// 5. Retrieve all keys under prefix
const items = await consul.kv.get('config/', { recurse: true });
for (const entry of items) {
    console.log(entry.Key, entry.Value);
}

// 6. List key names only
const keys = await consul.kv.keys('config/');
console.log(keys); // ['config/app.yaml', 'config/db.yaml']

Write and Delete Values

// Save string value
await consul.kv.set('config/app.yaml', 'port: 8080');

// Save JSON object (automatically serialized)
await consul.kv.set('config/app.json', { port: 8080, env: 'production' });

// Atomic update using CAS (Compare-And-Swap)
const updated = await consul.kv.set('config/lock', 'instance-1', { cas: item.ModifyIndex });
if (!updated) {
    console.warn('CAS mismatch! Key was modified by another process.');
}

// Delete key
await consul.kv.delete('config/old-key'); // or alias consul.kv.del()

// Delete prefix recursively
await consul.kv.delete('config/staging/', { recurse: true });

Real-Time Watch (consul.watch)

Consul uses Blocking Queries to monitor changes. The connection is held open on the server until a change occurs or the wait timeout is reached. It consumes virtually zero CPU on both client and server.

// 1. Watch a key for changes
const watcher = consul.watch({
    key: 'config/app.yaml',
    wait: '5m',             // Blocking query duration (default '5m', max '10m')
    minIntervalMs: 1000     // Rate-limiting guard against caching proxies (default 1000ms)
});

watcher.on('change', (item, meta) => {
    console.log(`Config updated (Index: ${meta.index}):`, item?.Value);
});

watcher.on('error', (err) => {
    console.error('Watch error (will auto-retry with exponential backoff):', err);
});

// 2. Shortcut helper: watch value directly
const valWatcher = consul.watchValue('config/feature-flags.json', (newVal) => {
    console.log('Feature flags reloaded:', newVal);
});

// Stop watching when shutting down
watcher.end();

// Or close the client, which automatically stops all active watchers
consul.close();

Singleton & Multi-Instance Registry

The client registry is preserved on globalThis under Symbol.for('@ticatec/consul-client.instances'), so ESM and CJS modules share the same instances:

// Initialize singleton at application bootstrap
ConsulClient.init({
    host: process.env.CONSUL_HOST,
    token: process.env.CONSUL_TOKEN
});

// Retrieve singleton in any controller or service
const consul = ConsulClient.getInstance();

// Or multi-instance named registry
ConsulClient.init('east', { host: 'consul-east.internal' });
ConsulClient.init('west', { host: 'consul-west.internal' });
const eastConsul = ConsulClient.getInstance('east');

License

MIT © Henry Feng / Ticatec