Compare commits
117 Commits
@nhost/cor
...
@nhost/rea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
024f026241 | ||
|
|
a422a4850d | ||
|
|
a7e67979fe | ||
|
|
1dcbf268db | ||
|
|
5c5d489740 | ||
|
|
a2559e3482 | ||
|
|
bbef104a85 | ||
|
|
7843b1aec1 | ||
|
|
4711bfa8ec | ||
|
|
6f3f8a5020 | ||
|
|
a120bcc8fc | ||
|
|
53e20e87f3 | ||
|
|
9479aeb596 | ||
|
|
c4f11af072 | ||
|
|
747aa96914 | ||
|
|
5682d92592 | ||
|
|
2cf6556499 | ||
|
|
89553fcaf6 | ||
|
|
10beea7246 | ||
|
|
1334ddb693 | ||
|
|
d212128815 | ||
|
|
302c28b202 | ||
|
|
f3f760b987 | ||
|
|
9d9caf9834 | ||
|
|
96cbf023ca | ||
|
|
1ed534cb4a | ||
|
|
dcdee0b426 | ||
|
|
e31f4756b4 | ||
|
|
259e198d80 | ||
|
|
1d10a47414 | ||
|
|
34470ff6e0 | ||
|
|
f30d6779bb | ||
|
|
2a3b2c3af5 | ||
|
|
a0db6b58de | ||
|
|
523d52aa7f | ||
|
|
6e1ee1802d | ||
|
|
51ad1eb355 | ||
|
|
ee2dd8481b | ||
|
|
b8e787cb47 | ||
|
|
2ef5c238c1 | ||
|
|
e084643032 | ||
|
|
5514e81186 | ||
|
|
16f38aa893 | ||
|
|
76c6e8d0d6 | ||
|
|
197d1d5cfc | ||
|
|
abd43d0a8b | ||
|
|
70383c8c80 | ||
|
|
a7d5c85f60 | ||
|
|
bc657251d6 | ||
|
|
5abc362a4d | ||
|
|
7a4c9fa806 | ||
|
|
348318d709 | ||
|
|
4e4600d769 | ||
|
|
44d57d4b89 | ||
|
|
84ba29dd7f | ||
|
|
b5f7f7fe5f | ||
|
|
7116a4df8a | ||
|
|
7e4c52dbd1 | ||
|
|
446dc01bde | ||
|
|
a1989c51f8 | ||
|
|
1383de558a | ||
|
|
d828107f74 | ||
|
|
4a1650cb35 | ||
|
|
913651d440 | ||
|
|
6af2d52666 | ||
|
|
da7c2a2362 | ||
|
|
4a7940b59a | ||
|
|
ddda8bb031 | ||
|
|
b146e60f7e | ||
|
|
5591789840 | ||
|
|
fac5ddb866 | ||
|
|
f2fab8dac2 | ||
|
|
6e3f2c382d | ||
|
|
05385d01dc | ||
|
|
7ea72b799c | ||
|
|
4936261cee | ||
|
|
80902b9cf1 | ||
|
|
c3af490e67 | ||
|
|
6a24e32857 | ||
|
|
0ebddd30cf | ||
|
|
d019f1de21 | ||
|
|
3abb57f510 | ||
|
|
4a2ad15f14 | ||
|
|
ca45b612c9 | ||
|
|
27ee9b721f | ||
|
|
2a373dd50f | ||
|
|
a91f714c4c | ||
|
|
3b4d89d5b6 | ||
|
|
16d1b26298 | ||
|
|
86d8beb044 | ||
|
|
17f870f31f | ||
|
|
fbfffe25ca | ||
|
|
87a472b27e | ||
|
|
779b03b0b2 | ||
|
|
9d933b6ffd | ||
|
|
34d643868d | ||
|
|
0023f5f6f6 | ||
|
|
48f5c8bfb9 | ||
|
|
f398b2e3ac | ||
|
|
11795abe61 | ||
|
|
e2eafc9ee1 | ||
|
|
4a908af7ef | ||
|
|
a7b6498053 | ||
|
|
7f418a7559 | ||
|
|
50474810bf | ||
|
|
ead2c16aac | ||
|
|
21fa83d115 | ||
|
|
522839d8f7 | ||
|
|
87aad599f3 | ||
|
|
5b097e635d | ||
|
|
bfdcacd5a3 | ||
|
|
dcb9055475 | ||
|
|
6f0bf3d67c | ||
|
|
3c96c561a0 | ||
|
|
3d319364f3 | ||
|
|
18ac56d097 | ||
|
|
366fc2403d |
@@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npx lint-staged
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"packages/(docgen|hasura-auth-js|hasura-storage-js|nextjs|nhost-js|react|core|vue)/src/**/*.{js,ts,jsx,tsx}": [
|
||||
"pnpm docgen",
|
||||
"git add docs"
|
||||
]
|
||||
}
|
||||
47
README.md
@@ -147,13 +147,6 @@ Here are some ways of contributing to making Nhost better:
|
||||
<sub><b>Johan Eliasson</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/szilarddoro">
|
||||
<img src="https://avatars.githubusercontent.com/u/310881?v=4" width="100;" alt="szilarddoro"/>
|
||||
<br />
|
||||
<sub><b>Szilárd Dóró</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/gdangelo">
|
||||
<img src="https://avatars.githubusercontent.com/u/4352286?v=4" width="100;" alt="gdangelo"/>
|
||||
@@ -174,15 +167,15 @@ Here are some ways of contributing to making Nhost better:
|
||||
<br />
|
||||
<sub><b>Guido Curcio</b></sub>
|
||||
</a>
|
||||
</td></tr>
|
||||
<tr>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/subatuba21">
|
||||
<img src="https://avatars.githubusercontent.com/u/34824571?v=4" width="100;" alt="subatuba21"/>
|
||||
<br />
|
||||
<sub><b>Subha Das</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://github.com/sebagudelo">
|
||||
<img src="https://avatars.githubusercontent.com/u/43288271?v=4" width="100;" alt="sebagudelo"/>
|
||||
@@ -204,21 +197,35 @@ Here are some ways of contributing to making Nhost better:
|
||||
<sub><b>Pratim</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/szilarddoro">
|
||||
<img src="https://avatars.githubusercontent.com/u/310881?v=4" width="100;" alt="szilarddoro"/>
|
||||
<br />
|
||||
<sub><b>Szilárd Dóró</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/GavanWilhite">
|
||||
<img src="https://avatars.githubusercontent.com/u/2085119?v=4" width="100;" alt="GavanWilhite"/>
|
||||
<br />
|
||||
<sub><b>Gavan Wilhite</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/FuzzyReason">
|
||||
<img src="https://avatars.githubusercontent.com/u/62517920?v=4" width="100;" alt="FuzzyReason"/>
|
||||
<br />
|
||||
<sub><b>Vadim Smirnov</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://github.com/macmac49">
|
||||
<img src="https://avatars.githubusercontent.com/u/831190?v=4" width="100;" alt="macmac49"/>
|
||||
<br />
|
||||
<sub><b>Macmac49</b></sub>
|
||||
</a>
|
||||
</td></tr>
|
||||
<tr>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/subhendukundu">
|
||||
<img src="https://avatars.githubusercontent.com/u/20059141?v=4" width="100;" alt="subhendukundu"/>
|
||||
@@ -253,13 +260,6 @@ Here are some ways of contributing to making Nhost better:
|
||||
<br />
|
||||
<sub><b>Filip Hájek</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/GavanWilhite">
|
||||
<img src="https://avatars.githubusercontent.com/u/2085119?v=4" width="100;" alt="GavanWilhite"/>
|
||||
<br />
|
||||
<sub><b>Gavan Wilhite</b></sub>
|
||||
</a>
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
@@ -391,6 +391,13 @@ Here are some ways of contributing to making Nhost better:
|
||||
</a>
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://github.com/nachoaldamav">
|
||||
<img src="https://avatars.githubusercontent.com/u/22749943?v=4" width="100;" alt="nachoaldamav"/>
|
||||
<br />
|
||||
<sub><b>Nacho Aldama</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/ghoshnirmalya">
|
||||
<img src="https://avatars.githubusercontent.com/u/6391763?v=4" width="100;" alt="ghoshnirmalya"/>
|
||||
|
||||
4
config/.husky/pre-commit
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npx lint-staged --config config/.lintstagedrc.js
|
||||
8
config/.lintstagedrc.js
Normal file
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
'packages/(docgen|hasura-auth-js|hasura-storage-js|nextjs|nhost-js|react|core|vue)/src/**/*.{js,ts,jsx,tsx}':
|
||||
['pnpm docgen', 'git add docs'],
|
||||
'(nhost-cloud.yaml|**/nhost/config.yaml)': () => [
|
||||
'pnpm sync-versions',
|
||||
"git add ':(glob)**/nhost/config.yaml'"
|
||||
]
|
||||
}
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost/docs
|
||||
|
||||
## 0.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 747aa969: fix: added twitch and discord as provider
|
||||
|
||||
## 0.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
---
|
||||
title: Sign In with Apple
|
||||
sidebar_label: Apple
|
||||
slug: /platform/authentication/sign-in-with-apple
|
||||
image: /img/og/platform/sign-in-with-apple.png
|
||||
---
|
||||
|
||||
Follow this guide to sign in users with Apple with your Nhost App.
|
||||
|
||||
<p align="center">
|
||||
<img
|
||||
alt="Apple Sign In Preview"
|
||||
src="/img/social-providers/apple-preview.svg"
|
||||
width={480}
|
||||
height={267}
|
||||
/>
|
||||
</p>
|
||||
|
||||
## Create Apple Developer Account
|
||||
|
||||
- Click on "Account" in the top menu.
|
||||
- Create a new [Apple Developer account](https://developer.apple.com) if you don't have one already and sign in to the Apple Developer platform.
|
||||
|
||||
## Get an App ID
|
||||
|
||||
- Go to the [Apple Developer Dashboard](https://developer.apple.com/account/).
|
||||
- Click on **Certificates, IDs & Profiles** in the left menu.
|
||||
- Click on **Identifiers** in the left menu.
|
||||
- Click on the "+" button in the header next to "Identifiers".
|
||||
- Select **App IDs** and click **Continue**.
|
||||
- Select type **App** and click **Continue**.
|
||||
- Fill in the App information:
|
||||
|
||||
- Description.
|
||||
- Bundle ID (ex. io.nhost.app or com.your-startup.app).
|
||||
- Scroll down and check **Sign In With Apple**.
|
||||
- Click **Continue** in the top right corner.
|
||||
- Click **Register** in the top right corner.
|
||||
|
||||
- Click on the newly created app to see **Team ID**.
|
||||
|
||||
- **Team ID**: Copy and paste the **Team ID** to your Nhost OAuth settings for Apple.
|
||||
|
||||
## Get a Service ID
|
||||
|
||||
- Go to the [Apple Developer Dashboard](https://developer.apple.com/account/).
|
||||
- Click on **Certificates, IDs & Profiles** in the left menu.
|
||||
- Click on **Identifiers** in the left menu.
|
||||
- Click on **Certificates, IDs & Profiles** in the left menu.
|
||||
- Click on **Identifiers** in the left menu.
|
||||
- Click on the "+" button in the header next to "Identifiers".
|
||||
- Select **Service IDs** and click **Continue**.
|
||||
|
||||
- Fill in the Service information:
|
||||
|
||||
- Description.
|
||||
- Identifier (Service ID) (ex. _service_.io.nhost.app or _service_.com.your-startup.app). Notice you can't use the same identifier as for the app so we recommend adding "service" at the beginning if the identifier.
|
||||
- **Service ID**: Copy and paste the **Identifier (Service ID)** to your Nhost OAuth settings for Apple.
|
||||
- Click **Continue** in the top right corner.
|
||||
- Click **Register** in the top right corner.
|
||||
|
||||
- Click on the newly created service in the list of Identifiers.
|
||||
- Click the checkbox to enable "Sign in with Apple".
|
||||
- Click **Configure** next to "Sign in with Apple".
|
||||
- Make sure your newly created Bundle ID is selected under Primary App ID.
|
||||
- Add your base auth domain under "Domains and Subdomains". E.g. `<subdomain>.nhost.run`.
|
||||
- Add the full callback URL under "Return URLs". E.g. `https://<subdomain>.nhost.run/v1/auth/signin/provider/apple/callback`.
|
||||
- Click **Next**.
|
||||
- Click **Done**.
|
||||
- Click **Continue** in the top right corner.
|
||||
- Click **Save** in the top right corner.
|
||||
|
||||
## Generate Key
|
||||
|
||||
- Go to the [Apple Developer Dashboard](https://developer.apple.com/account/).
|
||||
- Click on **Certificates, IDs & Profiles** in the left menu.
|
||||
- Click on **Keys** in the left menu.
|
||||
- Click on **Create a key**.
|
||||
- Fill in a name for your key.
|
||||
- Click the checkbox to enable "Sign in with Apple".
|
||||
- Click **Configure** next to "Sign in with Apple".
|
||||
- Select your newly created App ID in the dropdown selector.
|
||||
- Click **Save** in the top right corner.
|
||||
- Click **Continue** in the top right corner.
|
||||
- Click **Register** in the top right corner.
|
||||
- **Key ID**: Copy and paste the **Key ID** to your Nhost OAuth settings for Apple.
|
||||
- Click **Download** to download the key to your computer.
|
||||
- **Private Key**: Copy and paste the content of the downloaded key to your Nhost OAuth settings for Apple.
|
||||
|
||||
## Sign In Users
|
||||
|
||||
Use the [Nhost JavaScript client](/reference/javascript) to sign in users in your app:
|
||||
|
||||
```js
|
||||
nhost.auth.signIn({
|
||||
provider: 'apple'
|
||||
})
|
||||
```
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
title: Sign In with Discord
|
||||
sidebar_label: Discord
|
||||
slug: /platform/authentication/sign-in-with-discord
|
||||
image: /img/og/platform/sign-in-with-discord.png
|
||||
---
|
||||
|
||||
Follow this guide to sign in users with Discord with your Nhost App.
|
||||
|
||||
<p align="center">
|
||||
<img
|
||||
alt="Discord Sign In Preview"
|
||||
src="/img/social-providers/discord-preview.svg"
|
||||
width={480}
|
||||
height={267}
|
||||
/>
|
||||
</p>
|
||||
|
||||
## Create Discord Account
|
||||
|
||||
- Create a new [Discord account](https://discord.com/) if you don't have one already.
|
||||
|
||||
## Create Discord App
|
||||
|
||||
- Sign in to the [Discord Developer Portal](https://discord.com/developers/applications).
|
||||
- Click on **New Application** in the top right corner.
|
||||
- Fill in the name of your Discord Application and click **Create**.
|
||||
- Click on **OAuth2** settings in the left menu.
|
||||
- Copy the **Client ID** and paste it into your Nhost OAuth settings for Discord.
|
||||
- Click on **Reset Secret**.
|
||||
- Click **Yes, do it** to generate a new secret.
|
||||
- Copy the **Client Secret** and paste it into your Nhost OAuth settings for Discord.
|
||||
- Click on **Add Redirect**.
|
||||
- Copy and paste the callback URL from your Nhost OAuth settings for Discord to the input field in the Discord Developer portal.
|
||||
- Click **Save Changes** to save the added callback URL.
|
||||
|
||||
## Sign In Users
|
||||
|
||||
Use the [Nhost JavaScript client](/reference/javascript) to sign in users in your app:
|
||||
|
||||
```js
|
||||
nhost.auth.signIn({
|
||||
provider: 'discord'
|
||||
})
|
||||
```
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
title: Sign In with Twitch
|
||||
sidebar_label: Twitch
|
||||
slug: /platform/authentication/sign-in-with-twitch
|
||||
image: /img/og/platform/sign-in-with-twitch.png
|
||||
---
|
||||
|
||||
Follow this guide to sign in users with Twitch with your Nhost App.
|
||||
|
||||
<p align="center">
|
||||
<img
|
||||
alt="Twitch Sign In Preview"
|
||||
src="/img/social-providers/twitch-preview.svg"
|
||||
width={480}
|
||||
height={267}
|
||||
/>
|
||||
</p>
|
||||
|
||||
## Create Twitch Account
|
||||
|
||||
- Create a new [Twitch account](https://twitch.tv/) if you don't have one already.
|
||||
|
||||
## Create Twitch App
|
||||
|
||||
- Sign in to the [Twitch Developer Console](https://dev.twitch.tv/console).
|
||||
- Click on **Register Your Application**.
|
||||
- Fill in a **Twitch application name**.
|
||||
- Copy and paste the callback URL from your Nhost OAuth settings for Twitch to the input field under **OAuth Redirect URLs** and click **Add** to the right of the input field.
|
||||
- Select an application **Category**. E.g. _Application Integration_.
|
||||
- Click **Create**.
|
||||
|
||||
## Get Twitch Appplication Client ID and Client Secret
|
||||
|
||||
- Click on **Manage** on your newly created Twitch application.
|
||||
- Copy the **Client ID** and paste it into your Nhost OAuth settings for Twitch.
|
||||
- Click on **New Secret** to generate a new client secret.
|
||||
- Copy the **Client Secret** and paste it into your Nhost OAuth settings for Twitch.
|
||||
|
||||
## Sign In Users
|
||||
|
||||
Use the [Nhost JavaScript client](/reference/javascript) to sign in users in your app:
|
||||
|
||||
```js
|
||||
nhost.auth.signIn({
|
||||
provider: 'twitch'
|
||||
})
|
||||
```
|
||||
@@ -35,6 +35,18 @@ nhost.auth.signIn({
|
||||
|
||||
Users are redirected to your Nhost app's **client URL** by default. By default, your Nhost app's client URL is set to `http://localhost:3000`. You can change the value of your client URL in the Nhost console by going to **Users** → **Authentication Settings** → **Client URL**.
|
||||
|
||||
|
||||
Here is an example of how to redirect to another host or path:
|
||||
|
||||
```js
|
||||
nhost.auth.signIn({
|
||||
provider: '<provider>'
|
||||
options: {
|
||||
redirectTo: "<host>/<slug>" // Example: "https://example.com/dashboard"
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
## Provider OAuth scopes
|
||||
|
||||
Scopes are a mechanism in OAuth to allow or limit an application's access to a user's account.
|
||||
|
||||
@@ -22,4 +22,6 @@ type Provider =
|
||||
| 'strava'
|
||||
| 'gitlab'
|
||||
| 'bitbucket'
|
||||
| 'discord'
|
||||
| 'twitch'
|
||||
```
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
# ⚠️ AUTO-GENERATED CONTENT. DO NOT EDIT THIS FILE DIRECTLY! ⚠️
|
||||
title: useSignInSmsPasswordless()
|
||||
sidebar_label: useSignInSmsPasswordless()
|
||||
slug: /reference/nextjs/use-sign-in-sms-passwordless
|
||||
description: Use the hook `useSignInSmsPasswordless` to sign in a user with a one-time password sent via SMS to a phone.
|
||||
custom_edit_url: https://github.com/nhost/nhost/edit/main/packages/react/src/useSignInSmsPasswordless.ts#L57
|
||||
---
|
||||
|
||||
# `useSignInSmsPasswordless()`
|
||||
|
||||
Use the hook `useSignInSmsPasswordless` to sign in a user with a one-time password sent via SMS to a phone.
|
||||
|
||||
1. The `signInSmsPasswordless` action sends a one-time password to the given phone number.
|
||||
2. The client is then awaiting the OTP. `needsOtp` equals true.
|
||||
3. After the code is received by SMS, the client sends the code with `sendOtp`. On success, the client is authenticated, and `isSuccess` equals `true`.
|
||||
|
||||
Any error is monitored through `isError` and `error`. While the `signInSmsPasswordless` and `sendOtp` actions are running, `isLoading` equals `true`.
|
||||
|
||||
```tsx
|
||||
const {
|
||||
signInSmsPasswordless,
|
||||
sendOtp,
|
||||
needsOtp,
|
||||
isLoading,
|
||||
isSuccess,
|
||||
isError,
|
||||
error
|
||||
} = useSignInSmsPasswordless()
|
||||
|
||||
console.log({ isLoading, isSuccess, isError, error })
|
||||
|
||||
const askCode = async (e) => {
|
||||
e.preventDefault()
|
||||
await signInSmsPasswordless('+32455555555')
|
||||
}
|
||||
|
||||
const sendCode = async (e) => {
|
||||
e.preventDefault()
|
||||
await sendOtp('123456')
|
||||
}
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
---
|
||||
|
||||
**<span className="parameter-name">stateOptions</span>** <span className="optional-status">optional</span> `PasswordlessOptions`
|
||||
|
||||
---
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
# ⚠️ AUTO-GENERATED CONTENT. DO NOT EDIT THIS FILE DIRECTLY! ⚠️
|
||||
title: SignInSmsPasswordlessHandler
|
||||
sidebar_label: SignInSmsPasswordlessHandler
|
||||
description: No description provided.
|
||||
displayed_sidebar: referenceSidebar
|
||||
custom_edit_url: https://github.com/nhost/nhost/edit/main/packages/react/src/useSignInSmsPasswordless.ts#L14
|
||||
---
|
||||
|
||||
# `SignInSmsPasswordlessHandler`
|
||||
@@ -0,0 +1,62 @@
|
||||
---
|
||||
# ⚠️ AUTO-GENERATED CONTENT. DO NOT EDIT THIS FILE DIRECTLY! ⚠️
|
||||
title: SignInSmsPasswordlessHookResult
|
||||
sidebar_label: SignInSmsPasswordlessHookResult
|
||||
description: No description provided.
|
||||
displayed_sidebar: referenceSidebar
|
||||
custom_edit_url: https://github.com/nhost/nhost/edit/main/packages/react/src/useSignInSmsPasswordless.ts#L23
|
||||
---
|
||||
|
||||
# `SignInSmsPasswordlessHookResult`
|
||||
|
||||
## Parameters
|
||||
|
||||
---
|
||||
|
||||
**<span className="parameter-name">needsOtp</span>** <span className="optional-status">required</span> `boolean`
|
||||
|
||||
Returns true when the one-time password has been sent over by SMS, and the user needs to send it back to complete sign-in.
|
||||
|
||||
---
|
||||
|
||||
**<span className="parameter-name">isError</span>** <span className="optional-status">required</span> `boolean`
|
||||
|
||||
**`@returns`**
|
||||
|
||||
`true` if an error occurred
|
||||
|
||||
**`@depreacted`**
|
||||
|
||||
use `!isSuccess` or `!!error` instead
|
||||
|
||||
---
|
||||
|
||||
**<span className="parameter-name">error</span>** <span className="optional-status">required</span> `null` | `ErrorPayload`
|
||||
|
||||
Provides details about the error
|
||||
|
||||
---
|
||||
|
||||
**<span className="parameter-name">isLoading</span>** <span className="optional-status">required</span> `boolean`
|
||||
|
||||
**`@returns`**
|
||||
|
||||
`true` when the action is executing, `false` when it finished its execution.
|
||||
|
||||
---
|
||||
|
||||
**<span className="parameter-name">isSuccess</span>** <span className="optional-status">required</span> `boolean`
|
||||
|
||||
Returns `true` if the action is successful.
|
||||
|
||||
---
|
||||
|
||||
**<span className="parameter-name">signInSmsPasswordless</span>** <span className="optional-status">required</span> [`SignInSmsPasswordlessHandler`](/reference/docgen/nextjs/types/sign-in-sms-passwordless-handler)
|
||||
|
||||
Sends a one-time code to the given phoneNumber
|
||||
|
||||
---
|
||||
|
||||
**<span className="parameter-name">sendOtp</span>** <span className="optional-status">required</span> [`SignInSmsPasswordlessOtpHandler`](/reference/docgen/nextjs/types/sign-in-sms-passwordless-otp-handler)
|
||||
|
||||
---
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
# ⚠️ AUTO-GENERATED CONTENT. DO NOT EDIT THIS FILE DIRECTLY! ⚠️
|
||||
title: SignInSmsPasswordlessOtpHandler
|
||||
sidebar_label: SignInSmsPasswordlessOtpHandler
|
||||
description: No description provided.
|
||||
displayed_sidebar: referenceSidebar
|
||||
custom_edit_url: https://github.com/nhost/nhost/edit/main/packages/react/src/useSignInSmsPasswordless.ts#L18
|
||||
---
|
||||
|
||||
# `SignInSmsPasswordlessOtpHandler`
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
# ⚠️ AUTO-GENERATED CONTENT. DO NOT EDIT THIS FILE DIRECTLY! ⚠️
|
||||
title: useSignInSmsPasswordless()
|
||||
sidebar_label: useSignInSmsPasswordless()
|
||||
slug: /reference/react/use-sign-in-sms-passwordless
|
||||
description: Use the hook `useSignInSmsPasswordless` to sign in a user with a one-time password sent via SMS to a phone.
|
||||
custom_edit_url: https://github.com/nhost/nhost/edit/main/packages/react/src/useSignInSmsPasswordless.ts#L57
|
||||
---
|
||||
|
||||
# `useSignInSmsPasswordless()`
|
||||
|
||||
Use the hook `useSignInSmsPasswordless` to sign in a user with a one-time password sent via SMS to a phone.
|
||||
|
||||
1. The `signInSmsPasswordless` action sends a one-time password to the given phone number.
|
||||
2. The client is then awaiting the OTP. `needsOtp` equals true.
|
||||
3. After the code is received by SMS, the client sends the code with `sendOtp`. On success, the client is authenticated, and `isSuccess` equals `true`.
|
||||
|
||||
Any error is monitored through `isError` and `error`. While the `signInSmsPasswordless` and `sendOtp` actions are running, `isLoading` equals `true`.
|
||||
|
||||
```tsx
|
||||
const {
|
||||
signInSmsPasswordless,
|
||||
sendOtp,
|
||||
needsOtp,
|
||||
isLoading,
|
||||
isSuccess,
|
||||
isError,
|
||||
error
|
||||
} = useSignInSmsPasswordless()
|
||||
|
||||
console.log({ isLoading, isSuccess, isError, error })
|
||||
|
||||
const askCode = async (e) => {
|
||||
e.preventDefault()
|
||||
await signInSmsPasswordless('+32455555555')
|
||||
}
|
||||
|
||||
const sendCode = async (e) => {
|
||||
e.preventDefault()
|
||||
await sendOtp('123456')
|
||||
}
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
---
|
||||
|
||||
**<span className="parameter-name">stateOptions</span>** <span className="optional-status">optional</span> `PasswordlessOptions`
|
||||
|
||||
---
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
# ⚠️ AUTO-GENERATED CONTENT. DO NOT EDIT THIS FILE DIRECTLY! ⚠️
|
||||
title: SignInSmsPasswordlessHandler
|
||||
sidebar_label: SignInSmsPasswordlessHandler
|
||||
description: No description provided.
|
||||
displayed_sidebar: referenceSidebar
|
||||
custom_edit_url: https://github.com/nhost/nhost/edit/main/packages/react/src/useSignInSmsPasswordless.ts#L14
|
||||
---
|
||||
|
||||
# `SignInSmsPasswordlessHandler`
|
||||
@@ -0,0 +1,62 @@
|
||||
---
|
||||
# ⚠️ AUTO-GENERATED CONTENT. DO NOT EDIT THIS FILE DIRECTLY! ⚠️
|
||||
title: SignInSmsPasswordlessHookResult
|
||||
sidebar_label: SignInSmsPasswordlessHookResult
|
||||
description: No description provided.
|
||||
displayed_sidebar: referenceSidebar
|
||||
custom_edit_url: https://github.com/nhost/nhost/edit/main/packages/react/src/useSignInSmsPasswordless.ts#L23
|
||||
---
|
||||
|
||||
# `SignInSmsPasswordlessHookResult`
|
||||
|
||||
## Parameters
|
||||
|
||||
---
|
||||
|
||||
**<span className="parameter-name">needsOtp</span>** <span className="optional-status">required</span> `boolean`
|
||||
|
||||
Returns true when the one-time password has been sent over by SMS, and the user needs to send it back to complete sign-in.
|
||||
|
||||
---
|
||||
|
||||
**<span className="parameter-name">isError</span>** <span className="optional-status">required</span> `boolean`
|
||||
|
||||
**`@returns`**
|
||||
|
||||
`true` if an error occurred
|
||||
|
||||
**`@depreacted`**
|
||||
|
||||
use `!isSuccess` or `!!error` instead
|
||||
|
||||
---
|
||||
|
||||
**<span className="parameter-name">error</span>** <span className="optional-status">required</span> `null` | `ErrorPayload`
|
||||
|
||||
Provides details about the error
|
||||
|
||||
---
|
||||
|
||||
**<span className="parameter-name">isLoading</span>** <span className="optional-status">required</span> `boolean`
|
||||
|
||||
**`@returns`**
|
||||
|
||||
`true` when the action is executing, `false` when it finished its execution.
|
||||
|
||||
---
|
||||
|
||||
**<span className="parameter-name">isSuccess</span>** <span className="optional-status">required</span> `boolean`
|
||||
|
||||
Returns `true` if the action is successful.
|
||||
|
||||
---
|
||||
|
||||
**<span className="parameter-name">signInSmsPasswordless</span>** <span className="optional-status">required</span> [`SignInSmsPasswordlessHandler`](/reference/docgen/react/types/sign-in-sms-passwordless-handler)
|
||||
|
||||
Sends a one-time code to the given phoneNumber
|
||||
|
||||
---
|
||||
|
||||
**<span className="parameter-name">sendOtp</span>** <span className="optional-status">required</span> [`SignInSmsPasswordlessOtpHandler`](/reference/docgen/react/types/sign-in-sms-passwordless-otp-handler)
|
||||
|
||||
---
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
# ⚠️ AUTO-GENERATED CONTENT. DO NOT EDIT THIS FILE DIRECTLY! ⚠️
|
||||
title: SignInSmsPasswordlessOtpHandler
|
||||
sidebar_label: SignInSmsPasswordlessOtpHandler
|
||||
description: No description provided.
|
||||
displayed_sidebar: referenceSidebar
|
||||
custom_edit_url: https://github.com/nhost/nhost/edit/main/packages/react/src/useSignInSmsPasswordless.ts#L18
|
||||
---
|
||||
|
||||
# `SignInSmsPasswordlessOtpHandler`
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
# ⚠️ AUTO-GENERATED CONTENT. DO NOT EDIT THIS FILE DIRECTLY! ⚠️
|
||||
title: useSignInSmsPasswordless()
|
||||
sidebar_label: useSignInSmsPasswordless()
|
||||
slug: /reference/vue/use-sign-in-sms-passwordless
|
||||
description: Use the composable `useSignInSmsPasswordless` to sign in a user with a one-time password sent via SMS to a phone.
|
||||
custom_edit_url: https://github.com/nhost/nhost/edit/main/packages/vue/src/useSignInSmsPasswordless.ts#L65
|
||||
---
|
||||
|
||||
# `useSignInSmsPasswordless()`
|
||||
|
||||
Use the composable `useSignInSmsPasswordless` to sign in a user with a one-time password sent via SMS to a phone.
|
||||
|
||||
1. The `signInSmsPasswordless` action sends a one-time password to the given phone number.
|
||||
2. The client is then awaiting the OTP. `needsOtp` equals true.
|
||||
3. After the code is received by SMS, the client sends the code with `sendOtp`. On success, the client is authenticated, and `isSuccess` equals `true`.
|
||||
|
||||
Any error is monitored through `isError` and `error`. While the `signInSmsPasswordless` and `sendOtp` actions are running, `isLoading` equals `true`.
|
||||
|
||||
```tsx
|
||||
const {
|
||||
signInSmsPasswordless,
|
||||
sendOtp,
|
||||
needsOtp,
|
||||
isLoading,
|
||||
isSuccess,
|
||||
isError,
|
||||
error
|
||||
} = useSignInSmsPasswordless()
|
||||
|
||||
console.log({ isLoading, isSuccess, isError, error })
|
||||
|
||||
const askCode = async (e) => {
|
||||
e.preventDefault()
|
||||
await signInSmsPasswordless('+32455555555')
|
||||
}
|
||||
|
||||
const sendCode = async (e) => {
|
||||
e.preventDefault()
|
||||
await sendOtp('123456')
|
||||
}
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
---
|
||||
|
||||
**<span className="parameter-name">stateOptions</span>** <span className="optional-status">optional</span> `NestedRefOfValue<undefined | PasswordlessOptions>`
|
||||
|
||||
---
|
||||
@@ -0,0 +1,62 @@
|
||||
---
|
||||
# ⚠️ AUTO-GENERATED CONTENT. DO NOT EDIT THIS FILE DIRECTLY! ⚠️
|
||||
title: SignInSmsPasswordlessComposableResult
|
||||
sidebar_label: SignInSmsPasswordlessComposableResult
|
||||
description: No description provided.
|
||||
displayed_sidebar: referenceSidebar
|
||||
custom_edit_url: https://github.com/nhost/nhost/edit/main/packages/vue/src/useSignInSmsPasswordless.ts#L31
|
||||
---
|
||||
|
||||
# `SignInSmsPasswordlessComposableResult`
|
||||
|
||||
## Parameters
|
||||
|
||||
---
|
||||
|
||||
**<span className="parameter-name">needsOtp</span>** <span className="optional-status">required</span> `Ref<boolean>`
|
||||
|
||||
Returns true when the one-time password has been sent over by SMS, and the user needs to send it back to complete sign-in.
|
||||
|
||||
---
|
||||
|
||||
**<span className="parameter-name">isError</span>** <span className="optional-status">required</span> `Ref<boolean>`
|
||||
|
||||
**`@returns`**
|
||||
|
||||
`true` if an error occurred
|
||||
|
||||
**`@depreacted`**
|
||||
|
||||
use `!isSuccess` or `!!error` instead
|
||||
|
||||
---
|
||||
|
||||
**<span className="parameter-name">error</span>** <span className="optional-status">required</span> `Ref<null | ErrorPayload>`
|
||||
|
||||
Provides details about the error
|
||||
|
||||
---
|
||||
|
||||
**<span className="parameter-name">isLoading</span>** <span className="optional-status">required</span> `Ref<boolean>`
|
||||
|
||||
**`@returns`**
|
||||
|
||||
`true` when the action is executing, `false` when it finished its execution.
|
||||
|
||||
---
|
||||
|
||||
**<span className="parameter-name">isSuccess</span>** <span className="optional-status">required</span> `Ref<boolean>`
|
||||
|
||||
Returns `true` if the action is successful.
|
||||
|
||||
---
|
||||
|
||||
**<span className="parameter-name">signInSmsPasswordless</span>** <span className="optional-status">required</span> [`SignInSmsPasswordlessHandler`](/reference/docgen/vue/types/sign-in-sms-passwordless-handler)
|
||||
|
||||
Sends a one-time code to the given phoneNumber
|
||||
|
||||
---
|
||||
|
||||
**<span className="parameter-name">sendOtp</span>** <span className="optional-status">required</span> [`SignInSmsPasswordlessOtpHandler`](/reference/docgen/vue/types/sign-in-sms-passwordless-otp-handler)
|
||||
|
||||
---
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
# ⚠️ AUTO-GENERATED CONTENT. DO NOT EDIT THIS FILE DIRECTLY! ⚠️
|
||||
title: SignInSmsPasswordlessHandler
|
||||
sidebar_label: SignInSmsPasswordlessHandler
|
||||
description: No description provided.
|
||||
displayed_sidebar: referenceSidebar
|
||||
custom_edit_url: https://github.com/nhost/nhost/edit/main/packages/vue/src/useSignInSmsPasswordless.ts#L16
|
||||
---
|
||||
|
||||
# `SignInSmsPasswordlessHandler`
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
# ⚠️ AUTO-GENERATED CONTENT. DO NOT EDIT THIS FILE DIRECTLY! ⚠️
|
||||
title: SignInSmsPasswordlessOtpHandler
|
||||
sidebar_label: SignInSmsPasswordlessOtpHandler
|
||||
description: No description provided.
|
||||
displayed_sidebar: referenceSidebar
|
||||
custom_edit_url: https://github.com/nhost/nhost/edit/main/packages/vue/src/useSignInSmsPasswordless.ts#L23
|
||||
---
|
||||
|
||||
# `SignInSmsPasswordlessOtpHandler`
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/docs",
|
||||
"version": "0.0.1",
|
||||
"version": "0.0.2",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
|
||||
BIN
docs/static/img/og/platform/sign-in-with-apple.png
vendored
Normal file
|
After Width: | Height: | Size: 165 KiB |
BIN
docs/static/img/og/platform/sign-in-with-discord.png
vendored
Normal file
|
After Width: | Height: | Size: 165 KiB |
BIN
docs/static/img/og/platform/sign-in-with-twitch.png
vendored
Normal file
|
After Width: | Height: | Size: 160 KiB |
16
docs/static/img/social-providers/apple-preview.svg
vendored
Normal file
|
After Width: | Height: | Size: 22 KiB |
1
docs/static/img/social-providers/discord-preview.svg
vendored
Normal file
|
After Width: | Height: | Size: 67 KiB |
1
docs/static/img/social-providers/twitch-preview.svg
vendored
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
docs/static/videos/add-user.mp4
vendored
BIN
docs/static/videos/open-hasura-console.mp4
vendored
@@ -1,4 +1,5 @@
|
||||
metadata_directory: metadata
|
||||
services:
|
||||
mailhog:
|
||||
port: 8025
|
||||
hasura:
|
||||
@@ -6,9 +7,9 @@ metadata_directory: metadata
|
||||
environment:
|
||||
hasura_graphql_enable_remote_schema_permissions: false
|
||||
auth:
|
||||
version: 0.9.1
|
||||
version: 0.10.0
|
||||
storage:
|
||||
version: 0.2.2
|
||||
version: 0.2.3
|
||||
minio:
|
||||
environment:
|
||||
minio_root_password: minioaccesskey123123
|
||||
@@ -20,12 +21,12 @@ metadata_directory: metadata
|
||||
auth:
|
||||
access_control:
|
||||
email:
|
||||
allowed_email_domains: ""
|
||||
allowed_emails: ""
|
||||
blocked_email_domains: ""
|
||||
blocked_emails: ""
|
||||
allowed_email_domains: ''
|
||||
allowed_emails: ''
|
||||
blocked_email_domains: ''
|
||||
blocked_emails: ''
|
||||
url:
|
||||
allowed_redirect_urls: ""
|
||||
allowed_redirect_urls: ''
|
||||
anonymous_users_enabled: false
|
||||
client_url: http://localhost:3000
|
||||
disable_new_users: false
|
||||
@@ -34,11 +35,11 @@ auth:
|
||||
passwordless:
|
||||
enabled: false
|
||||
signin_email_verified_required: true
|
||||
template_fetch_url: ""
|
||||
template_fetch_url: ''
|
||||
gravatar:
|
||||
default: ""
|
||||
default: ''
|
||||
enabled: true
|
||||
rating: ""
|
||||
rating: ''
|
||||
locale:
|
||||
allowed: en
|
||||
default: en
|
||||
@@ -47,65 +48,65 @@ auth:
|
||||
min_length: 3
|
||||
provider:
|
||||
apple:
|
||||
client_id: ""
|
||||
client_id: ''
|
||||
enabled: false
|
||||
key_id: ""
|
||||
private_key: ""
|
||||
key_id: ''
|
||||
private_key: ''
|
||||
scope: name,email
|
||||
team_id: ""
|
||||
team_id: ''
|
||||
bitbucket:
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
client_id: ''
|
||||
client_secret: ''
|
||||
enabled: false
|
||||
facebook:
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
client_id: ''
|
||||
client_secret: ''
|
||||
enabled: false
|
||||
scope: email,photos,displayName
|
||||
github:
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
client_id: ''
|
||||
client_secret: ''
|
||||
enabled: false
|
||||
scope: user:email
|
||||
token_url: ""
|
||||
user_profile_url: ""
|
||||
token_url: ''
|
||||
user_profile_url: ''
|
||||
gitlab:
|
||||
base_url: ""
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
base_url: ''
|
||||
client_id: ''
|
||||
client_secret: ''
|
||||
enabled: false
|
||||
scope: read_user
|
||||
google:
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
client_id: ''
|
||||
client_secret: ''
|
||||
enabled: false
|
||||
scope: email,profile
|
||||
linkedin:
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
client_id: ''
|
||||
client_secret: ''
|
||||
enabled: false
|
||||
scope: r_emailaddress,r_liteprofile
|
||||
spotify:
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
client_id: ''
|
||||
client_secret: ''
|
||||
enabled: false
|
||||
scope: user-read-email,user-read-private
|
||||
strava:
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
client_id: ''
|
||||
client_secret: ''
|
||||
enabled: false
|
||||
twilio:
|
||||
account_sid: ""
|
||||
auth_token: ""
|
||||
account_sid: ''
|
||||
auth_token: ''
|
||||
enabled: false
|
||||
messaging_service_id: ""
|
||||
messaging_service_id: ''
|
||||
twitter:
|
||||
consumer_key: ""
|
||||
consumer_secret: ""
|
||||
consumer_key: ''
|
||||
consumer_secret: ''
|
||||
enabled: false
|
||||
windows_live:
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
client_id: ''
|
||||
client_secret: ''
|
||||
enabled: false
|
||||
scope: wl.basic,wl.emails,wl.contacts_emails
|
||||
sms:
|
||||
@@ -114,13 +115,13 @@ auth:
|
||||
enabled: false
|
||||
provider:
|
||||
twilio:
|
||||
account_sid: ""
|
||||
auth_token: ""
|
||||
from: ""
|
||||
messaging_service_id: ""
|
||||
account_sid: ''
|
||||
auth_token: ''
|
||||
from: ''
|
||||
messaging_service_id: ''
|
||||
smtp:
|
||||
host: nhost_mailhog
|
||||
method: ""
|
||||
method: ''
|
||||
pass: password
|
||||
port: 1706
|
||||
secure: false
|
||||
|
||||
@@ -101,7 +101,7 @@ services:
|
||||
- "traefik.http.routers.storage.middlewares=strip-suffix@docker"
|
||||
command: serve
|
||||
functions:
|
||||
build: docker-functions
|
||||
image: nhost/functions:latest
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.middlewares.strip-functions.stripprefix.prefixes=/v1/functions"
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
FROM node:14-alpine
|
||||
|
||||
# * Same version as in Watchtower
|
||||
ARG EXPRESS_VERSION 4.17.1
|
||||
ENV EXPRESS_VERSION $EXPRESS_VERSION
|
||||
|
||||
# * path to the server files
|
||||
ARG SERVER_PATH /opt/server
|
||||
ENV SERVER_PATH=$SERVER_PATH
|
||||
|
||||
# * Required to access to the globally installed modules
|
||||
ENV NODE_PATH=/usr/local/lib/node_modules
|
||||
|
||||
# * Add path to the stored pnpm packages
|
||||
ENV PNPM_HOME=/root/.local/share/pnpm
|
||||
ENV PATH=$PATH:$PNPM_HOME
|
||||
|
||||
# * Directory where the Nhost project is located
|
||||
ENV NHOST_PROJECT_PATH=/opt/project
|
||||
|
||||
# * Default package manager
|
||||
ENV PACKAGE_MANAGER=pnpm
|
||||
|
||||
# * Install packages that are required for this docker image to run
|
||||
RUN npm install -g pnpm nodemon express@$EXPRESS_VERSION glob @swc-node/register typescript @antfu/ni
|
||||
|
||||
# * The pnpm store should be mounted in the same volume as node_modules (requires hard links)
|
||||
# * See https://pnpm.io/6.x/npmrc#store-dir
|
||||
RUN pnpm config set store-dir $NHOST_PROJECT_PATH/node_modules/.pnpm-store
|
||||
|
||||
# * Copy server files
|
||||
COPY nodemon.json start.sh server.ts $SERVER_PATH/
|
||||
|
||||
# * Change working directory to the Nhost project directory
|
||||
WORKDIR $NHOST_PROJECT_PATH
|
||||
|
||||
CMD $SERVER_PATH/start.sh
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"ignore": ["!(package*.json|pnpm-*.yaml|yarn.lock)"],
|
||||
"execMap": {
|
||||
"json": "ni && nodemon -w functions -x 'node -r @swc-node/register' $SERVER_PATH/server.ts"
|
||||
},
|
||||
"ext": "json,yaml,lock"
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
import path from 'path'
|
||||
|
||||
import express from 'express'
|
||||
import glob from 'glob'
|
||||
|
||||
const PORT = 3000
|
||||
|
||||
const main = async () => {
|
||||
const app = express()
|
||||
|
||||
// * Same settings as in Watchtower
|
||||
app.use(express.json())
|
||||
app.use(express.urlencoded({ extended: true }))
|
||||
app.disable('x-powered-by')
|
||||
|
||||
const functionsPath = path.join(process.cwd(), 'functions')
|
||||
const files = glob.sync('**/*.@(js|ts)', { cwd: functionsPath })
|
||||
|
||||
for (const file of files) {
|
||||
const { default: handler } = await import(path.join(functionsPath, file))
|
||||
if (handler) {
|
||||
const route = `/${file}`
|
||||
.replace(/(\.ts|\.js)$/, '')
|
||||
.replace(/\/index$/, '/')
|
||||
app.all(route, handler)
|
||||
console.log(`Loaded route ${route} from ./functions/${file}`)
|
||||
} else {
|
||||
console.warn(`No default export in ./functions/${file}`)
|
||||
}
|
||||
}
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Listening on port ${PORT}`)
|
||||
})
|
||||
}
|
||||
|
||||
main()
|
||||
@@ -1,9 +0,0 @@
|
||||
# * Set the default package manager to use if cannot be guessed from lock files
|
||||
echo "defaultAgent=$PACKAGE_MANAGER" > ~/.nirc
|
||||
|
||||
# * Create a default package.json file if it doesn't exist yet
|
||||
npm init -y 1> /dev/null
|
||||
|
||||
# * Start nodemon that listens to package.json and lock files and run npm/pnpm/yarn install,
|
||||
# * Then run another nodemon that listens to the functions directory and run the server
|
||||
nodemon --config $SERVER_PATH/nodemon.json package.json
|
||||
@@ -3,6 +3,7 @@ services:
|
||||
hasura:
|
||||
environment:
|
||||
hasura_graphql_enable_remote_schema_permissions: false
|
||||
version: v2.8.0
|
||||
minio:
|
||||
environment:
|
||||
minio_root_password: minioaccesskey123123
|
||||
@@ -11,6 +12,10 @@ services:
|
||||
environment:
|
||||
postgres_password: postgres
|
||||
postgres_user: postgres
|
||||
auth:
|
||||
version: 0.10.0
|
||||
storage:
|
||||
version: 0.2.3
|
||||
auth:
|
||||
access_control:
|
||||
email:
|
||||
|
||||
@@ -7,9 +7,9 @@ services:
|
||||
environment:
|
||||
hasura_graphql_enable_remote_schema_permissions: false
|
||||
auth:
|
||||
version: 0.9.1
|
||||
version: 0.10.0
|
||||
storage:
|
||||
version: 0.2.2
|
||||
version: 0.2.3
|
||||
auth:
|
||||
access_control:
|
||||
email:
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"verify:fix": "run-p prettier:fix lint:fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.6.2",
|
||||
"@apollo/client": "^3.6.9",
|
||||
"@mantine/core": "^4.2.2",
|
||||
"@mantine/hooks": "^4.2.2",
|
||||
"@mantine/next": "^4.2.2",
|
||||
|
||||
@@ -5,9 +5,9 @@ services:
|
||||
environment:
|
||||
hasura_graphql_enable_remote_schema_permissions: true
|
||||
auth:
|
||||
version: 0.9.1
|
||||
version: 0.10.0
|
||||
storage:
|
||||
version: 0.2.2
|
||||
version: 0.2.3
|
||||
auth:
|
||||
access_control:
|
||||
email:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.5.10",
|
||||
"@apollo/client": "^3.6.9",
|
||||
"@headlessui/react": "^1.5.0",
|
||||
"@heroicons/react": "^1.0.6",
|
||||
"@nhost/react": "*",
|
||||
@@ -55,11 +55,11 @@
|
||||
"@graphql-codegen/typescript": "^2.4.8",
|
||||
"@graphql-codegen/typescript-operations": "^2.3.5",
|
||||
"@graphql-codegen/typescript-react-apollo": "^3.2.11",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/jest": "^26.0.24",
|
||||
"@types/node": "^12.20.48",
|
||||
"@types/react": "^17.0.44",
|
||||
"@types/react-dom": "^17.0.15",
|
||||
"@types/express": "^4.17.13",
|
||||
"@vitejs/plugin-react": "^1.3.2",
|
||||
"autoprefixer": "^10.4.4",
|
||||
"express": "^4.17.3",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# React-Apollo example
|
||||
# Nhost React + Apollo example
|
||||
|
||||
## See this example live
|
||||
|
||||
@@ -13,20 +13,26 @@ git clone https://github.com/nhost/nhost
|
||||
cd nhost
|
||||
```
|
||||
|
||||
2. Install dependencies
|
||||
2. Install and build dependencies
|
||||
|
||||
```sh
|
||||
pnpm install
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
3. Go to the example folder
|
||||
|
||||
```sh
|
||||
cd examples/react-apollo
|
||||
pnpm install
|
||||
```
|
||||
|
||||
3. Terminal 1: Start Nhost
|
||||
4. Terminal 1: Start Nhost
|
||||
|
||||
```sh
|
||||
nhost dev
|
||||
```
|
||||
|
||||
4. Terminal 2: Start the React application
|
||||
5. Terminal 2: Start the React application
|
||||
|
||||
```sh
|
||||
pnpm run dev
|
||||
|
||||
@@ -43,36 +43,32 @@ context('Sign in with email+password', () => {
|
||||
.findByRole('button')
|
||||
.click()
|
||||
|
||||
cy.findByText(/Activate 2-step verification/i)
|
||||
.get('img')
|
||||
.then(async (img) => {
|
||||
// * Activate MFA
|
||||
const result = await new Decoder().scan(img.prop('src'))
|
||||
const [, params] = result.data.split('?')
|
||||
const { secret, algorithm, digits, period } = Object.fromEntries(
|
||||
new URLSearchParams(params)
|
||||
)
|
||||
const code = totp(secret, {
|
||||
algorithm: algorithm.replace('SHA1', 'SHA-1'),
|
||||
digits: parseInt(digits),
|
||||
period: parseInt(period)
|
||||
})
|
||||
cy.findByPlaceholderText('Enter activation code').type(code)
|
||||
cy.findByRole('button', { name: /Activate/i }).click()
|
||||
cy.contains('MFA has been activated!!!')
|
||||
cy.signOut()
|
||||
|
||||
// * Sign-in with MFA
|
||||
cy.visit('/sign-in')
|
||||
cy.findByRole('button', { name: /Continue with email \+ password/i }).click()
|
||||
cy.findByPlaceholderText('Email Address').type(email)
|
||||
cy.findByPlaceholderText('Password').type(password)
|
||||
cy.findByRole('button', { name: /Sign in/i }).click()
|
||||
cy.contains('Send 2-step verification code')
|
||||
const newCode = totp(secret, { timestamp: Date.now() })
|
||||
cy.findByPlaceholderText('One-time password').type(newCode)
|
||||
cy.findByRole('button', { name: /Send 2-step verification code/i }).click()
|
||||
cy.contains('You are authenticated')
|
||||
cy.findAllByAltText(/qrcode/i).then(async (img) => {
|
||||
// * Activate MFA
|
||||
const result = await new Decoder().scan(img.prop('src'))
|
||||
const [, params] = result.data.split('?')
|
||||
const { secret, algorithm, digits, period } = Object.fromEntries(new URLSearchParams(params))
|
||||
const code = totp(secret, {
|
||||
algorithm: algorithm.replace('SHA1', 'SHA-1'),
|
||||
digits: parseInt(digits),
|
||||
period: parseInt(period)
|
||||
})
|
||||
cy.findByPlaceholderText('Enter activation code').type(code)
|
||||
cy.findByRole('button', { name: /Activate/i }).click()
|
||||
cy.contains('MFA has been activated!!!')
|
||||
cy.signOut()
|
||||
|
||||
// * Sign-in with MFA
|
||||
cy.visit('/sign-in')
|
||||
cy.findByRole('button', { name: /Continue with email \+ password/i }).click()
|
||||
cy.findByPlaceholderText('Email Address').type(email)
|
||||
cy.findByPlaceholderText('Password').type(password)
|
||||
cy.findByRole('button', { name: /Sign in/i }).click()
|
||||
cy.contains('Send 2-step verification code')
|
||||
const newCode = totp(secret, { timestamp: Date.now() })
|
||||
cy.findByPlaceholderText('One-time password').type(newCode)
|
||||
cy.findByRole('button', { name: /Send 2-step verification code/i }).click()
|
||||
cy.contains('You are authenticated')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Nhost with React and Apollo</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -7,9 +7,9 @@ services:
|
||||
environment:
|
||||
hasura_graphql_enable_remote_schema_permissions: false
|
||||
auth:
|
||||
version: 0.9.1
|
||||
version: 0.10.0
|
||||
storage:
|
||||
version: 0.2.2
|
||||
version: 0.2.3
|
||||
auth:
|
||||
access_control:
|
||||
email:
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
table:
|
||||
name: user_authenticators
|
||||
schema: auth
|
||||
configuration:
|
||||
column_config:
|
||||
credential_id:
|
||||
custom_name: credentialId
|
||||
credential_public_key:
|
||||
custom_name: credentialPublicKey
|
||||
user_id:
|
||||
custom_name: userId
|
||||
custom_column_names:
|
||||
credential_id: credentialId
|
||||
credential_public_key: credentialPublicKey
|
||||
user_id: userId
|
||||
custom_name: authUserAuthenticators
|
||||
custom_root_fields:
|
||||
delete: deleteAuthUserAuthenticators
|
||||
delete_by_pk: deleteAuthUserAuthenticator
|
||||
insert: insertAuthUserAuthenticators
|
||||
insert_one: insertAuthUserAuthenticator
|
||||
select: authUserAuthenticators
|
||||
select_aggregate: authUserAuthenticatorsAggregate
|
||||
select_by_pk: authUserAuthenticator
|
||||
update: updateAuthUserAuthenticators
|
||||
update_by_pk: updateAuthUserAuthenticator
|
||||
object_relationships:
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
@@ -39,6 +39,8 @@ configuration:
|
||||
custom_name: totpSecret
|
||||
updated_at:
|
||||
custom_name: updatedAt
|
||||
webauthn_current_challenge:
|
||||
custom_name: currentChallenge
|
||||
custom_column_names:
|
||||
active_mfa_type: activeMfaType
|
||||
avatar_url: avatarUrl
|
||||
@@ -58,6 +60,7 @@ configuration:
|
||||
ticket_expires_at: ticketExpiresAt
|
||||
totp_secret: totpSecret
|
||||
updated_at: updatedAt
|
||||
webauthn_current_challenge: currentChallenge
|
||||
custom_name: users
|
||||
custom_root_fields:
|
||||
delete: deleteUsers
|
||||
@@ -74,6 +77,13 @@ object_relationships:
|
||||
using:
|
||||
foreign_key_constraint_on: default_role
|
||||
array_relationships:
|
||||
- name: authenticators
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: user_id
|
||||
table:
|
||||
name: user_authenticators
|
||||
schema: auth
|
||||
- name: refreshTokens
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
- "!include auth_providers.yaml"
|
||||
- "!include auth_refresh_tokens.yaml"
|
||||
- "!include auth_roles.yaml"
|
||||
- "!include auth_user_authenticators.yaml"
|
||||
- "!include auth_user_providers.yaml"
|
||||
- "!include auth_user_roles.yaml"
|
||||
- "!include auth_users.yaml"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.6.2",
|
||||
"@apollo/client": "^3.6.9",
|
||||
"@mantine/core": "^4.2.2",
|
||||
"@mantine/dropzone": "^4.2.6",
|
||||
"@mantine/hooks": "^4.2.2",
|
||||
@@ -16,7 +16,8 @@
|
||||
"react-dom": "^18.1.0",
|
||||
"react-icons": "^4.3.1",
|
||||
"react-router": "^6.3.0",
|
||||
"react-router-dom": "^6.3.0"
|
||||
"react-router-dom": "^6.3.0",
|
||||
"tabler-icons-react": "^1.52.0"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -66,4 +67,4 @@
|
||||
"ws": "^8.7.0",
|
||||
"xstate": "^4.32.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
10
examples/react-apollo/public/favicon.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0)">
|
||||
<path d="M88.0355 21.4793L53.1776 1.35118C50.0502 -0.450393 46.168 -0.450393 43.0343 1.35118C39.9069 3.1591 37.9657 6.52119 37.9657 10.1307V12.7569L35.6948 11.4438C32.5674 9.64222 28.6851 9.64222 25.5514 11.4438C22.424 13.2517 20.4829 16.6138 20.4829 20.2296V22.8559L18.2119 21.5428C15.0845 19.7412 11.2022 19.7412 8.06851 21.5428C4.94113 23.3507 3 26.7128 3 30.3286V93.3963C3 95.2106 4.05303 96.898 5.68967 97.6846C7.31996 98.4775 9.29916 98.2619 10.7201 97.1391L28.0063 83.5067L54.662 98.8962C55.3979 99.3212 56.2225 99.5306 57.0472 99.5306C57.8719 99.5306 58.6965 99.3149 59.4324 98.8962C60.9041 98.0462 61.8176 96.4666 61.8176 94.7666V56.813C61.8176 50.5836 58.4682 44.7856 53.0761 41.6709L44.3347 36.6214V10.137C44.3347 8.79218 45.0579 7.53616 46.2251 6.86374C47.3923 6.19132 48.8386 6.19132 50.0058 6.86374L84.8638 26.9855C88.2956 28.9647 90.4271 32.663 90.4271 36.6214V83.881C90.4271 85.2258 89.7039 86.4819 88.5367 87.1543L79.3004 92.4892V46.714C79.3004 40.4846 75.951 34.6866 70.559 31.5719L49.0987 19.1829V26.5225L67.3809 37.0782C70.8127 39.0573 72.9442 42.7493 72.9442 46.714V95.236C72.9442 96.9297 73.8577 98.5156 75.3294 99.3656C76.0652 99.7907 76.8899 100 77.7145 100C78.5392 100 79.3639 99.7843 80.0997 99.3656L91.7212 92.6541C94.8485 90.8462 96.7897 87.4841 96.7897 83.8683V36.6087C96.777 30.3984 93.4276 24.594 88.0355 21.4793ZM49.8853 47.1771C53.3172 49.1563 55.4486 52.8483 55.4486 56.813V92.0198L33.373 79.2756L40.4588 73.6932C42.9137 71.7584 44.322 68.8594 44.322 65.732V43.9736L49.8853 47.1771ZM37.9657 40.2943V65.7194C37.9657 66.8866 37.4392 67.9713 36.5258 68.6881L9.35626 90.1104V30.3223C9.35626 28.9774 10.0794 27.7214 11.2466 27.049C12.4139 26.3766 13.8602 26.3766 15.0274 27.049L20.4829 30.1954V75.2664L26.8391 70.255V20.2296C26.8391 18.8848 27.5623 17.6288 28.7295 16.9564C29.8967 16.2839 31.3431 16.2839 32.5103 16.9564L37.9657 20.1028V32.9485L31.6095 29.2756V36.6214L37.9657 40.2943Z" fill="#0052CD"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0">
|
||||
<rect width="93.7897" height="100" fill="white" transform="translate(3)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
@@ -1,6 +1,7 @@
|
||||
import { Route, Routes } from 'react-router-dom'
|
||||
import { BrandGithub } from 'tabler-icons-react'
|
||||
|
||||
import { AppShell, Header, MantineProvider } from '@mantine/core'
|
||||
import { AppShell, Button, Group, Header, Image, MantineProvider, Title } from '@mantine/core'
|
||||
import { NotificationsProvider } from '@mantine/notifications'
|
||||
|
||||
import { AuthGate, PublicGate } from './components/auth-gates'
|
||||
@@ -17,13 +18,13 @@ import './App.css'
|
||||
const title = 'Nhost with React and Apollo'
|
||||
|
||||
function App() {
|
||||
const colorScheme = 'light'
|
||||
return (
|
||||
<MantineProvider
|
||||
withGlobalStyles
|
||||
withNormalizeCSS
|
||||
theme={{
|
||||
/** Put your mantine theme override here */
|
||||
colorScheme: 'light'
|
||||
colorScheme
|
||||
}}
|
||||
>
|
||||
<NotificationsProvider>
|
||||
@@ -32,7 +33,24 @@ function App() {
|
||||
navbar={<NavBar />}
|
||||
header={
|
||||
<Header height={60} p="xs">
|
||||
{title}
|
||||
<Group position="apart" noWrap>
|
||||
<Group noWrap>
|
||||
<Image src="/logo.svg" height={35} fit="contain" width={120} />
|
||||
<Title order={3} style={{ whiteSpace: 'nowrap' }}>
|
||||
{title}
|
||||
</Title>
|
||||
</Group>
|
||||
<Button
|
||||
leftIcon={<BrandGithub />}
|
||||
variant="outline"
|
||||
color={colorScheme}
|
||||
component="a"
|
||||
href="https://github.com/nhost/nhost/tree/main/examples/react-apollo"
|
||||
target="_blank"
|
||||
>
|
||||
GitHub
|
||||
</Button>
|
||||
</Group>
|
||||
</Header>
|
||||
}
|
||||
styles={(theme) => ({
|
||||
|
||||
@@ -1 +1,39 @@
|
||||
# Nhost Vue3 Apollo example
|
||||
# Nhost Vue 3 + Apollo example
|
||||
|
||||
## See this example live
|
||||
|
||||
Visit our demo application on [vue-apollo.example.nhost.io](https://vue-apollo.example.nhost.io)
|
||||
|
||||
## Get started
|
||||
|
||||
1. Clone the repository
|
||||
|
||||
```sh
|
||||
git clone https://github.com/nhost/nhost
|
||||
cd nhost
|
||||
```
|
||||
|
||||
2. Install and build dependencies
|
||||
|
||||
```sh
|
||||
pnpm install
|
||||
pnpm build
|
||||
```
|
||||
|
||||
3. Go to the example folder
|
||||
|
||||
```sh
|
||||
cd examples/vue-apollo
|
||||
```
|
||||
|
||||
4. Terminal 1: Start Nhost
|
||||
|
||||
```sh
|
||||
nhost dev
|
||||
```
|
||||
|
||||
5. Terminal 2: Start the Vue application
|
||||
|
||||
```sh
|
||||
pnpm run dev
|
||||
```
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Nhost with Vue and Apollo</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -7,9 +7,9 @@ services:
|
||||
environment:
|
||||
hasura_graphql_enable_remote_schema_permissions: false
|
||||
auth:
|
||||
version: 0.9.1
|
||||
version: 0.10.0
|
||||
storage:
|
||||
version: 0.2.2
|
||||
version: 0.2.3
|
||||
auth:
|
||||
access_control:
|
||||
email:
|
||||
@@ -18,7 +18,7 @@ auth:
|
||||
blocked_email_domains: ''
|
||||
blocked_emails: ''
|
||||
allowed_redirect_urls: ''
|
||||
anonymous_users_enabled: false
|
||||
anonymous_users_enabled: true
|
||||
client_url: http://localhost:3000
|
||||
disable_new_users: false
|
||||
email:
|
||||
|
||||
@@ -2,6 +2,7 @@ table:
|
||||
name: provider_requests
|
||||
schema: auth
|
||||
configuration:
|
||||
column_config: {}
|
||||
custom_column_names: {}
|
||||
custom_name: authProviderRequests
|
||||
custom_root_fields:
|
||||
|
||||
@@ -2,6 +2,7 @@ table:
|
||||
name: providers
|
||||
schema: auth
|
||||
configuration:
|
||||
column_config: {}
|
||||
custom_column_names: {}
|
||||
custom_name: authProviders
|
||||
custom_root_fields:
|
||||
|
||||
@@ -2,6 +2,15 @@ table:
|
||||
name: refresh_tokens
|
||||
schema: auth
|
||||
configuration:
|
||||
column_config:
|
||||
created_at:
|
||||
custom_name: createdAt
|
||||
expires_at:
|
||||
custom_name: expiresAt
|
||||
refresh_token:
|
||||
custom_name: refreshToken
|
||||
user_id:
|
||||
custom_name: userId
|
||||
custom_column_names:
|
||||
created_at: createdAt
|
||||
expires_at: expiresAt
|
||||
|
||||
@@ -2,6 +2,7 @@ table:
|
||||
name: roles
|
||||
schema: auth
|
||||
configuration:
|
||||
column_config: {}
|
||||
custom_column_names: {}
|
||||
custom_name: authRoles
|
||||
custom_root_fields:
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
table:
|
||||
name: user_authenticators
|
||||
schema: auth
|
||||
configuration:
|
||||
column_config:
|
||||
credential_id:
|
||||
custom_name: credentialId
|
||||
credential_public_key:
|
||||
custom_name: credentialPublicKey
|
||||
user_id:
|
||||
custom_name: userId
|
||||
custom_column_names:
|
||||
credential_id: credentialId
|
||||
credential_public_key: credentialPublicKey
|
||||
user_id: userId
|
||||
custom_name: authUserAuthenticators
|
||||
custom_root_fields:
|
||||
delete: deleteAuthUserAuthenticators
|
||||
delete_by_pk: deleteAuthUserAuthenticator
|
||||
insert: insertAuthUserAuthenticators
|
||||
insert_one: insertAuthUserAuthenticator
|
||||
select: authUserAuthenticators
|
||||
select_aggregate: authUserAuthenticatorsAggregate
|
||||
select_by_pk: authUserAuthenticator
|
||||
update: updateAuthUserAuthenticators
|
||||
update_by_pk: updateAuthUserAuthenticator
|
||||
object_relationships:
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: user_id
|
||||
@@ -2,6 +2,21 @@ table:
|
||||
name: user_providers
|
||||
schema: auth
|
||||
configuration:
|
||||
column_config:
|
||||
access_token:
|
||||
custom_name: accessToken
|
||||
created_at:
|
||||
custom_name: createdAt
|
||||
provider_id:
|
||||
custom_name: providerId
|
||||
provider_user_id:
|
||||
custom_name: providerUserId
|
||||
refresh_token:
|
||||
custom_name: refreshToken
|
||||
updated_at:
|
||||
custom_name: updatedAt
|
||||
user_id:
|
||||
custom_name: userId
|
||||
custom_column_names:
|
||||
access_token: accessToken
|
||||
created_at: createdAt
|
||||
|
||||
@@ -2,6 +2,11 @@ table:
|
||||
name: user_roles
|
||||
schema: auth
|
||||
configuration:
|
||||
column_config:
|
||||
created_at:
|
||||
custom_name: createdAt
|
||||
user_id:
|
||||
custom_name: userId
|
||||
custom_column_names:
|
||||
created_at: createdAt
|
||||
user_id: userId
|
||||
|
||||
@@ -2,6 +2,45 @@ table:
|
||||
name: users
|
||||
schema: auth
|
||||
configuration:
|
||||
column_config:
|
||||
active_mfa_type:
|
||||
custom_name: activeMfaType
|
||||
avatar_url:
|
||||
custom_name: avatarUrl
|
||||
created_at:
|
||||
custom_name: createdAt
|
||||
default_role:
|
||||
custom_name: defaultRole
|
||||
display_name:
|
||||
custom_name: displayName
|
||||
email_verified:
|
||||
custom_name: emailVerified
|
||||
is_anonymous:
|
||||
custom_name: isAnonymous
|
||||
last_seen:
|
||||
custom_name: lastSeen
|
||||
new_email:
|
||||
custom_name: newEmail
|
||||
otp_hash:
|
||||
custom_name: otpHash
|
||||
otp_hash_expires_at:
|
||||
custom_name: otpHashExpiresAt
|
||||
otp_method_last_used:
|
||||
custom_name: otpMethodLastUsed
|
||||
password_hash:
|
||||
custom_name: passwordHash
|
||||
phone_number:
|
||||
custom_name: phoneNumber
|
||||
phone_number_verified:
|
||||
custom_name: phoneNumberVerified
|
||||
ticket_expires_at:
|
||||
custom_name: ticketExpiresAt
|
||||
totp_secret:
|
||||
custom_name: totpSecret
|
||||
updated_at:
|
||||
custom_name: updatedAt
|
||||
webauthn_current_challenge:
|
||||
custom_name: currentChallenge
|
||||
custom_column_names:
|
||||
active_mfa_type: activeMfaType
|
||||
avatar_url: avatarUrl
|
||||
@@ -21,6 +60,7 @@ configuration:
|
||||
ticket_expires_at: ticketExpiresAt
|
||||
totp_secret: totpSecret
|
||||
updated_at: updatedAt
|
||||
webauthn_current_challenge: currentChallenge
|
||||
custom_name: users
|
||||
custom_root_fields:
|
||||
delete: deleteUsers
|
||||
@@ -37,6 +77,13 @@ object_relationships:
|
||||
using:
|
||||
foreign_key_constraint_on: default_role
|
||||
array_relationships:
|
||||
- name: authenticators
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: user_id
|
||||
table:
|
||||
name: user_authenticators
|
||||
schema: auth
|
||||
- name: refreshTokens
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
|
||||
@@ -2,6 +2,23 @@ table:
|
||||
name: buckets
|
||||
schema: storage
|
||||
configuration:
|
||||
column_config:
|
||||
cache_control:
|
||||
custom_name: cacheControl
|
||||
created_at:
|
||||
custom_name: createdAt
|
||||
download_expiration:
|
||||
custom_name: downloadExpiration
|
||||
id:
|
||||
custom_name: id
|
||||
max_upload_file_size:
|
||||
custom_name: maxUploadFileSize
|
||||
min_upload_file_size:
|
||||
custom_name: minUploadFileSize
|
||||
presigned_urls_enabled:
|
||||
custom_name: presignedUrlsEnabled
|
||||
updated_at:
|
||||
custom_name: updatedAt
|
||||
custom_column_names:
|
||||
cache_control: cacheControl
|
||||
created_at: createdAt
|
||||
|
||||
@@ -2,6 +2,27 @@ table:
|
||||
name: files
|
||||
schema: storage
|
||||
configuration:
|
||||
column_config:
|
||||
bucket_id:
|
||||
custom_name: bucketId
|
||||
created_at:
|
||||
custom_name: createdAt
|
||||
etag:
|
||||
custom_name: etag
|
||||
id:
|
||||
custom_name: id
|
||||
is_uploaded:
|
||||
custom_name: isUploaded
|
||||
mime_type:
|
||||
custom_name: mimeType
|
||||
name:
|
||||
custom_name: name
|
||||
size:
|
||||
custom_name: size
|
||||
updated_at:
|
||||
custom_name: updatedAt
|
||||
uploaded_by_user_id:
|
||||
custom_name: uploadedByUserId
|
||||
custom_column_names:
|
||||
bucket_id: bucketId
|
||||
created_at: createdAt
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
- "!include auth_providers.yaml"
|
||||
- "!include auth_refresh_tokens.yaml"
|
||||
- "!include auth_roles.yaml"
|
||||
- "!include auth_user_authenticators.yaml"
|
||||
- "!include auth_user_providers.yaml"
|
||||
- "!include auth_user_roles.yaml"
|
||||
- "!include auth_users.yaml"
|
||||
|
||||
@@ -14,16 +14,16 @@
|
||||
"verify:fix": "run-p prettier:fix lint:fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.6.2",
|
||||
"@apollo/client": "^3.6.9",
|
||||
"@mdi/font": "5.9.55",
|
||||
"@nhost/apollo": "*",
|
||||
"@nhost/vue": "*",
|
||||
"@vue/apollo-composable": "^4.0.0-alpha.17",
|
||||
"@vue/apollo-composable": "4.0.0-alpha.18",
|
||||
"graphql": "15.7.2",
|
||||
"graphql-tag": "^2.12.6",
|
||||
"roboto-fontface": "*",
|
||||
"vue": "^3.2.25",
|
||||
"vue-router": "^4.0.3",
|
||||
"vue": "^3.2.37",
|
||||
"vue-router": "^4.1.2",
|
||||
"vuetify": "^3.0.0-beta.0",
|
||||
"webfontloader": "^1.0.0"
|
||||
},
|
||||
@@ -31,12 +31,12 @@
|
||||
"@nhost/core": "*",
|
||||
"@types/webfontloader": "^1.0.0",
|
||||
"@vitejs/plugin-vue": "^2.3.1",
|
||||
"@vuetify/vite-plugin": "^1.0.0-alpha.0",
|
||||
"@vuetify/vite-plugin": "1.0.0-alpha.11",
|
||||
"@xstate/inspect": "^0.6.2",
|
||||
"sass": "1.32.0",
|
||||
"typescript": "^4.5.4",
|
||||
"typescript": "^4.7.4",
|
||||
"vite": "^2.9.0",
|
||||
"vue-tsc": "^0.29.8"
|
||||
"vue-tsc": "^0.38.5"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
<template #prepend>
|
||||
<v-app-bar-nav-icon @click.stop="drawer = !drawer" />
|
||||
</template>
|
||||
<v-app-bar-title>Nhost with Vue and Apollo</v-app-bar-title>
|
||||
<template #append>
|
||||
<v-btn icon="mdi-github" href="https://github.com/nhost/nhost/tree/main/examples/vue-apollo" target="_blank" />
|
||||
<v-btn v-if="isAuthenticated" icon="mdi-exit-to-app" @click="signOutHandler" />
|
||||
</template>
|
||||
</v-app-bar>
|
||||
<v-navigation-drawer v-model="drawer" permanent>
|
||||
<v-navigation-drawer v-model="drawer" :permanent="mdAndUp">
|
||||
<nav-bar />
|
||||
</v-navigation-drawer>
|
||||
<v-main class="my-4">
|
||||
@@ -17,30 +19,22 @@
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
<script lang="ts" setup>
|
||||
import { useDisplay } from 'vuetify'
|
||||
import { ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import { useAuthenticated, useSignOut } from '@nhost/vue'
|
||||
|
||||
import NavBar from './components/NavBar.vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: { NavBar },
|
||||
setup() {
|
||||
const router = useRouter()
|
||||
const isAuthenticated = useAuthenticated()
|
||||
const { signOut } = useSignOut()
|
||||
const drawer = ref(true)
|
||||
const signOutHandler = async () => {
|
||||
await signOut()
|
||||
router.replace('/signout')
|
||||
}
|
||||
return {
|
||||
drawer,
|
||||
isAuthenticated,
|
||||
signOutHandler
|
||||
}
|
||||
}
|
||||
})
|
||||
const { mdAndUp } = useDisplay()
|
||||
const router = useRouter()
|
||||
const isAuthenticated = useAuthenticated()
|
||||
const { signOut } = useSignOut()
|
||||
const drawer = ref()
|
||||
const signOutHandler = async () => {
|
||||
await signOut()
|
||||
router.replace('/signout')
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,25 +1,45 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-text-field v-model="email" placeholder="Email Address" autofocus />
|
||||
<v-btn block color="primary" @click="signIn"> Continue with email </v-btn>
|
||||
<form @submit="submit">
|
||||
<v-text-field v-model="email" placeholder="Email Address" autofocus />
|
||||
<v-btn block color="primary" type="submit" :disabled="isLoading" :loading="isLoading"> Continue with email
|
||||
</v-btn>
|
||||
</form>
|
||||
<error-snack-bar :error="error" />
|
||||
<v-dialog v-model="emailSentDialog">
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
<span class="text-h5">Verification email sent</span>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
A email has been sent to {{ email }}. Please follow the link to sign in to the application.
|
||||
</v-card-text>
|
||||
<v-card-actions class="d-flex justify-center">
|
||||
<v-btn text @click="emailSentDialog = false">
|
||||
Close
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { useSignInEmailPasswordless } from '@nhost/vue'
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const email = ref('')
|
||||
const { signInEmailPasswordless, error } = useSignInEmailPasswordless({
|
||||
redirectTo: '/#/profile'
|
||||
})
|
||||
const email = ref('')
|
||||
const emailSentDialog = ref(false)
|
||||
|
||||
const signIn = () => signInEmailPasswordless(email)
|
||||
return { email, signIn, error }
|
||||
}
|
||||
const { signInEmailPasswordless, error, isLoading } = useSignInEmailPasswordless({
|
||||
redirectTo: '/profile'
|
||||
})
|
||||
|
||||
const submit = async (e: Event) => {
|
||||
e.preventDefault()
|
||||
const { isSuccess } = await signInEmailPasswordless(email)
|
||||
if (isSuccess) {
|
||||
emailSentDialog.value = true
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,39 +1,27 @@
|
||||
<template>
|
||||
<v-snackbar
|
||||
v-model="snack"
|
||||
:timeout="2_000"
|
||||
>
|
||||
<v-snackbar v-model="snack" :timeout="2_000" top>
|
||||
{{ error?.message }}
|
||||
<template #actions>
|
||||
<v-btn
|
||||
color="blue"
|
||||
variant="text"
|
||||
@click="snack = false"
|
||||
>
|
||||
Close
|
||||
</v-btn>
|
||||
<v-btn color="blue" variant="text" @click="snack = false"> Close </v-btn>
|
||||
</template>
|
||||
</v-snackbar>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, ref, watchEffect } from 'vue'
|
||||
<script lang="ts" setup>
|
||||
import { PropType, ref, watchEffect } from 'vue'
|
||||
|
||||
import { ErrorPayload } from '@nhost/core'
|
||||
export default defineComponent({
|
||||
props: {
|
||||
error: Object as PropType<ErrorPayload | null>
|
||||
},
|
||||
setup(props) {
|
||||
const snack = ref(false)
|
||||
|
||||
watchEffect(() => {
|
||||
if (props.error) {
|
||||
snack.value = true
|
||||
}
|
||||
})
|
||||
|
||||
return { snack }
|
||||
const props = defineProps({
|
||||
error: Object as PropType<ErrorPayload | null>
|
||||
})
|
||||
const snack = ref(false)
|
||||
|
||||
watchEffect(() => {
|
||||
if (props.error) {
|
||||
snack.value = true
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
@@ -7,25 +7,17 @@
|
||||
<v-list-item v-if="authenticated" title="Sign out" prepend-icon="mdi-exit-to-app" @click="signOutHandler" />
|
||||
</v-list>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import { useAuthenticated, useSignOut } from '@nhost/vue'
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const router = useRouter()
|
||||
const { signOut } = useSignOut()
|
||||
const authenticated = useAuthenticated()
|
||||
const signOutHandler = async () => {
|
||||
await signOut()
|
||||
router.push('/')
|
||||
}
|
||||
return {
|
||||
authenticated,
|
||||
signOutHandler
|
||||
}
|
||||
}
|
||||
})
|
||||
const router = useRouter()
|
||||
const { signOut } = useSignOut()
|
||||
const authenticated = useAuthenticated()
|
||||
const signOutHandler = async () => {
|
||||
await signOut()
|
||||
router.push('/')
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,48 +1,21 @@
|
||||
<template>
|
||||
<v-btn
|
||||
class="my-1"
|
||||
block
|
||||
variant="contained-text"
|
||||
prepend-icon="mdi-github"
|
||||
color="white"
|
||||
style="background-color: #333"
|
||||
:href="github"
|
||||
>
|
||||
<v-btn class="my-1" block variant="contained-text" prepend-icon="mdi-github" color="white"
|
||||
style="background-color: #333" :href="github">
|
||||
Continue with GitHub
|
||||
</v-btn>
|
||||
<v-btn
|
||||
class="my-1"
|
||||
block
|
||||
variant="contained-text"
|
||||
prepend-icon="mdi-google"
|
||||
color="white"
|
||||
style="background-color: #de5246"
|
||||
:href="google"
|
||||
>
|
||||
<v-btn class="my-1" block variant="contained-text" prepend-icon="mdi-google" color="white"
|
||||
style="background-color: #de5246" :href="google">
|
||||
Continue with Google
|
||||
</v-btn>
|
||||
<v-btn
|
||||
class="my-1"
|
||||
block
|
||||
variant="contained-text"
|
||||
prepend-icon="mdi-facebook"
|
||||
color="white"
|
||||
style="background-color: #3b5998"
|
||||
:href="facebook"
|
||||
>
|
||||
<v-btn class="my-1" block variant="contained-text" prepend-icon="mdi-facebook" color="white"
|
||||
style="background-color: #3b5998" :href="facebook">
|
||||
Continue with Facebook
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
<script lang="ts" setup>
|
||||
|
||||
import { useProviderLink } from '@nhost/vue'
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const { github, google, facebook } = useProviderLink()
|
||||
return { github, google, facebook }
|
||||
}
|
||||
})
|
||||
const { github, google, facebook } = useProviderLink({ redirectTo: '/' })
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<v-dialog v-model="modelValue">
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
<span class="text-h5">Verification email sent</span>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
A email has been sent to {{ email }}. Please follow the link to verify your email address and to
|
||||
complete your registration.
|
||||
</v-card-text>
|
||||
<v-card-actions class="d-flex justify-center">
|
||||
<v-btn text @click="$emit('update:modelValue', false)">
|
||||
Close
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
defineProps(['modelValue', 'email'])
|
||||
</script>
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createApp } from 'vue'
|
||||
import { createRouter, createWebHashHistory } from 'vue-router'
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { createVuetify, ThemeDefinition } from 'vuetify'
|
||||
|
||||
import { createApolloClient } from '@nhost/apollo'
|
||||
@@ -13,6 +13,7 @@ import 'vuetify/styles'
|
||||
import EmailPasswordless from './components/EmailPasswordlessForm.vue'
|
||||
import ErrorSnackBar from './components/ErrorSnackBar.vue'
|
||||
import OauthLinks from './components/OAuthLinks.vue'
|
||||
import VerificationEmailDialog from './components/VerificationEmailDialog.vue'
|
||||
import App from './App.vue'
|
||||
import { routes } from './routes'
|
||||
|
||||
@@ -43,7 +44,7 @@ const vuetify = createVuetify({
|
||||
}
|
||||
})
|
||||
|
||||
const devTools = !!import.meta.env.VITE_DEBUG
|
||||
const devTools = import.meta.env.VITE_DEBUG === 'true'
|
||||
if (devTools) {
|
||||
inspect({
|
||||
url: 'https://stately.ai/viz?inspect',
|
||||
@@ -52,7 +53,9 @@ if (devTools) {
|
||||
}
|
||||
|
||||
const nhost = new NhostClient({
|
||||
backendUrl: import.meta.env.VITE_NHOST_URL
|
||||
subdomain: import.meta.env.VITE_NHOST_SUBDOMAIN || 'localhost:1337',
|
||||
region: import.meta.env.VITE_NHOST_REGION,
|
||||
devTools
|
||||
})
|
||||
|
||||
const apolloClient = createApolloClient({ nhost })
|
||||
@@ -66,7 +69,7 @@ nhost.auth.onAuthStateChanged((d) => {
|
||||
})
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
history: createWebHistory(),
|
||||
routes
|
||||
})
|
||||
|
||||
@@ -86,4 +89,5 @@ createApp(App)
|
||||
.component('ErrorSnackBar', ErrorSnackBar)
|
||||
.component('EmailPasswordless', EmailPasswordless)
|
||||
.component('OauthLinks', OauthLinks)
|
||||
.component('VerificationEmailDialog', VerificationEmailDialog)
|
||||
.mount('#app')
|
||||
|
||||
@@ -1,7 +1,29 @@
|
||||
<template>
|
||||
<div className="d-flex align-center flex-column">
|
||||
<v-card width="400">
|
||||
<v-card-text> About </v-card-text>
|
||||
<v-card-title>About this example</v-card-title>
|
||||
<v-card-text>This application demonstrates the available features of the Nhost stack.
|
||||
<p class="pt-2">Nhost cloud leverages the
|
||||
following services in the backend:
|
||||
<ul class="px-8">
|
||||
<li>Hasura</li>
|
||||
<li>Hasura Auth</li>
|
||||
<li>Hasura Storage</li>
|
||||
<li>Lambda Functions</li>
|
||||
</ul>
|
||||
</p>
|
||||
<p class="py-2">
|
||||
This frontend is built with the following technologies:
|
||||
<ul class="px-8">
|
||||
<li>Vue 3</li>
|
||||
<li>Vue-router</li>
|
||||
<li>Vuetify 3</li>
|
||||
<li>and of course, the Nhost Vue client</li>
|
||||
</ul>
|
||||
|
||||
</p>
|
||||
Now let's go to the <router-link to="/">Home page</router-link>.
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
<template>
|
||||
<div className="d-flex align-center flex-column">
|
||||
<v-card width="400" tile>
|
||||
<v-card-text> Apollo </v-card-text>
|
||||
<v-list density="compact" v-if="result">
|
||||
<v-list-subheader>Books</v-list-subheader>
|
||||
<v-list-item v-for="(item, i) in result.books" :key="i" :value="item.id">
|
||||
<v-list-item-title v-text="item.title"></v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<v-card-title> Apollo </v-card-title>
|
||||
<v-card-text>
|
||||
<v-list density="compact" v-if="result">
|
||||
<v-list-subheader>Books</v-list-subheader>
|
||||
<v-list-item v-for="(item, i) in result.books" :key="i" :value="item.id">
|
||||
<v-list-item-title v-text="item.title"></v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from 'vue'
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue'
|
||||
|
||||
import { gql } from '@apollo/client/core'
|
||||
import { useAuthenticated } from '@nhost/vue'
|
||||
@@ -28,20 +30,15 @@ const GET_BOOKS = gql`
|
||||
}
|
||||
`
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const isAuthenticated = useAuthenticated()
|
||||
// TODO check if the query always runs with the headers
|
||||
const { result } = useQuery(
|
||||
GET_BOOKS,
|
||||
null,
|
||||
computed(() => ({
|
||||
pollInterval: 5000,
|
||||
fetchPolicy: 'cache-and-network',
|
||||
enabled: isAuthenticated.value
|
||||
}))
|
||||
)
|
||||
return { result }
|
||||
}
|
||||
})
|
||||
const isAuthenticated = useAuthenticated()
|
||||
// TODO check if the query always runs with the headers
|
||||
const { result } = useQuery(
|
||||
GET_BOOKS,
|
||||
null,
|
||||
computed(() => ({
|
||||
pollInterval: 5000,
|
||||
fetchPolicy: 'cache-and-network',
|
||||
enabled: isAuthenticated.value
|
||||
}))
|
||||
)
|
||||
</script>
|
||||
|
||||
@@ -6,14 +6,8 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
<script lang="ts" setup>
|
||||
import { useRouter } from 'vue-router'
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const router = useRouter()
|
||||
setTimeout(() => router.replace('/'), 2_500)
|
||||
return {}
|
||||
}
|
||||
})
|
||||
const router = useRouter()
|
||||
setTimeout(() => router.replace('/'), 2_500)
|
||||
</script>
|
||||
|
||||
@@ -11,13 +11,7 @@
|
||||
>
|
||||
Continue with passwordless email
|
||||
</v-btn>
|
||||
<v-btn
|
||||
class="my-1"
|
||||
block
|
||||
variant="text"
|
||||
color="primary"
|
||||
to="/signin/email-password"
|
||||
>
|
||||
<v-btn class="my-1" block variant="text" color="primary" to="/signin/email-password">
|
||||
Continue with email + password
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
@@ -1,59 +1,37 @@
|
||||
<template>
|
||||
<v-text-field
|
||||
v-model="email"
|
||||
label="Email"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="password"
|
||||
label="Password"
|
||||
type="password"
|
||||
/>
|
||||
<v-btn
|
||||
block
|
||||
color="primary"
|
||||
class="my-1"
|
||||
@click="signIn"
|
||||
>
|
||||
Sign in
|
||||
</v-btn>
|
||||
<v-btn
|
||||
class="my-1"
|
||||
block
|
||||
variant="text"
|
||||
color="primary"
|
||||
to="/signin"
|
||||
>
|
||||
← Other Login Options
|
||||
<form @submit="handleSignIn">
|
||||
<v-text-field v-model="email" label="Email" />
|
||||
<v-text-field v-model="password" label="Password" type="password" />
|
||||
<v-btn block color="primary" class="my-1" type="submit" :disabled="isLoading" :loading="isLoading"> Sign in </v-btn>
|
||||
</form>
|
||||
<v-btn class="my-1" block variant="text" color="primary" to="/signin">
|
||||
← Other Sign-in Options
|
||||
</v-btn>
|
||||
<error-snack-bar :error="error" />
|
||||
<verification-email-dialog v-model="emailVerificationDialog" :email="email" />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import { useSignInEmailPassword } from '@nhost/vue'
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const email = ref('')
|
||||
const password = ref('')
|
||||
const email = ref('')
|
||||
const password = ref('')
|
||||
const emailVerificationDialog = ref(false)
|
||||
|
||||
const router = useRouter()
|
||||
const { signInEmailPassword, error } = useSignInEmailPassword()
|
||||
const signIn = async () => {
|
||||
const { isSuccess } = await signInEmailPassword(email, password)
|
||||
if (isSuccess) {
|
||||
router.replace('/')
|
||||
}
|
||||
}
|
||||
const router = useRouter()
|
||||
const { signInEmailPassword, error, isLoading } = useSignInEmailPassword()
|
||||
|
||||
return {
|
||||
email,
|
||||
error,
|
||||
password,
|
||||
signIn
|
||||
}
|
||||
const handleSignIn = async (e: Event) => {
|
||||
e.preventDefault()
|
||||
const { isSuccess, needsEmailVerification } = await signInEmailPassword(email, password)
|
||||
if (isSuccess) {
|
||||
router.replace('/')
|
||||
}
|
||||
})
|
||||
if (needsEmailVerification) {
|
||||
emailVerificationDialog.value = true
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
<template>
|
||||
<email-passwordless />
|
||||
<v-btn
|
||||
class="my-1"
|
||||
block
|
||||
variant="text"
|
||||
color="primary"
|
||||
to="/signin"
|
||||
>
|
||||
← Other Login Options
|
||||
<v-btn class="my-1" block variant="text" color="primary" to="/signin">
|
||||
← Other Sign-in Options
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
@@ -1,33 +1,32 @@
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import { useSignInAnonymous } from '@nhost/vue'
|
||||
const { signInAnonymous } = useSignInAnonymous()
|
||||
const router = useRouter()
|
||||
const handleSignInAnonymous = async (e: Event) => {
|
||||
e.preventDefault()
|
||||
const { isSuccess, error } = await signInAnonymous()
|
||||
if (isSuccess) {
|
||||
router.push('/profile')
|
||||
} else {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div className="d-flex align-center flex-column">
|
||||
<v-card width="400">
|
||||
<v-card-title>Log in to the Application</v-card-title>
|
||||
<v-card-title>Sign in to the Application</v-card-title>
|
||||
<v-card-text>
|
||||
<router-view />
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
<v-divider class="my-4" style="min-width: 90%" />
|
||||
<div>
|
||||
Don‘t have an account? <router-link to="/signup">
|
||||
Sign up
|
||||
</router-link> or <a href="#" @click="handleSignInAnonymous">sign in anonymously</a>
|
||||
Don‘t have an account? <router-link to="/signup"> Sign up </router-link> or
|
||||
<a v-if="!isLoading" href="#" @click="handleSignInAnonymous">sign in anonymously</a>
|
||||
<v-progress-circular v-else indeterminate />
|
||||
</div>
|
||||
</div>
|
||||
<error-snack-bar :error="error" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import { useSignInAnonymous } from '@nhost/vue'
|
||||
const { signInAnonymous, error, isLoading } = useSignInAnonymous()
|
||||
const router = useRouter()
|
||||
const handleSignInAnonymous = async (e: Event) => {
|
||||
e.preventDefault()
|
||||
const { isSuccess } = await signInAnonymous()
|
||||
if (isSuccess) {
|
||||
router.push('/profile')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -11,13 +11,7 @@
|
||||
>
|
||||
Continue with passwordless email
|
||||
</v-btn>
|
||||
<v-btn
|
||||
class="my-1"
|
||||
block
|
||||
variant="text"
|
||||
color="primary"
|
||||
to="/signup/email-password"
|
||||
>
|
||||
<v-btn class="my-1" block variant="text" color="primary" to="/signup/email-password">
|
||||
Continue with email + password
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
@@ -1,56 +1,33 @@
|
||||
<template>
|
||||
<v-text-field
|
||||
v-model="email"
|
||||
label="Email"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="password"
|
||||
label="Password"
|
||||
type="password"
|
||||
/>
|
||||
<v-btn
|
||||
block
|
||||
color="primary"
|
||||
class="my-1"
|
||||
@click="signUp"
|
||||
>
|
||||
Sign up
|
||||
</v-btn>
|
||||
<v-btn
|
||||
class="my-1"
|
||||
block
|
||||
variant="text"
|
||||
color="primary"
|
||||
to="/signup"
|
||||
>
|
||||
<form @submit="handleSignUp">
|
||||
<v-text-field v-model="email" label="Email" />
|
||||
<v-text-field v-model="password" label="Password" type="password" />
|
||||
<v-btn block color="primary" class="my-1" type="submit" :disabled="isLoading" :loading="isLoading"> Sign up </v-btn>
|
||||
</form>
|
||||
<v-btn class="my-1" block variant="text" color="primary" to="/signup">
|
||||
← Other registration Options!
|
||||
</v-btn>
|
||||
<error-snack-bar :error="error" />
|
||||
<verification-email-dialog v-model="emailVerificationDialog" :email="email" />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { useSignUpEmailPassword } from '@nhost/vue'
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const email = ref('')
|
||||
const password = ref('')
|
||||
const { signUpEmailPassword, error } = useSignUpEmailPassword()
|
||||
|
||||
const signUp = async () => {
|
||||
const result = await signUpEmailPassword(email, password)
|
||||
if (result.error) {
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
email,
|
||||
error,
|
||||
password,
|
||||
signUp
|
||||
}
|
||||
}
|
||||
const emailVerificationDialog = ref(false)
|
||||
const email = ref('')
|
||||
const password = ref('')
|
||||
const { signUpEmailPassword, error, isLoading } = useSignUpEmailPassword({
|
||||
redirectTo: '/'
|
||||
})
|
||||
|
||||
const handleSignUp = async (e: Event) => {
|
||||
e.preventDefault()
|
||||
const result = await signUpEmailPassword(email, password)
|
||||
if (result.needsEmailVerification) {
|
||||
emailVerificationDialog.value = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
<template>
|
||||
<email-passwordless />
|
||||
<v-btn
|
||||
class="my-1"
|
||||
block
|
||||
variant="text"
|
||||
color="primary"
|
||||
to="/signup"
|
||||
>
|
||||
<v-btn class="my-1" block variant="text" color="primary" to="/signup">
|
||||
← Other registration Options
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -6,14 +6,7 @@
|
||||
<router-view />
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
<v-divider
|
||||
class="my-4"
|
||||
style="min-width: 90%"
|
||||
/>
|
||||
<div>
|
||||
Already have an account? <router-link to="/signin">
|
||||
Sign in
|
||||
</router-link>
|
||||
</div>
|
||||
<v-divider class="my-4" style="min-width: 90%" />
|
||||
<div>Already have an account? <router-link to="/signin"> Sign in </router-link></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -50,5 +50,5 @@ export const routes: RouteRecordRaw[] = [
|
||||
}
|
||||
]
|
||||
},
|
||||
{ path: '/apollo', component: ApolloPage }
|
||||
{ path: '/apollo', component: ApolloPage, meta: { auth: true } }
|
||||
]
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"noEmit": true,
|
||||
"jsx": "preserve",
|
||||
"declaration": false,
|
||||
"declarationMap": false
|
||||
"declarationMap": false,
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
||||
3
examples/vue-apollo/vercel.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"rewrites": [{ "source": "/(.*)", "destination": "/" }]
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
import path from 'path'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import vuetify from '@vuetify/vite-plugin'
|
||||
|
||||
|
||||
11
examples/vue-quickstart/auto-imports.d.ts
vendored
@@ -47,6 +47,8 @@ declare global {
|
||||
const refDefault: typeof import('@vueuse/core')['refDefault']
|
||||
const refThrottled: typeof import('@vueuse/core')['refThrottled']
|
||||
const refWithControl: typeof import('@vueuse/core')['refWithControl']
|
||||
const resolveRef: typeof import('@vueuse/core')['resolveRef']
|
||||
const resolveUnref: typeof import('@vueuse/core')['resolveUnref']
|
||||
const syncRef: typeof import('@vueuse/core')['syncRef']
|
||||
const syncRefs: typeof import('@vueuse/core')['syncRefs']
|
||||
const templateRef: typeof import('@vueuse/core')['templateRef']
|
||||
@@ -65,6 +67,7 @@ declare global {
|
||||
const useAsyncState: typeof import('@vueuse/core')['useAsyncState']
|
||||
const useBase64: typeof import('@vueuse/core')['useBase64']
|
||||
const useBattery: typeof import('@vueuse/core')['useBattery']
|
||||
const useBluetooth: typeof import('@vueuse/core')['useBluetooth']
|
||||
const useBreakpoints: typeof import('@vueuse/core')['useBreakpoints']
|
||||
const useBroadcastChannel: typeof import('@vueuse/core')['useBroadcastChannel']
|
||||
const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation']
|
||||
@@ -89,6 +92,7 @@ declare global {
|
||||
const useDisplayMedia: typeof import('@vueuse/core')['useDisplayMedia']
|
||||
const useDocumentVisibility: typeof import('@vueuse/core')['useDocumentVisibility']
|
||||
const useDraggable: typeof import('@vueuse/core')['useDraggable']
|
||||
const useDropZone: typeof import('@vueuse/core')['useDropZone']
|
||||
const useElementBounding: typeof import('@vueuse/core')['useElementBounding']
|
||||
const useElementByPoint: typeof import('@vueuse/core')['useElementByPoint']
|
||||
const useElementHover: typeof import('@vueuse/core')['useElementHover']
|
||||
@@ -100,6 +104,7 @@ declare global {
|
||||
const useEyeDropper: typeof import('@vueuse/core')['useEyeDropper']
|
||||
const useFavicon: typeof import('@vueuse/core')['useFavicon']
|
||||
const useFetch: typeof import('@vueuse/core')['useFetch']
|
||||
const useFileDialog: typeof import('@vueuse/core')['useFileDialog']
|
||||
const useFileSystemAccess: typeof import('@vueuse/core')['useFileSystemAccess']
|
||||
const useFocus: typeof import('@vueuse/core')['useFocus']
|
||||
const useFocusWithin: typeof import('@vueuse/core')['useFocusWithin']
|
||||
@@ -108,6 +113,7 @@ declare global {
|
||||
const useGamepad: typeof import('@vueuse/core')['useGamepad']
|
||||
const useGeolocation: typeof import('@vueuse/core')['useGeolocation']
|
||||
const useIdle: typeof import('@vueuse/core')['useIdle']
|
||||
const useImage: typeof import('@vueuse/core')['useImage']
|
||||
const useInfiniteScroll: typeof import('@vueuse/core')['useInfiniteScroll']
|
||||
const useIntersectionObserver: typeof import('@vueuse/core')['useIntersectionObserver']
|
||||
const useInterval: typeof import('@vueuse/core')['useInterval']
|
||||
@@ -129,6 +135,7 @@ declare global {
|
||||
const useNavigatorLanguage: typeof import('@vueuse/core')['useNavigatorLanguage']
|
||||
const useNetwork: typeof import('@vueuse/core')['useNetwork']
|
||||
const useNow: typeof import('@vueuse/core')['useNow']
|
||||
const useObjectUrl: typeof import('@vueuse/core')['useObjectUrl']
|
||||
const useOffsetPagination: typeof import('@vueuse/core')['useOffsetPagination']
|
||||
const useOnline: typeof import('@vueuse/core')['useOnline']
|
||||
const usePageLeave: typeof import('@vueuse/core')['usePageLeave']
|
||||
@@ -153,11 +160,13 @@ declare global {
|
||||
const useShare: typeof import('@vueuse/core')['useShare']
|
||||
const useSpeechRecognition: typeof import('@vueuse/core')['useSpeechRecognition']
|
||||
const useSpeechSynthesis: typeof import('@vueuse/core')['useSpeechSynthesis']
|
||||
const useStepper: typeof import('@vueuse/core')['useStepper']
|
||||
const useStorage: typeof import('@vueuse/core')['useStorage']
|
||||
const useStorageAsync: typeof import('@vueuse/core')['useStorageAsync']
|
||||
const useStyleTag: typeof import('@vueuse/core')['useStyleTag']
|
||||
const useSwipe: typeof import('@vueuse/core')['useSwipe']
|
||||
const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList']
|
||||
const useTextareaAutosize: typeof import('@vueuse/core')['useTextareaAutosize']
|
||||
const useTextSelection: typeof import('@vueuse/core')['useTextSelection']
|
||||
const useThrottle: typeof import('@vueuse/core')['useThrottle']
|
||||
const useThrottledRefHistory: typeof import('@vueuse/core')['useThrottledRefHistory']
|
||||
@@ -184,12 +193,14 @@ declare global {
|
||||
const useWindowFocus: typeof import('@vueuse/core')['useWindowFocus']
|
||||
const useWindowScroll: typeof import('@vueuse/core')['useWindowScroll']
|
||||
const useWindowSize: typeof import('@vueuse/core')['useWindowSize']
|
||||
const watchArray: typeof import('@vueuse/core')['watchArray']
|
||||
const watchAtMost: typeof import('@vueuse/core')['watchAtMost']
|
||||
const watchDebounced: typeof import('@vueuse/core')['watchDebounced']
|
||||
const watchIgnorable: typeof import('@vueuse/core')['watchIgnorable']
|
||||
const watchOnce: typeof import('@vueuse/core')['watchOnce']
|
||||
const watchPausable: typeof import('@vueuse/core')['watchPausable']
|
||||
const watchThrottled: typeof import('@vueuse/core')['watchThrottled']
|
||||
const watchTriggerable: typeof import('@vueuse/core')['watchTriggerable']
|
||||
const watchWithFilter: typeof import('@vueuse/core')['watchWithFilter']
|
||||
const whenever: typeof import('@vueuse/core')['whenever']
|
||||
}
|
||||
|
||||
@@ -10,15 +10,15 @@
|
||||
"test": "vitest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.6.2",
|
||||
"@apollo/client": "^3.6.9",
|
||||
"@nhost/apollo": "*",
|
||||
"@nhost/vue": "*",
|
||||
"@vue/apollo-composable": "^4.0.0-alpha.17",
|
||||
"@vueuse/core": "^8.4.2",
|
||||
"@vue/apollo-composable": "4.0.0-alpha.18",
|
||||
"@vueuse/core": "^8.9.2",
|
||||
"graphql": "^15.7.2",
|
||||
"graphql-tag": "^2.12.6",
|
||||
"vue": "^3.2.33",
|
||||
"vue-router": "^4.0.15"
|
||||
"vue": "^3.2.37",
|
||||
"vue-router": "^4.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "^0.23.0",
|
||||
@@ -26,7 +26,7 @@
|
||||
"@types/node": "^17.0.32",
|
||||
"@unocss/reset": "^0.33.2",
|
||||
"@vitejs/plugin-vue": "^2.3.2",
|
||||
"@vue/test-utils": "^2.0.0-rc.21",
|
||||
"@vue/test-utils": "^2.0.2",
|
||||
"eslint": "^8.15.0",
|
||||
"jsdom": "^19.0.0",
|
||||
"pnpm": "^7.0.1",
|
||||
@@ -37,6 +37,6 @@
|
||||
"vite": "^2.9.8",
|
||||
"vite-plugin-pages": "^0.23.0",
|
||||
"vitest": "^0.12.4",
|
||||
"vue-tsc": "^0.34.12"
|
||||
"vue-tsc": "^0.38.5"
|
||||
}
|
||||
}
|
||||
|
||||
4
nhost-cloud.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
# Docker image versions used in the cloud
|
||||
hasura: v2.8.0
|
||||
auth: 0.10.0
|
||||
storage: 0.2.3
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"prepare": "husky install",
|
||||
"prepare": "husky install config/.husky",
|
||||
"build": "pnpm run build:all --filter=!@nhost/docs --filter=!@nhost-examples/*",
|
||||
"build:docs": "pnpm run build:all --filter=@nhost/docs",
|
||||
"build:all": "turbo run build --include-dependencies",
|
||||
@@ -34,7 +34,8 @@
|
||||
"test": "turbo run test --filter=!@nhost/docs --filter=!@nhost-examples/* --no-deps --include-dependencies",
|
||||
"e2e": "turbo run e2e --concurrency=1",
|
||||
"changeset": "changeset",
|
||||
"docgen": "turbo run build --filter=@nhost/docgen --no-deps && turbo run docgen --filter='@nhost/*' && :"
|
||||
"docgen": "turbo run build --filter=@nhost/docgen --no-deps && turbo run docgen --filter='@nhost/*' && :",
|
||||
"sync-versions": "turbo run start --filter=@nhost/sync-versions --no-deps"
|
||||
},
|
||||
"workspaces": [
|
||||
"packages/*",
|
||||
|
||||