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

@alwian/cache

v1.0.0

Published

Type safe caching of data with ttls.

Downloads

1

Readme

Cache

Cache is a type safe way to store data with ttls. Event listneners are also available for different operations, see Events.

Contents

Getting Started

Installation

Run npm install @alwian/cache to install the latest version.

Basic Usage

import Cache from "@alwian/cache";

// Create a cache using the default config and no initial data, you must call .init() before you can use a cache.
const cache = new Cache().init();

// Create a cache with some custom config and initial data
const cacheWithConfig = new Cache().init({
  initialData: [{ key: "myKey", value: "myValue" }],
  defaultTtl: 10,
  ...
})

API


Types

Type Safety

This package has been built with type safety in mind. It allows you to define what keys are allowed to be stored in a cache, and what type of value each key corresponds too. For example -

type ItemMap = {
  key1: string;
  key2: number;
  key3: string;
};

// Create cache using predefined key value pairs in ItemMap
const cache = new Cache<ItemMap>().init();

// Won't compile as key4 is not a permitted key
cache.set({ key: "key4", value: "value4" });

// Won't compile as key1 should correspond to a string
cache.set({ key: "key1", value: 10 });

// Will compile as key2 is a valid key and the type of value is correct
cache.set({ key: "key2", value: 10 });

Each method available has been written to be type safe -

  • When you use a method which requires you to enter keys, it will restrict the available keys to those provided.
  • When you need to enter key/value pairs, it will ensure the type of value is correct based on the key provided.

To omit type safety and allow any keys/values, just create the cache without providing ItemMap.

CacheConfig

This type represents the config used by the cache.

| Field | Type | Default Value | Description | | ------------------ | --------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | interval | number | 1 | How frequently to check if items have expired (in seconds). Set to 0 to stop checking. | | defaultTtl | number | 0 | The default number a seconds before an item should expire once it is added to the cache, 0 mean don't expire. | | removeOnExpire | boolean | true | Whether expired items should be removed from the cache. | | expireOnce | boolean | true | Whether an expired item should only trigger a single expire event, even if it is not removed from the cache and is still expired the next time the cache checks for expired items. | | capacity | number | Infinity | The maximum number of items that can be in the cache. | | errorOnFull | boolean | false | Whether to throw an error when attemtpting to add items which would result in capacity being exceeded. | | errorOnMiss | boolean | false | Whether to throw and error when attempting to retrieve a non existent item. | | errorOnDuplicate | boolean | false | Whether to throw an error when adding an item with a key that is already in use. |

CacheItem

This type represents an item to add to the cache.

| Field | Type | Description | | ------- | -------- | ----------------------------------------------------------------------------------- | | key | string | The key used to access the item. | | value | any | The value of the item. | | ttl? | number | How long before the item should expire after it is added to the cache (in seconds). |

ItemStats

This type represents the stats that are stored about an item.

| Field | Type | Description | | ---------- | -------- | ------------------------------------------ | | accesses | number | How many times the item has been accessed. |

Methods

set(...items: CacheItem[]): void

Use this to add items to the cache. If the key being used already exists, by default the existing item will be replaced.

const cache = new DataCache().init();

cache.set({ key: "key1", value: "key2" }, { key: "key2", value: "value2" });

Has the potential to throw an error if -

  • capacity is set, errorOnFull is true and the number of items being added would exceed capacity. In this case no items will be added before the error is thrown.
  • errorOnDuplicate is true and an item is being added with a key that already exists in the cache.

get(...keys: string[]): unknown | Record<string,unknown>

Use this to retrieve items from the cache.

There are 3 potential ways this method can return -

  • If no keys are provided then all items will be returned in an object containing each key/value pair.
  • If a single key is provided then the corresponding value will be returned on it's own.
  • If multiple keys are provided an object containing each key/value pair will be returned.
const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "key2" },
    { key: "key2", value: "value2" },
    { key: "key3", value: "value3" }
  ]
});

cache.get("key1"); // "key2"
cache.get("key1", "key2"); // { key1: "value1", key2: "value2" }
cache.get(); // { key1: "value1", key2: "value2", key3: "value3" }
cache.get("key4"); // undefined

Has the potential to throw an error if -

  • errorOnMiss is true and a key is requested that doesn't exist.

pop(...keys: string[]): unknown | Record<string, unknown>

Use this to retrieve items whilst simultaneousely removing them from the cache.

There are 3 potential ways this method can return -

  • If no keys are provided then all items will be returned in an object containing each key/value pair.
  • If a single key is provided then the corresponding value will be returned on it's own.
  • If multiple keys are provided an object containing each key/value pair will be returned.
const cache = new DataCache({
  initialData: [
    { key: "key1", value: "key2" },
    { key: "key2", value: "value2" },
    { key: "key3", value: "value3" }
  ]
});

cache.pop("key1"); // "key2"
cache.pop("key1", "key2"); // { key1: "value1", key2: "value2" }
cache.pop(); // { key1: "value1", key2: "value2", key3: "value3" }

cache.get("key1"); // undefined (key was removed with the initial pop call)

Has the potential to throw an error if -

  • errorOnMiss is true and a key is requested that doesn't exist. In this case no items will have been removed.

remove(...keys: string[]): void

Remove items from the cache.

There are 2 possible uses for this method -

  • Passing 1 or more keys will remove those items from the cache.
  • When no keys are specified then all items are removed. This gives the same affect as calling clear().
const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "key2" },
    { key: "key2", value: "value2" },
    { key: "key3", value: "value3" }
  ]
});

cache.remove("key1", "key2");
cache.get("key1", "key2"); // { key1: undefined, key2: undefined }

cache.remove();
cache.get(); // { key1: undefined, key2: undefined, key3: undefined }

Has the potential to throw an error if -

  • errorOnMiss is true and a key is passed that doesn't exist. In this case no items will have been removed.

clear(): void

Remove all items from the cache.

const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" },
    { key: "key3", value: "value3" }
  ]
});

cache.clear();

cache.get(); // {}

has(key: string): boolean

Check whether a key exists in the cache.

const cache = new DataCache().init({
  initialData: [{ key: "key1", value: "value1" }]
});

cache.has("key1"); // true
cache.has("key2"); // false

keys(): string[]

Get each key stored in the cache.

const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" },
    { key: "key3", value: "value3" }
  ]
});

cache.keys(); // ["key1", "key2", "key3"]

stats(...keys: string[]): ItemStats | Record<string, ItemStats>

Get the stats of items in the cache.

There are 3 possible uses for this method -

  • Passing a single key will return an ItemStats object containing the stats for that key.
  • Passing multiple keys will return an object containing key/ItemStats pairs.
  • Passing in no keys will result in the stats for all items being returned in an object of containing key/ItemStats pairs.
const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" },
    { key: "key3", value: "value3" }
  ]
});

cache.stats("key1"); // { accesses: 0 }
cache.stats("key1", "key2"); // { key1: { accesses: 0 }, keys2: { accesses: 0 }}
cache.stats(); // { key1: { accesses: 0 }, keys2: { accesses: 0 }, key3: { accesses: 0 }}

Has the potential to throw an error if -

  • errorOnMiss is true and a key is passed that doesn't exist.

clearStats(...keys: string[]): void

Reset the stats of items in the cache.

There are 2 possible uses for this method -

  • Passing 1 or more keys will reset the stats for the specified keys.
  • If no keys are passed then the stats for all items will be reset.
const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" }
  ]
});

cache.get("key1");
cache.stats("key1"); // { accesses: 1 }

cache.clearStats("key1");
cache.stats("key1"); // { accesses: 0 }

cache.get("key1", "key2");
cache.stats(); // { key1: { accesses: 1 }, key2: { accesses: 1 } }

cache.clearStats();
cache.stats(); // { key1: { accesses: 0 }, key2: { accesses: 0 } }

Has the potential to throw an error if -

  • errorOnMiss is true and a key is passed that doesn't exist. In this case no items will have been modified.

config(config: Partial<Omit<CacheConfig, "initialData">>): void

Update the config being used by the cache.

const cache = new DataCache().init();

cache.config({
  errorOnMiss: true,
  errorOnDuplicate: true
});

ttl(ttl: number, ...keys: string[]): void

Update the ttl of items in the cache.

There are 2 ways to use this method -

  • Passing in 1 or more keys will update the ttl for the specified keys.
  • If no keys are specified then all items will have their ttl updated.
const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" }
  ]
});

cache.ttl(10, "key1"); // key1 will now expire 10 seconds after it was added.
cache.ttl(15); // key1 and key2 will now expire 15 seconds after they were added.

Has the potential to throw an error if -

  • errorOnMiss is true and a key is passed that doesn't exist. In this case no items will have been modified.

purge(): void

Remove expired items from the cache.

const cache = new DataCache().init({
  config: {
    defaultTtl: 10, // Items expire after 10 seconds by default
    removeOnExpire: false
  },
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" },
    { key: "key3", value: "value3", ttl: 15 } // Item will expire after 15 seconds
  ]
});

// 10 seconds later
cache.purge();
cache.get(); // "value3"

resetExpiry(...keys: string[]): void

Reset the expiry counter for items in the cache.

This method resets the time at which an item was added to the cache, restarting the countdown to it's expiry. If an item has already expired, it's will no longer be expired.

There are 2 ways to use this method -

  • Passing in 1 or more keys will reset the expiry for the specified keys.
  • If no keys are passed in then all items are reset.
const cache = new DataCache().init({
  config: {
    defaultTtl: 10, // Items expire after 10 seconds by default
    removeOnExpire: false
  },
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" },
    { key: "key3", value: "value3", ttl: 15 } // Item will expire after 15 seconds
  ]
});

// 10 Seconds later key1 and key2 are expired

cache.resetExpiry("key1"); // key1 no longer expired and will expire in 10 seconds
cache.resetExpiry(); // All keys have been reset and will expire in the relevant number of seconds

Has the potential to throw an error if -

  • errorOnMiss is true and a key is passed that doesn't exist. In this case no items will have been modified.

values(): unknown[]

Get each value stored in the cache.

const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" },
    { key: "key3", value: "value3" }
  ]
});

cache.values(); // ["value1", "value2", "value3"]

entries(): [string, unknown][]

Get each key/value pair stored in the cache.

const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" },
    { key: "key3", value: "value3" }
  ]
});

cache.entries(); // [["key1", "value1"], ["key2", "value2"], ["key3", "value3"]]

size(): number

Get the number of items stored in the cache.

const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" },
    { key: "key3", value: "value3" }
  ]
});

cache.size(); // 3

Events

set

This event is triggered for each item that is added to the cache using set.

const cache = new DataCache().init();

cache.on("set", (key: string, value: unknown) => {
  console.log(`${key} + ${value as string}`);
});

cache.set({ key: "key1", value: "value1" }, { key: "key2", value: "value2" });

// console.log: key1 + value1
// console.log: key2 + value2

get

This is event is triggered for each item that is retrieved using get.

const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" }
  ]
});

cache.on("get", (key: string, value: unknown) => {
  console.log(`${key} + ${value as string}`);
});

cache.get();

// console.log: key1 + value1
// console.log: key2 + value2

pop

This is event is triggered for each item that is retrieved using pop.

const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" }
  ]
});

cache.on("pop", (key: string, value: unknown) => {
  console.log(`${key} + ${value as string}`);
});

cache.pop();

// console.log: key1 + value1
// console.log: key2 + value2

remove

This event is triggered for each item that is removed using remove.

const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" }
  ]
});

cache.on("remove", (key: string, value: unknown) => {
  console.log(`${key} + ${value as string}`);
});

cache.remove();

// console.log: key1 + value1
// console.log: key2 + value2

clear

This is event is triggered when the cache is cleared using clear.

const cache = new DataCache().init({
  initialData: [
    { key: "key1", value: "value1" },
    { key: "key2", value: "value2" }
  ]
});

cache.on("pop", () => {
  console.log("Cache cleared");
});

cache.clear();

// console.log: Cache cleared

Release History

| Version | Date | Description | | ------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | 1.0.0 | 31/05/2023 | This release introduces type safety throughout Cache. Can be used to predefine keys that can be used and the type of value they correspond to, this also makes it possible to narrow down the return types of various methods. | | 0.0.2 | 28/05/2023 | Initial release (I messed up 0.0.1 so had to skip). This release contains the initial version of Cache with all of the standard functionality I thought should be included. |