diff --git a/README.md b/README.md
index a2249ed..a6fb2c9 100644
--- a/README.md
+++ b/README.md
@@ -2,13 +2,13 @@
A implementation of Meteor Accounts only in GraphQL with Apollo.
-This package uses the Meteor Accounts methods in GraphQL, it's compatible with the accounts you have saved in your database and you may use apollo-accounts and Meteor's DPP accounts at the same time.
+This package uses the Meteor Accounts methods in GraphQL, it's compatible with the accounts you have saved in your database and you may use apollo-accounts and Meteor's DPP accounts at the same time. It is also compatible with React Native using AsyncStorage (see guide at end of ReadMe).
> Sorry for all the api changes, now we will use [graphql-loader](https://github.com/orionsoft/graphql-loader) for a long term solution.
## Installing
-### Install on Meteor server
+## Install on Meteor server
```sh
meteor add nicolaslopezj:apollo-accounts
@@ -37,7 +37,7 @@ const executableSchema = makeExecutableSchema(schema)
```
-### Install on your apollo app
+## Install on your apollo app
May or may not be the same app.
@@ -45,26 +45,125 @@ May or may not be the same app.
npm install meteor-apollo-accounts
```
-## Examples
+### Examples
- [janikvonrotz/meteor-apollo-accounts-example](https://github.com/janikvonrotz/meteor-apollo-accounts-example): Meteor client and server side.
- [orionsoft/server-boilerplate](https://github.com/orionsoft/server-boilerplate): Large Meteor server side only starter app.
-## Tutorials
+### Tutorials
- [Using Meteor With Apollo and React](https://blog.orionsoft.io/using-meteor-accounts-with-apollo-and-react-df3c89b46b17#.znozw2zbd)
-## Methods
+### Example Usage
+
+```js
+// client.js
+import ApolloClient, { createNetworkInterface } from 'apollo-client';
+import Accounts from 'meteor-apollo-accounts';
+
+const networkInterface = createNetworkInterface({ uri: 'localhost:3000/graphql' });
+
+networkInterface.use([{
+ applyMiddleware(req, next) {
+ if (!req.options.headers) {
+ req.options.headers = {};
+ }
+ req.options.headers.authorization = Accounts.getLoginToken() || null;
+ next();
+ }
+}]);
+
+const client = new ApolloClient({
+ networkInterface,
+ dataIdFromObject: (result) => result._id
+});
+
+export default client;
+```
+
+```js
+// Login.jsx
+import React, { Component } from 'react';
+import Accounts from 'meteor-apollo-accounts';
+import client from './client'; // instance of apollo-client
+
+Accounts.initWithClient(client); //do this only once
+
+Accounts.onLogin(() => {
+ console.log(Accounts.userId());
+});
+
+export default class Login extends Component {
+ constructor() {
+ this.state = {
+ username: '',
+ password: ''
+ };
+ this.login = this.login.bind(this);
+ this.onUsernameChange = this.onUsernameChange.bind(this);
+ this.onPwdChange = this.onPwdChange.bind(this);
+ }
+
+ login(e) {
+ const { username, password } = this.state;
+ e.preventDefault();
+ Accounts.loginWithPassword({ username, password })
+ .catch(function(err) {
+ console.log("Error logging in", err);
+ });
+ }
+
+ onUsernameChange(event) {
+ this.setState({username: event.target.value});
+ }
+
+ onPwdChange(event) {
+ this.setState({password: event.target.value});
+ }
+
+ render() {
+ const { username, password } = this.state;
+ return (
+
+ )
+ }
+}
+
+```
+
+### Methods
Meteor accounts methods, client side only. All methods are promises.
+#### initWithClient
+
+Initialize the accounts system with an instance of Apollo Client. You only need to do this once in your app, typically upon startup.
+
+```js
+import ApolloClient from 'apollo-client';
+import Accounts from 'meteor-apollo-accounts';
+
+const client = new ApolloClient();
+
+Accounts.initWithClient(client);
+```
+
+- ```client```: Your instance of Apollo Client
+
+
#### loginWithPassword
Log the user in with a password.
```js
-import { loginWithPassword } from 'meteor-apollo-accounts'
-
-loginWithPassword({username, email, password, plainPassword}, apollo)
+Accounts.loginWithPassword({username, email, password, plainPassword})
```
- ```username```: Optional. The user's username.
@@ -75,159 +174,150 @@ loginWithPassword({username, email, password, plainPassword}, apollo)
- ```plainPassword```: Optional. The plain user's password. Recommended only for use in testing tools, like GraphiQL.
-- ```apollo```: Apollo client instance.
-#### changePassword
+#### logout
-Change the current user's password. Must be logged in.
+Log the user out.
```js
-import { changePassword } from 'meteor-apollo-accounts'
+Accounts.logout()
+```
+
+#### onLogin
-changePassword({oldPassword, newPassword}, apollo)
+Register a function to be called when a user logged in
+
+```js
+Accounts.onLogin(() => {
+ console.log('Current User: ', Accounts.userId())
+ ...
+ // Fetch data, change routes, etc
+})
```
-- ```oldPassword```: The user's current password. This is not sent in plain text over the wire.
+#### onLoginFailure
-- ```newPassword```: A new password for the user. This is not sent in plain text over the wire.
+Register a function to be called when a login attempt is failed
-- ```apollo```: Apollo client instance.
+```js
+Accounts.onLoginFailure(() => {
+ console.log('Login Failed')
+ ...
+ // Set route to login page, reset store, etc
+})
+```
-#### logout
+#### onLogout
-Log the user out.
+Register a function to be called when a user logs out
+
+```js
+Accounts.onLogout(() => {
+ console.log('User Logged Out')
+ ...
+ // Set route to login page, reset store, etc
+})
+```
+
+#### loggingIn
+
+Returns true if a login method (such as Accounts.loginWithPassword, Accounts.loginWithFacebook, or Accounts.createUser) is currently in progress.
+```js
+console.log('Currently logging in? : ', Accounts.loggingIn())
+```
+
+#### userId
+
+Returns the id of the logged in user.
```js
-import { logout } from 'meteor-apollo-accounts'
+console.log('The user id is:', Accounts.userId())
+```
-logout(apollo)
+#### changePassword
+
+Change the current user's password. Must be logged in.
+
+```js
+Accounts.changePassword({oldPassword, newPassword})
```
-- ```apollo```: Apollo client instance.
+- `oldPassword`: The user's current password. This is not sent in plain text over the wire.
+
+- `newPassword`: A new password for the user. This is not sent in plain text over the wire.
+
#### createUser
Create a new user.
```js
-import { createUser } from 'meteor-apollo-accounts'
-
-createUser({username, email, password, profile}, apollo)
+Accounts.createUser({username, email, password, profile})
```
-- ```username```: A unique name for this user.
+- `username`: A unique name for this user.
-- ```email```: The user's email address.
+- `email`: The user's email address.
-- ```password```: The user's password. This is not sent in plain text over the wire.
+- `password`: The user's password. This is not sent in plain text over the wire.
-- ```profile```: The profile object based on the ```UserProfileInput``` input type.
+- `profile`: The profile object based on the ```UserProfileInput``` input type.
-- ```apollo```: Apollo client instance.
#### verifyEmail
Marks the user's email address as verified. Logs the user in afterwards.
```js
-import { verifyEmail } from 'meteor-apollo-accounts'
-
-verifyEmail({token}, apollo)
+Accounts.verifyEmail({token})
```
- ```token```: The token retrieved from the verification URL.
-- ```apollo```: Apollo client instance.
-
-
#### forgotPassword
Request a forgot password email.
```js
-import { forgotPassword } from 'meteor-apollo-accounts'
-
-forgotPassword({email}, apollo)
+Accounts.forgotPassword({email})
```
- ```email```: The email address to send a password reset link.
-- ```apollo```: Apollo client instance.
-
#### resetPassword
Reset the password for a user using a token received in email. Logs the user in afterwards.
```js
-import { resetPassword } from 'meteor-apollo-accounts'
-
-resetPassword({newPassword, token}, apollo)
+Accounts.resetPassword({newPassword, token})
```
- ```newPassword```: A new password for the user. This is not sent in plain text over the wire.
- ```token```: The token retrieved from the reset password URL.
-- ```apollo```: Apollo client instance.
-
-
#### loginWithFacebook
Logins the user with a facebook accessToken
```js
-import { loginWithFacebook } from 'meteor-apollo-accounts'
-
-loginWithFacebook({accessToken}, apollo)
+Accounts.loginWithFacebook({accessToken})
```
- ```accessToken```: A Facebook accessToken. It's recommended to use
https://github.com/keppelen/react-facebook-login to fetch the accessToken.
-- ```apollo```: Apollo client instance.
-
#### loginWithGoogle
Logins the user with a google accessToken
```js
-import { loginWithGoogle } from 'meteor-apollo-accounts'
-
-loginWithGoogle({accessToken}, apollo)
+Accounts.loginWithGoogle({accessToken})
```
- ```accessToken```: A Google accessToken. It's recommended to use
https://github.com/anthonyjgrove/react-google-login to fetch the accessToken.
-- ```apollo```: Apollo client instance.
-
-
-#### onTokenChange
-
-Register a function to be called when a user is logged in or out.
-
-```js
-import { onTokenChange } from 'meteor-apollo-accounts'
-
-onTokenChange(function () {
- console.log('token did change')
- apollo.resetStore()
-})
-```
-
-#### userId
-
-Returns the id of the logged in user.
-
-```js
-import { userId } from 'meteor-apollo-accounts'
-
-async function () {
- console.log('The user id is:', await userId())
-}
-
-```
-
### React-Native usage
@@ -241,35 +331,58 @@ import {
AsyncStorage
} from 'react-native';
-import { loginWithPassword, userId, setTokenStore} from 'meteor-apollo-accounts'
-
-// Then you'll have to define a TokenStore for your user data using setTokenStore
-// (for instance when your component is mounted):
-setTokenStore({
- set: async function ({userId, token, tokenExpires}) {
- await AsyncStorage.setItem('Meteor.userId', userId)
- await AsyncStorage.setItem('Meteor.loginToken', token)
- // AsyncStorage doesn't support Date type so we'll store it as a String
- await AsyncStorage.setItem('Meteor.loginTokenExpires', tokenExpires.toString())
+import Accounts, { USER_ID_KEY, TOKEN_KEY, TOKEN_EXPIRES_KEY } from 'meteor-apollo-accounts';
+import client from './ApolloClient'; // Your instance of apollo client
+
+// Then you'll have to define a TokenStore for your user data using setTokenStore.
+// This should be done before calling Accounts.initWithClient:
+Accounts.setTokenStore({
+ async set({ userId, token, tokenExpires }) {
+ return AsyncStorage.multiSet([
+ [USER_ID_KEY, userId],
+ [TOKEN_KEY, token],
+ [TOKEN_EXPIRES_KEY, tokenExpires.toString()]
+ ]);
},
- get: async function () {
- return {
- userId: await AsyncStorage.getItem('Meteor.userId'),
- token: await AsyncStorage.getItem('Meteor.loginToken'),
- tokenExpires: await AsyncStorage.getItem('Meteor.loginTokenExpires')
- }
+ async get() {
+ const stores = await AsyncStorage.multiGet([
+ USER_ID_KEY,
+ TOKEN_KEY,
+ TOKEN_EXPIRES_KEY
+ ]);
+
+ const userId = stores[0][1];
+ const token = stores[1][1];
+ const tokenExpires = stores[2][1];
+
+ return { userId, token, tokenExpires };
+ },
+ async remove() {
+ return AsyncStorage.multiRemove([
+ USER_ID_KEY,
+ TOKEN_KEY,
+ TOKEN_EXPIRES_KEY
+ ]);
}
-})
+});
+
+// Make sure to initialize before calling anything else in Accounts:
+Accounts.initWithClient(client);
+
// Finally, you'll be able to use asynchronously any method from the library:
+
+Accounts.onLogin(() => {
+ console.log(Accounts.userId());
+});
+
async login (event) {
event.preventDefault();
try {
- const id_ = await loginWithPassword({ "email", "password" }, this.client)
- this.client.resetStore()
+ const id = await Accounts.loginWithPassword({ "email", "password" })
} catch (error) {
-
+ console.log("Error logging in: ", error);
}
}
diff --git a/client/CHANGELOG.md b/client/CHANGELOG.md
index b4ce074..369128d 100644
--- a/client/CHANGELOG.md
+++ b/client/CHANGELOG.md
@@ -1,5 +1,13 @@
# Changelog
+### vNEXT
+
+- Add `initWithClient(apolloClientInstance)` function to remove need for passing apollo with every function call
+- Calling `userId()` is now synchronous and more performant since it's cached in memory
+- Added the following hooks/callbacks: `onLogin`, `onLoginFailure`, `onLogout` so the API is similar to Meteor Accounts
+- Added `loggingIn` function, similar to Meteor Accounts
+- Added support for persisting login automatically. As soon as you call `initWithClient` in your app, it will check for a stored token and attempt to login, calling the `onLogin` callback if it succeeds.
+
### v2.0.0
- React Native support.
diff --git a/meteor-server/CHANGELOG.md b/meteor-server/CHANGELOG.md
index 2a5ab71..daa5621 100644
--- a/meteor-server/CHANGELOG.md
+++ b/meteor-server/CHANGELOG.md
@@ -1,5 +1,9 @@
# Changelog
+### vNEXT
+
+- Added `loginWithToken` mutation
+
### v3.0.1
- Fix bug with ```tmeasday:check-npm-versions```.