Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

with-simple-caching

ehmpathy8930.14.1TypeScript support: included

A wrapper that makes it simple to add caching to any function

cache, wrapper, functional, function, simple, browser, browser cache, nodejs, nodejs cache, simple, simple cache

readme

with-simple-caching

with-simple-caching

ci_on_commit deploy_on_tag

A wrapper that makes it simple to add caching to any function.

Notable features:

  • Wrapper pattern for simple and clean usage
  • Automatic cache key definition
  • Customizable cache data store

Install

npm install --save with-simple-caching

Quick start

Synchronous Cache, Synchronous Logic

in order prevent redundant sync computations from one machine, you can use a synchronous cache

for example:

import { createCache } from 'simple-in-memory-cache';
import { withSimpleCaching } from 'with-simple-caching';

const solveSuperToughMathProblem = withSimpleCaching(
  ({ a, b }) => ({ solution: a + b }),
  { cache: createCache() },
);
const result1 = solveSuperToughMathProblem({ a: 1, b: 1 }); // runs the logic, sticks the output into the cache, returns a reference to that output
const result2 = getApiResult({ name: 'casey', number: 821 }); // finds the output in the cache, returns a reference to that output
expect(result1).toBe(result2); // same exact object, identified by same reference

Synchronous Cache, Asynchronous Logic

in order to prevent duplicate async requests from one machine, you can use a synchronous cache

for example:

import { createCache } from 'simple-in-memory-cache';
import { withSimpleCaching } from 'with-simple-caching';

const getApiResult = withSimpleCaching(
  async ({ name, number }) => axios.get(URL, { name, number }),
  { cache: createCache() },
);
const result1 = getApiResult({ name: 'casey', number: 821 }); // calls the api, puts promise of results into cache, returns that promise
const result2 = getApiResult({ name: 'casey', number: 821 }); // returns the same promise from above, because it was found in cache - since same input as request above was used
expect(result1).toBe(result2); // same exact object - the promise
expect(await result1).toBe(await result2); // same exact object - the result of the promise

Asynchronous Cache, Asynchronous Logic

in order to cache the output of async logic in a persistant store or across machines, you'll likely find you need to use an async cache.

for example

import { createCache as createOnDiskCache } from 'simple-on-disk-cache';
import { withSimpleCachingAsync } from 'with-simple-caching';

const getApiResult = withSimpleCachingAsync(
  async ({ name, number }) => axios.get(URL, { name, number }),
  { cache: createOnDiskCache() },
);
const result1 = getApiResult({ name: 'casey', number: 821 }); // calls the api, puts promise of results into cache, returns that promise
const result2 = getApiResult({ name: 'casey', number: 821 }); // returns the same promise from above, because it was found in cache - since same input as request above was used
expect(result1).toBe(result2); // same exact object - the promise
expect(await result1).toBe(await result2); // same exact object - the result of the promise

note: this wrapper additionally uses an in-memory cache internally to cache the promise the async cache returns, to prevent duplicate requests

Examples

Add caching to an existing function

import { createCache } from 'simple-in-memory-cache';
import { withSimpleCaching } from 'with-simple-caching';

const getRecipesFromApiWithCaching = withSimpleCaching(getRecipesFromApi, { cache: createCache() });

Define the function with caching directly

import { createCache } from 'simple-in-memory-cache';
import { withSimpleCaching } from 'with-simple-caching';

const getBookByName = withSimpleCaching(
  async (name: string) => {
    /* ... get the book ... */
    return book;
  },
  {
    cache: createCache(),
  },
);

Use a custom persistance layer

local storage, for example:

import { withSimpleCaching } from 'with-simple-caching';

const getRecipesFromApiWithLocalStorageCaching = withSimpleCaching(getRecipesFromApi, {
  // just define how a cache can `get` from and `set` to this data store
  cache: {
    get: (key) => localStorage.getItem(key),
    set: (key, value) => localStorage.setItem(key, value),
  },
});

Use an asynchronous persistance layer

some extra logic is required in order to work with asynchronous caches. therefore, a different wrapper is available for this usecase: withSimpleCachingAsync.

asynchronous caching on-disk, for example:

import { createCache } from 'simple-on-disk-cache';
import { withSimpleCachingAsync } from 'with-simple-caching';

const getRecipesFromApiWithAsyncCaching = withSimpleCachingAsync(getRecipesFromApi, {
  cache: createCache({ directory: { s3: { bucket: '__bucket__', prefix: '__prefix__' } } }),
});

Use a custom key serialization method

serialize the key as the sha hash of the args, for example

import { createCache } from 'simple-in-memory-cache';
import { withSimpleCaching } from 'with-simple-caching';

const getRecipesFromApiWithLocalStorageCaching = withSimpleCaching(getRecipesFromApi, {
  cache: createCache(),
  serialize: {
    key: (args) =>
        crypto.createHash('sha256').update(JSON.stringify(args)).digest('hex'),
  }
});

Use a custom value serialization and deserialization method

if your cache requires you to store data as a string, as is typically the case with asynchronous caches, you can define how to serialize and deserialize the response of your logic

import { createCache } from 'simple-on-disk-cache';
import { withSimpleCachingAsync } from 'with-simple-caching';

const getRecipesFromApiWithLocalStorageCaching = withSimpleCachingAsync(getRecipesFromApi, {
  cache: createCache({ directory: { s3: { bucket: '__bucket__', prefix: '__prefix__' } } }),
  serialize: {
    value: async (response) => JSON.stringify(await response),
  },
  deserialize: {
    value: async (cached) => JSON.parse(await cached)
  }
});

Define the cache at runtime from function inputs

if your cache is defined as part of the inputs to your function (e.g., if you're using the input context pattern), you define where to find the cache in the inputs

for example

import { createCache, SimpleInMemoryCache } from 'simple-in-memory-cache';
import { withSimpleCaching } from 'with-simple-caching';

const getBookByName = withSimpleCaching(
  async ({ name: string}, context: { cache: SimpleInMemoryCache<Book> }) => {
    /* ... get the book ... */
    return book;
  },
  {
    cache: ({ fromInput }) => fromInput[1].context.cache, // grab the cache from the input's "context" parameter (the second input parameter)
  },
);

const book = await getBookByName({ name: 'Hitchhikers Guide to the Galaxy' }, { cache: createCache() });

Features

Automatic cache key

The arguments your function is invoked with is used as the cache key, after serialization. For example:

import { createCache } from 'simple-in-memory-cache';
import { withSimpleCaching } from 'with-simple-caching';

const getZodiacSign = withSimpleCaching(async ({ birthday }: { birthday: string }) => /* ... */, { cache: createCache() });

getZodiacSign({ birthday: '2020-07-21' }); // here the cache key is `[{"birthday":"2020-07-21"}]`

note: array order does matter

Customizable cache data store

You can easily use a custom cache or custom data store / persistance layer for caching with this wrapper.

import { withSimpleCaching } from 'with-simple-caching';

const getZodiacSign = withSimpleCaching(
  async ({ birthday }: { birthday: string }) => /* ... */,
  {
    cache: {
      get: (key: string) => /* ... how to get from your custom data store ... */,
      set: (key: string, value: any) => /** ... how to set to your custom data store ... */,
    }
  }
);

changelog

Changelog

0.14.1 (2025-02-02)

Bug Fixes

  • ondisk: ensure cache key ignores context of procedure (9254f1e)

0.14.0 (2024-12-26)

Features

  • wrapper: expose wrapper to further simplify ondisk caching (f7f5522)

0.13.0 (2024-12-26)

Features

  • terms: use uni-time glossary for duration term (dc74524)

0.12.0 (2024-06-06)

Features

  • bypass: enable bypass of cache.set or cache.get via input or env (677a950)

0.11.4 (2023-08-11)

Bug Fixes

  • async: enable deduplication cache input to with-async-cache (2f8ad46)

0.11.3 (2023-07-28)

Bug Fixes

  • cicd: remove publish-on-tag in favor of publish (52581fa)

0.11.2 (2023-07-28)

Bug Fixes

  • async: enable async caching wrapper to use a sync cache (#26) (6138a92)
  • practs: use latest best practices (#27) (4f6a144)

0.11.1 (2022-11-28)

Bug Fixes

  • async: ensure that the async caching wrapper uses same key serialization for its internal request deduplication cache (608785d)

0.11.0 (2022-11-28)

Features

  • async: deduplicate parallel requests against async-cached logic in-memory w/ sync cache (#23) (6526c3b)
  • sync: add a sync with-extendable-caching method (6a128cc)

0.10.1 (2022-11-25)

Bug Fixes

  • logs: dont warn about undefined get-after-set if output really was undefined (9c3a3a1)

0.10.0 (2022-11-25)

Features

  • contract: extract out async support into withSimpleCachingAsync for better types (eebbc00)
  • types: formally distinguish between SimpleSyncCache and SimpleAsyncCache (0d81b4c)

Bug Fixes

  • serde: ensure that cache-miss and cache-hit responses are guaranteed equivalent (752962d)
  • types: assert that the deserialization input and serialization output are notundefined (d857348)

0.9.5 (2022-11-25)

Bug Fixes

  • update: provide a deserialized cached output to the update toValue function for user (3fe2522)

0.9.4 (2022-11-24)

Bug Fixes

  • types: update SimpleCacheResolutionMethod to support extending the cache type (3bd778f)

0.9.3 (2022-11-24)

Bug Fixes

  • exports: expose default serde methods (94f5dde)
  • failfast: failfast if could not find cache from cache resolution function from input args (91d36e1)

0.9.2 (2022-11-24)

Bug Fixes

  • types: simplify generics by removing extended input and output methods (b492de1)

0.9.1 (2022-11-24)

Bug Fixes

  • types: add a generic for the logic input, for extendability (bfd78c9)

0.9.0 (2022-11-23)

Features

  • extendability: enable invalidation and update of extendable cache forKey, not just forInput (fa25170)

0.8.2 (2022-11-23)

Bug Fixes

  • types: update the name of the onset hooks trigger arg (45139c4)

0.8.1 (2022-11-23)

Bug Fixes

  • hooks: trigger onset hook from extended invalidate and update methods (e9f4fe5)

0.8.0 (2022-11-23)

Features

  • hooks: allow users to specify an onSet hook, which gets triggered exactly after set is confirmed (be77bf6)

0.7.2 (2022-11-23)

Bug Fixes

  • references: replace final references from uladkasach org to ehmpathy org (e874165)
  • types: expose an explicit type for the output of logic wrapped with extendable caching (87446c0)
  • types: update the type of the cache resolution method for easier readability in implementation (de4ce8d)

0.7.1 (2022-11-23)

Bug Fixes

  • tests: ensure that expiration time test has delay buffer for reliability (940cf03)
  • types: generalize WithSimpleCachingOptions and expose from package for extensibility (bfa77a3)

0.7.0 (2022-11-23)

Features

  • extend: expose withExtendableCaching enabling easy external invalidation and update of the wrapped logic cache (d86c628)

0.6.0 (2022-11-23)

Features

  • cache: enable defining cache from logic input args at runtime (f96a291)

0.5.0 (2022-11-22)

Features

  • expiration: enable using custom expiration policy per wrapper (f4611dc)

0.4.1 (2022-11-22)

Bug Fixes

  • invalidation: ensure null is treated as a valid cached value; only undefined as the invalidation literal (4a2327c)

0.4.0 (2022-11-20)

Features

  • async-caches: explicitly support caches with async setters (5b3bc22)

Bug Fixes

  • docs: update readme example of custom serialize and deserialize (a38d1d4)
  • tests: add tests proving correct handing of errors (0ad7f9b)

0.3.0 (2022-10-06)

Features

  • serde: enable custom serialization and deserialization of cached value (0065891)

0.2.1 (2022-10-06)

Bug Fixes

  • promises: handle case where the cache get method is async (45987fe)

0.2.0 (2022-10-06)

Features

  • cicd: add please-release to cicd (b8fc9c5)
  • serialize: enable users to specify a custom key serialization method (67041a1)

Bug Fixes

  • types: correctly support async caches that promise T | undefined (c1c9c12)