Compare commits
16 Commits
@nhost/rea
...
@nhost/rea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1446a8f13b | ||
|
|
ff75998e93 | ||
|
|
9cc044ca9f | ||
|
|
c65e44b8d6 | ||
|
|
9ec73b4c22 | ||
|
|
94b70e0ce9 | ||
|
|
d108dff4f4 | ||
|
|
7a8e771a72 | ||
|
|
f8fb4bbedd | ||
|
|
c6b1c33a8e | ||
|
|
65b36eff13 | ||
|
|
c192cb9503 | ||
|
|
94ff290264 | ||
|
|
78781ebfec | ||
|
|
63d6059981 | ||
|
|
022d49fb25 |
34
README.md
34
README.md
@@ -1,8 +1,8 @@
|
||||
<div align="center">
|
||||
<img width="237" src="https://raw.githubusercontent.com/nhost/nhost/main/assets/logo.png"/>
|
||||

|
||||
|
||||
<br />
|
||||
<br />
|
||||
<div align="center">
|
||||
|
||||
# Nhost
|
||||
|
||||
<a href="https://docs.nhost.io/get-started">Quickstart</a>
|
||||
<span> • </span>
|
||||
@@ -20,9 +20,9 @@
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
**Nhost is a serverless backend for web and mobile apps** built with the following things in mind:
|
||||
**Nhost is a open-source GraphQL backend,** built with the following things in mind:
|
||||
|
||||
- Open Source
|
||||
- Open-Source
|
||||
- Developer Productivity
|
||||
- SQL
|
||||
- GraphQL
|
||||
@@ -184,6 +184,13 @@ Here are some ways of contributing to making Nhost better:
|
||||
<sub><b>Mrinal Wahal</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/gdangelo">
|
||||
<img src="https://avatars.githubusercontent.com/u/4352286?v=4" width="100;" alt="gdangelo"/>
|
||||
<br />
|
||||
<sub><b>Grégory D'Angelo</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/FuzzyReason">
|
||||
<img src="https://avatars.githubusercontent.com/u/62517920?v=4" width="100;" alt="FuzzyReason"/>
|
||||
@@ -204,15 +211,15 @@ Here are some ways of contributing to making Nhost better:
|
||||
<br />
|
||||
<sub><b>Christopher Möller</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://github.com/jerryjappinen">
|
||||
<img src="https://avatars.githubusercontent.com/u/1101002?v=4" width="100;" alt="jerryjappinen"/>
|
||||
<br />
|
||||
<sub><b>Jerry Jäppinen</b></sub>
|
||||
</a>
|
||||
</td></tr>
|
||||
<tr>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/mustafa-hanif">
|
||||
<img src="https://avatars.githubusercontent.com/u/30019262?v=4" width="100;" alt="mustafa-hanif"/>
|
||||
@@ -247,15 +254,15 @@ Here are some ways of contributing to making Nhost better:
|
||||
<br />
|
||||
<sub><b>Colin Broderick</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://github.com/dohomi">
|
||||
<img src="https://avatars.githubusercontent.com/u/489221?v=4" width="100;" alt="dohomi"/>
|
||||
<br />
|
||||
<sub><b>Dominic Garms</b></sub>
|
||||
</a>
|
||||
</td></tr>
|
||||
<tr>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/alveshelio">
|
||||
<img src="https://avatars.githubusercontent.com/u/8176422?v=4" width="100;" alt="alveshelio"/>
|
||||
@@ -290,7 +297,8 @@ Here are some ways of contributing to making Nhost better:
|
||||
<br />
|
||||
<sub><b>Quentin Decré</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://github.com/komninoschat">
|
||||
<img src="https://avatars.githubusercontent.com/u/29049104?v=4" width="100;" alt="komninoschat"/>
|
||||
|
||||
@@ -409,10 +409,41 @@ const Component = () => {
|
||||
|
||||
## User data
|
||||
|
||||
<!-- TODO ellaborate -->
|
||||
|
||||
```js
|
||||
const userData = useUserData()
|
||||
const { id, email, displayName, avatarUrl, isAnonymous, locale, defaultRole, roles, metadata, createdAt } = useUserData()
|
||||
```
|
||||
|
||||
| Name | Type | Default | Notes |
|
||||
| ------------- | ------------- | ---------------- | ------------------------------------------------------ |
|
||||
| `id` | string | | User's unique identifier (uuid) |
|
||||
| `email` | string | | User's email address |
|
||||
| `displayName` | string | `""` | User's display name |
|
||||
| `avatarUrl` | string | `""` | The URL to the user's profile picture |
|
||||
| `isAnonymous` | boolean | `false` | Whether or not the user is anonymous |
|
||||
| `locale` | string | `"en"` | A two-characters locale |
|
||||
| `defaultRole` | string | `"user"` | The default role of the user |
|
||||
| `roles` | string[] | `["me", "user"]` | The roles assigned to the user |
|
||||
| `metadata` | JSON object | `null` | Additional attributes used for user information |
|
||||
| `createdAt` | string | | The date-time when the user has been created |
|
||||
|
||||
Example of an authenticated user:
|
||||
|
||||
```json
|
||||
{
|
||||
"avatarUrl": "https://s.gravatar.com/avatar/3020737ed9d932c6665111a5550454d2?r=g&default=blank",
|
||||
"createdAt": "2022-04-11T16:33:14.780439+00:00",
|
||||
"defaultRole": "user",
|
||||
"displayName": "Grégory D'Angelo",
|
||||
"email": "greg@nhost.io",
|
||||
"id": "05e054c7-a722-42e7-90a6-3f77a2f118c8",
|
||||
"isAnonymous": false,
|
||||
"locale": "en",
|
||||
"metadata": {
|
||||
"lastName": "D'Angelo",
|
||||
"firstName": "Grégory"
|
||||
},
|
||||
"roles": ["user", "me"]
|
||||
}
|
||||
```
|
||||
|
||||
### Avatar
|
||||
|
||||
@@ -4,49 +4,67 @@ title: 'Protecting routes'
|
||||
|
||||
## React Router
|
||||
|
||||
You can protect routes by creating an `AuthGate` component when using `@nhost/react` with [React Router](https://reactrouter.com/web/guides/quick-start).
|
||||
> This example uses the latest version of [React Router (v6)](https://reactrouter.com/docs/en/v6).
|
||||
|
||||
You can protect routes by creating a wrapper component, `ProtectedRoute`, to implement the authentication logic using `@nhost/react`.
|
||||
|
||||
```jsx
|
||||
import { useAuthenticationStatus } from '@nhost/react'
|
||||
import { Redirect } from 'react-router-dom'
|
||||
// src/components/ProtectedRoute.js
|
||||
|
||||
export function AuthGate({ children }) {
|
||||
const { isLoading, isAuthenticated } = useAuthenticationStatus()
|
||||
import { useAuthenticationStatus } from '@nhost/react';
|
||||
import { Navigate, Outlet, useLocation } from 'react-router-dom';
|
||||
|
||||
const ProtectedRoute = () => {
|
||||
const { isAuthenticated, isLoading } = useAuthenticationStatus();
|
||||
const location = useLocation();
|
||||
|
||||
if (isLoading) {
|
||||
return <div>Loading...</div>
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
|
||||
if (!isAuthenticated) {
|
||||
return <Redirect to="/login" />
|
||||
return <Navigate to="/login" />;
|
||||
}
|
||||
|
||||
return children
|
||||
}
|
||||
return <Outlet />;
|
||||
};
|
||||
|
||||
export default ProtectedRoute;
|
||||
```
|
||||
|
||||
Then, in your React Router, wrap the `AuthGate` component around the routes you want to protect:
|
||||
So, if the user is not authenticated, we redirect him to the `/login` route using the [`Navigate`](https://reactrouter.com/docs/en/v6/api#navigate) component from React Router. Otherwise, we render the [`Outlet`](https://reactrouter.com/docs/en/v6/api#outlet) component, also provided by React Router, to render the `ProtectedRoute` child route elements.
|
||||
|
||||
Then, in your `App.js` file, you can use a [layout route](https://reactrouter.com/docs/en/v6/getting-started/concepts#layout-route) to wrap the `ProtectedRoute` component around the routes you want to protect:
|
||||
|
||||
```jsx
|
||||
import { AuthGate } from 'components/AuthGate'
|
||||
import { BrowserRouter, Routes, Route } from 'react-router-dom'
|
||||
// src/App.js
|
||||
|
||||
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
||||
import { NhostReactProvider } from '@nhost/react';
|
||||
|
||||
import ProtectedRoute from './components/ProtectedRoute';
|
||||
|
||||
import Home from './pages/Home';
|
||||
import Login from './pages/Login';
|
||||
import Dashboard from './pages/Dashboard';
|
||||
import Profile from './pages/Profile';
|
||||
|
||||
import { nhost } from './lib/nhost';
|
||||
|
||||
export function App() {
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route path="/login">
|
||||
<Login />
|
||||
</Route>
|
||||
|
||||
<Route path="/" exact>
|
||||
{/* Use AuthGate component like this */}
|
||||
<AuthGate>
|
||||
<div>My protected dashboard</div>
|
||||
</AuthGate>
|
||||
</Route>
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
)
|
||||
<NhostReactProvider nhost={nhost}>
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="/login" element={<Login />} />
|
||||
<Route path="/dashboard" element={<ProtectedRoute />}>
|
||||
<Route index element={<Dashboard />} />
|
||||
<Route path="profile" element={<Profile />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
</NhostReactProvider>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @nhost/apollo
|
||||
|
||||
## 0.3.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [63d6059]
|
||||
- Updated dependencies [63d6059]
|
||||
- @nhost/core@0.3.10
|
||||
|
||||
## 0.3.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/apollo",
|
||||
"version": "0.3.8",
|
||||
"version": "0.3.9",
|
||||
"description": "Nhost Apollo Client library",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @nhost/core
|
||||
|
||||
## 0.3.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 63d6059: Set onTokenChanged before the state interpreter started
|
||||
Fixes [#384](https://github.com/nhost/nhost/issues/384), thanks [@noverby](https://github.com/noverby)
|
||||
- 63d6059: Trigger onTokenChanged when token changes
|
||||
Fixes [#373](https://github.com/nhost/nhost/issues/373), thanks [@yureckey](https://github.com/yureckey)
|
||||
|
||||
## 0.3.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/core",
|
||||
"version": "0.3.9",
|
||||
"version": "0.3.10",
|
||||
"description": "Nhost core client library",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -401,7 +401,12 @@ export const createAuthMachine = ({
|
||||
src: 'refreshToken',
|
||||
id: 'refreshToken',
|
||||
onDone: {
|
||||
actions: ['saveSession', 'persist', 'resetTimer'],
|
||||
actions: [
|
||||
'saveSession',
|
||||
'persist',
|
||||
'resetTimer',
|
||||
'reportTokenChanged'
|
||||
],
|
||||
target: 'pending'
|
||||
},
|
||||
onError: [
|
||||
|
||||
@@ -32,6 +32,7 @@ export interface Typegen0 {
|
||||
| 'done.invoke.authenticateAnonymously'
|
||||
| 'done.invoke.signInMfaTotp'
|
||||
| 'done.invoke.registerUser'
|
||||
| 'done.invoke.refreshToken'
|
||||
| 'done.invoke.authenticateWithToken'
|
||||
saveRefreshToken: 'done.invoke.importRefreshToken'
|
||||
saveInvalidEmail: 'SIGNIN_PASSWORD' | 'SIGNIN_PASSWORDLESS_EMAIL'
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
# @nhost/hasura-auth-js
|
||||
|
||||
## 1.0.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 63d6059: Add TSDoc information about Nhost client options
|
||||
- 63d6059: Set onTokenChanged before the state interpreter started
|
||||
Fixes [#384](https://github.com/nhost/nhost/issues/384), thanks [@noverby](https://github.com/noverby)
|
||||
- 63d6059: Trigger onTokenChanged when token changes
|
||||
Fixes [#373](https://github.com/nhost/nhost/issues/373), thanks [@yureckey](https://github.com/yureckey)
|
||||
- Updated dependencies [63d6059]
|
||||
- Updated dependencies [63d6059]
|
||||
- @nhost/core@0.3.10
|
||||
|
||||
## 1.0.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/hasura-auth-js",
|
||||
"version": "1.0.10",
|
||||
"version": "1.0.11",
|
||||
"description": "Hasura-auth client",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -54,8 +54,6 @@ const EMAIL_NEEDS_VERIFICATION: ApiError = {
|
||||
}
|
||||
export class HasuraAuthClient {
|
||||
private _client: AuthClient
|
||||
private onTokenChangedSubscriptions: Set<AuthInterpreter> = new Set()
|
||||
private onAuthStateChangedSubscriptions: Set<AuthInterpreter> = new Set()
|
||||
|
||||
constructor({
|
||||
url,
|
||||
@@ -414,17 +412,23 @@ export class HasuraAuthClient {
|
||||
* @docs https://docs.nhost.io/TODO
|
||||
*/
|
||||
onTokenChanged(fn: OnTokenChangedFunction): Function {
|
||||
if (this._client.interpreter)
|
||||
this.onTokenChangedSubscriptions.add(
|
||||
this._client.interpreter?.onTransition(({ event, context }) => {
|
||||
if (event.type === 'TOKEN_CHANGED') fn(getSession(context))
|
||||
})
|
||||
)
|
||||
else {
|
||||
console.log('onTokenChanged: no interpreter is set yet', fn)
|
||||
}
|
||||
return () => {
|
||||
this.onTokenChangedSubscriptions.forEach((subscription) => subscription.stop())
|
||||
const listen = (interpreter: AuthInterpreter) =>
|
||||
interpreter.onTransition(({ event, context }) => {
|
||||
if (event.type === 'TOKEN_CHANGED') fn(getSession(context))
|
||||
})
|
||||
|
||||
if (this._client.interpreter) {
|
||||
const subscription = listen(this._client.interpreter)
|
||||
return () => subscription.stop()
|
||||
} else {
|
||||
this._client.onStart((client) => {
|
||||
listen(client.interpreter as AuthInterpreter)
|
||||
})
|
||||
return () => {
|
||||
console.log(
|
||||
'onTokenChanged was added before the interpreter started. Cannot unsubscribe listener.'
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -441,18 +445,23 @@ export class HasuraAuthClient {
|
||||
* @docs https://docs.nhost.io/reference/sdk/authentication#nhost-auth-onauthstatechangedevent,-session
|
||||
*/
|
||||
onAuthStateChanged(fn: AuthChangedFunction): Function {
|
||||
if (this._client.interpreter)
|
||||
this.onAuthStateChangedSubscriptions.add(
|
||||
this._client.interpreter?.onTransition(({ event, context }) => {
|
||||
if (event.type === 'SIGNED_IN') fn('SIGNED_IN', getSession(context))
|
||||
else if (event.type === 'SIGNED_OUT') fn('SIGNED_OUT', getSession(context))
|
||||
})
|
||||
)
|
||||
else {
|
||||
console.log('onAuthStateChanged: no interpreter is set yet', fn)
|
||||
}
|
||||
return () => {
|
||||
this.onAuthStateChangedSubscriptions.forEach((subscription) => subscription.stop())
|
||||
const listen = (interpreter: AuthInterpreter) =>
|
||||
interpreter.onTransition(({ event, context }) => {
|
||||
if (event.type === 'SIGNED_IN' || event.type === 'SIGNED_OUT')
|
||||
fn(event.type, getSession(context))
|
||||
})
|
||||
if (this._client.interpreter) {
|
||||
const subscription = listen(this._client.interpreter)
|
||||
return () => subscription.stop()
|
||||
} else {
|
||||
this._client.onStart((client) => {
|
||||
listen(client.interpreter as AuthInterpreter)
|
||||
})
|
||||
return () => {
|
||||
console.log(
|
||||
'onAuthStateChanged was added before the interpreter started. Cannot unsubscribe listener.'
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,14 +12,19 @@ import {
|
||||
export type { AuthClient, Provider, StorageGetter, StorageSetter, User }
|
||||
export interface NhostAuthConstructorParams {
|
||||
url: string
|
||||
/** Time interval until token refreshes, in seconds */
|
||||
refreshIntervalTime?: number
|
||||
/** @deprecated Use clientStorageGetter and clientStorageSetter options instead */
|
||||
clientStorage?: ClientStorage
|
||||
/** @deprecated Use clientStorageGetter and clientStorageSetter options instead */
|
||||
clientStorageType?: ClientStorageType
|
||||
/** Define a way to get information about the refresh token and its exipration date */
|
||||
clientStorageGetter?: StorageGetter
|
||||
/** Define a way to set information about the refresh token and its exipration date */
|
||||
clientStorageSetter?: StorageSetter
|
||||
/** When set to true, will automatically refresh token before it expires */
|
||||
autoRefreshToken?: boolean
|
||||
/** When set to true, will parse the url on startup to check if it contains a refresh token to start the session with */
|
||||
autoLogin?: boolean
|
||||
start?: boolean
|
||||
Client?: typeof AuthClient
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @nhost/nextjs
|
||||
|
||||
## 1.0.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@1.0.11
|
||||
- @nhost/react@0.5.2
|
||||
|
||||
## 1.0.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/nextjs",
|
||||
"version": "1.0.11",
|
||||
"version": "1.0.12",
|
||||
"description": "Nhost NextJS library",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @nhost/nhost-js
|
||||
|
||||
## 1.0.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [63d6059]
|
||||
- Updated dependencies [63d6059]
|
||||
- Updated dependencies [63d6059]
|
||||
- @nhost/hasura-auth-js@1.0.11
|
||||
|
||||
## 1.0.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/nhost-js",
|
||||
"version": "1.0.10",
|
||||
"version": "1.0.11",
|
||||
"description": "Nhost JavaScript SDK",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @nhost/react-apollo
|
||||
|
||||
## 4.0.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@0.5.2
|
||||
- @nhost/apollo@0.3.9
|
||||
|
||||
## 4.0.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/react-apollo",
|
||||
"version": "4.0.11",
|
||||
"version": "4.0.12",
|
||||
"description": "Nhost React Apollo client",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost/react
|
||||
|
||||
## 0.5.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@1.0.11
|
||||
|
||||
## 0.5.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/react",
|
||||
"version": "0.5.1",
|
||||
"version": "0.5.2",
|
||||
"description": "Nhost React library",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
Reference in New Issue
Block a user