Compare commits
30 Commits
nhost-docu
...
@nhost/nex
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ee1df3be4 | ||
|
|
47ffca945e | ||
|
|
d60f5e623c | ||
|
|
6f80643ee0 | ||
|
|
8d5084725d | ||
|
|
693498dd09 | ||
|
|
4d36a966ea | ||
|
|
239a075f1d | ||
|
|
931194812e | ||
|
|
c8f80c58f3 | ||
|
|
7fdb5aee0a | ||
|
|
1710808fef | ||
|
|
696815d4a8 | ||
|
|
5cc9be00b6 | ||
|
|
28dae23a91 | ||
|
|
7819e20cf4 | ||
|
|
6be3758668 | ||
|
|
658c67faf4 | ||
|
|
e7f3a5f6e0 | ||
|
|
7135aee78b | ||
|
|
587eaff734 | ||
|
|
7cf875f4b8 | ||
|
|
657cfb91c5 | ||
|
|
103dd6e98e | ||
|
|
3c8caa680b | ||
|
|
1bcee357fe | ||
|
|
b729aa9290 | ||
|
|
9b840f7c4a | ||
|
|
83d3c90f43 | ||
|
|
058956bdcb |
5
.github/workflows/changesets.yaml
vendored
5
.github/workflows/changesets.yaml
vendored
@@ -30,6 +30,9 @@ jobs:
|
||||
with:
|
||||
node-version: '17.8.0'
|
||||
cache: 'pnpm'
|
||||
- name: Pick the right npm version
|
||||
# * See: https://github.com/pnpm/pnpm/issues/4348
|
||||
run: npm install --global npm@8.4
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
- name: Create PR or Publish release
|
||||
@@ -39,7 +42,7 @@ jobs:
|
||||
version: pnpm run ci:version
|
||||
commit: 'chore: update versions'
|
||||
title: 'chore: update versions'
|
||||
publish: pnpm run ci:publish
|
||||
publish: pnpm run release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
@@ -2,15 +2,15 @@ import { lightNhostTheme } from '@/data/lightTheme'
|
||||
import { useState } from 'react'
|
||||
import { Light as SyntaxHighlighter } from 'react-syntax-highlighter'
|
||||
import js from 'react-syntax-highlighter/dist/cjs/languages/hljs/javascript'
|
||||
import ts from 'react-syntax-highlighter/dist/cjs/languages/hljs/typescript'
|
||||
|
||||
import Check from '../icons/Check'
|
||||
import Copy from '../icons/Copy'
|
||||
|
||||
// @ts-ignore -> add to types
|
||||
// @ts-ignore -> add to types
|
||||
SyntaxHighlighter.registerLanguage('js', js)
|
||||
SyntaxHighlighter.registerLanguage('language-js', js)
|
||||
SyntaxHighlighter.registerLanguage('language-ts', ts)
|
||||
// TODO highlight JSX
|
||||
SyntaxHighlighter.registerLanguage('jsx', js)
|
||||
SyntaxHighlighter.registerLanguage('language-jsx', js)
|
||||
|
||||
export interface CodeEditorProps {
|
||||
code: string
|
||||
@@ -24,7 +24,7 @@ export interface CodeEditorProps {
|
||||
}
|
||||
|
||||
const CodeEditor = (props: CodeEditorProps) => {
|
||||
const { children, url } = props
|
||||
const { children, className } = props
|
||||
const [copied, setCopied] = useState(false)
|
||||
|
||||
return (
|
||||
@@ -53,6 +53,7 @@ const CodeEditor = (props: CodeEditorProps) => {
|
||||
</button>
|
||||
</div>
|
||||
<SyntaxHighlighter
|
||||
language={className}
|
||||
style={lightNhostTheme}
|
||||
wrapLongLines={true}
|
||||
wrapLines={true}
|
||||
|
||||
@@ -45,10 +45,10 @@ title: Environment Variables
|
||||
| AUTH_SMS_TWILIO_FROM | | |
|
||||
| AUTH_EMAIL_SIGNIN_EMAIL_VERIFIED_REQUIRED | When enabled, any email-based authentication requires emails to be verified by a link sent to this email. | `true` |
|
||||
| AUTH_ACCESS_CONTROL_ALLOWED_REDIRECT_URLS | | |
|
||||
| AUTH_MFA_ENABLED | Enables users to use Multi Factor Authentication | `false` |
|
||||
| AUTH_MFA_ENABLED | Enables users to use Multi Factor Authentication. | `false` |
|
||||
| AUTH_MFA_TOTP_ISSUER | The name of the One Time Password (OTP) issuer. Probably your app's name. | `hasura-auth` |
|
||||
| AUTH_ACCESS_TOKEN_EXPIRES_IN | | `900`(15 minutes) |
|
||||
| AUTH_REFRESH_TOKEN_EXPIRES_IN | | `43200` (12 hours) |
|
||||
| AUTH_ACCESS_TOKEN_EXPIRES_IN | Number of seconds before the access token (JWT) expires. | `900`(15 minutes) |
|
||||
| AUTH_REFRESH_TOKEN_EXPIRES_IN | Number of seconds before the refresh token expires. | `2592000` (30 days) |
|
||||
| AUTH_EMAIL_TEMPLATE_FETCH_URL | | |
|
||||
| AUTH_JWT_CUSTOM_CLAIMS | | |
|
||||
|
||||
|
||||
@@ -8,23 +8,25 @@ title: 'Hooks'
|
||||
|
||||
```js
|
||||
const { signUpEmailPassword, isLoading, isSuccess, needsEmailVerification, isError, error } =
|
||||
useSignUpEmailPassword(email?: string, password?: string, options?: Options )
|
||||
useSignUpEmailPassword(options?: Options)
|
||||
```
|
||||
|
||||
| Name | Type | Notes |
|
||||
| ------------------------ | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `signUpEmailPassword` | (email?: string, password?: string) => void | Used for a new user to sign up. The email/password arguments will take precedence over the possible state values used when creating the hook. |
|
||||
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
|
||||
| `needsEmailVerification` | boolean | Returns `true` if the sign-up has been accepted, but a verificaiton email has been sent and is awaiting. |
|
||||
| `isSuccess` | boolean | Returns `true` if the sign-up suceeded. Returns `false` if the new email needs to be verified first, or if an error occurred. |
|
||||
| `isError` | boolean | Returns `true` if an error occurred. |
|
||||
| `error` | {status: number, error: string, message: string} \| undefined | Provides details about the error. |
|
||||
| `options.locale` | string \| undefined | Locale of the user, in two digits, for instance `en`. |
|
||||
| `options.allowedRoles` | string[] \| undefined | Allowed roles of the user. Must be a subset of the default allowed roles defined in Hasura Auth. |
|
||||
| `options.defaultRole` | string \| undefined | Default role of the user. Must be part of the default allowed roles defined in Hasura Auth. |
|
||||
| `options.displayName` | string \| undefined | |
|
||||
| `options.metadata` | Record<string, unknown> \| undefined | Custom additional user information stored in the `metadata` column. Can be any JSON object. |
|
||||
| `options.redirectTo` | string \| undefined | redirection path in the client application that will be used in the link in the verification email. For instance, if you want to redirect to `https://myapp.com/success`, the `redirectTo` value is `'/success'`. |
|
||||
| Name | Type | Notes |
|
||||
| ------------------------ | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `signUpEmailPassword` | (email?: string, password?: string) => void | Used for a new user to sign up. Returns a promise with the current context |
|
||||
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
|
||||
| `needsEmailVerification` | boolean | Returns `true` if the sign-up has been accepted, but a verificaiton email has been sent and is awaiting. |
|
||||
| `isSuccess` | boolean | Returns `true` if the sign-up suceeded. Returns `false` if the new email needs to be verified first, or if an error occurred. |
|
||||
| `isError` | boolean | Returns `true` if an error occurred. |
|
||||
| `error` | {status: number, error: string, message: string} \| null | Provides details about the error. |
|
||||
| `user` | User \| null | User information |
|
||||
| `accessToken` | string \| null | Access token (JWT) |
|
||||
| `options.locale` | string \| undefined | Locale of the user, in two digits, for instance `en`. |
|
||||
| `options.allowedRoles` | string[] \| undefined | Allowed roles of the user. Must be a subset of the default allowed roles defined in Hasura Auth. |
|
||||
| `options.defaultRole` | string \| undefined | Default role of the user. Must be part of the default allowed roles defined in Hasura Auth. |
|
||||
| `options.displayName` | string \| undefined | |
|
||||
| `options.metadata` | Record<string, unknown> \| undefined | Custom additional user information stored in the `metadata` column. Can be any JSON object. |
|
||||
| `options.redirectTo` | string \| undefined | redirection path in the client application that will be used in the link in the verification email. For instance, if you want to redirect to `https://myapp.com/success`, the `redirectTo` value is `'/success'`. |
|
||||
|
||||
#### Usage
|
||||
|
||||
@@ -36,7 +38,7 @@ const Component = () => {
|
||||
const [email, setEmail] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
const { signUpEmailPassword, isLoading, isSuccess, needsEmailVerification, isError, error } =
|
||||
useSignUpEmailPassword(email, password)
|
||||
useSignUpEmailPassword()
|
||||
return (
|
||||
<div>
|
||||
<input value={email} onChange={(event) => setEmail(event.target.value)} placeholder="Email" />
|
||||
@@ -45,7 +47,7 @@ const Component = () => {
|
||||
onChange={(event) => setPassword(event.target.value)}
|
||||
placeholder="Password"
|
||||
/>
|
||||
<button onClick={signUpEmailPassword}>Register</button>
|
||||
<button onClick={() => signUpEmailPassword(email, password)}>Register</button>
|
||||
{isSuccess && <div>Your account have beed created! You are now authenticated</div>}
|
||||
{needsEmailVerification && (
|
||||
<div>Please check your mailbox and follow the verification link to verify your email</div>
|
||||
@@ -58,20 +60,31 @@ const Component = () => {
|
||||
### Email and Password Sign-In
|
||||
|
||||
```js
|
||||
const { signInEmailPassword, isLoading, needsEmailVerification, needsMfaOtp, sendMfaOtp, isSuccess, isError, error } =
|
||||
useSignInEmailPassword(email?: string, password?: string)
|
||||
const {
|
||||
signInEmailPassword,
|
||||
isLoading,
|
||||
needsEmailVerification,
|
||||
needsMfaOtp,
|
||||
sendMfaOtp,
|
||||
isSuccess,
|
||||
isError,
|
||||
error,
|
||||
user
|
||||
} = useSignInEmailPassword()
|
||||
```
|
||||
|
||||
| Name | Type | Notes |
|
||||
| ------------------------ | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `signInEmailPassword` | (email?: string, password?: string) => void | Will try to authenticate. The email/password arguments will take precedence over the possible state values used when creating the hook. |
|
||||
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
|
||||
| `needsEmailVerification` | boolean | Returns `true` if the user email is still pending email verification. |
|
||||
| `needsMfaOtp` | boolean | Returns `true` if the server is awaiting an MFA one-time password to complete the authentication. |
|
||||
| `sendMfaOtp` | (otp: string) => void | Sends MFA One-time password. Will turn either `isSuccess` or `isError` to true, and store potential error in `error`. |
|
||||
| `isSuccess` | boolean | Returns `true` if the user has successfully authenticated. Returns `false` in case or error or if the new email needs to be verified first. |
|
||||
| `isError` | boolean | Returns `true` if an error occurred. |
|
||||
| `error` | {status: number, error: string, message: string} \| undefined | Provides details about the error. |
|
||||
| Name | Type | Notes |
|
||||
| ------------------------ | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `signInEmailPassword` | (email?: string, password?: string) | Will try to authenticate. Returns a promise with the current context |
|
||||
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
|
||||
| `needsEmailVerification` | boolean | Returns `true` if the user email is still pending email verification. |
|
||||
| `needsMfaOtp` | boolean | Returns `true` if the server is awaiting an MFA one-time password to complete the authentication. |
|
||||
| `sendMfaOtp` | (otp: string) => void | Sends MFA One-time password. Will turn either `isSuccess` or `isError` to true, and store potential error in `error`. |
|
||||
| `isSuccess` | boolean | Returns `true` if the user has successfully authenticated. Returns `false` in case or error or if the new email needs to be verified first. |
|
||||
| `isError` | boolean | Returns `true` if an error occurred. |
|
||||
| `error` | {status: number, error: string, message: string} \| null | Provides details about the error. |
|
||||
| `user` | User \| null | User information |
|
||||
| `accessToken` | string \| null | Access token (JWT) |
|
||||
|
||||
#### Usage
|
||||
|
||||
@@ -83,7 +96,7 @@ const Component = () => {
|
||||
const [email, setEmail] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
const { signInEmailPassword, isLoading, isSuccess, needsEmailVerification, isError, error } =
|
||||
useSignInEmailPassword(email, password)
|
||||
useSignInEmailPassword()
|
||||
return (
|
||||
<div>
|
||||
<input value={email} onChange={(event) => setEmail(event.target.value)} placeholder="Email" />
|
||||
@@ -92,7 +105,7 @@ const Component = () => {
|
||||
onChange={(event) => setPassword(event.target.value)}
|
||||
placeholder="Password"
|
||||
/>
|
||||
<button onClick={signInEmailPassword}>Register</button>
|
||||
<button onClick={() => signInEmailPassword(email, password)}>Register</button>
|
||||
{isSuccess && <div>Authentication suceeded</div>}
|
||||
{needsEmailVerification && (
|
||||
<div>
|
||||
@@ -139,12 +152,12 @@ const Component = () => {
|
||||
|
||||
```js
|
||||
const { signInEmailPasswordless, isLoading, isSuccess, isError, error } =
|
||||
useSignInEmailPasswordless(email?: string, options?: Options)
|
||||
useSignInEmailPasswordless(options?: Options)
|
||||
```
|
||||
|
||||
| Name | Type | Notes |
|
||||
| ------------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `signInEmailPasswordless` | (email?: string) => void | Sends a magic link to the given email The email argument will take precedence over the the possible state value used when creating the hook. |
|
||||
| `signInEmailPasswordless` | (email?: string) => void | Sends a magic link to the given email. |
|
||||
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
|
||||
| `isSuccess` | boolean | Returns `true` if the magic link email user has successfully send. |
|
||||
| `isError` | boolean | Returns `true` if an error occurred. |
|
||||
@@ -165,11 +178,11 @@ import { useSignInEmailPasswordless } from '@nhost/react'
|
||||
const Component = () => {
|
||||
const [email, setEmail] = useState('')
|
||||
const { signInEmailPasswordless, isLoading, isSuccess, isError, error } =
|
||||
useSignInEmailPasswordless(email)
|
||||
useSignInEmailPasswordless()
|
||||
return (
|
||||
<div>
|
||||
<input value={email} onChange={(event) => setEmail(event.target.value)} placeholder="Email" />
|
||||
<button onClick={signInEmailPasswordless}>Authenticate</button>
|
||||
<button onClick={() => signInEmailPasswordless(email)}>Authenticate</button>
|
||||
{isSuccess && (
|
||||
<div>
|
||||
An email has been sent to {email}. Please check your mailbox and click on the
|
||||
@@ -253,17 +266,17 @@ const accessToken = useAccessToken()
|
||||
|
||||
```js
|
||||
const { changeEmail, isLoading, isSuccess, needsEmailVerification, isError, error } =
|
||||
useChangeEmail(email?: string, options?: { redirectTo?: string })
|
||||
useChangeEmail(options?: { redirectTo?: string })
|
||||
```
|
||||
|
||||
| Name | Type | Notes |
|
||||
| ------------------------ | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `changeEmail` | (email?: string) => void | Requests the email change. The arguement password will take precedence over the the possible state value used when creating the hook. |
|
||||
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
|
||||
| `needsEmailVerification` | boolean | Returns `true` if the email change has been requested, but that a email has been sent to the user to verify the new email. |
|
||||
| `isError` | boolean | Returns `true` if an error occurred. |
|
||||
| `error` | {status: number, error: string, message: string} \| undefined | Provides details about the error. |
|
||||
| `redirectTo` | string \| undefined | Redirection path in the client application that will be used in the link in the verification email. For instance, if you want to redirect to `https://myapp.com/success`, the `redirectTo` value is `'/success'`. |
|
||||
| Name | Type | Notes |
|
||||
| ------------------------ | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `changeEmail` | (email?: string) => void | Requests the email change. Returns a promise with the current context |
|
||||
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
|
||||
| `needsEmailVerification` | boolean | Returns `true` if the email change has been requested, but that a email has been sent to the user to verify the new email. |
|
||||
| `isError` | boolean | Returns `true` if an error occurred. |
|
||||
| `error` | {status: number, error: string, message: string} \| null | Provides details about the error. |
|
||||
| `redirectTo` | string \| undefined | Redirection path in the client application that will be used in the link in the verification email. For instance, if you want to redirect to `https://myapp.com/success`, the `redirectTo` value is `'/success'`. |
|
||||
|
||||
#### Usage
|
||||
|
||||
@@ -273,12 +286,11 @@ import { useChangeEmail } from '@nhost/react'
|
||||
|
||||
const Component = () => {
|
||||
const [email, setEmail] = useState('')
|
||||
const { changeEmail, isLoading, needsEmailVerification, isError, error } =
|
||||
useChangeEmail(password)
|
||||
const { changeEmail, isLoading, needsEmailVerification, isError, error } = useChangeEmail()
|
||||
return (
|
||||
<div>
|
||||
<input value={email} onChange={(event) => setEmail(event.target.value)} />
|
||||
<button onClick={changeEmail}>Change password</button>
|
||||
<button onClick={() => changeEmail(email)}>Change email</button>
|
||||
{needsEmailVerification && (
|
||||
<div>
|
||||
Please check your mailbox and follow the verification link to confirm your new email
|
||||
@@ -292,16 +304,16 @@ const Component = () => {
|
||||
### Change password
|
||||
|
||||
```js
|
||||
const { changePassword, isLoading, isSuccess, isError, error } = useChangePassword(password?: string)
|
||||
const { changePassword, isLoading, isSuccess, isError, error } = useChangePassword()
|
||||
```
|
||||
|
||||
| Name | Type | Notes |
|
||||
| ---------------- | ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `changePassword` | (password?: string) => void | Requests the password change. The arguement password will take precedence over the the possible state value used when creating the hook. |
|
||||
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
|
||||
| `isSuccess` | boolean | Returns `true` if the password has beed successfully changed. |
|
||||
| `isError` | boolean | Returns `true` if an error occurred. |
|
||||
| `error` | {status: number, error: string, message: string} \| undefined | Provides details about the error. |
|
||||
| Name | Type | Notes |
|
||||
| ---------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------ |
|
||||
| `changePassword` | (password?: string) | Requests the password change. Returns a promise with the current context |
|
||||
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
|
||||
| `isSuccess` | boolean | Returns `true` if the password has beed successfully changed. |
|
||||
| `isError` | boolean | Returns `true` if an error occurred. |
|
||||
| `error` | {status: number, error: string, message: string} \| null | Provides details about the error. |
|
||||
|
||||
#### Usage
|
||||
|
||||
@@ -311,11 +323,11 @@ import { useChangePassword } from '@nhost/react'
|
||||
|
||||
const Component = () => {
|
||||
const [password, setPassword] = useState('')
|
||||
const { changePassword, isLoading, isSuccess, isError, error } = useChangePassword(password)
|
||||
const { changePassword, isLoading, isSuccess, isError, error } = useChangePassword()
|
||||
return (
|
||||
<div>
|
||||
<input value={password} onChange={(event) => setPassword(event.target.value)} />
|
||||
<button onClick={changePassword}>Change password</button>
|
||||
<button onClick={() => changePassword(password)}>Change password</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -326,17 +338,17 @@ const Component = () => {
|
||||
If a user loses their password, we can resend them an email to authenticate so that they can change it to a new one:
|
||||
|
||||
```js
|
||||
const { resetPassword, isLoading, isSent, isError, error } = useResetPassword(email?: string, options?: { redirectTo?: string })
|
||||
const { resetPassword, isLoading, isSent, isError, error } = useResetPassword(options?: { redirectTo?: string })
|
||||
```
|
||||
|
||||
| Name | Type | Notes |
|
||||
| --------------- | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `resetPassword` | (email?: string) => void | Sends an email with a temporary connection link. The arguement email will take precedence over the the possible state value used when creating the hook. |
|
||||
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
|
||||
| `isSent` | boolean | Returns `true` when the email has been successfully sent. |
|
||||
| `isError` | boolean | Returns `true` if an error occurred. |
|
||||
| `error` | {status: number, error: string, message: string} \| undefined | Provides details about the error. |
|
||||
| `redirectTo` | string \| undefined | Redirection path in the client application that will be used in the link in the verification email. For instance, if you want to redirect to `https://myapp.com/success`, the `redirectTo` value is `'/success'`. |
|
||||
| Name | Type | Notes |
|
||||
| --------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `resetPassword` | (email?: string) | Sends an email with a temporary connection link. Returns a promise with the current context |
|
||||
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
|
||||
| `isSent` | boolean | Returns `true` when the email has been successfully sent. |
|
||||
| `isError` | boolean | Returns `true` if an error occurred. |
|
||||
| `error` | {status: number, error: string, message: string} \| null | Provides details about the error. |
|
||||
| `redirectTo` | string \| undefined | Redirection path in the client application that will be used in the link in the verification email. For instance, if you want to redirect to `https://myapp.com/success`, the `redirectTo` value is `'/success'`. |
|
||||
|
||||
#### Usage
|
||||
|
||||
@@ -345,12 +357,12 @@ import { useState } from 'react'
|
||||
import { useResetPassword } from '@nhost/react'
|
||||
|
||||
const Component = () => {
|
||||
const [email, setEamil] = useState('')
|
||||
const { resetPassword, isLoading, isSent, isError, error } = useResetPassword(email?: string)
|
||||
const [email, setEmail] = useState('')
|
||||
const { resetPassword, isLoading, isSent, isError, error } = useResetPassword()
|
||||
return (
|
||||
<div>
|
||||
<input value={email} onChange={(event) => setEmail(event.target.value)} />
|
||||
<button onClick={resetPassword}>Send reset link</button>
|
||||
<button onClick={() => resetPassword(email)}>Send reset link</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -360,17 +372,17 @@ const Component = () => {
|
||||
|
||||
```js
|
||||
const { sendEmail, isLoading, isSent, isError, error } =
|
||||
useSendVerificationEmail(email?: string, options?: { redirectTo?: string })
|
||||
useSendVerificationEmail(options?: { redirectTo?: string })
|
||||
```
|
||||
|
||||
| Name | Type | Notes |
|
||||
| ------------ | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `sendEmail` | (email?: string) => void | Resend the verification email. |
|
||||
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
|
||||
| `isSent` | boolean | Returns `true` if the verification email has been sent |
|
||||
| `isError` | boolean | Returns `true` if an error occurred. |
|
||||
| `error` | {status: number, error: string, message: string} \| undefined | Provides details about the error. |
|
||||
| `redirectTo` | string \| undefined | Redirection path in the client application that will be used in the link in the verification email. For instance, if you want to redirect to `https://myapp.com/success`, the `redirectTo` value is `'/success'`. |
|
||||
| Name | Type | Notes |
|
||||
| ------------ | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `sendEmail` | (email?: string) | Resend the verification email. Returns a promise with the current context |
|
||||
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
|
||||
| `isSent` | boolean | Returns `true` if the verification email has been sent |
|
||||
| `isError` | boolean | Returns `true` if an error occurred. |
|
||||
| `error` | {status: number, error: string, message: string} \| null | Provides details about the error. |
|
||||
| `redirectTo` | string \| undefined | Redirection path in the client application that will be used in the link in the verification email. For instance, if you want to redirect to `https://myapp.com/success`, the `redirectTo` value is `'/success'`. |
|
||||
|
||||
#### Usage
|
||||
|
||||
@@ -380,11 +392,11 @@ import { useSendVerificationEmail } from '@nhost/react'
|
||||
|
||||
const Component = () => {
|
||||
const [email, setEmail] = useState('')
|
||||
const { sendEmail, isLoading, isSent, isError, error } = useSendVerificationEmail(email)
|
||||
const { sendEmail, isLoading, isSent, isError, error } = useSendVerificationEmail()
|
||||
return (
|
||||
<div>
|
||||
<input value={email} onChange={(event) => setEmail(event.target.value)} />
|
||||
<button onClick={sendEmail}>Send email verification</button>
|
||||
<button onClick={() => sendEmail(email)}>Send email verification</button>
|
||||
{isSent && (
|
||||
<div>Please check your mailbox and follow the verification link to confirm your email</div>
|
||||
)}
|
||||
|
||||
@@ -668,6 +668,23 @@
|
||||
"additionalProperties": false,
|
||||
"example": { "firstName": "John", "lastName": "Smith" },
|
||||
"default": {}
|
||||
},
|
||||
"activeMfaType": {
|
||||
"anyOf": [
|
||||
{ "type": "string", "enum": [""] },
|
||||
{ "type": "string", "enum": ["totp"] }
|
||||
],
|
||||
"description": "Multi-factor authentication type. A null value deactivates MFA",
|
||||
"example": "totp"
|
||||
},
|
||||
"emailVerified": { "type": "boolean", "default": false },
|
||||
"phoneNumber": { "type": "string" },
|
||||
"phoneNumberVerified": { "type": "boolean", "default": false },
|
||||
"roles": {
|
||||
"type": "array",
|
||||
"items": { "oneOf": [{ "enum": ["me"] }, { "enum": ["user"] }] },
|
||||
"example": ["me", "user"],
|
||||
"default": ["me", "user"]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -678,7 +695,12 @@
|
||||
"email",
|
||||
"isAnonymous",
|
||||
"defaultRole",
|
||||
"metadata"
|
||||
"metadata",
|
||||
"activeMfaType",
|
||||
"emailVerified",
|
||||
"phoneNumber",
|
||||
"phoneNumberVerified",
|
||||
"roles"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.5.10",
|
||||
"@nhost/nextjs": "^1.0.0",
|
||||
"@nhost/react": "^0.3.0",
|
||||
"@nhost/react-apollo": "^4.0.0",
|
||||
"@nhost/nextjs": "^1.0.8",
|
||||
"@nhost/react": "^0.4.6",
|
||||
"@nhost/react-apollo": "^4.0.8",
|
||||
"graphql": "^16.3.0",
|
||||
"next": "12.1.0",
|
||||
"react": "17.0.2",
|
||||
|
||||
@@ -25,11 +25,11 @@ const Home: NextPage = () => {
|
||||
const [newPassword, setNewPassword] = useState('')
|
||||
const accessToken = useAccessToken()
|
||||
const { signOut } = useSignOut()
|
||||
const { signUpEmailPassword, ...signUpResult } = useSignUpEmailPassword(email, password)
|
||||
const { signInEmailPassword } = useSignInEmailPassword(email, password)
|
||||
const { signInEmailPasswordless } = useSignInEmailPasswordless(email)
|
||||
const { changeEmail, ...changeEmailResult } = useChangeEmail(newEmail)
|
||||
const { changePassword, ...changePasswordResult } = useChangePassword(newPassword)
|
||||
const { signUpEmailPassword, ...signUpResult } = useSignUpEmailPassword()
|
||||
const { signInEmailPassword } = useSignInEmailPassword()
|
||||
const { signInEmailPasswordless } = useSignInEmailPasswordless()
|
||||
const { changeEmail, ...changeEmailResult } = useChangeEmail()
|
||||
const { changePassword, ...changePasswordResult } = useChangePassword()
|
||||
const { loading, data, error } = useAuthQuery(BOOKS_QUERY)
|
||||
return (
|
||||
<div>
|
||||
@@ -37,20 +37,24 @@ const Home: NextPage = () => {
|
||||
<>
|
||||
<button onClick={signOut}>Logout</button>
|
||||
<input value={newEmail} onChange={(e) => setNewEmail(e.target.value)} />
|
||||
<button onClick={changeEmail}>Change email</button>
|
||||
<button onClick={() => changeEmail(email)}>Change email</button>
|
||||
<div>{JSON.stringify(changeEmailResult)}</div>
|
||||
<button onClick={changePassword}>Change password</button>
|
||||
<button onClick={() => changePassword(password)}>Change password</button>
|
||||
<input value={newPassword} onChange={(e) => setNewPassword(e.target.value)} />
|
||||
<div>{JSON.stringify(changePasswordResult)}</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<input value={email} onChange={(e) => setEmail(e.target.value)} />
|
||||
<button onClick={signInEmailPasswordless}>Passwordless signin</button>
|
||||
<button onClick={() => signInEmailPasswordless(email)}>Passwordless signin</button>
|
||||
<div>{JSON.stringify(signUpResult)}</div>
|
||||
<input value={password} onChange={(e) => setPassword(e.target.value)} type="password" />
|
||||
<button onClick={signUpEmailPassword}>Email + password sign-up</button>
|
||||
<button onClick={signInEmailPassword}>Email + password sign-in</button>
|
||||
<button onClick={() => signUpEmailPassword(email, password)}>
|
||||
Email + password sign-up
|
||||
</button>
|
||||
<button onClick={() => signInEmailPassword(email, password)}>
|
||||
Email + password sign-in
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
@@ -136,71 +136,71 @@
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.0.tgz#d27e7e76c87a460a4da99c5bfdb1618dcd6cd064"
|
||||
integrity sha512-aBvcbMwuanDH4EMrL2TthNJy+4nP59Bimn8egqv6GHMVj0a44cU6Au4PjOhLNqEh9l+IpRGBqMTzec94UdC5xg==
|
||||
|
||||
"@nhost/apollo@0.3.0":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/apollo/-/apollo-0.3.0.tgz#89a66e97aa6af4de6045bf0c780e8b9590c06d9b"
|
||||
integrity sha512-97DSycgPEnQQtzAWPB36yENAuQFDEl8c7qLB9xOzSnplImv5NGces40XMAkTDEWam0eD//PtXP9zi+TYNeMNjw==
|
||||
"@nhost/apollo@^0.3.6":
|
||||
version "0.3.6"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/apollo/-/apollo-0.3.6.tgz#c3902c8ea9250bbe7428098ddfe145d9a2d82f2f"
|
||||
integrity sha512-+UtPMKPkqQ9MuJ24TQB0p59uytoyBXOBYLJ0SEHvs6cAfhkOkLljk+WhWSBhUdRkD+k4iRmHrVvVCyVzLGFRPg==
|
||||
dependencies:
|
||||
"@nhost/core" "0.3.0"
|
||||
"@nhost/core" "^0.3.7"
|
||||
graphql "16"
|
||||
subscriptions-transport-ws "^0.11.0"
|
||||
|
||||
"@nhost/core@0.3.0":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/core/-/core-0.3.0.tgz#fa630afef50840cd7b8415e17894c7765cda273f"
|
||||
integrity sha512-wEdq+BLOHH7bOhBvF5gql9vtWuEtlLWvw65AtpstfX8pAUY8ce2yqamV6Z8kxr/RSYXZA+aLsKwig50qSZa99w==
|
||||
"@nhost/core@^0.3.7":
|
||||
version "0.3.7"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/core/-/core-0.3.7.tgz#115cd770dc8ea1d277a71802958c89c1aa83578b"
|
||||
integrity sha512-sQZp+aet/gCbu4R7cLgRbOrZarfBc1ZTuUwsfpVChLCYtVlPtY5ZWk4pfvU9tbfGEpmbkC4Bk9KqD9AFOzT27A==
|
||||
dependencies:
|
||||
axios "^0.25.0"
|
||||
broadcast-channel "^4.10.0"
|
||||
js-cookie "^3.0.1"
|
||||
xstate "^4.30.5"
|
||||
|
||||
"@nhost/hasura-auth-js@1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/hasura-auth-js/-/hasura-auth-js-1.0.0.tgz#0f3c267614ca328c944797f33a1921c8103dd3e5"
|
||||
integrity sha512-hENPB1aMdekYxfDejthPAdoj9JarqaVkBKNRa+jun247Un1X6eFGDPo52Y2tZfP44pJEUK4EqTqkWH3DwT4uXg==
|
||||
"@nhost/hasura-auth-js@^1.0.7":
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/hasura-auth-js/-/hasura-auth-js-1.0.7.tgz#2c6a81d64155bd8b24bbf314154ed2e40396b151"
|
||||
integrity sha512-fj2aNY3gTt89SLMe3H4MYA50EhZz0OcBUdnES8sv1raOJyxjH94+8TfBVT0xNUqvubOM0J+0ewHAnDCkbodbXA==
|
||||
dependencies:
|
||||
"@nhost/core" "0.3.0"
|
||||
"@nhost/core" "^0.3.7"
|
||||
|
||||
"@nhost/hasura-storage-js@0.2.0":
|
||||
"@nhost/hasura-storage-js@^0.2.0":
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/hasura-storage-js/-/hasura-storage-js-0.2.0.tgz#e8c127d883d231313cd262553732da3b0dccb858"
|
||||
integrity sha512-JumgUhnScU6Bv8SBmN2F4sY+LbrD3i25Ppr30Zjbv4MvbUguBclx9zzAwqub/P2n/azc7bjjRvYl2n2/jjKRXw==
|
||||
dependencies:
|
||||
axios "^0.21.1"
|
||||
|
||||
"@nhost/nextjs@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/nextjs/-/nextjs-1.0.0.tgz#2e91cce4352ec7c521099c8f9fccd5fef94ec902"
|
||||
integrity sha512-yrRXd3796wcLjabeqIbBgZ/IdD40xpC9LhBA9LoXHqHfNaqZ4ujtcMnSc7IZWJv45P5rDO3T8kKKk+Sm6vTAvQ==
|
||||
"@nhost/nextjs@^1.0.8":
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/nextjs/-/nextjs-1.0.8.tgz#761a447fd6aaef43625d82c0304b027d62360d76"
|
||||
integrity sha512-lej1ZlSzh7+FNEizZuXrH4De9emRD7wvW8+huwRhTkFTxislsBuZt2tDrzktkRa5sdHSnyYyuVwZY3TEsm3JmA==
|
||||
dependencies:
|
||||
"@nhost/nhost-js" "1.0.0"
|
||||
"@nhost/nhost-js" "^1.0.7"
|
||||
cookies "^0.8.0"
|
||||
|
||||
"@nhost/nhost-js@1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/nhost-js/-/nhost-js-1.0.0.tgz#d57aa66c889922926b9bde6278d35000729f884c"
|
||||
integrity sha512-ve5+TqYGcQbRwDqxVDMCJKZQlj5BFCsTzqEhIAUnLP6Gu8YlNVeUQL3Bbc19j71OkHDNhw8TAJbE2zcFUBT2Fw==
|
||||
"@nhost/nhost-js@^1.0.7":
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/nhost-js/-/nhost-js-1.0.7.tgz#90ccac91f5d61d32caa8544029b71d47aa7c8b2f"
|
||||
integrity sha512-XBy370bVfP2IYAozeSu62/caQ+bvwvFjj+76LjatqYc7PhHwJV/Kd5SIyvWgqLFO1xQ3kAX0if137IGC+dgBOw==
|
||||
dependencies:
|
||||
"@nhost/hasura-auth-js" "1.0.0"
|
||||
"@nhost/hasura-storage-js" "0.2.0"
|
||||
"@nhost/hasura-auth-js" "^1.0.7"
|
||||
"@nhost/hasura-storage-js" "^0.2.0"
|
||||
axios "^0.23.0"
|
||||
jwt-decode "^3.1.2"
|
||||
query-string "^7.0.1"
|
||||
|
||||
"@nhost/react-apollo@^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/react-apollo/-/react-apollo-4.0.0.tgz#08be35946eadbb746f27435c3fc72cd092a97b61"
|
||||
integrity sha512-ZmFgBgHFJE2Z2ZBYx3U4Gry9TprUOb4NXw/K5lSKv11zPeEaclfpqn+aeQbtCj02oCnzRe+MJLsJenpcuhQRuw==
|
||||
"@nhost/react-apollo@^4.0.8":
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/react-apollo/-/react-apollo-4.0.8.tgz#69c015086837c1aaa828c566f33e22b6c852529a"
|
||||
integrity sha512-G9F5AFLhXJV67MKvraRwSrJpkebqd/oEGgznK5knGL+B9FYuuXtBVbr5m95ESyYkYL+y3iPU3BY5GufL/9pCGw==
|
||||
dependencies:
|
||||
"@nhost/apollo" "0.3.0"
|
||||
"@nhost/apollo" "^0.3.6"
|
||||
|
||||
"@nhost/react@^0.3.0":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/react/-/react-0.3.0.tgz#5401922dce91bb66db5d575de1869df00fabbb8e"
|
||||
integrity sha512-jxyt4dYfphgv3bf6jvV7qDKnV5qUArFvdTYExKlBA9tsBQYta0heawMsJk0rEarEZGUw1iioiUYFKdZyl2Qi5Q==
|
||||
"@nhost/react@^0.4.6":
|
||||
version "0.4.6"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/react/-/react-0.4.6.tgz#e7f01d9cd1d3d24999a3a68a7b9c72cb3ef8fe04"
|
||||
integrity sha512-bqQI2T91tDI0PkVpnfcCDsQUWgXqwcrU6r29S7u4dziEt5RVG0NJjjg2SK35VbqZvJ9vU5z0KHM+4Cd5PKql2g==
|
||||
dependencies:
|
||||
"@nhost/nhost-js" "1.0.0"
|
||||
"@nhost/nhost-js" "^1.0.7"
|
||||
"@xstate/react" "^2.0.1"
|
||||
immer "^9.0.12"
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.5.10",
|
||||
"@nhost/react": "^0.3.0",
|
||||
"@nhost/react-apollo": "^4.0.0",
|
||||
"@nhost/react": "^0.4.6",
|
||||
"@nhost/react-apollo": "^4.0.8",
|
||||
"@rsuite/icons": "^1.0.2",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"react": "^17.0.2",
|
||||
@@ -13,7 +13,7 @@
|
||||
"react-icons": "^4.3.1",
|
||||
"react-json-view": "^1.21.3",
|
||||
"react-router-dom": "^6.2.1",
|
||||
"rsuite": "^5.6.2"
|
||||
"rsuite": "^5.7.1"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -6,9 +6,13 @@ import React, { useState, useEffect } from 'react'
|
||||
export const EmailPasswordlessForm: React.FC = () => {
|
||||
const [email, setEmail] = useState('')
|
||||
const navigate = useNavigate()
|
||||
const { signInEmailPasswordless, isError, isSuccess, error } = useSignInEmailPasswordless(email, {
|
||||
redirectTo: '/profile'
|
||||
})
|
||||
const { signInEmailPasswordless, isError, isSuccess, error } = useSignInEmailPasswordless(
|
||||
// TODO correct this once the new packages are released
|
||||
undefined,
|
||||
{
|
||||
redirectTo: '/profile'
|
||||
}
|
||||
)
|
||||
const [showError, setShowError] = useState(true)
|
||||
useEffect(() => {
|
||||
setShowError(false)
|
||||
@@ -42,7 +46,7 @@ export const EmailPasswordlessForm: React.FC = () => {
|
||||
style={{ marginTop: '0.5em' }}
|
||||
onClick={() => {
|
||||
setShowError(true)
|
||||
signInEmailPasswordless()
|
||||
signInEmailPasswordless(email)
|
||||
}}
|
||||
>
|
||||
Continue with email
|
||||
|
||||
@@ -5,9 +5,13 @@ import { Button, FlexboxGrid, Input, Message, Panel, toaster, Notification } fro
|
||||
export const ChangeEmail: React.FC = () => {
|
||||
const [newEmail, setNewEmail] = useState('')
|
||||
const email = useEmail()
|
||||
const { changeEmail, error, needsEmailVerification } = useChangeEmail(newEmail, {
|
||||
redirectTo: '/profile'
|
||||
})
|
||||
const { changeEmail, error, needsEmailVerification } = useChangeEmail(
|
||||
// TODO correct this once the new packages are released
|
||||
undefined,
|
||||
{
|
||||
redirectTo: '/profile'
|
||||
}
|
||||
)
|
||||
const [errorMessage, setErrorMessage] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
@@ -45,7 +49,7 @@ export const ChangeEmail: React.FC = () => {
|
||||
<Input value={newEmail} onChange={setNewEmail} placeholder="New email" />
|
||||
</FlexboxGrid.Item>
|
||||
<FlexboxGrid.Item colspan={12}>
|
||||
<Button onClick={changeEmail} block appearance="primary">
|
||||
<Button onClick={() => changeEmail(email)} block appearance="primary">
|
||||
Change
|
||||
</Button>
|
||||
</FlexboxGrid.Item>
|
||||
|
||||
@@ -4,13 +4,9 @@ import { Button, FlexboxGrid, Input, Message, Panel, toaster, Notification } fro
|
||||
|
||||
export const ChangePassword: React.FC = () => {
|
||||
const [password, setPassword] = useState('')
|
||||
const { changePassword, isSuccess, error } = useChangePassword(password)
|
||||
const { changePassword, isSuccess, error } = useChangePassword()
|
||||
const [errorMessage, setErrorMessage] = useState('')
|
||||
|
||||
// * See https://github.com/rsuite/rsuite/issues/2336
|
||||
useEffect(() => {
|
||||
toaster.push(<div />)
|
||||
}, [])
|
||||
useEffect(() => {
|
||||
if (isSuccess) {
|
||||
setPassword('')
|
||||
@@ -44,7 +40,7 @@ export const ChangePassword: React.FC = () => {
|
||||
/>
|
||||
</FlexboxGrid.Item>
|
||||
<FlexboxGrid.Item colspan={12}>
|
||||
<Button onClick={changePassword} block appearance="primary">
|
||||
<Button onClick={() => changePassword(password)} block appearance="primary">
|
||||
Change
|
||||
</Button>
|
||||
</FlexboxGrid.Item>
|
||||
|
||||
@@ -4,8 +4,7 @@ import { Button, Input, Panel } from 'rsuite'
|
||||
|
||||
export const Mfa: React.FC = () => {
|
||||
const [code, setCode] = useState('')
|
||||
const { generateQrCode, activateMfa, isActivated, isGenerated, qrCodeDataUrl } =
|
||||
useConfigMfa(code)
|
||||
const { generateQrCode, activateMfa, isActivated, isGenerated, qrCodeDataUrl } = useConfigMfa()
|
||||
|
||||
return (
|
||||
<Panel header="Activate 2-step verification" bordered>
|
||||
@@ -18,7 +17,7 @@ export const Mfa: React.FC = () => {
|
||||
<div>
|
||||
<img alt="qrcode" src={qrCodeDataUrl} />
|
||||
<Input value={code} onChange={setCode} placeholder="Enter activation code" />
|
||||
<Button block appearance="primary" onClick={activateMfa}>
|
||||
<Button block appearance="primary" onClick={() => activateMfa(code)}>
|
||||
Activate
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -80,7 +80,7 @@ export const EmailPassword: React.FC = () => {
|
||||
</Message>
|
||||
)}
|
||||
|
||||
<Button appearance="primary" onClick={signInEmailPassword} block>
|
||||
<Button appearance="primary" onClick={() => signInEmailPassword(email, password)} block>
|
||||
Sign in
|
||||
</Button>
|
||||
<Button as={NavLink} block to="/sign-in/forgot-password">
|
||||
|
||||
@@ -5,7 +5,11 @@ import { NavLink } from 'react-router-dom'
|
||||
|
||||
export const ForgotPassword: React.FC = () => {
|
||||
const [email, setEmail] = useState('')
|
||||
const { resetPassword, isSent, error } = useResetPassword(email, { redirectTo: '/profile' })
|
||||
const { resetPassword, isSent, error } = useResetPassword(
|
||||
// TODO correct this once the new packages are released
|
||||
undefined,
|
||||
{ redirectTo: '/profile' }
|
||||
)
|
||||
|
||||
const [errorMessage, setErrorMessage] = useState('')
|
||||
// * Set error message from the authentication hook errors
|
||||
@@ -16,10 +20,6 @@ export const ForgotPassword: React.FC = () => {
|
||||
useEffect(() => {
|
||||
setErrorMessage('')
|
||||
}, [email])
|
||||
// * See https://github.com/rsuite/rsuite/issues/2336
|
||||
useEffect(() => {
|
||||
toaster.push(<div />)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (isSent) {
|
||||
@@ -48,7 +48,7 @@ export const ForgotPassword: React.FC = () => {
|
||||
</Message>
|
||||
)}
|
||||
|
||||
<Button appearance="primary" onClick={resetPassword} block>
|
||||
<Button appearance="primary" onClick={() => resetPassword(email)} block>
|
||||
Reset your password
|
||||
</Button>
|
||||
<Divider />
|
||||
|
||||
@@ -15,8 +15,9 @@ export const EmailPassword: React.FC = () => {
|
||||
const navigate = useNavigate()
|
||||
const [confirmPassword, setConfirmPassword] = useState('')
|
||||
const { signUpEmailPassword, error, needsEmailVerification, isSuccess } = useSignUpEmailPassword(
|
||||
email,
|
||||
password,
|
||||
// TODO change once the new packages have been release
|
||||
undefined,
|
||||
undefined,
|
||||
options
|
||||
)
|
||||
const [errorMessage, setErrorMessage] = useState('')
|
||||
@@ -91,7 +92,7 @@ export const EmailPassword: React.FC = () => {
|
||||
appearance="primary"
|
||||
onClick={() => {
|
||||
setErrorMessage('')
|
||||
signUpEmailPassword()
|
||||
signUpEmailPassword(email, password)
|
||||
}}
|
||||
block
|
||||
>
|
||||
|
||||
@@ -296,63 +296,63 @@
|
||||
resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.3.1.tgz#b50a781709c81e10701004214340f25475a171a0"
|
||||
integrity sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw==
|
||||
|
||||
"@nhost/apollo@0.3.0":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/apollo/-/apollo-0.3.0.tgz#89a66e97aa6af4de6045bf0c780e8b9590c06d9b"
|
||||
integrity sha512-97DSycgPEnQQtzAWPB36yENAuQFDEl8c7qLB9xOzSnplImv5NGces40XMAkTDEWam0eD//PtXP9zi+TYNeMNjw==
|
||||
"@nhost/apollo@^0.3.6":
|
||||
version "0.3.6"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/apollo/-/apollo-0.3.6.tgz#c3902c8ea9250bbe7428098ddfe145d9a2d82f2f"
|
||||
integrity sha512-+UtPMKPkqQ9MuJ24TQB0p59uytoyBXOBYLJ0SEHvs6cAfhkOkLljk+WhWSBhUdRkD+k4iRmHrVvVCyVzLGFRPg==
|
||||
dependencies:
|
||||
"@nhost/core" "0.3.0"
|
||||
"@nhost/core" "^0.3.7"
|
||||
graphql "16"
|
||||
subscriptions-transport-ws "^0.11.0"
|
||||
|
||||
"@nhost/core@0.3.0":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/core/-/core-0.3.0.tgz#fa630afef50840cd7b8415e17894c7765cda273f"
|
||||
integrity sha512-wEdq+BLOHH7bOhBvF5gql9vtWuEtlLWvw65AtpstfX8pAUY8ce2yqamV6Z8kxr/RSYXZA+aLsKwig50qSZa99w==
|
||||
"@nhost/core@^0.3.7":
|
||||
version "0.3.7"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/core/-/core-0.3.7.tgz#115cd770dc8ea1d277a71802958c89c1aa83578b"
|
||||
integrity sha512-sQZp+aet/gCbu4R7cLgRbOrZarfBc1ZTuUwsfpVChLCYtVlPtY5ZWk4pfvU9tbfGEpmbkC4Bk9KqD9AFOzT27A==
|
||||
dependencies:
|
||||
axios "^0.25.0"
|
||||
broadcast-channel "^4.10.0"
|
||||
js-cookie "^3.0.1"
|
||||
xstate "^4.30.5"
|
||||
|
||||
"@nhost/hasura-auth-js@1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/hasura-auth-js/-/hasura-auth-js-1.0.0.tgz#0f3c267614ca328c944797f33a1921c8103dd3e5"
|
||||
integrity sha512-hENPB1aMdekYxfDejthPAdoj9JarqaVkBKNRa+jun247Un1X6eFGDPo52Y2tZfP44pJEUK4EqTqkWH3DwT4uXg==
|
||||
"@nhost/hasura-auth-js@^1.0.7":
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/hasura-auth-js/-/hasura-auth-js-1.0.7.tgz#2c6a81d64155bd8b24bbf314154ed2e40396b151"
|
||||
integrity sha512-fj2aNY3gTt89SLMe3H4MYA50EhZz0OcBUdnES8sv1raOJyxjH94+8TfBVT0xNUqvubOM0J+0ewHAnDCkbodbXA==
|
||||
dependencies:
|
||||
"@nhost/core" "0.3.0"
|
||||
"@nhost/core" "^0.3.7"
|
||||
|
||||
"@nhost/hasura-storage-js@0.2.0":
|
||||
"@nhost/hasura-storage-js@^0.2.0":
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/hasura-storage-js/-/hasura-storage-js-0.2.0.tgz#e8c127d883d231313cd262553732da3b0dccb858"
|
||||
integrity sha512-JumgUhnScU6Bv8SBmN2F4sY+LbrD3i25Ppr30Zjbv4MvbUguBclx9zzAwqub/P2n/azc7bjjRvYl2n2/jjKRXw==
|
||||
dependencies:
|
||||
axios "^0.21.1"
|
||||
|
||||
"@nhost/nhost-js@1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/nhost-js/-/nhost-js-1.0.0.tgz#d57aa66c889922926b9bde6278d35000729f884c"
|
||||
integrity sha512-ve5+TqYGcQbRwDqxVDMCJKZQlj5BFCsTzqEhIAUnLP6Gu8YlNVeUQL3Bbc19j71OkHDNhw8TAJbE2zcFUBT2Fw==
|
||||
"@nhost/nhost-js@^1.0.7":
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/nhost-js/-/nhost-js-1.0.7.tgz#90ccac91f5d61d32caa8544029b71d47aa7c8b2f"
|
||||
integrity sha512-XBy370bVfP2IYAozeSu62/caQ+bvwvFjj+76LjatqYc7PhHwJV/Kd5SIyvWgqLFO1xQ3kAX0if137IGC+dgBOw==
|
||||
dependencies:
|
||||
"@nhost/hasura-auth-js" "1.0.0"
|
||||
"@nhost/hasura-storage-js" "0.2.0"
|
||||
"@nhost/hasura-auth-js" "^1.0.7"
|
||||
"@nhost/hasura-storage-js" "^0.2.0"
|
||||
axios "^0.23.0"
|
||||
jwt-decode "^3.1.2"
|
||||
query-string "^7.0.1"
|
||||
|
||||
"@nhost/react-apollo@^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/react-apollo/-/react-apollo-4.0.0.tgz#08be35946eadbb746f27435c3fc72cd092a97b61"
|
||||
integrity sha512-ZmFgBgHFJE2Z2ZBYx3U4Gry9TprUOb4NXw/K5lSKv11zPeEaclfpqn+aeQbtCj02oCnzRe+MJLsJenpcuhQRuw==
|
||||
"@nhost/react-apollo@^4.0.8":
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/react-apollo/-/react-apollo-4.0.8.tgz#69c015086837c1aaa828c566f33e22b6c852529a"
|
||||
integrity sha512-G9F5AFLhXJV67MKvraRwSrJpkebqd/oEGgznK5knGL+B9FYuuXtBVbr5m95ESyYkYL+y3iPU3BY5GufL/9pCGw==
|
||||
dependencies:
|
||||
"@nhost/apollo" "0.3.0"
|
||||
"@nhost/apollo" "^0.3.6"
|
||||
|
||||
"@nhost/react@^0.3.0":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/react/-/react-0.3.0.tgz#5401922dce91bb66db5d575de1869df00fabbb8e"
|
||||
integrity sha512-jxyt4dYfphgv3bf6jvV7qDKnV5qUArFvdTYExKlBA9tsBQYta0heawMsJk0rEarEZGUw1iioiUYFKdZyl2Qi5Q==
|
||||
"@nhost/react@^0.4.6":
|
||||
version "0.4.6"
|
||||
resolved "https://registry.yarnpkg.com/@nhost/react/-/react-0.4.6.tgz#e7f01d9cd1d3d24999a3a68a7b9c72cb3ef8fe04"
|
||||
integrity sha512-bqQI2T91tDI0PkVpnfcCDsQUWgXqwcrU6r29S7u4dziEt5RVG0NJjjg2SK35VbqZvJ9vU5z0KHM+4Cd5PKql2g==
|
||||
dependencies:
|
||||
"@nhost/nhost-js" "1.0.0"
|
||||
"@nhost/nhost-js" "^1.0.7"
|
||||
"@xstate/react" "^2.0.1"
|
||||
immer "^9.0.12"
|
||||
|
||||
@@ -1409,10 +1409,10 @@ rsuite-table@^5.3.6:
|
||||
lodash "^4.17.21"
|
||||
react-is "^17.0.2"
|
||||
|
||||
rsuite@^5.6.2:
|
||||
version "5.6.6"
|
||||
resolved "https://registry.yarnpkg.com/rsuite/-/rsuite-5.6.6.tgz#03b97ec32a24212aaa95e3d14e5e85db2255175a"
|
||||
integrity sha512-N4xnfnOpbxkEQ4+6GP/ll76XC8motkCQUNy1WL5wayZGgmOjzbVLbOUUHn9iGN32sBLyH8/d3Lo/WxfAjprj3g==
|
||||
rsuite@^5.7.1:
|
||||
version "5.7.1"
|
||||
resolved "https://registry.yarnpkg.com/rsuite/-/rsuite-5.7.1.tgz#2c50161e568cbf0074b42e7b65592b25a3b9412d"
|
||||
integrity sha512-vvqBadf9vJ49CW4gboFpj+Ol7M5sK7a72irwQxgxBxHBD2YEWUx9LQp137RIJV6w/nXg1P5yaObZULb5n77QoA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.8.4"
|
||||
"@juggle/resize-observer" "^3.3.1"
|
||||
|
||||
@@ -28,8 +28,10 @@
|
||||
"prettier:fix": "prettier --write .",
|
||||
"lint": "pnpm turbo run lint --stream",
|
||||
"lint:fix": "pnpm turbo run lint:fix --stream",
|
||||
"prerelease": "pnpm clean && pnpm install && pnpm build",
|
||||
"release": "pnpm run prerelease && changeset publish",
|
||||
"snapshot": "pnpm prerelease && changeset version --snapshot preview && pnpm install && changeset publish --tag preview",
|
||||
"test": "pnpm turbo run test --scope='@nhost/*' --no-deps --include-dependencies",
|
||||
"ci:publish": "pnpm run build && changeset tag && git push --follow-tags && pnpm -r publish && git status",
|
||||
"changeset": "changeset",
|
||||
"wait": "wait-on http://localhost:1337/v1/auth/healthz -i 500 -t 120000"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
# @nhost/apollo
|
||||
|
||||
## 0.3.4
|
||||
## 0.3.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [058956b]
|
||||
- Updated dependencies [7cf875f]
|
||||
- @nhost/core@0.3.8
|
||||
|
||||
## 0.3.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -39,7 +47,6 @@
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [744fd69]
|
||||
- Updated dependencies [744fd69]
|
||||
- @nhost/core@0.3.0
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/apollo",
|
||||
"version": "0.3.4",
|
||||
"version": "0.3.7",
|
||||
"description": "Nhost Apollo Client library",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
# @nhost/core
|
||||
|
||||
## 0.3.4
|
||||
## 0.3.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 058956b: Add missing provider types
|
||||
`strava`, `gitlab`, and `bitbucket` were missing from the list of providers in Typescript and are now available.
|
||||
- 058956b: Add `emailVerified`, `phoneNumber`, `phoneNumberVerified`, and `activeMfaType` to User type
|
||||
|
||||
Some information is missing in the `User` payload (see [this issue](https://github.com/nhost/nhost/issues/306)). The above properties have been added in the Typescript `User` type and are available when using Hasura Auth versions from [this pull request](https://github.com/nhost/hasura-auth/pull/128) (tentative version number: `0.5.1`)
|
||||
|
||||
- 7cf875f: Export error code payloads and type
|
||||
|
||||
## 0.3.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/core",
|
||||
"version": "0.3.4",
|
||||
"version": "0.3.8",
|
||||
"description": "Nhost core client library",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -2,6 +2,7 @@ export type { NhostClientOptions } from './client'
|
||||
export { AuthClient } from './client'
|
||||
export * from './constants'
|
||||
export { AuthClientSSR } from './coookie-client'
|
||||
export * from './errors'
|
||||
export * from './machines'
|
||||
export * from './storage'
|
||||
export * from './types'
|
||||
|
||||
@@ -71,6 +71,7 @@ export const createChangeEmailMachine = ({ backendUrl, clientUrl, interpreter }:
|
||||
error: (_, { data: { error } }: any) => error
|
||||
}),
|
||||
reportError: send((ctx) => ({ type: 'ERROR', error: ctx.error })),
|
||||
// TODO change email in the main machine (context.user.email)
|
||||
reportSuccess: send('SUCCESS')
|
||||
},
|
||||
guards: {
|
||||
|
||||
@@ -14,7 +14,7 @@ type RegistrationOptions = {
|
||||
metadata?: Record<string, unknown>
|
||||
}
|
||||
|
||||
type RedirectOption = {
|
||||
export type RedirectOption = {
|
||||
redirectTo?: string
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ export type SendVerificationEmailOptions = RedirectOption
|
||||
export type DeanonymizeOptions = { email?: string; password?: string } & RegistrationOptions
|
||||
export type ProviderOptions = RegistrationOptions & RedirectOption
|
||||
|
||||
// TODO share with hasura-auth
|
||||
export type User = {
|
||||
id: string
|
||||
createdAt: string
|
||||
@@ -37,9 +38,13 @@ export type User = {
|
||||
defaultRole: string
|
||||
roles: string[]
|
||||
metadata: Record<string, unknown>
|
||||
emailVerified: boolean
|
||||
phoneNumber: string | null
|
||||
phoneNumberVerified: boolean
|
||||
activeMfaType: 'totp' | null
|
||||
}
|
||||
|
||||
// ! copy-paste from hasura-auth
|
||||
// TODO share with hasura-auth
|
||||
export type NhostSession = {
|
||||
accessToken: string
|
||||
accessTokenExpiresIn: number
|
||||
@@ -51,6 +56,7 @@ export type Mfa = {
|
||||
ticket: string
|
||||
}
|
||||
|
||||
// TODO share with hasura-auth
|
||||
export type Provider =
|
||||
| 'apple'
|
||||
| 'facebook'
|
||||
@@ -60,3 +66,6 @@ export type Provider =
|
||||
| 'spotify'
|
||||
| 'twitter'
|
||||
| 'windowslive'
|
||||
| 'strava'
|
||||
| 'gitlab'
|
||||
| 'bitbucket'
|
||||
|
||||
@@ -1,6 +1,26 @@
|
||||
# @nhost/hasura-auth-js
|
||||
|
||||
## 1.0.5
|
||||
## 1.0.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 058956b: Add missing provider types
|
||||
`strava`, `gitlab`, and `bitbucket` were missing from the list of providers in Typescript and are now available.
|
||||
- 058956b: Add `emailVerified`, `phoneNumber`, `phoneNumberVerified`, and `activeMfaType` to User type
|
||||
|
||||
Some information is missing in the `User` payload (see [this issue](https://github.com/nhost/nhost/issues/306)). The above properties have been added in the Typescript `User` type and are available when using Hasura Auth versions from [this pull request](https://github.com/nhost/hasura-auth/pull/128) (tentative version number: `0.5.1`)
|
||||
|
||||
- Updated dependencies [058956b]
|
||||
- Updated dependencies [7cf875f]
|
||||
- @nhost/core@0.3.8
|
||||
|
||||
## 1.0.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6be3758: bug: Correct OAuth provider link.
|
||||
|
||||
## 1.0.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -62,7 +82,6 @@
|
||||
2. hasura-auth validates the link, attaches the token and redirects to the frontend
|
||||
3. the sdk gets the refresh token from the url
|
||||
4. the sdk consumes the refresh token
|
||||
- Updated dependencies [744fd69]
|
||||
- Updated dependencies [744fd69]
|
||||
- @nhost/core@0.3.0
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/hasura-auth-js",
|
||||
"version": "1.0.5",
|
||||
"version": "1.0.9",
|
||||
"description": "Hasura-auth client",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -157,7 +157,7 @@ export class HasuraAuthClient {
|
||||
if ('provider' in params) {
|
||||
const { provider, options } = params
|
||||
const providerUrl = encodeQueryParameters(
|
||||
`${this.#client.backendUrl}/v1/auth/signin/provider/${provider}`,
|
||||
`${this.#client.backendUrl}/signin/provider/${provider}`,
|
||||
rewriteRedirectTo(this.#client.clientUrl, options)
|
||||
)
|
||||
if (isBrowser()) {
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
import { AuthClient, StorageGetter, StorageSetter, User } from '@nhost/core'
|
||||
|
||||
import {
|
||||
AuthClient,
|
||||
PasswordlessOptions,
|
||||
Provider,
|
||||
ProviderOptions,
|
||||
RedirectOption,
|
||||
SignUpOptions,
|
||||
StorageGetter,
|
||||
StorageSetter,
|
||||
User
|
||||
} from '@nhost/core'
|
||||
export type { AuthClient, Provider, StorageGetter, StorageSetter, User }
|
||||
export interface NhostAuthConstructorParams {
|
||||
url: string
|
||||
refreshIntervalTime?: number
|
||||
@@ -30,14 +40,7 @@ export interface ApiError {
|
||||
export interface SignUpEmailPasswordParams {
|
||||
email: string
|
||||
password: string
|
||||
options?: {
|
||||
locale?: string
|
||||
allowedRoles?: string[]
|
||||
defaultRole?: string
|
||||
displayName?: string
|
||||
redirectTo?: string
|
||||
metadata?: Record<string, unknown>
|
||||
}
|
||||
options?: SignUpOptions
|
||||
}
|
||||
|
||||
export type SignUpParams = SignUpEmailPasswordParams
|
||||
@@ -54,55 +57,21 @@ export interface SignInEmailPasswordParams {
|
||||
|
||||
export interface SignInPasswordlessEmailParams {
|
||||
email: string
|
||||
options?: {
|
||||
locale?: string
|
||||
allowedRoles?: string[]
|
||||
defaultRole?: string
|
||||
displayName?: string
|
||||
redirectTo?: string
|
||||
metadata?: Record<string, unknown>
|
||||
}
|
||||
options?: PasswordlessOptions
|
||||
}
|
||||
|
||||
export interface SignInPasswordlessSmsParams {
|
||||
phoneNumber: string
|
||||
options?: {
|
||||
locale?: string
|
||||
allowedRoles?: string[]
|
||||
defaultRole?: string
|
||||
displayName?: string
|
||||
redirectTo?: string
|
||||
metadata?: Record<string, unknown>
|
||||
}
|
||||
options?: PasswordlessOptions
|
||||
}
|
||||
|
||||
export interface SignInPasswordlessSmsOtpParams {
|
||||
phoneNumber: string
|
||||
otp: string
|
||||
}
|
||||
|
||||
export type Provider =
|
||||
| 'facebook'
|
||||
| 'github'
|
||||
| 'google'
|
||||
| 'linkedin'
|
||||
| 'spotify'
|
||||
| 'discord'
|
||||
| 'twitch'
|
||||
| 'apple'
|
||||
| 'twitter'
|
||||
| 'windowslive'
|
||||
|
||||
export interface SignInWithProviderOptions {
|
||||
provider: Provider
|
||||
options?: {
|
||||
locale?: string
|
||||
allowedRoles?: string[]
|
||||
defaultRole?: string
|
||||
displayName?: string
|
||||
redirectTo?: string
|
||||
metadata?: Record<string, unknown>
|
||||
}
|
||||
options?: ProviderOptions
|
||||
}
|
||||
|
||||
export type SignInParams =
|
||||
@@ -125,18 +94,15 @@ export interface ChangePasswordParams {
|
||||
|
||||
export interface SendVerificationEmailParams {
|
||||
email: string
|
||||
options?: {
|
||||
redirectTo?: string
|
||||
}
|
||||
options?: RedirectOption
|
||||
}
|
||||
|
||||
export interface ChangeEmailParams {
|
||||
newEmail: string
|
||||
options?: {
|
||||
redirectTo?: string
|
||||
}
|
||||
options?: RedirectOption
|
||||
}
|
||||
|
||||
// TODO define type in @nhost/core
|
||||
export interface DeanonymizeParams {
|
||||
signInMethod: 'email-password' | 'passwordless'
|
||||
email: string
|
||||
|
||||
@@ -1,6 +1,23 @@
|
||||
# @nhost/nextjs
|
||||
|
||||
## 1.0.6
|
||||
## 1.0.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [7cf875f]
|
||||
- Updated dependencies [7135aee]
|
||||
- Updated dependencies [587eaff]
|
||||
- @nhost/react@0.5.0
|
||||
- @nhost/nhost-js@1.0.9
|
||||
|
||||
## 1.0.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@1.0.8
|
||||
- @nhost/react@0.4.7
|
||||
|
||||
## 1.0.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/nextjs",
|
||||
"version": "1.0.6",
|
||||
"version": "1.0.10",
|
||||
"description": "Nhost NextJS library",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,20 @@
|
||||
# @nhost/nhost-js
|
||||
|
||||
## 1.0.5
|
||||
## 1.0.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [058956b]
|
||||
- @nhost/hasura-auth-js@1.0.9
|
||||
|
||||
## 1.0.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [6be3758]
|
||||
- @nhost/hasura-auth-js@1.0.8
|
||||
|
||||
## 1.0.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -52,8 +66,6 @@
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [744fd69]
|
||||
- Updated dependencies [744fd69]
|
||||
- Updated dependencies [744fd69]
|
||||
- @nhost/hasura-auth-js@1.0.0
|
||||
- @nhost/hasura-storage-js@0.2.0
|
||||
@@ -73,7 +85,6 @@
|
||||
Some systems based on older versions of Webpack or Babel don't support the current esbuild configuration e.g, [this issue](https://github.com/nhost/nhost/issues/275).
|
||||
- Updated dependencies [e688600]
|
||||
- Updated dependencies [8f7643a]
|
||||
- Updated dependencies [e688600]
|
||||
- Updated dependencies [50b9d76]
|
||||
- @nhost/hasura-auth-js@0.1.15
|
||||
- @nhost/hasura-storage-js@0.0.12
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/nhost-js",
|
||||
"version": "1.0.5",
|
||||
"version": "1.0.9",
|
||||
"description": "Nhost JavaScript SDK",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,23 @@
|
||||
# @nhost/react-apollo
|
||||
|
||||
## 4.0.6
|
||||
## 4.0.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [7cf875f]
|
||||
- Updated dependencies [7135aee]
|
||||
- Updated dependencies [587eaff]
|
||||
- @nhost/react@0.5.0
|
||||
- @nhost/apollo@0.3.7
|
||||
|
||||
## 4.0.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@0.4.7
|
||||
- @nhost/apollo@0.3.6
|
||||
|
||||
## 4.0.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/react-apollo",
|
||||
"version": "4.0.6",
|
||||
"version": "4.0.10",
|
||||
"description": "Nhost React Apollo client",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,64 @@
|
||||
# @nhost/react
|
||||
|
||||
## 0.4.4
|
||||
## 0.5.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 7135aee: Add user and accessToken to authentication hooks
|
||||
|
||||
Hooks that can complete a successful authentication now have two additional `user` and `accessToken` exported states:
|
||||
|
||||
- `useSignInEmailPassword`
|
||||
- `useSignInAnonymous`
|
||||
- `useSignUpEmailPassword`
|
||||
|
||||
- 587eaff: Return a promise with the current context to hooks actions
|
||||
It is now possible to get the result of an action. Hook handlers return the action context in a promise.
|
||||
|
||||
```jsx
|
||||
const { signInEmailPasswordless, isError } = useSignInEmailPasswordless()
|
||||
const MyComponent = () => {
|
||||
return <div>
|
||||
<button onClick={async () => {
|
||||
const { isSuccess, isError, error } = await signInEmailPasswordless('johan@ikea.se')
|
||||
if (isError) {
|
||||
console.log(error)
|
||||
}}}/>
|
||||
{isError && <div>an error occurred</div>}
|
||||
<div>
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 7cf875f: Deprecate the use of values sent as hook parameters
|
||||
|
||||
Although handlers parameters of authentication hooks can be given when creating the hook, it is recommended to use them when executing the handler. For instance, instead of:
|
||||
|
||||
```js
|
||||
const { signInEmailPasswordless } = useSignInEmailPasswordless('nuno@fcporto.pt')
|
||||
signInEmailPasswordless()
|
||||
```
|
||||
|
||||
It is recommended to use the following syntax:
|
||||
|
||||
```js
|
||||
const { signInEmailPasswordless } = useSignInEmailPasswordless()
|
||||
signInEmailPasswordless('nuno@fcporto.pt')
|
||||
```
|
||||
|
||||
No breaking change has been introduced. For instance, `useSignUpEmailPassword('szilard@brussels.be','1234', options)` will appear as deprecated but will work, while `useSignUpEmailPassword(options)` will work too.
|
||||
|
||||
- @nhost/nhost-js@1.0.9
|
||||
|
||||
## 0.4.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@1.0.8
|
||||
|
||||
## 0.4.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/react",
|
||||
"version": "0.4.4",
|
||||
"version": "0.5.0",
|
||||
"description": "Nhost React library",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -5,35 +5,123 @@ import {
|
||||
PasswordlessOptions,
|
||||
Provider,
|
||||
ProviderOptions,
|
||||
rewriteRedirectTo
|
||||
rewriteRedirectTo,
|
||||
User
|
||||
} from '@nhost/core'
|
||||
import { useSelector } from '@xstate/react'
|
||||
|
||||
import { NhostReactContext } from '../provider'
|
||||
|
||||
import { useAuthenticated, useAuthInterpreter } from './common'
|
||||
import { ActionHookState, useAuthenticated, useAuthInterpreter } from './common'
|
||||
|
||||
export const useSignInEmailPassword = (
|
||||
type SignInEmailPasswordHookState = ActionHookState & {
|
||||
needsMfaOtp: boolean
|
||||
needsEmailVerification: boolean
|
||||
user: User | null
|
||||
accessToken: string | null
|
||||
}
|
||||
|
||||
type SignInEmailPasswordHandlerResult = Omit<SignInEmailPasswordHookState, 'isLoading'>
|
||||
|
||||
type SignInEmailPasswordHandler = {
|
||||
(email: string, password: string): Promise<SignInEmailPasswordHandlerResult>
|
||||
/** @deprecated */
|
||||
(email?: unknown, password?: string): Promise<SignInEmailPasswordHandlerResult>
|
||||
}
|
||||
|
||||
type SendMfaOtpHander = {
|
||||
(otp: string): void
|
||||
/** @deprecated */
|
||||
(otp?: unknown): void
|
||||
}
|
||||
|
||||
type SignInEmailPasswordHookResult = {
|
||||
signInEmailPassword: SignInEmailPasswordHandler
|
||||
sendMfaOtp: SendMfaOtpHander
|
||||
} & SignInEmailPasswordHookState
|
||||
|
||||
type SignInEmailPasswordHook = {
|
||||
(): SignInEmailPasswordHookResult
|
||||
/** @deprecated */
|
||||
(email?: string, password?: string, otp?: string): SignInEmailPasswordHookResult
|
||||
}
|
||||
|
||||
export const useSignInEmailPassword: SignInEmailPasswordHook = (
|
||||
stateEmail?: string,
|
||||
statePassword?: string,
|
||||
stateOtp?: string
|
||||
) => {
|
||||
const service = useAuthInterpreter()
|
||||
const signInEmailPassword = (valueEmail?: string | unknown, valuePassword?: string | unknown) =>
|
||||
service.send({
|
||||
type: 'SIGNIN_PASSWORD',
|
||||
email: typeof valueEmail === 'string' ? valueEmail : stateEmail,
|
||||
password: typeof valuePassword === 'string' ? valuePassword : statePassword
|
||||
const signInEmailPassword: SignInEmailPasswordHandler = (
|
||||
valueEmail?: string | unknown,
|
||||
valuePassword?: string
|
||||
) =>
|
||||
new Promise<SignInEmailPasswordHandlerResult>((resolve) => {
|
||||
service.send({
|
||||
type: 'SIGNIN_PASSWORD',
|
||||
email: typeof valueEmail === 'string' ? valueEmail : stateEmail,
|
||||
password: typeof valuePassword === 'string' ? valuePassword : statePassword
|
||||
})
|
||||
service.onTransition((state) => {
|
||||
if (state.matches({ authentication: { signedOut: 'needsEmailVerification' } })) {
|
||||
resolve({
|
||||
accessToken: null,
|
||||
error: null,
|
||||
isError: false,
|
||||
isSuccess: false,
|
||||
needsEmailVerification: true,
|
||||
needsMfaOtp: false,
|
||||
user: null
|
||||
})
|
||||
} else if (state.matches({ authentication: { signedOut: 'needsMfa' } })) {
|
||||
resolve({
|
||||
accessToken: null,
|
||||
error: null,
|
||||
isError: false,
|
||||
isSuccess: false,
|
||||
needsEmailVerification: false,
|
||||
needsMfaOtp: true,
|
||||
user: null
|
||||
})
|
||||
} else if (state.matches({ authentication: { signedOut: 'failed' } })) {
|
||||
resolve({
|
||||
accessToken: null,
|
||||
error: state.context.errors.authentication || null,
|
||||
isError: true,
|
||||
isSuccess: false,
|
||||
needsEmailVerification: false,
|
||||
needsMfaOtp: false,
|
||||
user: null
|
||||
})
|
||||
} else if (state.matches({ authentication: 'signedIn' })) {
|
||||
resolve({
|
||||
accessToken: state.context.accessToken.value,
|
||||
error: null,
|
||||
isError: false,
|
||||
isSuccess: true,
|
||||
needsEmailVerification: false,
|
||||
needsMfaOtp: false,
|
||||
user: state.context.user
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
const sendMfaOtp = (valueOtp?: string | unknown) => {
|
||||
|
||||
const sendMfaOtp: SendMfaOtpHander = (valueOtp?: string | unknown) => {
|
||||
service.send({
|
||||
type: 'SIGNIN_MFA_TOTP',
|
||||
otp: typeof valueOtp === 'string' ? valueOtp : stateOtp
|
||||
})
|
||||
}
|
||||
const user = useSelector(
|
||||
service,
|
||||
(state) => state.context.user,
|
||||
(a, b) => a?.id === b?.id
|
||||
)
|
||||
const accessToken = useSelector(service, (state) => state.context.accessToken.value)
|
||||
const error = useSelector(
|
||||
service,
|
||||
(state) => state.context.errors.authentication,
|
||||
(state) => state.context.errors.authentication || null,
|
||||
(a, b) => a?.error === b?.error
|
||||
)
|
||||
const isSuccess = useAuthenticated()
|
||||
@@ -59,32 +147,70 @@ export const useSignInEmailPassword = (
|
||||
)
|
||||
|
||||
return {
|
||||
signInEmailPassword,
|
||||
accessToken,
|
||||
error,
|
||||
isError,
|
||||
isLoading,
|
||||
isSuccess,
|
||||
needsEmailVerification,
|
||||
needsMfaOtp,
|
||||
sendMfaOtp,
|
||||
isError,
|
||||
error
|
||||
signInEmailPassword,
|
||||
user
|
||||
}
|
||||
}
|
||||
|
||||
export const useSignInEmailPasswordless = (
|
||||
stateEmail?: string,
|
||||
stateOptions?: PasswordlessOptions
|
||||
type SignInEmailPasswordlessHandlerResult = Omit<ActionHookState, 'isLoading'>
|
||||
type SignInEmailPasswordlessHandler = {
|
||||
(email: string, options?: PasswordlessOptions): Promise<SignInEmailPasswordlessHandlerResult>
|
||||
/** @deprecated */
|
||||
(email?: unknown, options?: PasswordlessOptions): Promise<SignInEmailPasswordlessHandlerResult>
|
||||
}
|
||||
|
||||
type SignInEmailPasswordlessHookResult = {
|
||||
signInEmailPasswordless: SignInEmailPasswordlessHandler
|
||||
} & ActionHookState
|
||||
|
||||
type SignInEmailPasswordlessdHook = {
|
||||
(options?: PasswordlessOptions): SignInEmailPasswordlessHookResult
|
||||
/** @deprecated */
|
||||
(email?: string, options?: PasswordlessOptions): SignInEmailPasswordlessHookResult
|
||||
}
|
||||
|
||||
export const useSignInEmailPasswordless: SignInEmailPasswordlessdHook = (
|
||||
a?: string | PasswordlessOptions,
|
||||
b?: PasswordlessOptions
|
||||
) => {
|
||||
const stateEmail = typeof a === 'string' ? a : undefined
|
||||
const stateOptions = typeof a === 'string' ? b : a
|
||||
const service = useAuthInterpreter()
|
||||
const signInEmailPasswordless = (valueEmail?: string | unknown, valueOptions = stateOptions) =>
|
||||
service.send({
|
||||
type: 'SIGNIN_PASSWORDLESS_EMAIL',
|
||||
email: typeof valueEmail === 'string' ? valueEmail : stateEmail,
|
||||
options: valueOptions
|
||||
|
||||
const signInEmailPasswordless: SignInEmailPasswordlessHandler = (
|
||||
valueEmail?: string | unknown,
|
||||
valueOptions = stateOptions
|
||||
) =>
|
||||
new Promise<SignInEmailPasswordlessHandlerResult>((resolve) => {
|
||||
service.send({
|
||||
type: 'SIGNIN_PASSWORDLESS_EMAIL',
|
||||
email: typeof valueEmail === 'string' ? valueEmail : stateEmail,
|
||||
options: valueOptions
|
||||
})
|
||||
service.onTransition((state) => {
|
||||
if (state.matches({ authentication: { signedOut: 'failed' } })) {
|
||||
resolve({
|
||||
error: state.context.errors.authentication || null,
|
||||
isError: true,
|
||||
isSuccess: false
|
||||
})
|
||||
} else if (state.matches({ authentication: { signedOut: 'needsEmailVerification' } })) {
|
||||
resolve({ error: null, isError: false, isSuccess: true })
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const error = useSelector(
|
||||
service,
|
||||
(state) => state.context.errors.authentication,
|
||||
(state) => state.context.errors.authentication || null,
|
||||
(a, b) => a?.error === b?.error
|
||||
)
|
||||
const isLoading =
|
||||
@@ -93,9 +219,9 @@ export const useSignInEmailPasswordless = (
|
||||
const isSuccess =
|
||||
!!service.status &&
|
||||
service.state.matches({ authentication: { signedOut: 'needsEmailVerification' } })
|
||||
|
||||
const isError =
|
||||
!!service.status && service.state.matches({ authentication: { signedOut: 'failed' } })
|
||||
|
||||
return { signInEmailPasswordless, isLoading, isSuccess, isError, error }
|
||||
}
|
||||
|
||||
@@ -115,7 +241,13 @@ export const useSignInAnonymous = () => {
|
||||
const isSuccess = useAuthenticated()
|
||||
const isError =
|
||||
!!service.status && service.state.matches({ authentication: { signedOut: 'failed' } })
|
||||
return { signInAnonymous, isLoading, isSuccess, isError, error }
|
||||
const user = useSelector(
|
||||
service,
|
||||
(state) => state.context.user,
|
||||
(a, b) => a?.id === b?.id
|
||||
)
|
||||
const accessToken = useSelector(service, (state) => state.context.accessToken.value)
|
||||
return { accessToken, error, isError, isLoading, isSuccess, signInAnonymous, user }
|
||||
}
|
||||
|
||||
export const useProviderLink = (options?: ProviderOptions) => {
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
import { useContext, useEffect, useState } from 'react'
|
||||
import { InterpreterFrom } from 'xstate'
|
||||
|
||||
import { AuthMachine } from '@nhost/core'
|
||||
import { AuthMachine, ErrorPayload } from '@nhost/core'
|
||||
import { NhostClient } from '@nhost/nhost-js'
|
||||
import { useSelector } from '@xstate/react'
|
||||
|
||||
import { NhostReactContext } from '../provider'
|
||||
|
||||
export type ActionHookState<T extends string = 'isSuccess'> = {
|
||||
isLoading: boolean
|
||||
|
||||
isError: boolean
|
||||
error: ErrorPayload | null
|
||||
} & Record<T, boolean>
|
||||
|
||||
export const useNhostClient = (): NhostClient => {
|
||||
const nhost = useContext(NhostReactContext)
|
||||
return nhost
|
||||
|
||||
@@ -1,21 +1,55 @@
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import { SignUpOptions } from '@nhost/core'
|
||||
import { SignUpOptions, User } from '@nhost/core'
|
||||
import { useSelector } from '@xstate/react'
|
||||
|
||||
import { useAuthenticationStatus, useAuthInterpreter } from './common'
|
||||
import { ActionHookState, useAuthenticationStatus, useAuthInterpreter } from './common'
|
||||
|
||||
export const useSignUpEmailPassword = (
|
||||
stateEmail?: string,
|
||||
statePassword?: string,
|
||||
stateOptions?: SignUpOptions
|
||||
type SignUpEmailPasswordHookState = ActionHookState & {
|
||||
needsEmailVerification: boolean
|
||||
user: User | null
|
||||
accessToken: string | null
|
||||
}
|
||||
type SignUpEmailPasswordHandlerResult = Omit<SignUpEmailPasswordHookState, 'isLoading'>
|
||||
|
||||
type SignUpEmailPasswordHandler = {
|
||||
(
|
||||
email: string,
|
||||
password: string,
|
||||
options?: SignUpOptions
|
||||
): Promise<SignUpEmailPasswordHandlerResult>
|
||||
/** @deprecated */
|
||||
(
|
||||
email?: unknown,
|
||||
password?: string,
|
||||
options?: SignUpOptions
|
||||
): Promise<SignUpEmailPasswordHandlerResult>
|
||||
}
|
||||
|
||||
type SignUpEmailPasswordHookResult = {
|
||||
signUpEmailPassword: SignUpEmailPasswordHandler
|
||||
} & SignUpEmailPasswordHookState
|
||||
|
||||
type SignUpEmailPasswordHook = {
|
||||
(options?: SignUpOptions): SignUpEmailPasswordHookResult
|
||||
/** @deprecated */
|
||||
(email?: string, password?: string, options?: SignUpOptions): SignUpEmailPasswordHookResult
|
||||
}
|
||||
export const useSignUpEmailPassword: SignUpEmailPasswordHook = (
|
||||
a?: string | SignUpOptions,
|
||||
b?: string,
|
||||
c?: SignUpOptions
|
||||
) => {
|
||||
const stateEmail: string | undefined = typeof a === 'string' ? a : undefined
|
||||
const statePassword: string | undefined = typeof b === 'string' ? b : undefined
|
||||
const stateOptions = c || (typeof a !== 'string' ? a : undefined)
|
||||
|
||||
const service = useAuthInterpreter()
|
||||
const isError =
|
||||
!!service.status && service.state.matches({ authentication: { signedOut: 'failed' } })
|
||||
const error = useSelector(
|
||||
service,
|
||||
(state) => state.context.errors.registration,
|
||||
(state) => state.context.errors.registration || null,
|
||||
(a, b) => a?.error === b?.error
|
||||
)
|
||||
const { isLoading: loading, isAuthenticated: isSuccess } = useAuthenticationStatus()
|
||||
@@ -24,23 +58,65 @@ export const useSignUpEmailPassword = (
|
||||
!!service.status &&
|
||||
service.state.matches({ authentication: { signedOut: 'needsEmailVerification' } })
|
||||
|
||||
const signUpEmailPassword = (
|
||||
const signUpEmailPassword: SignUpEmailPasswordHandler = (
|
||||
valueEmail?: string | unknown,
|
||||
valuePassword = statePassword,
|
||||
valueOptions = stateOptions
|
||||
) =>
|
||||
service.send({
|
||||
type: 'SIGNUP_EMAIL_PASSWORD',
|
||||
email: typeof valueEmail === 'string' ? valueEmail : stateEmail,
|
||||
password: valuePassword,
|
||||
options: valueOptions
|
||||
new Promise<SignUpEmailPasswordHandlerResult>((resolve) => {
|
||||
service.send({
|
||||
type: 'SIGNUP_EMAIL_PASSWORD',
|
||||
email: typeof valueEmail === 'string' ? valueEmail : stateEmail,
|
||||
password: valuePassword,
|
||||
options: valueOptions
|
||||
})
|
||||
service.onTransition((state) => {
|
||||
if (state.matches({ authentication: { signedOut: 'failed' } })) {
|
||||
resolve({
|
||||
accessToken: null,
|
||||
error: state.context.errors.registration || null,
|
||||
isError: true,
|
||||
isSuccess: false,
|
||||
needsEmailVerification: false,
|
||||
user: null
|
||||
})
|
||||
} else if (state.matches({ authentication: { signedOut: 'needsEmailVerification' } })) {
|
||||
resolve({
|
||||
accessToken: null,
|
||||
error: null,
|
||||
isError: false,
|
||||
isSuccess: false,
|
||||
needsEmailVerification: true,
|
||||
user: null
|
||||
})
|
||||
} else if (state.matches({ authentication: 'signedIn' })) {
|
||||
resolve({
|
||||
accessToken: state.context.accessToken.value,
|
||||
error: null,
|
||||
isError: false,
|
||||
isSuccess: true,
|
||||
needsEmailVerification: false,
|
||||
user: state.context.user
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const user = useSelector(
|
||||
service,
|
||||
(state) => state.context.user,
|
||||
(a, b) => a?.id === b?.id
|
||||
)
|
||||
const accessToken = useSelector(service, (state) => state.context.accessToken.value)
|
||||
|
||||
return {
|
||||
signUpEmailPassword,
|
||||
accessToken,
|
||||
error,
|
||||
isError,
|
||||
isLoading,
|
||||
isSuccess,
|
||||
isError,
|
||||
error,
|
||||
needsEmailVerification
|
||||
needsEmailVerification,
|
||||
signUpEmailPassword,
|
||||
user
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useMemo } from 'react'
|
||||
import { useMemo, useState } from 'react'
|
||||
|
||||
import {
|
||||
ChangeEmailOptions,
|
||||
@@ -7,64 +7,171 @@ import {
|
||||
createEnableMfaMachine,
|
||||
createResetPasswordMachine,
|
||||
createSendVerificationEmailMachine,
|
||||
ErrorPayload,
|
||||
ResetPasswordOptions,
|
||||
SendVerificationEmailOptions
|
||||
} from '@nhost/core'
|
||||
import { useMachine, useSelector } from '@xstate/react'
|
||||
|
||||
import { useAuthInterpreter, useNhostClient } from './common'
|
||||
import { ActionHookState, useAuthInterpreter, useNhostClient } from './common'
|
||||
|
||||
export const useChangeEmail = (stateEmail?: string, stateOptions?: ChangeEmailOptions) => {
|
||||
type ChangeEmailHookState = ActionHookState<'needsEmailVerification'>
|
||||
type ChangeEmailHandlerResult = Omit<ChangeEmailHookState, 'isLoading'>
|
||||
type ChangeEmailHandler = {
|
||||
(email: string, options?: ChangeEmailOptions): Promise<ChangeEmailHandlerResult>
|
||||
/** @deprecated */
|
||||
(email?: unknown, options?: ChangeEmailOptions): Promise<ChangeEmailHandlerResult>
|
||||
}
|
||||
|
||||
type ChangeEmailHookResult = {
|
||||
changeEmail: ChangeEmailHandler
|
||||
} & ChangeEmailHookState
|
||||
|
||||
type ChangeEmailHook = {
|
||||
(options?: ChangeEmailOptions): ChangeEmailHookResult
|
||||
/** @deprecated */
|
||||
(email?: string, options?: ChangeEmailOptions): ChangeEmailHookResult
|
||||
}
|
||||
|
||||
export const useChangeEmail: ChangeEmailHook = (
|
||||
a?: string | ChangeEmailOptions,
|
||||
b?: ChangeEmailOptions
|
||||
) => {
|
||||
const stateEmail = typeof a === 'string' ? a : undefined
|
||||
const stateOptions = typeof a !== 'string' ? a : b
|
||||
const nhost = useNhostClient()
|
||||
const machine = useMemo(() => createChangeEmailMachine(nhost.auth.client), [nhost])
|
||||
const [current, send] = useMachine(machine)
|
||||
|
||||
const isError = current.matches({ idle: 'error' })
|
||||
const needsEmailVerification = current.matches({ idle: 'success' })
|
||||
const error = current.context.error
|
||||
const isLoading = current.matches('requesting')
|
||||
|
||||
const changeEmail = (valueEmail?: string | unknown, valueOptions = stateOptions) =>
|
||||
send({
|
||||
type: 'REQUEST',
|
||||
email: typeof valueEmail === 'string' ? valueEmail : stateEmail,
|
||||
options: valueOptions
|
||||
const [, send, service] = useMachine(machine)
|
||||
const [isError, setIsError] = useState(false)
|
||||
const [needsEmailVerification, setNeedsEmailVerification] = useState(false)
|
||||
const [error, setError] = useState<ErrorPayload | null>(null)
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const changeEmail: ChangeEmailHandler = async (
|
||||
valueEmail?: string | unknown,
|
||||
valueOptions = stateOptions
|
||||
) =>
|
||||
new Promise<ChangeEmailHandlerResult>((resolve) => {
|
||||
send({
|
||||
type: 'REQUEST',
|
||||
email: typeof valueEmail === 'string' ? valueEmail : stateEmail,
|
||||
options: valueOptions
|
||||
})
|
||||
service.onTransition((state) => {
|
||||
if (state.matches({ idle: 'error' })) {
|
||||
const error = state.context.error
|
||||
setIsError(true)
|
||||
setError(error)
|
||||
setIsLoading(false)
|
||||
resolve({ isError: true, error, needsEmailVerification })
|
||||
} else if (state.matches('requesting')) {
|
||||
setIsLoading(true)
|
||||
} else if (state.matches({ idle: 'success' })) {
|
||||
setIsError(false)
|
||||
setError(null)
|
||||
setIsLoading(false)
|
||||
setNeedsEmailVerification(true)
|
||||
resolve({ isError: false, error: null, needsEmailVerification: true })
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return { changeEmail, isLoading, needsEmailVerification, isError, error }
|
||||
}
|
||||
|
||||
export const useChangePassword = (statePassword?: string) => {
|
||||
type ChangePasswordHandlerResult = Omit<ActionHookState, 'isLoading'>
|
||||
type ChangePasswordHandler = {
|
||||
(password: string): Promise<ChangePasswordHandlerResult>
|
||||
/** @deprecated */
|
||||
(password?: unknown): Promise<ChangePasswordHandlerResult>
|
||||
}
|
||||
|
||||
type ChangePasswordHookResult = {
|
||||
changePassword: ChangePasswordHandler
|
||||
} & ActionHookState
|
||||
|
||||
type ChangePasswordHook = {
|
||||
(): ChangePasswordHookResult
|
||||
/** @deprecated */
|
||||
(email?: string): ChangePasswordHookResult
|
||||
}
|
||||
|
||||
export const useChangePassword: ChangePasswordHook = (statePassword?: string) => {
|
||||
const nhost = useNhostClient()
|
||||
const machine = useMemo(() => createChangePasswordMachine(nhost.auth.client), [nhost])
|
||||
const [current, send] = useMachine(machine)
|
||||
const [current, send, service] = useMachine(machine)
|
||||
const isError = current.matches({ idle: 'error' })
|
||||
const isSuccess = current.matches({ idle: 'success' })
|
||||
const error = current.context.error
|
||||
const isLoading = current.matches('requesting')
|
||||
|
||||
const changePassword = (valuePassword?: string | unknown) =>
|
||||
send({
|
||||
type: 'REQUEST',
|
||||
password: typeof valuePassword === 'string' ? valuePassword : statePassword
|
||||
const changePassword: ChangePasswordHandler = (valuePassword?: string | unknown) =>
|
||||
new Promise<ChangePasswordHandlerResult>((resolve) => {
|
||||
send({
|
||||
type: 'REQUEST',
|
||||
password: typeof valuePassword === 'string' ? valuePassword : statePassword
|
||||
})
|
||||
service.onTransition((state) => {
|
||||
if (state.matches({ idle: 'error' })) {
|
||||
resolve({ error: state.context.error, isError: true, isSuccess: false })
|
||||
} else if (state.matches({ idle: 'success' })) {
|
||||
resolve({ error: null, isError: false, isSuccess: true })
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return { changePassword, isLoading, isSuccess, isError, error }
|
||||
}
|
||||
|
||||
export const useResetPassword = (stateEmail?: string, stateOptions?: ResetPasswordOptions) => {
|
||||
type ResetPasswordHandlerResult = Omit<ResetPasswordHookState, 'isLoading'>
|
||||
type ResetPasswordHandler = {
|
||||
(email: string, options?: ResetPasswordOptions): Promise<ResetPasswordHandlerResult>
|
||||
/** @deprecated */
|
||||
(email?: unknown, options?: ResetPasswordOptions): Promise<ResetPasswordHandlerResult>
|
||||
}
|
||||
|
||||
type ResetPasswordHookState = ActionHookState<'isSent'>
|
||||
|
||||
type ResetPasswordHookResult = {
|
||||
resetPassword: ResetPasswordHandler
|
||||
} & ResetPasswordHookState
|
||||
|
||||
type ResetPasswordHook = {
|
||||
(options?: ResetPasswordOptions): ResetPasswordHookResult
|
||||
/** @deprecated */
|
||||
(email?: string, options?: ResetPasswordOptions): ResetPasswordHookResult
|
||||
}
|
||||
|
||||
export const useResetPassword: ResetPasswordHook = (
|
||||
a?: string | ResetPasswordOptions,
|
||||
b?: ResetPasswordOptions
|
||||
) => {
|
||||
const stateEmail = typeof a === 'string' ? a : undefined
|
||||
const stateOptions = typeof a !== 'string' ? a : b
|
||||
const nhost = useNhostClient()
|
||||
const machine = useMemo(() => createResetPasswordMachine(nhost.auth.client), [nhost])
|
||||
const [current, send] = useMachine(machine)
|
||||
const [current, send, service] = useMachine(machine)
|
||||
const isError = current.matches({ idle: 'error' })
|
||||
const isSent = current.matches({ idle: 'success' })
|
||||
const error = current.context.error
|
||||
const isLoading = current.matches('requesting')
|
||||
|
||||
const resetPassword = (valueEmail?: string | unknown, valueOptions = stateOptions) =>
|
||||
send({
|
||||
type: 'REQUEST',
|
||||
email: typeof valueEmail === 'string' ? valueEmail : stateEmail,
|
||||
options: valueOptions
|
||||
const resetPassword: ResetPasswordHandler = (
|
||||
valueEmail?: string | unknown,
|
||||
valueOptions = stateOptions
|
||||
) =>
|
||||
new Promise<ResetPasswordHandlerResult>((resolve) => {
|
||||
send({
|
||||
type: 'REQUEST',
|
||||
email: typeof valueEmail === 'string' ? valueEmail : stateEmail,
|
||||
options: valueOptions
|
||||
})
|
||||
service.onTransition((state) => {
|
||||
if (state.matches({ idle: 'error' })) {
|
||||
resolve({ error: state.context.error, isError: true, isSent: false })
|
||||
} else if (state.matches({ idle: 'success' })) {
|
||||
resolve({ error: null, isError: false, isSent: true })
|
||||
}
|
||||
})
|
||||
})
|
||||
return { resetPassword, isLoading, isSent, isError, error }
|
||||
}
|
||||
@@ -150,37 +257,103 @@ export const useUserRoles = () => {
|
||||
)
|
||||
}
|
||||
|
||||
export const useSendVerificationEmail = (
|
||||
stateEmail?: string,
|
||||
stateOptions?: SendVerificationEmailOptions
|
||||
type SendVerificationEmailHandlerResult = Omit<SendVerificationEmailHookState, 'isLoading'>
|
||||
type SendVerificationEmailHandler = {
|
||||
(
|
||||
email: string,
|
||||
options?: SendVerificationEmailOptions
|
||||
): Promise<SendVerificationEmailHandlerResult>
|
||||
/** @deprecated */
|
||||
(
|
||||
email?: unknown,
|
||||
options?: SendVerificationEmailOptions
|
||||
): Promise<SendVerificationEmailHandlerResult>
|
||||
}
|
||||
|
||||
type SendVerificationEmailHookState = ActionHookState<'isSent'>
|
||||
|
||||
type SendVerificationEmailHookResult = {
|
||||
sendEmail: SendVerificationEmailHandler
|
||||
} & SendVerificationEmailHookState
|
||||
|
||||
type SendVerificationEmailHook = {
|
||||
(options?: SendVerificationEmailOptions): SendVerificationEmailHookResult
|
||||
/** @deprecated */
|
||||
(email?: string, options?: SendVerificationEmailOptions): SendVerificationEmailHookResult
|
||||
}
|
||||
export const useSendVerificationEmail: SendVerificationEmailHook = (
|
||||
a?: string | SendVerificationEmailOptions,
|
||||
b?: SendVerificationEmailOptions
|
||||
) => {
|
||||
const stateEmail = typeof a === 'string' ? a : undefined
|
||||
const stateOptions = typeof a !== 'string' ? a : b
|
||||
const nhost = useNhostClient()
|
||||
const machine = useMemo(() => createSendVerificationEmailMachine(nhost.auth.client), [nhost])
|
||||
const [current, send] = useMachine(machine)
|
||||
const [current, send, service] = useMachine(machine)
|
||||
const isError = current.matches({ idle: 'error' })
|
||||
const isSent = current.matches({ idle: 'success' })
|
||||
const error = current.context.error
|
||||
const isLoading = current.matches('requesting')
|
||||
|
||||
const sendEmail = (valueEmail?: string | unknown, valueOptions = stateOptions) =>
|
||||
send({
|
||||
type: 'REQUEST',
|
||||
email: typeof valueEmail === 'string' ? valueEmail : stateEmail,
|
||||
options: valueOptions
|
||||
const sendEmail: SendVerificationEmailHandler = (
|
||||
valueEmail?: string | unknown,
|
||||
valueOptions = stateOptions
|
||||
) =>
|
||||
new Promise<SendVerificationEmailHandlerResult>((resolve) => {
|
||||
send({
|
||||
type: 'REQUEST',
|
||||
email: typeof valueEmail === 'string' ? valueEmail : stateEmail,
|
||||
options: valueOptions
|
||||
})
|
||||
service.onTransition((state) => {
|
||||
if (state.matches({ idle: 'error' })) {
|
||||
resolve({ error: state.context.error, isError: true, isSent: false })
|
||||
} else if (state.matches({ idle: 'success' })) {
|
||||
resolve({ error: null, isError: false, isSent: true })
|
||||
}
|
||||
})
|
||||
})
|
||||
return { sendEmail, isLoading, isSent, isError, error }
|
||||
}
|
||||
|
||||
type ActivateMfaHookState = {
|
||||
isActivating: boolean
|
||||
isActivated: boolean
|
||||
isError: boolean
|
||||
error: ErrorPayload | null
|
||||
}
|
||||
type GenerateQrCodeHookState = {
|
||||
qrCodeDataUrl: string
|
||||
isGenerating: boolean
|
||||
isGenerated: boolean
|
||||
isError: boolean
|
||||
error: ErrorPayload | null
|
||||
}
|
||||
type ActivateMfaHandlerResult = Omit<ActivateMfaHookState, 'isActivating'>
|
||||
type ActivateMfaHandler = (code: string) => Promise<ActivateMfaHandlerResult>
|
||||
|
||||
type GenerateQrCodeHandlerResult = Omit<GenerateQrCodeHookState, 'isGenerating'>
|
||||
type GenerateQrCodeHandler = () => Promise<GenerateQrCodeHandlerResult>
|
||||
|
||||
type ConfigMfaHookState = ActivateMfaHookState &
|
||||
GenerateQrCodeHookState & {
|
||||
generateQrCode: GenerateQrCodeHandler
|
||||
activateMfa: ActivateMfaHandler
|
||||
}
|
||||
|
||||
type ConfigMfaHook = () => ConfigMfaHookState
|
||||
|
||||
// TODO documentation when available in Nhost Cloud - see changelog
|
||||
export const useConfigMfa = (stateCode?: string) => {
|
||||
export const useConfigMfa: ConfigMfaHook = () => {
|
||||
const nhost = useNhostClient()
|
||||
|
||||
const machine = useMemo(() => createEnableMfaMachine(nhost.auth.client), [nhost])
|
||||
const [current, send] = useMachine(machine)
|
||||
const [current, send, service] = useMachine(machine)
|
||||
|
||||
const isError = useMemo(() => {
|
||||
current.matches({ idle: 'error' }) || current.matches({ generated: { idle: 'error' } })
|
||||
}, [current])
|
||||
const isError = useMemo(
|
||||
() => current.matches({ idle: 'error' }) || current.matches({ generated: { idle: 'error' } }),
|
||||
[current]
|
||||
)
|
||||
const isGenerating = current.matches('generating')
|
||||
const isGenerated = current.matches('generated')
|
||||
const isActivating = current.matches({ generated: 'activating' })
|
||||
@@ -188,12 +361,41 @@ export const useConfigMfa = (stateCode?: string) => {
|
||||
const error = current.context.error
|
||||
const qrCodeDataUrl = current.context.imageUrl || ''
|
||||
|
||||
const generateQrCode = () => send('GENERATE')
|
||||
const activateMfa = (valueCode?: string | unknown) =>
|
||||
send({
|
||||
type: 'ACTIVATE',
|
||||
activeMfaType: 'totp',
|
||||
code: typeof valueCode === 'string' ? valueCode : stateCode
|
||||
const generateQrCode: GenerateQrCodeHandler = () =>
|
||||
new Promise<GenerateQrCodeHandlerResult>((resolve) => {
|
||||
send('GENERATE')
|
||||
service.onTransition((state) => {
|
||||
if (state.matches('generated')) {
|
||||
resolve({
|
||||
error: null,
|
||||
isError: false,
|
||||
isGenerated: true,
|
||||
qrCodeDataUrl: state.context.imageUrl || ''
|
||||
})
|
||||
} else if (state.matches({ idle: 'error' })) {
|
||||
resolve({
|
||||
error: state.context.error || null,
|
||||
isError: true,
|
||||
isGenerated: false,
|
||||
qrCodeDataUrl: ''
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
const activateMfa: ActivateMfaHandler = (code: string) =>
|
||||
new Promise<ActivateMfaHandlerResult>((resolve) => {
|
||||
send({
|
||||
type: 'ACTIVATE',
|
||||
activeMfaType: 'totp',
|
||||
code
|
||||
})
|
||||
service.onTransition((state) => {
|
||||
if (state.matches({ generated: 'activated' })) {
|
||||
resolve({ error: null, isActivated: true, isError: false })
|
||||
} else if (state.matches({ generated: { idle: 'error' } })) {
|
||||
resolve({ error: state.context.error, isActivated: false, isError: true })
|
||||
}
|
||||
})
|
||||
})
|
||||
return {
|
||||
generateQrCode,
|
||||
|
||||
Reference in New Issue
Block a user