Git Product home page Git Product logo

immortaldb's Introduction

ImmortalDB

ImmortalDB

ImmortalDB is a resilient key-value store for the browser.

ImmortalDB is the best way to store persistent key-value data in the browser. Data saved to ImmortalDB is redundantly stored in Cookies, IndexedDB, and LocalStorage, and relentlessly self heals if any data therein is deleted or corrupted.

For example, clearing cookies is a common user action, even for non-technical users. And browsers unceremoniously delete IndexedDB, LocalStorage, and/or SessionStorage without warning under storage pressure.

ImmortalDB is resilient in the face of such events.

In this way, ImmortalDB is like Evercookie, but

  1. Is actively maintained and well documented.

  2. Provides a simple, modern, Promise-based API.

  3. Strikes an equitable balance between reliability and respect for the user. Data is stored reliably but can also be voluntarily purged if the user designedly clears cookies and application storage.

  4. Doesn't use nefarious exploits nor deprecated third party plugins like Flash, Silverlight, or Java. Only standard, ratified HTML5 APIs are used.

  5. Doesn't vandalize performance or the user experience. For example, Evercookie's CSS History Knocking can beget a deluge of background HTTP requests, and loading Silverlight or Flash can raise unsought permission modals or thrash the user's disk.

How ImmortalDB works.

When you store a key-value pair in ImmortalDB, that key and value are saved redundantly in the browser's cookies, IndexedDB, and LocalStorage data stores.

When a value is retrieved via its key, ImmortalDB

  1. Looks up that key in every data store.
  2. Counts each unique returned value.
  3. Determines the most commonly returned unique value as the 'correct' value.
  4. Returns this correct value.

Then ImmortalDB self-heals: if any data store(s) returned a value different than the determined correct value, or no value at all, the correct value is rewritten to that store. In this way, consensus, reliability, and redundancy is maintained.

API

Set

ImmortalDB's API is simple. To store a value, use set(key, value):

import { ImmortalDB } from 'immortal-db'

await ImmortalDB.set('key', 'value')

key and value must be DOMStrings. ImmortalDB.set(key, value) also always returns value, so it can be chained or embedded, like

const countPlusOne = (await ImmortalDB.set('count', numberOfClowns)) + 1

Get

To retrieve a value, use get(key, default=null):

const value = await ImmortalDB.get('key', default=null)

get() returns the value associated with key, if key exists. If key doesn't exist, default is returned. key must be a DOMString.

Remove

Finally, to remove a key, use remove(key):

ImmortalDB.set('hi', 'bonjour')
console.log(await ImmortalDB.get('hi'))  // Prints 'bonjour'.

await ImmortalDB.remove('hi')

console.log(await ImmortalDB.get('hi'))  // Prints 'null'.

key must be a DOMString.

Data Stores

The data stores that ImmortalDB stores data in can also be configured. For example, this is how to store data reliably in cookies and LocalStorage only:

import { ImmortalStorage, CookieStore, LocalStorageStore } from 'immortal-db'

const stores = [await CookieStore(), await LocalStorageStore()]
const db = new ImmortalStorage(stores)

await db.set(key, JSON.stringify({1:1}))

By default, stores used by ImmortalDB are:

  • CookieStore -> Keys and values are stored in document.cookie.
  • IndexedDbStore -> Keys and values are stored in window.indexedDB.
  • LocalStorageStore -> Keys and values are stored in window.localStorage.

Other, optional stores are:

  • SessionStorageStore -> Keys and values are stored in window.sessionStorage.

New storage implementations can easily be added, too; they need only implement the async methods get(key, default), set(key, value), and remove(key).

Installation

Installing ImmortalDB with npm is easy.

$ npm install immortal-db

Or include dist/immortal-db[.min].js and use window.ImmortalDB directly.

<html>
  <head>
    <script src="immortal-db.min.js"></script>
    <script>
      ;(async () => {
        const db = ImmortalDB.ImmortalDB
        await db.set('hi', 'lolsup')
      })()
    </script>
  </head>

  ...
</html>

Development

To test ImmortalDB, run

npm run start

This starts a webpack dev server and opens ImmortalDB's testing website, http://localhost:9234/.

Once tested, to produce new production-ready files immortal-db.js and immortal-db.min.js in dist/, run

npm run build

immortaldb's People

Contributors

coolreader18 avatar dependabot[bot] avatar fairfieldt avatar gruns avatar kmd09 avatar masaha03 avatar mmv08 avatar pruthvikar avatar zproxyz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

immortaldb's Issues

Indexed DB

Hi,
I am trying to use ImmortalDB to store a counter.

I am storing the value in Local, Indexed and Cookie storage and it works well.
When I clear values (I use Forget me chrome extension) it correctly clears Local and cookie storage but not Indexed (and this is perfect for me because I don't want the counter to be erased by the common user).
But when I reload the page and trying to get the counter value it returns undefined even if chrome dev shows it in Indexed db tab.

Is it possible for ImmortalDb to replicate data from this db to the others if the value is missing in them?

Thanks

Nextjs window is not defined error

Hi!

i'm recently working on the nextjs project and i started using immortalDB, but i'm getting the error "window not defined", even before using any of the functions (get, set, delete), when i import immortalDB the error starts to show up, how can i fix this? thanks!

Good job, ImmortalDB is awesome!๐Ÿ˜„

how to handle expired mechanism

as cookie expired time for auth and privacy info,
how about other storage api? there is a away to auto handle expired value?

Events

Hello, is it possible to trigger a callback when a key is set?
Thank you in advance

SSR compatible

Hey, thanks for ImmortalDB. It's really awesome. ๐Ÿ˜ƒ

Though I'm trying to use this inside a nuxt.js project which has SSR built-in. I want to use ImmortalDB with SSR but the window keyword use stops it from being SSR friendly. Could you make it ssr-friendly. So that it uses cookies on the server-side and the same current choice of dbs on the client-side.

Making it ssr-friendly would be a great add-on. Thanks! :)

I wouldn't recommend using SessionStorage

SessionStorage is per-tab (with navigation-inheritance from navigated-from tabs), while the rest of these storage systems are per-origin. This means that if you have multiple tabs / contexts, and they are all doing changes, then sessionstorage will always be wrong on all of them. Also, it will have to have unique data per tab / context, so you'll get a per-tab copy of the data in session storage on disk, which means (other than the already duplicate data being stored in other storage systems), tabs*data size extra data.

Also, the first get or put (on both SessionStorage and LocalStorage) actually does a synchronous read from disk. This is unfortunately by design of the very old spec, as the API is synchronous. So just keep that in mind, this isn't great for the user, as the page freezes, and it can be bad for machines that are old / spinning disk / slow.

(I'd also recommend just using IndexedDB by itself and not using any of these other storage backends... but that's a separate issue, and probably not a constructive one)

Undefined should not be counted as value?

Consider the case:

  • 3 stores (cookie, localstorage, indexdb) are used.
  • 2 out of 3 loses value (no matter which).
  • Value counter makes 3rd value disappear too, since "undefined" response from first storages is treated as some value.

Expected behaviour: value will be recreated in 2 stores that returned undefined.

๐Ÿ˜ฎ WOW!

I have created this issue to thank the author, feel free to close it once read.

I am always researching good readme documentation as I am a fan of making things concise and useful โ€” while reading the READMe.md file on this project I am in awe! Seriously, the lingo used is concise and extremely helpful in explaining each topic discussed therein.

Mad props! Peace! โœŒ๏ธ

What's the capacity of IronDB?

IndexedDB has initial 5MB limitation and whole Harddisk capacity after confirmation (is IronDB handling such confirmation protocols?)

Cookies have a 4KB limit per cookie.

LocalStorage and SessionStorage have 10MB limitiation?

How are these limitations reconciliated in IronDB

It would be nice to have a "capacity / usage" api available in IronDB to monitor the current and available storage capacity.

Thanks!

Performance Comparison Benchmark

Definitely gonna use this in my next project. It looks extremely promising ๐Ÿ‘๐Ÿผ

Just wondering if a benchmark comparison would be done in the future to compare it to other localstorage/cache-based solutions already out there.

We don't use NPM or any module manager, so am getting "Cannot use import statement outside a module"....

Hi,

So I have a very simple page as follows:

<!DOCTYPE html>
 ย 
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/src/index.min.js"></script>
</head>
<body>
</body>
</html>

But now I get the following error in the console.

image

  1. So how do I use the library without any module manager etc.?
  2. The rest of our application does not use module management amd I don't want to have to add one if I don't really have to. But if there is no other option can you provide a sample using my simple HTML page from above?

You are only allowing strings and return undefined for JSON

In fact returning JSON it would work like normal - but you explicitely check and return only if the value is string otherwise undefined.

This is rather a bug, as INDEXEDDB can store JSON and retrieve JSON
So please remove this rather unfortunate limitation!

Add eslint and prettier

I'm creating this issue since I think we need it for organizing the code better.
Any preference @gruns about code style and lint?
I'm planing to open a PR tonight with this changes.

How do we run tests?

I don't see any test script here in package.json. How are you guys running tests?
I think this should be added, also to maintain consistency accross the team we can add prettier and eslint.
Let me know your thoughts, I'm really excited about this

Disable cookie store by default.

I'd suggest disabling the cookie storage option by default, making it opt-in.

  • amount of storage for cookies is more limited,
  • every cookie set is sent to the server on every request
    • increases transmission overhead
    • increases server-side time spent loading/parsing cookies

Reset database

For testing purposes, I need to reset the values set by ImmortalDB. Currently I am doing the following to achieve this, but it would be great if the library offered this functionality:

const clearStorage = () => Promise.all(
  Object.keys(localStorage)
    .filter(key => key.startsWith('_immortal'))
    .map(key => ImmortalDB.remove(key.replace('_immortal|', '')))
);

Option to remove all cookies set with ImmortalDB

From a quick glance at the code this could relatively easy be implemented via a seperate function (something like removeAll()) or as a default behaviour when no key argument is provided to the remove() method. If you tell me if this is something you want and if so, which way you prefer I would try and write this as a PR myself.

Synchronous get / set?

Very helpful package! Thank you.

I'm using ImmortalDB with React to save some page state to local.
I would like to init a component's state by loading locally stored state, like:

const MyComponent = () => {
  const [state, setState] = useState(() => {
    return ImmortalDB.get('key')
  })
}

But ImmortalDB.get returns a Promise, so the above line would be return await ImmortalDB.get('key').
And React's useState does not support async functions,
so a synchronous get would be very helpful

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.