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

kev

v2.6.0

Published

Key-Value API with pluggable backends. So simple, even Kevin Malone could use it.

Downloads

331

Readme

Kev

Plugin-based universal key-value storage API.

This is the story of Kev.

Kev started building his first Node application recently. He decided to use LevelDB for some basic key-value storage. Some 10k SLOC later, new requirements were added that required distributed connections to this persistent storage, and Kev decided Redis was probably now a better storage solution. No big deal. Search and replace to the rescue, right? Tell that to Murphy and his law, who apparently teamed up with a handful of third-party LevelDB dependencies and Kev's embarrassing lack of engineering discipline to make this a much larger refactoring effort than it should have been. "Oh well," Kev says to himself after carefully building some better abstractions and replacing all of the LevelDB API references in his project with their Redis counterparts, "at least I won't have to do that again."

Spoken like a true idiot, Kev.

Two weeks later, Kev's server starts running out of memory. After a not-so-quick foray into the Heap Profiling House of Horrors, Kev discovers that his simple key-value store has grown much larger than he had originally anticipated (5GB), and Redis was keeping this all in memory.

Thud.

Kev's not a Silicon Valley billionaire. He can't afford to just throw more RAM at his problems.

Thud.

He needs out-of-memory persistence and is going to have to change his key-value APIs. Again.

Thud.

Like a metronome counting off 10,000 brain cells per minute, Kev bangs his head against the wall. Poor, heartbroken Kev, exhausted by the mere thought of learning yet another API to do the exact .thud. same .thud. simple .thud. task he was doing before: connect to a data source, then push and pull values by id. Kev's not the brightest fellow, but even he knows it shouldn't be this much work.

But Kev's pity party is short-lived. "Fool me twice...," he mutters under his breath, accepting responsibility for the path of shortsightedness that led him to this cleverly disguised opportunity. He's finally acknowledged the possibility (nay, probability) that he will need to swap his backend again at some point. Even if he doesn't, he shouldn't be relying on a particular storage engine if he wants to reuse any of these components in a different project. So his fingers hit the keys and like tiny little boxers punch out three simple functions:

async get(key)

async set(key, value[, { tags, ttl }])

async del(key)

So far so good. Kev writes a basic in-memory adapter and sets up the simplest conceivable test as a sanity check. It passes! Convinced he is on to something, Kev hastily refactors his project to use this new API and gives it a spin.

var settings = Kev()

His console explodes in a flurry of incomprehensible stack traces. A brief moment of panic ensues before Kev realizes that his application is simply expecting data that still lives in Redis. He whips up an adapter and with a single-line change reconnects his project to its old storage backend.

var settings = Kev({ url: process.env.REDIS_URL })

It works! Kev's hands clench into fists and fly above his head in a celebratory spasm just awkward enough to expose a man whose encounters with success must be infrequent at best. But there is no time for victory dances; the moment of truth has arrived. Kev still needs out-of-memory persistence and already has a remote mongo store setup that he can use. He quickly pulls together a MongoDB adapter and writes a simple script (using his new API) to populate his new instance with the data from Redis. One more single-line change and Kev's project is using MongoDB instead of Redis.

var settings = Kev({ url: process.env.MONGO_URL })

Kev is ecstatic. Where against a wall a head once beat in despair, a heart now beats in excitement. The skies have opened up and Kev has seen the light. Never again will his time be wasted on meaningless refactoring efforts. Never again will his settings, his caches, his packages, his life be bound to a particular persistence layer. He is free, and so are we.

You see, I am Kev. You are Kev. We are all Kev, living in fear of trading speed for tight coupling and leaky abstractions. Because the struggle is real, the struggle is constant. And in this battle we sometimes point the barrel at our own damn feet and pull the trigger. But blood alone moves the wheels of history, and we cannot forget that it is a privilege to fight. We must never give up! We must never acquiesce! We must rise to be worthy of this historic hour and unite as one because it is together...TOGETHER THAT WE WILL PREVAIL!

Epilogue

There is, of course, still work to do. Kev plans to implement the following features as the need arises:

  • [x] Prefixed namespaces
  • [x] Atomic operations
  • [x] Update batching
  • [x] Glob-matching keys
  • [x] Key streams
  • [x] At-rest compression
  • [ ] LevelDB adapter

Getting Kev

npm install kev