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

@ambicuity/etcd

v1.0.3

Published

Etcd storage adapter for Storely

Readme

⚠️ Experimental. Per-call lease creation leaks server-side leases on every set with a TTL — high-frequency writes will exhaust etcd's lease table. The shared instance lease (when configured) is also never renewed, so all keys evict simultaneously when it expires. Do not put live traffic on this adapter until lease lifecycle is fixed. See docs/audits/2026-05-09.

Etcd storage adapter for Storely using the etcd3 client

npm npm

Features

  • Built on the etcd3 package with full TypeScript support
  • TTL support via etcd leases (millisecond input, converted to seconds internally)
  • Namespace support for key isolation across multiple Storely instances
  • Async iterator support for scanning keys
  • setMany, getMany, deleteMany, and hasMany batch operations
  • createStorely helper for quick setup

Table of Contents

Install

npm install --save storely @ambicuity/etcd

Quick Start with createStorely

import { createStorely } from '@ambicuity/etcd';

const storely = createStorely('etcd://localhost:2379');

// set a value
await storely.set('foo', 'bar');

// get a value
const value = await storely.get('foo');

// set with TTL (milliseconds)
await storely.set('foo', 'bar', 6000);

// delete a value
await storely.delete('foo');

You can also pass options:

import { createStorely } from '@ambicuity/etcd';

const storely = createStorely('etcd://localhost:2379', { ttl: 5000 });

// or using an options object
const storely2 = createStorely({ url: '127.0.0.1:2379', ttl: 5000 });

Usage

import Storely from '@ambicuity/ambicore';
import StorelyEtcd from '@ambicuity/etcd';

const store = new StorelyEtcd('etcd://localhost:2379');
const storely = new Storely({ store });

// set a value
await storely.set('foo', 'bar');

// set a value with TTL (in milliseconds)
await storely.set('foo', 'bar', 6000);

// get a value
const value = await storely.get('foo');

// delete a value
await storely.delete('foo');

// clear all values
await storely.clear();

// disconnect
await store.disconnect();

Usage with Namespaces

import Storely from '@ambicuity/ambicore';
import StorelyEtcd from '@ambicuity/etcd';

const store = new StorelyEtcd('etcd://localhost:2379');
const storely1 = new Storely({ store, namespace: 'namespace1' });
const storely2 = new Storely({ store, namespace: 'namespace2' });

// keys are isolated by namespace
await storely1.set('foo', 'bar1');
await storely2.set('foo', 'bar2');

const value1 = await storely1.get('foo'); // 'bar1'
const value2 = await storely2.get('foo'); // 'bar2'

Options

| Option | Type | Default | Description | |---|---|---|---| | url | string | '127.0.0.1:2379' | The etcd server URL. The etcd:// protocol prefix is automatically stripped. | | uri | string | — | Alias for url | | ttl | number | undefined | Default TTL in milliseconds for all keys. Uses etcd leases internally. | | busyTimeout | number | undefined | Busy timeout in milliseconds | | namespace | string | undefined | Key prefix for namespace isolation |

import StorelyEtcd from '@ambicuity/etcd';

// Using a URI string
const store = new StorelyEtcd('etcd://localhost:2379');

// Using an options object
const store2 = new StorelyEtcd({ url: '127.0.0.1:2379', ttl: 5000 });

// Using a URI string with additional options
const store3 = new StorelyEtcd('etcd://localhost:2379', { ttl: 5000, busyTimeout: 3000 });

Properties

.client

The underlying Etcd3 client instance. Can be used to access the etcd3 client directly.

| Type | Default | |---|---| | Etcd3 | Created from the url option |

.lease

The etcd lease used for TTL support. Only set when a ttl is configured.

| Type | Default | |---|---| | Lease \| undefined | undefined |

.url

The etcd server URL.

| Type | Default | |---|---| | string | '127.0.0.1:2379' |

.ttl

Default TTL in milliseconds for all keys. Converted to seconds internally for etcd leases.

| Type | Default | |---|---| | number \| undefined | undefined |

.busyTimeout

Busy timeout in milliseconds.

| Type | Default | |---|---| | number \| undefined | undefined |

.namespace

Key prefix for namespace isolation. When set, all keys are prefixed with namespace:.

| Type | Default | |---|---| | string \| undefined | undefined |

.keyPrefixSeparator

The separator between the namespace and key.

| Type | Default | |---|---| | string | ':' |

Methods

constructor(url?, options?)

Creates a new StorelyEtcd instance.

  • url — An etcd server URI string (e.g., 'etcd://localhost:2379') or a StorelyEtcdOptions object. Defaults to '127.0.0.1:2379' if not provided.
  • options — Optional StorelyEtcdOptions object. When both url and options are objects, they are merged together.
import StorelyEtcd from '@ambicuity/etcd';

// Using a URI string
const store = new StorelyEtcd('etcd://localhost:2379');

// Using an options object
const store2 = new StorelyEtcd({ url: '127.0.0.1:2379', ttl: 5000 });

// Using a URI string with additional options
const store3 = new StorelyEtcd('etcd://localhost:2379', { ttl: 5000 });

.get(key)

Retrieves a value from the etcd server. Returns the stored value or undefined if the key does not exist.

const store = new StorelyEtcd('etcd://localhost:2379');
await store.set('foo', 'bar');
const result = await store.get('foo'); // 'bar'

.getMany(keys)

Retrieves multiple values from the etcd server. Returns an array of stored data corresponding to each key.

const store = new StorelyEtcd('etcd://localhost:2379');
await store.set('key1', 'value1');
await store.set('key2', 'value2');
const results = await store.getMany(['key1', 'key2']);

.set(key, value, ttl?)

Stores a value in the etcd server. If a ttl is provided, a dedicated etcd lease is created for that key. Otherwise, if a default TTL is configured via the constructor ttl option, the shared lease is used. Returns true on success, false on failure.

  • key (string) - The key to set.
  • value (any) - The value to store.
  • ttl (number, optional) - Time to live in milliseconds.
  • Returns: Promise<boolean>
const store = new StorelyEtcd('etcd://localhost:2379');
await store.set('foo', 'bar');
await store.set('foo', 'bar', 5000); // expires in 5 seconds

.setMany(entries)

Stores multiple values in the etcd server. Each entry is a StorelyEntry<Value> object ({ key: string, value: Value, ttl?: number }), where Value is inferred from the entries provided. Returns a boolean[] indicating whether each entry was set successfully.

const store = new StorelyEtcd('etcd://localhost:2379');
const results = await store.setMany([
  { key: 'key1', value: 'value1' },
  { key: 'key2', value: 'value2' },
]); // [true, true]

.delete(key)

Deletes a key from the etcd server. Returns true if the key was deleted, false otherwise.

const store = new StorelyEtcd('etcd://localhost:2379');
await store.set('foo', 'bar');
const deleted = await store.delete('foo'); // true

.deleteMany(keys)

Deletes multiple keys from the etcd server. Returns a boolean[] indicating whether each key was deleted.

const store = new StorelyEtcd('etcd://localhost:2379');
await store.set('key1', 'value1');
await store.set('key2', 'value2');
const results = await store.deleteMany(['key1', 'key2']); // [true, true]

.clear()

Clears data from the etcd server. If a namespace is set, only keys with the namespace prefix are deleted. Otherwise, all keys are deleted.

const store = new StorelyEtcd('etcd://localhost:2379');
await store.clear();

.has(key)

Checks whether a key exists in the etcd server.

const store = new StorelyEtcd('etcd://localhost:2379');
await store.set('foo', 'bar');
const exists = await store.has('foo'); // true
const missing = await store.has('baz'); // false

.hasMany(keys)

Checks whether multiple keys exist in the etcd server. Returns an array of booleans corresponding to each key.

const store = new StorelyEtcd('etcd://localhost:2379');
await store.set('key1', 'value1');
await store.set('key2', 'value2');
const results = await store.hasMany(['key1', 'key2', 'key3']); // [true, true, false]

.iterator()

Returns an async iterator over key-value pairs. The iterator uses the namespace configured on the instance.

const store = new StorelyEtcd('etcd://localhost:2379');
await store.set('key1', 'value1');
await store.set('key2', 'value2');

for await (const [key, value] of store.iterator()) {
  console.log(key, value);
}

.disconnect()

Gracefully disconnects from the etcd server.

const store = new StorelyEtcd('etcd://localhost:2379');
await store.disconnect();

.formatKey(key)

Formats a key by prepending the namespace if one is set. If the key already starts with the namespace prefix, it is returned as-is to avoid double-prefixing.

const store = new StorelyEtcd('etcd://localhost:2379');
store.formatKey('foo'); // 'foo'

store.namespace = 'myapp';
store.formatKey('foo'); // 'myapp:foo'
store.formatKey('myapp:foo'); // 'myapp:foo' (no double-prefix)

License

MIT © Ritesh Rana