Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

choo-persist

Package Overview
Dependencies
Maintainers
2
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

choo-persist - npm Package Compare versions

Comparing version 2.0.1 to 3.0.0

105

index.js

@@ -1,94 +0,33 @@

const explain = require('explain-error')
const window = require('global/window')
const Idb = require('idb-wrapper')
const assert = require('assert')
const xtend = require('xtend')
var mutate = require('xtend/mutable')
module.exports = persist
// create a choo persistance plugin that stores stuff in indexedDB
// (obj?, fn(obj) -> null
function persist (opts, cb) {
if (!cb) {
cb = opts
opts = {}
}
function persist (opts) {
opts = opts || {}
assert.equal(typeof opts, 'object', 'choo-persist: opts should be an object')
assert.equal(typeof cb, 'function', 'choo-persist: cb should be an function')
var name = opts.name || 'choo-persist'
var filter = opts.filter
const name = opts.name || 'app'
const filter = opts.filter || noop
if (!window.indexedDB) return cb({})
return function (state, bus) {
var savedState = null
try {
savedState = JSON.parse(window.localStorage.getItem(name))
} catch (e) {
savedState = {}
}
const db = new Idb({
dbVersion: 1,
storeName: name,
keyPath: 'id',
autoIncrement: false,
onStoreReady: onStoreReady
})
mutate(state, savedState)
bus.on('*', listener)
function onStoreReady () {
getState(db, function (err, state) {
if (err) throw err
cb({
onStateChange: createStateChange(db, filter),
wrapInitialState: function (appState) {
return xtend(appState, state)
}
})
bus.on('clear', function () {
bus.removeListener('*', listener)
window.localStorage.removeItem(name)
bus.emit('log:warn', 'Wiping localStorage ' + name)
})
}
}
// persist stuff to the local database
// (obj) -> (obj, obj, obj, str, fn) -> null
function createStateChange (db, filter) {
return function onStateChange (state, data, prev, caller, createSend) {
if (filter) state = filter(state)
setState(db, state, function (err) {
if (err) {
const send = createSend('choo-persist')
send('error', err)
}
})
function listener (eventName, data) {
var savedState = filter ? filter(state) : state
window.localStorage.setItem(name, JSON.stringify(savedState))
}
}
}
// get the initial values from the database
// (obj, fn(err?, obj)) -> null
function getState (db, cb) {
db.getAll(onSuccess, onError)
function onSuccess (data) {
var state = data[data.length - 1] || {}
delete state.id
delete state.location
cb(null, state)
}
function onError (err) {
const nwErr = explain(err, 'choo-persist: something went wrong accessing the database while starting up')
cb(nwErr)
}
}
// set values on the database
// (obj, obj, fn(err?, obj)) -> null
function setState (db, state, cb) {
db.put(xtend(state), onSuccess, onError)
function onSuccess () {
cb()
}
function onError (err) {
const newErr = explain(err, 'choo-persist: expected database write to be successful')
cb(newErr)
}
}
function noop (state) {
return state
}
{
"name": "choo-persist",
"version": "2.0.1",
"version": "3.0.0",
"description": "Synchronize choo state with indexedDB",

@@ -8,5 +8,5 @@ "main": "index.js",

"deps": "dependency-check . && dependency-check . --extra --no-dev",
"test": "standard && npm run deps && NODE_ENV=test node test",
"test": "standard && npm run deps",
"start": "bankai start --entry=example.js -p 1337 --open",
"test:cov": "standard && npm run deps && NODE_ENV=test istanbul cover test.js"
"test:cov": "standard && npm run deps"
},

@@ -24,5 +24,2 @@ "repository": "yoshuawuyts/choo-persist",

"dependencies": {
"explain-error": "^1.0.3",
"global": "^4.3.0",
"idb-wrapper": "^1.7.1",
"xtend": "^4.0.1"

@@ -29,0 +26,0 @@ },

# choo-persist [![stability][0]][1]
[![npm version][2]][3] [![build status][4]][5] [![test coverage][6]][7]
[![npm version][2]][3] [![build status][4]][5]
[![downloads][8]][9] [![js-standard-style][10]][11]
![choo-persist gif](./reload.gif)
Synchronize [choo][choo] state with `localStorage`
Synchronize [choo][choo] state with [indexedDB][mdn]. Does nothing in [browsers
that don't support indexedDB][caniuse].
## Usage
```js
const persist = require('choo-persist')
const choo = require('choo')
var persist = require('choo-persist')
var choo = require('choo')
const app = choo()
var app = choo()
app.use(persist())
/* register router, views, models */
persist((persist) => {
app.use(persist)
const tree = app.start()
document.body.appendChild(tree)
})
```
## API
### persist(opts?, fn(plugin))
### `instance = persist([opts])`
Create a new `indexedDB` database instance, and call the callback with the

@@ -46,11 +37,2 @@ plugin when done. Can take an optional first argument of options:

### plugin.onStateChange
The plugin should be passed into `app.use()` directly. `onStateChange` listens
for every state change in the application and persists it to `indexedDB`.
### plugin.wrapInitialState
The plugin should be passed into `app.use()` directly. `wrapInitialState`
reads the state from `indexedDB` on start and overrides the initial application
state.
## Installation

@@ -61,28 +43,2 @@ ```sh

## FAQ
### Why does this plugin wrap the start() method?
Choo is initialized completely synchronously. This makes it easy to reason
about, implement, and profile. IndexedDB, however, cannot be accessed
synchronously so in order to get the initial state from the DB we must wait for
it to load first. This is why the application start must be wrapped in this
plugin.
### Why not load the default initial state first, and then apply indexedDB?
If the default initial state is loaded from the application before `indexedDB`
kicks in, there will be a flash of unstyled content. It's better to have
generic server side rendering (e.g. can be cached by CDNs) to lower the time to
first rendering, and then load the initial state from the local database after
that to serve the first uncacheable content. This will provide a smooth
experience; and with the addition of a few CSS transitions it might become
impressive even.
## Why would I want to load content from indexedDB?
Because time to first render matters, and connectivity might not always be
great, or available even. By synchronizing the application state with indexedDB
the biggest win for offline has already been achieved: users will be able to
pick up right where they left off; even if internet goes down. From there on
out, caching outgoing HTTP requests and other fancy connectivity tricks could
be applied. Consider this package as an easy way to get a big win for offline
first.
## Should I use this while developing.

@@ -94,11 +50,7 @@ No; state is persisted between page reloads which might put your page in very

## How / when should I invalidate the database cache?
Not sure yet; if you've got good ideas for upgrading / invalidating the local
database I'd love to hear from you; I'm sure people will run into this down the
road anyway.
Ah, this is where good ol' data persistance comes into play - there's loads of
approaches on this, but yeah you should def find a way to migrate data between
incompatible models. Perhaps some day we'll have a good chapter on this in the
choo handbook. Until then: have fun I guess?
## Can I use this with something other than choo?
Welp, there's not much code but if it talks the same API then yeah sure you
can. This is a bit specific to choo tho; but there's nothing stopping people
from building their own choo soooo...
## License

@@ -105,0 +57,0 @@ [MIT](https://tldrlegal.com/license/mit-license)

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc