API to manage databases, access and replications, backed by PouchDB
@hoodie/store-server-api
is a JavaScript API to manage databases, access
as well as persisted continuous replications. All data is persisted using
PouchDB and hence compatible with CouchDB as well as other PouchDB adapters.
var PouchDB = require('pouchdb')
var Store = require('@hoodie/store-server-api')(PouchDB)
Store.open('mydb')
.then(function (store) {
store.findAll().then(function (docs) {})
})
var StoreFactory = require('@hoodie/store-server-api')
var PouchDB = require('pouchdb')
var Store = StoreFactory(PouchDB)
Argument | Type | Description | Required |
---|---|---|---|
PouchDB |
PouchDB Constructor |
PouchDB constructor as returned by require('pouchdb') .
Note that you can set defaults to a PouchDB constructor using PouchDB.defaults(options)
|
Yes |
Returns Store.*
API. See below
Store.open(name)
Argument | Type | Description | Required |
---|---|---|---|
name |
String | Name of database. Based on PouchDB’s configuration, databases will be persisted in CouchDB, using LevelDB, in memory or using a custom adapter. | Yes |
Resolves with Store
instance.
Rejects with
Missing Error |
404 |
Store does not exist |
---|
Store.open('mydb')
.then(function (store) {
// use Hoodie’s store API
})
.catch(function (error) {
if (error.status === 404) {
console.log('Store "mydb" does not exist')
} else {
console.log('Something unexpected happened:', error)
}
})
Store.exists(name)
Argument | Type | Description | Required |
---|---|---|---|
name |
String | Name of database. | Yes |
Resolves with true
/ false
depending on whether database exists or not.
Example
Store.exists('foo')
.then(function (doesExist) {
if (doesExist) {
console.log('Database "foo" exists');
} else {
console.log('Database "foo" does not exists');
}
})
.catch(function (error) {
console.log('Something unexpected happened:', error)
})
Creates a database
Store.create(name, options)
Argument | Type | Description | Required |
---|---|---|---|
name |
String | Name of database. | Yes |
options.access |
String, Array |
Can be 'read' , 'write' or ['read', 'write'] .
|
No |
options.role |
String, Array |
Give access to one or multiple roles. Can only be passed if |
No |
Resolves with name
.
Rejects with:
Conflict Error |
409 |
Store already exist |
---|
Example
Store.create('mydb')
.then(function (dbName) {
console.log('Database %s created', dbName)
})
.catch(function (error) {
if (error.status === 409) {
console.log('Database %s already exists', dbName)
} else {
console.log('Something unexpected happened:', error)
}
})
Deletes a database
Store.destroy(name)
Argument | Type | Description | Required |
---|---|---|---|
name |
String | Name of database. | Yes |
Resolves with name
.
Rejects with:
Missing Error |
404 |
Store does not exist |
---|
Example
Store.destroy('mydb')
.then(function (dbName) {
console.log('Store "mydb" has been destroyed')
})
.catch(function (error) {
if (error.status === 404) {
console.log('Store "mydb" does not exist')
} else {
console.log('Something unexpected happened:', error)
}
})
Store.grant(dbName, options)
Every store is private by default. Read and write access must be granted explicitly. A store can be set to public read / write, or read / write access can be granted to specific roles only.
Behaviors in detail:
'public'
, all other roles will be removedArgument | Type | Description | Required |
---|---|---|---|
name |
String | Name of database. | Yes |
options.access |
String, Array |
Can be 'read' , 'write' or ['read', 'write'] .
|
Yes |
options.role |
String, Array | Give access to one or multiple roles. | No |
Resolves without arguments. Rejects with
Missing Error |
404 |
Store does not exist |
---|
Example
Store.grant('foo', {
access: 'read'
})
.then(function () {
console.log('"foo" can now be read by everyone');
})
.catch(function (error) {
console.log('Something unexpected happened:', error)
})
Store.revoke(dbName, options)
Revoke read / write access entirely or from one / multiple roles.
Argument | Type | Description | Required |
---|---|---|---|
name |
String | Name of database. | Yes |
options.access |
String, Array |
Can be 'read' , 'write' or ['read', 'write'] .
|
Yes |
options.role |
String, Array | Revoke access from one or multiple roles. | No |
Resolves without arguments. Rejects with
Missing Error |
404 |
Store does not exist |
---|
Example
Store.revoke('foo', {
access: 'read'
})
.then(function () {
console.log('"foo" can no longer be read by anyone');
})
.catch(function (error) {
console.log('Something unexpected happened:', error)
})
Store.hasAccess(dbName, options)
Checks if the given role has access to given database.
Argument | Type | Description | Required |
---|---|---|---|
name |
String | Name of database. | Yes |
options.access |
String, Array |
Can be 'read' , 'write' or ['read', 'write'] .
If array passed, checks for access for both.
|
Yes |
options.role |
String, Array | If Array passed, checks if any of the roles has access | No |
Resolves with true
/ false
depending on whether database exists or not.
Example
Store.hasAccess('foo', {
access: 'read'
})
.then(function (hasAccess) {
if (hasAccess) {
console.log('"foo" can be read by everyone');
} else {
console.log('"foo" cannot be read by everyone');
}
})
.catch(function (error) {
console.log('Something unexpected happened:', error)
})
Important: Make sure you have the pouchdb-replication package installed
Store.replicate(source, target, options)
Options are the same as PouchDB.replication. The only difference is that replications with {live: true}
will be persisted and resumed. Because of that, Store.replicate does not return a replication instance, but a Promise which resolves with a replication instance.
Store.cancelReplication(source, target)
Cancels a live replication removes it from the store so it will no longer be resumed. Returns a promise.
A Store instance has the Hoodie Store API (as returned by db.hoodieApi()
).
To get a Store instance call Store.open
// all methods return promises
store.add(object)
store.add([object1, id2])
store.find(id)
store.find(object) // with id property
store.findOrAdd(id, object)
store.findOrAdd(object)
store.findOrAdd([object1, id2])
store.findAll()
store.findAll(filterFunction)
store.update(id, changedProperties)
store.update(id, updateFunction)
store.update(object)
store.update([object1, id2])
store.updateOrAdd(id, object)
store.updateOrAdd(object)
store.updateOrAdd([object1, id2])
store.updateAll(changedProperties)
store.updateAll(updateFunction)
store.remove(id)
store.remove(object)
store.remove([object1, id2])
store.removeAll()
store.removeAll(filterFunction)
store.clear()
// events
store.on('add', function(object, options) {})
store.on('update', function(object, options) {})
store.on('remove', function(object, options) {})
store.on('change', function(eventName, object, options) {})
store.on('clear', function() {})
store.one(eventName, eventHandlerFunction)
store.off(eventName, eventHandlerFunction)
// implicit id prefixes for methods and events
store.withIdPrefix(prefix)
// original PouchDB (http://pouchdb.com/api.html) instance used for the store
store.db
Event | Description | Arguments |
---|---|---|
create |
New store created successfully | name |
destroy |
Existing store destroyed | name |
PouchDB only implements APIs on a database level without
any kind of access control. In order to keep track of all databases, access
settings and replications, we create a meta database hoodie-store
. Every
database that gets created using Store.create()
will also create a document
in hoodie-store
with _id
being db_<db name>
. All continuous replications
are stored with asreplication_<source db name>_<target db name>
.
The database documents have an access
property which we use for access control
on database level.
The replication documents are stored with source
, target
and options
properties. On server start continuous replications are started for all
replication documents.
CouchDB comes with its own REST API, so if it’s accessible at a public URL people
can directly access it. For that reason we set /_security
on each database
created by Hoodie so that it’s only readable by CouchDB admins.