Skip to content

Commit

Permalink
(pouchdb/express-pouchdb#232) - Modernize pouchdb-seamless-auth
Browse files Browse the repository at this point in the history
  • Loading branch information
marten-de-vries committed Dec 28, 2015
1 parent 9aee614 commit a773d17
Show file tree
Hide file tree
Showing 8 changed files with 294 additions and 71 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules
dist
coverage
30 changes: 30 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
sudo: false
language: node_js

cache:
directories:
- node_modules

node_js:
- "0.10"

services:
- couchdb

before_install:
- npm i -g npm@^2.0.0

before_script:
- npm prune

script: npm run $COMMAND

env:
matrix:
- COMMAND='helper -- lint'
- COMMAND='helper -- js-test'
- COMMAND='build'

#after_success:
# - npm run helper -- semantic-release

83 changes: 81 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
pouchdb-seamless-auth
=====================

[![Build Status](https://travis-ci.org/marten-de-vries/pouchdb-seamless-auth.svg?branch=master)](https://travis-ci.org/marten-de-vries/pouchdb-seamless-auth)
[![Dependency Status](https://david-dm.org/marten-de-vries/pouchdb-seamless-auth.svg)](https://david-dm.org/marten-de-vries/pouchdb-seamless-auth)
[![devDependency Status](https://david-dm.org/marten-de-vries/pouchdb-seamless-auth/dev-status.svg)](https://david-dm.org/marten-de-vries/pouchdb-seamless-auth#info=devDependencies)

Seamless switching between online (CouchDB) and offline (PouchDB)
authentication.

Expand All @@ -11,6 +15,81 @@ app, you should include a checkbox 'I trust this computer' and only use
back to **pouchdb-auth**. This functionality might be implemented as
part of the plug-in in the future.

See also [pouchdb-seamless-auth's documentation](http://pythonhosted.org/Python-PouchDB/js-plugins.html#pouchdb-seamless-auth-plug-in)
API
---

NodeJS package name: [pouchdb-seamless-auth](https://www.npmjs.org/package/pouchdb-seamless-auth)
Browser object name: ``window.SeamlessAuth``

This plug-in provides a convenience layer on top of the PouchDB Auth
plug-in. By default, it users a local database named ``_users`` as
backend for its log in, log out and get session actions. But, when you
set a remote database, that local database is synced with the given
database. In other words, it allows you to let your user log in one
time using the remote database, and from that moment on you can also the
session functions while offline! Very handy when using a per-user
database set up that PouchDB syncs.

Instead of passing this plug-in to the ``PouchDB.plugin()`` function, install
it like this:

```javascript
//NodeJS
require("pouchdb-seamless-auth")(PouchDB)

//Browser
SeamlessAuth(PouchDB)
```

After that is finished (a promise is returned to help determine when that is),
all functions documented below are available on the ``PouchDB`` object.

### PouchDB.setSeamlessAuthRemoteDB(remoteName[, remoteOptions[, callback]])

Set a remote database to be seamlessly synced to.

**Parameters**:

- *string* remoteName: The url to the remote database. Passed to the
``PouchDB`` constructor as the first argument.
- *object* remoteOptions: Options to pass on to the ``PouchDB`` constructor
as its second argument.
- *function* callback: An alternative for the returned promise.

**Returns**: a promise, which resolves to nothing when the remote database is
completely set up.

### PouchDB.unsetSeamlessAuthRemoteDB()

A synchronous function. Undos what ``PouchDB.setSeamlessAuthRemoteDB()`` did.

**Returns**: nothing.

### PouchDB.seamlessSession([opts[, callback]])

See **pouchdb-auth**'s ``db.session()``.

### PouchDB.seamlessLogIn(username, password, [opts[, callback]])

See **pouchdb-auth**'s ``db.logIn()``.

### PouchDB.seamlessLogOut([opts[, callback]])

See **pouchdb-auth**'s ``db.logOut()``.

### PouchDB.seamlessSignUp(username, password, [opts[, callback]])

See **pouchdb-auth**'s ``db.signUp()``.

### PouchDB.invalidateSeamlessAuthCache()

Used to invalidate the cache manually.

This is a synchronous function. Because an application might call
``PouchDB.seamlessSession()`` a lot of times, that method is cached. For most
of the time, you don't have to worry about that, because log in, log out and
sign up all invalidate that cache, making it pretty much unnoticable. There is
one known exception: when changing the user document in ``_users`` manually.
Call this to invalidate the cache when you do that.

[Website of this plug-in and a few others](http://python-pouchdb.marten-de-vries.nl/plugins.html)
**Returns**: nothing.
70 changes: 35 additions & 35 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2014, Marten de Vries
Copyright 2014-2015, Marten de Vries
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand All @@ -14,20 +14,20 @@
limitations under the License.
*/

"use strict";
'use strict';

var Auth = require("pouchdb-auth");
var extend = require("extend");
var Promise = require("pouchdb-promise");
var nodify = require("promise-nodify");
var Auth = require('pouchdb-auth');
var extend = require('extend');
var Promise = require('pouchdb-promise');
var nodify = require('promise-nodify');

var PouchDB, local, remote;
var cacheInvalidated;
var cache;

module.exports = function (thePouchDB) {
PouchDB = thePouchDB;
local = new PouchDB("_users");
local = new PouchDB('_users');

return Auth.useAsAuthenticationDB.call(local)
.then(invalidateCache)
Expand Down Expand Up @@ -63,12 +63,12 @@ api.invalidateSeamlessAuthCache = function () {
};

api.seamlessSession = function (opts, callback) {
//Getting the session is something that can happen quite often in a
//row. HTTP is slow (and _session is not HTTP cached), so a manual
//cache is implemented here.
// Getting the session is something that can happen quite often in a row. HTTP
// is slow (and _session is not HTTP cached), so a manual cache is implemented
// here.
var args = parseArgs(opts, callback);
if (cacheInvalidated) {
cache = callFromAvailableSource("session", args.opts)
cache = callFromAvailableSource('session', args.opts)
.then(function (info) {
if (info.resp.userCtx.name !== null) {
return startReplication(info.resp.userCtx.name, info);
Expand All @@ -85,7 +85,7 @@ api.seamlessSession = function (opts, callback) {

api.seamlessLogIn = function (username, password, opts, callback) {
var args = parseArgs(opts, callback);
var promise = callFromAvailableSource("logIn", username, password, args.opts, args.callback)
var promise = callFromAvailableSource('logIn', username, password, args.opts)
.then(startReplication.bind(null, username))
.then(invalidateCache)
.then(returnResp);
Expand All @@ -95,7 +95,7 @@ api.seamlessLogIn = function (username, password, opts, callback) {

api.seamlessLogOut = function (opts, callback) {
var args = parseArgs(opts, callback);
var promise = callFromAvailableSource("logOut", args.opts, args.callback)
var promise = callFromAvailableSource('logOut', args.opts)
.then(invalidateCache)
.then(returnResp);
nodify(promise, args.callback);
Expand All @@ -104,33 +104,33 @@ api.seamlessLogOut = function (opts, callback) {

api.seamlessSignUp = function (username, password, opts, callback) {
var args = parseArgs(opts, callback);
var promise = callFromAvailableSource("signUp", username, password, args.opts, args.callback)
var promise = callFromAvailableSource('signUp', username, password, args.opts)
.then(startReplication.bind(null, username))
.then(invalidateCache)
.then(returnResp);
nodify(promise, callback);
nodify(promise, args.callback);
return promise;
};

function callFromAvailableSource(name/*, arg1, ...*/) {
var args = Array.prototype.slice.call(arguments, 1);
return Promise.resolve()
.then(function () {
//promisifies the 'undefined has no attribute apply' error too
//when in a then-function instead of on top.
return remote[name].apply(remote, args)
.then(function (resp) {
return {
type: "remote",
resp: resp
};
});
// promisifies the 'undefined has no attribute apply' error too when in a
// then-function instead of on top.
return remote[name].apply(remote, args);
})
.then(function (resp) {
return {
type: 'remote',
resp: resp
};
})
.catch(function () {
return local[name].apply(local, args)
.then(function (resp) {
return {
type: "local",
type: 'local',
resp: resp
};
});
Expand All @@ -142,7 +142,7 @@ function returnResp(info) {
}

function parseArgs(opts, callback) {
if (typeof opts === "function") {
if (typeof opts === 'function') {
callback = opts;
opts = {};
}
Expand All @@ -153,13 +153,13 @@ function parseArgs(opts, callback) {
}

function startReplication(username, info) {
//can't use real replication because the changes feed of _users isn't
//publicly accessable for non-admins.
if (info.type === "remote") {
//can only 'replicate' when the remote db is available.
var getRemote = remote.get("org.couchdb.user:" + username, {revs: true})
// can't use real replication because the changes feed of _users isn't
// publicly accessable for non-admins.
if (info.type === 'remote') {
// can only 'replicate' when the remote db is available.
var getRemote = remote.get('org.couchdb.user:' + username, {revs: true})
.catch(useEmptyDoc);
var getLocal = local.get("org.couchdb.user:" + username, {revs: true})
var getLocal = local.get('org.couchdb.user:' + username, {revs: true})
.catch(useEmptyDoc);
Promise.all([getRemote, getLocal])
.then(Function.prototype.apply.bind(function (remoteDoc, localDoc) {
Expand All @@ -168,8 +168,8 @@ function startReplication(username, info) {
} else if (remoteDoc._rev < localDoc._rev) {
remote.bulkDocs([localDoc], {new_edits: false});
} else {
//both were up-to-date already. Prevent cache invalidation by
//returning directly.
// both were up-to-date already. Prevent cache invalidation by
// returning directly.
return;
}
invalidateCache();
Expand All @@ -179,5 +179,5 @@ function startReplication(username, info) {
}

function useEmptyDoc() {
return {_rev: "0"};
return {_rev: '0'};
}
70 changes: 36 additions & 34 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,36 +1,38 @@
{
"name": "pouchdb-seamless-auth",
"version": "1.0.2",
"main": "index.js",
"description": "Seamless switching between online (CouchDB) and offline (PouchDB) authentication.",
"repository": "marten-de-vries/pouchdb-seamless-auth",
"keywords": [
"pouch",
"pouchdb",
"couch",
"couchdb",
"users",
"authentication",
"auth",
"seamless",
"online",
"offline"
],
"license": "Apache-2.0",
"author": "Marten de Vries",
"dependencies": {
"pouchdb-promise": "^0.0.0",
"extend": "^1.2.1",
"promise-nodify": "^1.0.0",
"pouchdb-auth": "^1.0.0"
},
"devDependencies": {
"browserify": "^4.1.8",
"uglify-js": "^2.4.13",
"es3ify": "^0.1.3"
},
"scripts": {
"build-js": "mkdir -p dist && browserify index.js -s SeamlessAuth -g es3ify -o dist/pouchdb-seamless-auth.js",
"build": "npm run build-js; cd dist; uglifyjs pouchdb-seamless-auth.js -mc > pouchdb-seamless-auth.min.js"
}
"name": "pouchdb-seamless-auth",
"version": "1.0.3",
"main": "index.js",
"description": "Seamless switching between online (CouchDB) and offline (PouchDB) authentication.",
"repository": {
"type": "git",
"url": "https://github.com/marten-de-vries/pouchdb-seamless-auth.git"
},
"keywords": [
"pouch",
"pouchdb",
"couch",
"couchdb",
"users",
"authentication",
"auth",
"seamless",
"online",
"offline"
],
"license": "Apache-2.0",
"author": "Marten de Vries",
"dependencies": {
"pouchdb-promise": "^0.0.0",
"extend": "^1.2.1",
"promise-nodify": "^1.0.0",
"pouchdb-auth": "^2.0.0"
},
"devDependencies": {
"pouchdb-plugin-helper": "^2.0.1"
},
"scripts": {
"helper": "./node_modules/.bin/pouchdb-plugin-helper",
"test": "npm run helper -- test",
"build": "npm run helper -- build SeamlessAuth"
}
}
Loading

0 comments on commit a773d17

Please sign in to comment.