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

cashola

v1.0.0

Published

Persist the state of an object across processes with one line of code.

Downloads

9

Readme

cashola

Persist the state of an object across processes with one line of code.

There are two main benefits to using this project over a traditional state management solution. (1) Simpler than introducing a database-like resource into your architecture. Consider if this makes sense for your particular use case. (2) No need to write code to intercept state updates, save those updates, nor fetch the current state. Simply modify your state object like you normally would and the js Proxy object will take care of the rest.

cashola uses your local filesystem to persist state under-the-hood.

Install

npm install cashola

Usage

Basic usage

Here's a server that handles requests which alter some internal state object. After a server restart, myState variable would lose its state or need to fetch it from an external source. cashola allows myState to retain all state data from the previous server process.

import { rememberSync } from 'cashola';

const myState = rememberSync('event-server-example');

listener.on('event', (key, value) => {
    myState[key] = value;
});

// myState during first run: { event1: 'hello' }
// myState after server reboot during second run: { event1: 'hello', event2: 'world' }

Alternatively, you can use cashola to retain results from long-running calculations.

import { rememberSync } from 'cashola';

const myState = rememberSync('fibonacci-example');

if (!myState.result) {
    myState.result = calculateFibonacci(1000);
}

console.log('1000th fibanonacci value:', myState.result);

// The first run will calculate calculateFibonacci(1000)
// The second run will already have myState.result so the calculation will be skipped

In this exmaple, after the first run myState will hold one record. After the second run myState will hold two records, the original timeString from the first run and a newer timeString from the second run.

// ~Runnable example~
import { rememberSync } from 'cashola';

// Here we optionally add Record<string, string> type to
// the function call in order to type our return value using typescript.
const myState = rememberSync<Record<string, string>>('timestamp-example');

console.log('Before:', myState);
// First run: {}
// Second run: { <timeString1>: 'hi! }
myState[new Date.getTime().toString()] = 'hi!';
console.log('After:', myState);
// First run: { <timeString1>: 'hi! }
// Second run: { <timeString1>: 'hi!, <timeString2>: 'hi! }

Modify configuration

You can configure the filesystem storage directory as well as whether or not to disable cashola. If you disable cashola (using either an env var or the explicit property ignoreCashola: true) then none of the remember() functions will attempt to fetch data from the state storage.

import { rememberSync, configure } from 'cashola';

configure({
    /**
     * Directory to use as storage  
     * Default: .cashola/  
     */
    storageDir: 'my/state/dir',

    /**
     * Name of environment variable used to ignore cashola  
     * Default: IGNORE_CASHOLA  
     * To use, set to true `IGNORE_CASHOLA=true node index.js`  
     */
    ignoreCasholaEnvVar: 'IGNORE',

    /**
     * Boolean whether or not to ignore cashola  
     * This takes precedence over any env var that is passed
     * Default: false  
     */
    ignoreCashola: true
});

const myState = rememberSync('timestamp-example');
console.log(myState);
// {}

Starter object

You can optionally pass a starter object to any of the remember() functions. If no existing state is found for the given key, the starter object will be used to create the initial state. Run this example twice.

import { rememberSync } from 'cashola';

type MyType = {
    foo: string;
    bar?: number;
}

let myState: MyType = {
    foo: 'foo'
};

myState = rememberSync('starter-obj-example', myState);

console.log('Before:', myState);
// First run: { foo: 'foo' }
// Second run: { foo: 'foo', bar: 42 }
myState.bar = 42;
console.log('After:', myState);
// First run: { foo: 'foo', bar: 42 }
// Second run: { foo: 'foo', bar: 42 }

Async remember()

It is recommended to use the async version of the remember() functions.

import { remember } from 'cashola';

(async () => {
    const myState = await remember('starter-obj-example');
    console.log(myState);
    // { foo: 'foo', bar: 42 }
})()
.catch(console.error);

Using npm command

It is sometimes useful to remove storage from outside the sourcecode of a program.
The cashola-clear-all command takes an optional storageDir path.
The cashola-clear command takes an object key and an optional storageDir path.

package.json

"scripts": {
  "clear": "cashola-clear",
  "clear-all": "cashola-clear-all"
  ...
}
npm run clear -- starter-obj-example
# With storageDir specified as ./.cashola
npm run clear -- timestamp-example ./.cashola

npm run clear-all
# With storageDir specified as ./.cashola
npm run clear -- ./.cashola

Or without the package.json modifications:

./node_modules/cashola/.bin/cashola-clear-all

Methods

| Method | Description | | ----------- | ----------- | | rememberSync(key: string, obj?: object) | Remembers an object, with an optional starter object. Synchronous | | remember(key: string, obj?: object) | Remembers an object, with an optional starter object. Asynchronous | | rememberArraySync(key: string, obj?: any[]) | Remembers an array, with an optional starter array. Synchronous | | rememberArray(key: string, obj?: any[]) | Remembers an array, with an optional starter array. Asynchronous | | configure(config: Config) | Allows for disabling cashola and changing storage path. Configs shown in example above. | | clearSync(key: string) | Removes the state of a single object | | clear(key: string) | Removes the state of a single object | | clearAllSync() | Removes all stored state | | clearAll() | Removes all stored state | | list() | Lists keys of currently stored state objects. |

Further work

  • Implement TTL or some sort of storage expiration
  • Offer database connections (mongodb, postgres, redis) for storage instead of filesystem

Setup

git clone [email protected]:emileindik/cashola.git
cd cashola
npm ci
npm run build
npm test