@stanlemon/react-couchdb-authentication
Advanced tools
Comparing version 0.8.13 to 0.8.14
@@ -32,18 +32,2 @@ "use strict"; | ||
function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } | ||
function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } | ||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } | ||
function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } | ||
function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; } | ||
function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } | ||
function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } } | ||
const ROUTE_LOGIN = "login"; | ||
@@ -75,154 +59,40 @@ const ROUTE_SIGNUP = "signup"; | ||
var _localDb = /*#__PURE__*/new WeakMap(); | ||
class Authentication extends React.Component { | ||
static defaultProps = { | ||
login: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Login.Login, { | ||
component: _LoginView.LoginView | ||
}), | ||
signup: /*#__PURE__*/(0, _jsxRuntime.jsx)(_SignUp.SignUp, { | ||
component: _SignUpView.SignUpView | ||
}), | ||
loading: /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, { | ||
children: "Loading..." | ||
}), | ||
debug: false, | ||
sync: true, | ||
localDbName: "user", | ||
adapter: "idb", | ||
sessionInterval: 15000, | ||
scaffold: true | ||
}; | ||
state = { | ||
// If errors bubble up and need to be provided to the login screen | ||
error: undefined, | ||
// Used to denote before/after we've attempted an initial login | ||
loaded: false, | ||
// Whether or not a user is logged in | ||
authenticated: false, | ||
// User object, if they are logged in | ||
user: undefined, | ||
// Internal route path, defaults to the login screen | ||
internalRoute: ROUTE_LOGIN | ||
}; | ||
#localDb; | ||
#remoteDb; | ||
#syncHandler; | ||
#checkSessionInterval; | ||
var _remoteDb = /*#__PURE__*/new WeakMap(); | ||
var _syncHandler = /*#__PURE__*/new WeakMap(); | ||
var _checkSessionInterval = /*#__PURE__*/new WeakMap(); | ||
class Authentication extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
_defineProperty(this, "state", { | ||
// If errors bubble up and need to be provided to the login screen | ||
error: undefined, | ||
// Used to denote before/after we've attempted an initial login | ||
loaded: false, | ||
// Whether or not a user is logged in | ||
authenticated: false, | ||
// User object, if they are logged in | ||
user: undefined, | ||
// Internal route path, defaults to the login screen | ||
internalRoute: ROUTE_LOGIN | ||
}); | ||
_classPrivateFieldInitSpec(this, _localDb, { | ||
writable: true, | ||
value: void 0 | ||
}); | ||
_classPrivateFieldInitSpec(this, _remoteDb, { | ||
writable: true, | ||
value: void 0 | ||
}); | ||
_classPrivateFieldInitSpec(this, _syncHandler, { | ||
writable: true, | ||
value: void 0 | ||
}); | ||
_classPrivateFieldInitSpec(this, _checkSessionInterval, { | ||
writable: true, | ||
value: void 0 | ||
}); | ||
_defineProperty(this, "signUp", async (username, password, email) => { | ||
if (!username || !password || !email) { | ||
this.setState({ | ||
error: "Username, password and email are required fields." | ||
}); | ||
return; | ||
} | ||
const userId = "org.couchdb.user:" + username; | ||
const user = { | ||
name: username, | ||
password, | ||
roles: [], | ||
type: "user", | ||
_id: userId, | ||
// TODO: Allow for any metadata | ||
metadata: { | ||
} | ||
}; | ||
try { | ||
const response = await this.fetch(this.props.url + "_users/" + userId, { | ||
method: "PUT", | ||
body: JSON.stringify(user) | ||
}); | ||
if (response.error) { | ||
//{error: "conflict", reason: "Document update conflict."} | ||
this.setState({ | ||
error: response.reason | ||
}); | ||
return; | ||
} | ||
if (!response.ok) { | ||
this.setState({ | ||
error: "An unknown error has occurred" | ||
}); | ||
} | ||
await this.checkForDb(username); | ||
await this.login(username, password); | ||
} catch (err) { | ||
this.error(err); | ||
} | ||
}); | ||
_defineProperty(this, "logout", () => { | ||
void (async () => { | ||
try { | ||
await this.fetch(this.props.url + "_session", { | ||
method: "DELETE" | ||
}); // Clear the user and redirect them to our login screen | ||
this.setState({ | ||
user: undefined, | ||
authenticated: false, | ||
internalRoute: ROUTE_LOGIN | ||
}); | ||
} catch (err) { | ||
this.error(err); | ||
} | ||
})(); | ||
}); | ||
_defineProperty(this, "login", async (username, password) => { | ||
if (!username || !password) { | ||
this.setState({ | ||
error: "Invalid login" | ||
}); | ||
return; | ||
} | ||
try { | ||
const response = await this.fetch(this.props.url + "_session", { | ||
method: "POST", | ||
body: JSON.stringify({ | ||
username, | ||
password | ||
}) | ||
}); | ||
const userError = response; // If the login fails, set the reason as error and make sure we show as unauthenticated | ||
if (!userError || userError.error) { | ||
this.setState({ | ||
authenticated: false, | ||
error: userError.reason | ||
}); | ||
return; | ||
} | ||
const user = response; | ||
this.setState({ | ||
authenticated: true, | ||
user | ||
}); | ||
this.setupDb(username, password); | ||
} catch (err) { | ||
this.setState({ | ||
authenticated: false, | ||
user: undefined | ||
}); | ||
this.error(err); | ||
} | ||
}); | ||
if (!this.props.url) { | ||
@@ -232,5 +102,5 @@ throw new Error("A url to a couchdb instance is required"); | ||
_classPrivateFieldSet(this, _localDb, new _pouchdb.default(this.props.localDbName, { | ||
this.#localDb = new _pouchdb.default(this.props.localDbName, { | ||
adapter: this.props.adapter | ||
})); | ||
}); | ||
} // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
@@ -269,2 +139,50 @@ | ||
signUp = async (username, password, email) => { | ||
if (!username || !password || !email) { | ||
this.setState({ | ||
error: "Username, password and email are required fields." | ||
}); | ||
return; | ||
} | ||
const userId = "org.couchdb.user:" + username; | ||
const user = { | ||
name: username, | ||
password, | ||
roles: [], | ||
type: "user", | ||
_id: userId, | ||
// TODO: Allow for any metadata | ||
metadata: { | ||
} | ||
}; | ||
try { | ||
const response = await this.fetch(this.props.url + "_users/" + userId, { | ||
method: "PUT", | ||
body: JSON.stringify(user) | ||
}); | ||
if (response.error) { | ||
//{error: "conflict", reason: "Document update conflict."} | ||
this.setState({ | ||
error: response.reason | ||
}); | ||
return; | ||
} | ||
if (!response.ok) { | ||
this.setState({ | ||
error: "An unknown error has occurred" | ||
}); | ||
} | ||
await this.checkForDb(username); | ||
await this.login(username, password); | ||
} catch (err) { | ||
this.error(err); | ||
} | ||
}; | ||
async checkForDb(username) { | ||
@@ -300,3 +218,3 @@ await (0, _asyncRetry.default)(async () => { | ||
// not support storing cross-origin cookies across multiple requests. | ||
if (_classPrivateFieldGet(this, _remoteDb) && this.state && this.state.user && this.state.user.name) { | ||
if (this.#remoteDb && this.state && this.state.user && this.state.user.name) { | ||
const user = await this.fetch(`${this.props.url}/_users/org.couchdb.user:${this.state.user.name}`).catch(err => this.error(err)); | ||
@@ -321,3 +239,3 @@ return user; | ||
if (isLoggedIn && !_classPrivateFieldGet(this, _remoteDb)) { | ||
if (isLoggedIn && !this.#remoteDb) { | ||
this.log("User is already logged in, setting up db."); | ||
@@ -338,2 +256,60 @@ this.setupDb(); // Immediately check the session again so we fully load the user | ||
logout = () => { | ||
void (async () => { | ||
try { | ||
await this.fetch(this.props.url + "_session", { | ||
method: "DELETE" | ||
}); // Clear the user and redirect them to our login screen | ||
this.setState({ | ||
user: undefined, | ||
authenticated: false, | ||
internalRoute: ROUTE_LOGIN | ||
}); | ||
} catch (err) { | ||
this.error(err); | ||
} | ||
})(); | ||
}; | ||
login = async (username, password) => { | ||
if (!username || !password) { | ||
this.setState({ | ||
error: "Invalid login" | ||
}); | ||
return; | ||
} | ||
try { | ||
const response = await this.fetch(this.props.url + "_session", { | ||
method: "POST", | ||
body: JSON.stringify({ | ||
username, | ||
password | ||
}) | ||
}); | ||
const userError = response; // If the login fails, set the reason as error and make sure we show as unauthenticated | ||
if (!userError || userError.error) { | ||
this.setState({ | ||
authenticated: false, | ||
error: userError.reason | ||
}); | ||
return; | ||
} | ||
const user = response; | ||
this.setState({ | ||
authenticated: true, | ||
user | ||
}); | ||
this.setupDb(username, password); | ||
} catch (err) { | ||
this.setState({ | ||
authenticated: false, | ||
user: undefined | ||
}); | ||
this.error(err); | ||
} | ||
}; | ||
setupDb(username, password) { | ||
@@ -361,6 +337,4 @@ const opts = { | ||
const userDbUrl = this.getUserDbUrl(this.state.user.name); | ||
this.#remoteDb = new _pouchdb.default(userDbUrl, opts); // This is because we're setting important properties that aren't in state | ||
_classPrivateFieldSet(this, _remoteDb, new _pouchdb.default(userDbUrl, opts)); // This is because we're setting important properties that aren't in state | ||
this.forceUpdate(); | ||
@@ -373,8 +347,7 @@ | ||
_classPrivateFieldSet(this, _syncHandler, _pouchdb.default.sync(_classPrivateFieldGet(this, _localDb), _classPrivateFieldGet(this, _remoteDb), { | ||
this.#syncHandler = _pouchdb.default.sync(this.#localDb, this.#remoteDb, { | ||
live: true, | ||
retry: true | ||
})); | ||
_classPrivateFieldGet(this, _syncHandler).on("change", info => this.log("Change", info)).on("paused", info => this.log("Syncing Paused", info)).on("complete", info => this.log("Complete", info)).on("error", err => this.error("Error", err)).catch(err => this.error(err)); | ||
}); | ||
this.#syncHandler.on("change", info => this.log("Change", info)).on("paused", info => this.log("Syncing Paused", info)).on("complete", info => this.log("Complete", info)).on("error", err => this.error("Error", err)).catch(err => this.error(err)); | ||
} | ||
@@ -384,21 +357,20 @@ | ||
await this.checkSession(); | ||
_classPrivateFieldSet(this, _checkSessionInterval, window.setInterval(() => { | ||
this.#checkSessionInterval = window.setInterval(() => { | ||
// eslint-disable-next-line @typescript-eslint/no-floating-promises | ||
this.checkSession(); | ||
}, this.props.sessionInterval)); | ||
}, this.props.sessionInterval); | ||
} | ||
async componentWillUnmount() { | ||
if (_classPrivateFieldGet(this, _checkSessionInterval)) { | ||
window.clearInterval(_classPrivateFieldGet(this, _checkSessionInterval)); | ||
if (this.#checkSessionInterval) { | ||
window.clearInterval(this.#checkSessionInterval); | ||
} // Will not be set if sync has been disabled | ||
if (_classPrivateFieldGet(this, _syncHandler)) { | ||
_classPrivateFieldGet(this, _syncHandler).cancel(); | ||
if (this.#syncHandler) { | ||
this.#syncHandler.cancel(); | ||
} | ||
if (_classPrivateFieldGet(this, _remoteDb)) { | ||
await _classPrivateFieldGet(this, _remoteDb).close(); | ||
if (this.#remoteDb) { | ||
await this.#remoteDb.close(); | ||
} | ||
@@ -409,3 +381,3 @@ } | ||
// If we haven't completed our initial load yet, show a loader | ||
if (!this.state.loaded || !_classPrivateFieldGet(this, _localDb)) { | ||
if (!this.state.loaded || !this.#localDb) { | ||
this.log("Waiting for initial database"); | ||
@@ -428,4 +400,4 @@ return this.props.loading; | ||
const value = { | ||
db: _classPrivateFieldGet(this, _localDb), | ||
remoteDb: _classPrivateFieldGet(this, _remoteDb), | ||
db: this.#localDb, | ||
remoteDb: this.#remoteDb, | ||
authenticated: this.state.authenticated, | ||
@@ -463,20 +435,2 @@ user: this.state.user, | ||
exports.Authentication = Authentication; | ||
_defineProperty(Authentication, "defaultProps", { | ||
login: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Login.Login, { | ||
component: _LoginView.LoginView | ||
}), | ||
signup: /*#__PURE__*/(0, _jsxRuntime.jsx)(_SignUp.SignUp, { | ||
component: _SignUpView.SignUpView | ||
}), | ||
loading: /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, { | ||
children: "Loading..." | ||
}), | ||
debug: false, | ||
sync: true, | ||
localDbName: "user", | ||
adapter: "idb", | ||
sessionInterval: 15000, | ||
scaffold: true | ||
}); | ||
//# sourceMappingURL=Authentication.js.map |
@@ -20,42 +20,17 @@ "use strict"; | ||
function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } | ||
function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } | ||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } | ||
function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } | ||
function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } | ||
var _setUsername = /*#__PURE__*/new WeakMap(); | ||
var _setPassword = /*#__PURE__*/new WeakMap(); | ||
class Login extends React.Component { | ||
constructor(...args) { | ||
super(...args); | ||
static defaultProps = { | ||
component: _LoginView.LoginView | ||
}; | ||
state = { | ||
username: "", | ||
password: "" | ||
}; | ||
#setUsername = event => this.setState({ | ||
username: event.target.value | ||
}); | ||
#setPassword = event => this.setState({ | ||
password: event.target.value | ||
}); | ||
_defineProperty(this, "state", { | ||
username: "", | ||
password: "" | ||
}); | ||
_classPrivateFieldInitSpec(this, _setUsername, { | ||
writable: true, | ||
value: event => this.setState({ | ||
username: event.target.value | ||
}) | ||
}); | ||
_classPrivateFieldInitSpec(this, _setPassword, { | ||
writable: true, | ||
value: event => this.setState({ | ||
password: event.target.value | ||
}) | ||
}); | ||
} | ||
render() { | ||
@@ -73,5 +48,5 @@ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Authentication.Context.Consumer, { | ||
username: this.state.username, | ||
setUsername: _classPrivateFieldGet(this, _setUsername), | ||
setUsername: this.#setUsername, | ||
password: this.state.password, | ||
setPassword: _classPrivateFieldGet(this, _setPassword) | ||
setPassword: this.#setPassword | ||
}; | ||
@@ -86,6 +61,2 @@ return /*#__PURE__*/React.createElement(this.props.component, props); | ||
exports.Login = Login; | ||
_defineProperty(Login, "defaultProps", { | ||
component: _LoginView.LoginView | ||
}); | ||
//# sourceMappingURL=Login.js.map |
@@ -20,54 +20,23 @@ "use strict"; | ||
function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } | ||
function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } | ||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } | ||
function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } | ||
function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } | ||
var _setUsername = /*#__PURE__*/new WeakMap(); | ||
var _setEmail = /*#__PURE__*/new WeakMap(); | ||
var _setPassword = /*#__PURE__*/new WeakMap(); | ||
class SignUp extends React.Component { | ||
constructor(...args) { | ||
super(...args); | ||
_defineProperty(this, "state", { | ||
username: "", | ||
email: "", | ||
password: "" | ||
static defaultProps = { | ||
component: _SignUpView.SignUpView | ||
}; | ||
state = { | ||
username: "", | ||
email: "", | ||
password: "" | ||
}; | ||
#setUsername = event => { | ||
this.setState({ | ||
username: event.target.value | ||
}); | ||
}; | ||
#setEmail = event => this.setState({ | ||
email: event.target.value | ||
}); | ||
#setPassword = event => this.setState({ | ||
password: event.target.value | ||
}); | ||
_classPrivateFieldInitSpec(this, _setUsername, { | ||
writable: true, | ||
value: event => { | ||
this.setState({ | ||
username: event.target.value | ||
}); | ||
} | ||
}); | ||
_classPrivateFieldInitSpec(this, _setEmail, { | ||
writable: true, | ||
value: event => this.setState({ | ||
email: event.target.value | ||
}) | ||
}); | ||
_classPrivateFieldInitSpec(this, _setPassword, { | ||
writable: true, | ||
value: event => this.setState({ | ||
password: event.target.value | ||
}) | ||
}); | ||
} | ||
render() { | ||
@@ -87,7 +56,7 @@ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Authentication.Context.Consumer, { | ||
email: this.state.email, | ||
setEmail: _classPrivateFieldGet(this, _setEmail), | ||
setEmail: this.#setEmail, | ||
username: this.state.username, | ||
setUsername: _classPrivateFieldGet(this, _setUsername), | ||
setUsername: this.#setUsername, | ||
password: this.state.password, | ||
setPassword: _classPrivateFieldGet(this, _setPassword) | ||
setPassword: this.#setPassword | ||
}; | ||
@@ -102,6 +71,2 @@ return /*#__PURE__*/React.createElement(this.props.component, props); | ||
exports.SignUp = SignUp; | ||
_defineProperty(SignUp, "defaultProps", { | ||
component: _SignUpView.SignUpView | ||
}); | ||
//# sourceMappingURL=SignUp.js.map |
{ | ||
"name": "@stanlemon/react-couchdb-authentication", | ||
"version": "0.8.13", | ||
"version": "0.8.14", | ||
"description": "React component for authenticating against a CouchDB user db and syncing it locally with PouchDB.", | ||
@@ -43,6 +43,6 @@ "keywords": [ | ||
"@types/isomorphic-fetch": "^0.0.36", | ||
"@types/jest": "^27.5.1", | ||
"@types/jest": "^27.5.2", | ||
"@types/node": "^15.14.9", | ||
"@types/pouchdb": "^6.4.0", | ||
"@types/react": "^18.0.9", | ||
"@types/react": "^18.0.11", | ||
"@types/set-interval-async": "^1.0.0", | ||
@@ -49,0 +49,0 @@ "isomorphic-fetch": "^3.0.0", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
116798
1193