Compare commits

...

188 Commits

Author SHA1 Message Date
Szilárd Dóró
1446a8f13b Merge pull request #395 from nhost/changeset-release/main
chore: update versions
2022-04-12 14:54:23 +02:00
Johan Eliasson
ff75998e93 Merge pull request #397 from nhost/contributors-readme-action-v-3ccBloq6
contributors readme action update
2022-04-12 14:36:51 +02:00
github-actions[bot]
9cc044ca9f contrib-readme-action has updated readme 2022-04-12 12:28:41 +00:00
Johan Eliasson
c65e44b8d6 Merge pull request #396 from nhost/test/messaging-gql-be
Messaging test
2022-04-12 14:28:24 +02:00
Johan Eliasson
9ec73b4c22 edit readme 2022-04-12 14:25:47 +02:00
github-actions[bot]
94b70e0ce9 chore: update versions 2022-04-12 12:04:21 +00:00
Pilou
d108dff4f4 Merge pull request #387 from nhost/fix/sync-auth-state
fix onTokenChanged
2022-04-12 13:03:38 +01:00
Szilárd Dóró
7a8e771a72 Merge pull request #385 from gdangelo/patch-1
Add a table to detail the data returned by `useUserData`
2022-04-12 13:48:31 +02:00
Szilárd Dóró
f8fb4bbedd Merge pull request #393 from nhost/contributors-readme-action-L56J6ymmkI
contributors readme action update
2022-04-12 13:06:10 +02:00
github-actions[bot]
c6b1c33a8e contrib-readme-action has updated readme 2022-04-12 10:51:37 +00:00
Szilárd Dóró
65b36eff13 Merge pull request #391 from gdangelo/patch-2
Update example with the latest version of React Router, v6
2022-04-12 12:51:21 +02:00
Grégory D'Angelo
c192cb9503 refact: Remove additional props to simplify example 2022-04-12 11:44:36 +02:00
Grégory D'Angelo
94ff290264 fix: Return Outlet in ProtectedRoute component + add missing closing tag + add explanation 2022-04-12 11:40:03 +02:00
Grégory D'Angelo
78781ebfec Update example with the latest version of React Router, v6 2022-04-12 09:04:28 +02:00
Pierre-Louis Mercereau
63d6059981 fix: fix onTokenChanged bugs 2022-04-11 20:55:02 +01:00
Grégory D'Angelo
022d49fb25 Add a table to detail the data returned by useUserData 2022-04-11 19:06:30 +02:00
Pilou
3bd1aa4d53 Merge pull request #357 from nhost/changeset-release/main
chore: update versions
2022-04-10 08:51:47 +01:00
github-actions[bot]
f3cca4997b chore: update versions 2022-04-10 07:44:55 +00:00
Pilou
0fd7a487d6 Merge pull request #382 from nhost/fix/sync-auth-state
Keep authentication status and access token in sync
2022-04-10 08:44:15 +01:00
Pierre-Louis Mercereau
1bb032c1e7 chore: remove console.log and add explaination 2022-04-09 20:48:00 +01:00
Pierre-Louis Mercereau
2c97db68b5 fix: sync auth state with all the nhost sub-clients 2022-04-09 20:44:38 +01:00
Johan Eliasson
714f2872ee Merge pull request #380 from nhost/contributors-readme-action-nMk7JwQ8hY
contributors readme action update
2022-04-09 16:19:05 +02:00
github-actions[bot]
65fc26a0e8 contrib-readme-action has updated readme 2022-04-09 14:11:13 +00:00
Johan Eliasson
86a56f28c1 Merge pull request #379 from Savinvadim1312/patch-1
Fix a type in react documentation
2022-04-09 16:10:55 +02:00
Savin Vadim
6e8abe28d6 Fix a type in react documentation
Fix a typo in the `nhsot/react` documentation in the code example. 

The imported hook had a wrong name
2022-04-09 13:41:56 +01:00
Szilárd Dóró
39925ff5ca Merge pull request #376 from nhost/fix/documentation-react-router
React Router example upgraded to v6
2022-04-08 16:03:09 +02:00
Szilárd Dóró
583a77ed0d build fix and sitemap updates 2022-04-08 15:12:34 +02:00
Szilárd Dóró
e704831500 upgraded AuthGate example documentation to use react-router v6 2022-04-08 15:03:31 +02:00
Johan Eliasson
95948dd5b9 Merge pull request #372 from nhost/contributors-readme-action-9bzNZt6pM9
contributors readme action update
2022-04-08 07:24:40 +02:00
github-actions[bot]
247b69c952 contrib-readme-action has updated readme 2022-04-08 05:24:23 +00:00
Johan Eliasson
7d15b76402 Merge pull request #359 from nhost/contributors-readme-action-txEVhnQt0i
contributors readme action update
2022-04-08 07:24:11 +02:00
github-actions[bot]
b1ae65fd72 contrib-readme-action has updated readme 2022-04-07 18:55:02 +00:00
Pilou
0063fd1840 Merge pull request #358 from Savinvadim1312/patch-1
Fix a typo in the React docs
2022-04-07 19:54:48 +01:00
Savin Vadim
743a7e6507 Fix a typo in the React docs
Changed from `clientStorageGetter` to `clientStorageSetter` on the line referencing the setter function
2022-04-07 19:43:30 +01:00
Pilou
078652861f Merge pull request #345 from nhost/fix/dont-remove-ts-comments
fix: don't remove comments so they are present in the built .d.ts
2022-04-07 19:27:39 +01:00
Pilou
39840cfd95 Merge pull request #347 from nhost/docs/update-examples
Update examples to bump versions & hooks syntax, and fix dead link in react-apollo readme
2022-04-07 19:26:49 +01:00
Johan Eliasson
940a36a68f Merge pull request #352 from nhost/contributors-readme-action-YMeH8uC8qa
contributors readme action update
2022-04-07 13:23:41 +02:00
github-actions[bot]
77b109b3df contrib-readme-action has updated readme 2022-04-07 11:22:27 +00:00
Johan Eliasson
15907d65e6 Merge pull request #351 from nhost/contr-test-1
readme update
2022-04-07 13:22:12 +02:00
Johan Eliasson
7d7d16fa71 readme update 2022-04-07 13:21:56 +02:00
Johan Eliasson
3f39e48cbd Merge pull request #349 from nhost/contributors
contr init
2022-04-07 13:18:57 +02:00
Johan Eliasson
97ade32869 contr init 2022-04-07 13:18:22 +02:00
Pierre-Louis Mercereau
8583af8290 chore: changeset 2022-04-07 09:34:46 +02:00
Pierre-Louis Mercereau
a28193a6ba docs: correct link to documentation 2022-04-07 09:30:15 +02:00
Pierre-Louis Mercereau
9d6c64430a chore: remove rsuite toaster workaround 2022-04-06 15:44:57 +02:00
Pierre-Louis Mercereau
519d1bf5cb chore: prettier and lint fix 2022-04-06 15:39:29 +02:00
Pierre-Louis Mercereau
5ffb0320b5 docs: update examples to bump versions and to match the recommended hooks syntax 2022-04-06 15:31:58 +02:00
Pierre-Louis Mercereau
6607e73cc2 fix: don't remove comments so they are present in the built .d.ts 2022-04-06 15:07:37 +02:00
Pilou
b4bac161a5 Merge pull request #344 from timpratim/patch-2
Separated the commands for installation
2022-04-06 12:56:28 +02:00
Pratim
37d15377c8 Separated the commands for installation
Separated the commands for installation according to the package managers.
2022-04-06 15:33:45 +05:30
Pilou
8ee1df3be4 Merge pull request #343 from nhost/changeset-release/main
chore: update versions
2022-04-06 10:50:29 +02:00
Pilou
47ffca945e Update package.json 2022-04-06 10:46:11 +02:00
Pilou
d60f5e623c Update CHANGELOG.md 2022-04-06 10:45:41 +02:00
Pilou
6f80643ee0 Update package.json 2022-04-06 10:45:10 +02:00
Pilou
8d5084725d Update CHANGELOG.md 2022-04-06 10:44:56 +02:00
Pilou
693498dd09 Update CHANGELOG.md 2022-04-06 10:37:39 +02:00
Pilou
4d36a966ea Update CHANGELOG.md 2022-04-06 10:37:02 +02:00
Pilou
239a075f1d Update CHANGELOG.md 2022-04-06 10:36:37 +02:00
github-actions[bot]
931194812e chore: update versions 2022-04-06 08:33:17 +00:00
Pilou
c8f80c58f3 Merge pull request #335 from nhost/refactor/correct-react-hook-signature
React hook signature & add promises to hook action results
2022-04-06 10:32:33 +02:00
Pilou
7fdb5aee0a Merge pull request #334 from nhost/docs/bump-version-examples
docs: bump dependencies of react-apollo and nextjs examples
2022-04-05 20:52:12 +02:00
Pilou
1710808fef Merge pull request #321 from nhost/docs/correct-hljs
docs: pass language to react-syntax-highlighter
2022-04-05 20:52:00 +02:00
Pilou
696815d4a8 Merge pull request #311 from nhost/306-the-useuserdata-hook-does-not-return-the-emailverified-or-phonenumberverified-user-properties
Add `emailVerified`, `phoneNumber`, `phoneNumberVerified`, and `activeMfaType` to User type, and add missing providers types
2022-04-05 20:51:42 +02:00
Pilou
5cc9be00b6 Merge pull request #341 from nhost/changeset-release/main
chore: update versions
2022-04-05 16:14:26 +02:00
github-actions[bot]
28dae23a91 chore: update versions 2022-04-05 14:02:46 +00:00
Pilou
7819e20cf4 Merge pull request #340 from nhost/elitan-patch-1
Correct OAuth provider link
2022-04-05 16:01:42 +02:00
Johan Eliasson
6be3758668 Create ninety-eels-lick.md 2022-04-05 15:56:18 +02:00
Johan Eliasson
658c67faf4 Update hasura-auth-client.ts 2022-04-05 15:54:39 +02:00
Pierre-Louis Mercereau
e7f3a5f6e0 chore: ellaborate changesets 2022-04-05 10:50:55 +02:00
Pierre-Louis Mercereau
7135aee78b chore: add changeset 2022-04-05 10:42:44 +02:00
Pierre-Louis Mercereau
587eaff734 feat: add promise with the current context to hooks actions 2022-04-04 20:45:12 +02:00
Pierre-Louis Mercereau
7cf875f4b8 refactor: deprecate the use of values end as hook parameters 2022-04-04 16:56:46 +02:00
Pierre-Louis Mercereau
657cfb91c5 docs: update corresponding swagger api 2022-04-04 10:42:09 +02:00
Pierre-Louis Mercereau
103dd6e98e Merge branch 'main' into 306-the-useuserdata-hook-does-not-return-the-emailverified-or-phonenumberverified-user-properties 2022-04-04 10:40:05 +02:00
Pierre-Louis Mercereau
3c8caa680b docs: bump dependencies of react-apollo and nextjs examples
and remove workaround related to https://github.com/rsuite/rsuite/issues/2336
2022-04-03 23:45:06 +02:00
Pilou
1bcee357fe Merge pull request #325 from nhost/docs/auth-refresh-expiration
docs: change default refresh token expiration to 30 days
2022-04-03 22:32:21 +02:00
Pierre-Louis Mercereau
b729aa9290 ci: fix pnpm/npm/changeset 2022-04-03 22:26:58 +02:00
Pilou
57780ee645 Merge pull request #333 from nhost/changeset-release/main
chore: update versions
2022-04-03 15:35:58 +02:00
github-actions[bot]
aad8d22380 chore: update versions 2022-04-03 13:28:59 +00:00
Pilou
85d33c4de0 Merge pull request #332 from nhost/fix/auto-signin
fix: correct auto-signin bug introducted in previous version
2022-04-03 15:28:16 +02:00
Pierre-Louis Mercereau
ab3e2dcee9 refactor: remove log 2022-04-03 15:22:11 +02:00
Pierre-Louis Mercereau
12f4504b61 refactor: remove incorrect and unused snapshot script 2022-04-03 15:19:00 +02:00
Pierre-Louis Mercereau
71d7a11c96 refactor: correct script 2022-04-03 15:11:48 +02:00
Pierre-Louis Mercereau
16a6c5073e fix: correct auto-signin bug introducted in previous version 2022-04-03 15:05:13 +02:00
Pilou
3fcc86792a Merge branch 'main' into main 2022-04-03 13:40:31 +02:00
Pierre-Louis Mercereau
27909128e4 chore: bump versions to fix the workspace/package link bug 2022-04-02 11:25:38 +02:00
Pierre-Louis Mercereau
72371c72a1 chore: bump versions 2022-04-02 10:58:56 +02:00
Pierre-Louis Mercereau
d878414b10 ci: freeze node version 2022-04-02 10:52:27 +02:00
Pierre-Louis Mercereau
9b840f7c4a docs: change default refresh token expiration to 30 days 2022-04-01 21:15:40 +02:00
Pilou
4fd09b4080 Merge pull request #316 from nhost/changeset-release/main
chore: update versions
2022-04-01 16:18:58 +02:00
Pilou
bdb786fa83 Merge pull request #313 from chrtze/patch-2
Update hooks.mdx
2022-04-01 13:35:56 +02:00
Pierre-Louis Mercereau
d42be972b4 Merge branch 'main' into patch-2 2022-04-01 13:31:25 +02:00
Pierre-Louis Mercereau
5920c830b3 docs: minor adjustments 2022-04-01 13:25:32 +02:00
Pilou
5fc16653c0 Update index.mdx 2022-04-01 08:50:49 +02:00
Pilou
900ec48889 Update index.mdx 2022-04-01 08:45:55 +02:00
Pierre-Louis Mercereau
83d3c90f43 docs: pass language to react-syntax-highlighter 2022-03-31 21:57:40 +02:00
github-actions[bot]
cf20ee5a8f chore: update versions 2022-03-31 14:45:03 +00:00
Pilou
9180154325 Merge pull request #231 from nhost/hasura-auth-documentation
Hasura auth documentation
2022-03-31 16:44:19 +02:00
Pilou
1ae025b745 Merge pull request #310 from nhost/309-nhostclient-constructor-error-using-expo
fix: check if `window.location` exists
2022-03-31 16:16:55 +02:00
Pilou
ba538a4ad9 Merge pull request #315 from nhost/fix/wait-authentication-loaded
fix(sdk): wait for the authentication status to be known before executing auth actions
2022-03-31 16:15:07 +02:00
Szilárd Dóró
0e5e47b8f8 Merge pull request #314 from nhost/fix/token-refresh-usequery
fix: Query refetch and leaking GraphQL subscription
2022-03-31 15:06:05 +02:00
Szilárd Dóró
113beed447 added changeset 2022-03-31 14:53:10 +02:00
Pierre-Louis Mercereau
6eeb9d2e65 fix(sdk): wait for the authentication status to be known before executing auth actions 2022-03-31 14:47:31 +02:00
Szilárd Dóró
3db2959bc2 fixed query refetch and leaking GraphQL subscriptions when issuing new JWT token 2022-03-31 14:23:33 +02:00
Pierre-Louis Mercereau
16fcc08b0a refactor: simplify code 2022-03-31 13:53:08 +02:00
Christopher Möller
5b098c8ef4 Update hooks.mdx 2022-03-31 12:51:37 +02:00
Pierre-Louis Mercereau
058956bdcb feat: update types 2022-03-31 12:27:47 +02:00
Pierre-Louis Mercereau
d3384614b4 fix: typeof window still needs to be used 2022-03-31 11:28:16 +02:00
Pierre-Louis Mercereau
0064fccb12 docs: last missing suggestions 2022-03-31 11:25:16 +02:00
Pierre-Louis Mercereau
6efd45fcb7 docs: take suggestions into account - missing pieces 2022-03-31 11:23:22 +02:00
Pierre-Louis Mercereau
4420c0e070 fix: check if window.location exists 2022-03-31 11:18:05 +02:00
Pierre-Louis Mercereau
354b07947a docs(hasura-auth): update swagger to hasura-auth 0.5.0 2022-03-31 11:01:16 +02:00
Pierre-Louis Mercereau
2fa5c10e14 chore: merge main 2022-03-31 08:57:07 +02:00
Pierre-Louis Mercereau
94124c7754 docs: improve explainations 2022-03-31 08:54:49 +02:00
Johan Eliasson
e405b738a6 Update README.md (#307) 2022-03-30 16:19:30 +02:00
Pierre-Louis Mercereau
947b7e037f fix: correct dependency bump 2022-03-29 16:33:40 +02:00
Pierre-Louis Mercereau
63ee1d7659 docs: correct typo and code blocks 2022-03-28 17:18:58 +02:00
Pierre-Louis Mercereau
eb33952760 docs: take Szilard's comments into account 2022-03-28 14:18:59 +02:00
Pierre-Louis Mercereau
b2c398df22 docs: redirections 2022-03-23 14:35:05 +00:00
Pierre-Louis Mercereau
888192282f docs: hide missing chapters, and add todos 2022-03-23 14:23:07 +00:00
Pierre-Louis Mercereau
945b557dea docs: totp 2022-03-23 14:17:16 +00:00
Pierre-Louis Mercereau
4031d8a9e1 docs: smtp settings 2022-03-23 13:21:49 +00:00
Pierre-Louis Mercereau
c77aa16181 docs: email templates 2022-03-23 13:04:36 +00:00
Pierre-Louis Mercereau
ea2fb2e9a4 docs: extending user schema 2022-03-23 12:50:47 +00:00
Pierre-Louis Mercereau
e147487e27 docs: fix bullet points 2022-03-23 12:39:57 +00:00
Pierre-Louis Mercereau
6f52652e10 docs: hasura integration 2022-03-23 11:49:43 +00:00
Pierre-Louis Mercereau
1a8d9b5c28 docs: overview 2022-03-23 11:39:37 +00:00
Pierre-Louis Mercereau
9111299ddd docs: email passwordless 2022-03-23 11:27:31 +00:00
Pierre-Louis Mercereau
1c7f520073 docs: minor reshape 2022-03-23 11:09:26 +00:00
Pierre-Louis Mercereau
dff37a4cd0 docs: email and password checks 2022-03-23 11:04:53 +00:00
Pierre-Louis Mercereau
96a572379e docs: gravatar 2022-03-23 10:46:17 +00:00
Pierre-Louis Mercereau
da3bbf2e10 chore: update pnpm lockfile 2022-03-23 10:09:13 +00:00
Pierre-Louis Mercereau
a11fa372ff chore: merge main 2022-03-22 12:59:49 +00:00
Pierre-Louis Mercereau
47c57ff665 ci: scope ci script 2022-03-10 13:12:08 +01:00
Pierre-Louis Mercereau
1cb330016b ci: wrap up 2022-03-10 13:06:17 +01:00
Pierre-Louis Mercereau
497652d1b4 ci: cd, not cp 2022-03-10 13:00:22 +01:00
Pierre-Louis Mercereau
20eb7aa381 ci: correct cp 2022-03-10 12:58:54 +01:00
Pierre-Louis Mercereau
4a3c2f92b1 ci: correct cp arg 2022-03-10 12:57:38 +01:00
Pierre-Louis Mercereau
5647e64265 ci: copy existing nhost project 2022-03-10 12:55:43 +01:00
Pierre-Louis Mercereau
c113debf46 ci: again 2022-03-10 12:52:49 +01:00
Pierre-Louis Mercereau
3f0ae4a58c ci: manually create nhost project 2022-03-10 12:50:36 +01:00
Pierre-Louis Mercereau
3d5b8183e8 ci: deactivate nhost 2022-03-10 12:47:38 +01:00
Pierre-Louis Mercereau
789ef8f783 ci: exec nhost in tmp 2022-03-10 12:44:45 +01:00
Pierre-Louis Mercereau
94df175ca3 ci: remove testing project 2022-03-10 12:41:24 +01:00
Pierre-Louis Mercereau
c8bcefb0e5 ci: remove testing project 2022-03-10 12:40:20 +01:00
Pierre-Louis Mercereau
fc52f59eb8 ci: again 2022-03-10 12:37:39 +01:00
Pierre-Louis Mercereau
a80389e5c7 ci: again 2022-03-10 12:30:57 +01:00
Pierre-Louis Mercereau
923276422b ci: desesperant 2022-03-10 12:28:43 +01:00
Pierre-Louis Mercereau
7c9192f3a0 ci: correct 2022-03-10 12:24:33 +01:00
Pierre-Louis Mercereau
51d139b7aa ci: single ci command 2022-03-10 12:21:58 +01:00
Pierre-Louis Mercereau
8fe1bdb6f7 ci: deactivate cache 2022-03-10 12:19:01 +01:00
Pierre-Louis Mercereau
5b288bc0d1 ci: add options 2022-03-10 12:18:38 +01:00
Pierre-Louis Mercereau
27cd769c76 ci: frozen lockfile 2022-03-10 12:16:08 +01:00
Pierre-Louis Mercereau
5bb370869d ci: clean 2022-03-10 12:13:57 +01:00
Pierre-Louis Mercereau
ec68f64db4 ci: 1.1.5 2022-03-10 12:11:48 +01:00
Pierre-Louis Mercereau
4cf8f146c9 ci: another turbo version 2022-03-10 12:08:16 +01:00
Pierre-Louis Mercereau
61cf317541 ci: decrease pnpm version 2022-03-10 12:04:03 +01:00
Pierre-Louis Mercereau
a2066c9b41 ci: increase depth 2022-03-10 12:02:25 +01:00
Pierre-Louis Mercereau
817b152704 ci: pwd 2022-03-10 12:00:40 +01:00
Pierre-Louis Mercereau
cc73494c91 ci: installl again 2022-03-10 11:58:05 +01:00
Pierre-Louis Mercereau
64ed4083b9 ci: reverse version 2022-03-10 11:54:12 +01:00
Pierre-Louis Mercereau
77e8c58cc6 ci: downgrade turborepo 2022-03-10 11:48:33 +01:00
Pierre-Louis Mercereau
0cd2eab309 ci: debug 2022-03-10 11:43:58 +01:00
Pierre-Louis Mercereau
7d8c843c74 ci: deactivate turbo cache 2022-03-10 11:41:34 +01:00
Pierre-Louis Mercereau
da1c2d6914 ci: add src to files 2022-03-10 11:38:58 +01:00
Pierre-Louis Mercereau
3a949301f9 ci: remove scope 2022-03-10 11:34:43 +01:00
Pierre-Louis Mercereau
585eebab49 ci: updated packages 2022-03-10 11:30:05 +01:00
Pierre-Louis Mercereau
45c3e4686e ci: debug 2022-03-10 11:26:04 +01:00
Pierre-Louis Mercereau
52f2e67952 ci: install dependencies 2022-03-10 11:22:24 +01:00
Pierre-Louis Mercereau
929774aa5b ci: matrix 2022-03-10 11:21:04 +01:00
Pierre-Louis Mercereau
e711e338e7 ci: clean ci 2022-03-10 11:18:56 +01:00
Pierre-Louis Mercereau
4235eb812e Merge branch 'main' into hasura-auth-documentation 2022-03-04 09:59:48 +01:00
Pierre-Louis Mercereau
ed145234b2 Merge branch 'main' into hasura-auth-documentation 2022-03-04 09:52:42 +01:00
Pierre-Louis Mercereau
7c2597ddc7 chore: merge main 2022-03-04 09:52:11 +01:00
Pierre-Louis Mercereau
2b1f8182f2 docs: add hasura auth schema 2022-03-03 11:09:15 +01:00
Pierre-Louis Mercereau
ded9e7637a chore: fix lockfile 2022-02-24 22:31:07 +01:00
Pilou
c42fb85bae Merge branch 'main' into hasura-auth-documentation 2022-02-24 22:26:44 +01:00
Pierre-Louis Mercereau
33edc4291b docs(hasura-auth): structure documentation 2022-02-24 22:25:17 +01:00
Pierre-Louis Mercereau
df89d804c5 docs(hasura-auth): complete openapi documentation 2022-02-24 21:55:08 +01:00
Pierre-Louis Mercereau
89da44d715 docs: update hasura-auth swagger 2022-02-24 17:32:01 +01:00
Pierre-Louis Mercereau
789faad645 docs: add hasura-auth swagger documentation 2022-02-24 15:59:20 +01:00
Pierre-Louis Mercereau
8c7267cbee chore: merge main 2022-02-24 14:21:27 +01:00
Pilou
96c12ffff1 Correct typo 2022-02-19 13:01:15 +01:00
Pierre-Louis Mercereau
783729a6f6 docs(hasura-auth): move docs to the right directory and adjust the menu 2022-02-10 23:09:30 +01:00
Pierre-Louis Mercereau
60d4dbabdf Merge branch 'main' into hasura-auth-documentation 2022-02-10 22:47:07 +01:00
Pierre-Louis Mercereau
a77ddcdbc2 docs: document hasura-auth v0.2 features 2022-02-03 12:11:16 +01:00
Pierre-Louis Mercereau
f4c8a776a4 docs(wip): basic installation information 2022-02-01 10:37:11 +01:00
Pierre-Louis Mercereau
efbaf08483 docs(wip): add hasura-auth documentation 2022-02-01 10:02:38 +01:00
82 changed files with 4596 additions and 819 deletions

View File

@@ -16,29 +16,33 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Cache pnpm modules
uses: actions/cache@v2
- name: Checkout repository
uses: actions/checkout@v2
with:
path: ~/.pnpm-store
key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-
fetch-depth: 0
- uses: pnpm/action-setup@v2.1.0
with:
version: 6.32.3
run_install: true
# run_install: true
- name: Use Node.js 17
uses: actions/setup-node@v2
with:
node-version: '17.8.0'
cache: 'pnpm'
- name: Pick the right npm version
# * See: https://github.com/pnpm/pnpm/issues/4348
run: npm install --global npm@8.4
- name: Install dependencies
run: pnpm install
- name: Create PR or Publish release
id: changesets
uses: changesets/action@v1
with:
version: pnpm ci:version
version: pnpm run ci:version
commit: 'chore: update versions'
title: 'chore: update versions'
publish: pnpm release
publish: pnpm run release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

15
.github/workflows/contributors.yaml vendored Normal file
View File

@@ -0,0 +1,15 @@
name: Add contributors
on:
push:
branches:
- main
jobs:
contrib-readme-job:
runs-on: ubuntu-latest
name: A job to automate contrib in readme
steps:
- name: Contribute List
uses: akhilmhdh/contributors-readme-action@v2.3.4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

203
README.md
View File

@@ -1,8 +1,8 @@
<div align="center">
<img width="237" src="https://raw.githubusercontent.com/nhost/nhost/main/assets/logo.png"/>
![Nhost](https://imgur.com/fGo6E4d.png)
<br />
<br />
<div align="center">
# Nhost
<a href="https://docs.nhost.io/get-started">Quickstart</a>
<span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
@@ -20,9 +20,9 @@
<hr />
</div>
**Nhost is a serverless backend for web and mobile apps** built with the following things in mind:
**Nhost is a open-source GraphQL backend,** built with the following things in mind:
- Open Source
- Open-Source
- Developer Productivity
- SQL
- GraphQL
@@ -36,6 +36,8 @@ Nhost consists of open source software:
- Serverless Functions: Node.js (JavaScript and TypeScript)
- [Nhost CLI](https://docs.nhost.io/reference/cli) for local development
## Architecture of Nhost
<div align="center">
<br />
<img src="assets/nhost-diagram.png"/>
@@ -108,7 +110,7 @@ First and foremost: **Star and watch this repository** to stay up-to-date.
Also, follow Nhost on [GitHub Discussions](https://github.com/nhost/nhost/discussions), our [Blog](https://nhost.io/blog), and on [Twitter](https://twitter.com/nhostio). You can chat with the team and other members on [Discord](https://discord.com/invite/9V7Qb2U) and follow our tutorials and other video material at [YouTube](https://www.youtube.com/channel/UCJ7irtvV9Y0EQMxpabb6ntg?view_as=subscriber).
## Nhost is Open Source
### Nhost is Open Source
This repository, and most of our other open source projects, are licensed under the MIT license.
@@ -120,6 +122,189 @@ Here are some ways of contributing to making Nhost better:
- Join our [Discord](https://discord.com/invite/9V7Qb2U) and connect with other members to share and learn from.
- Send a pull request to any of our [open source repositories](https://github.com/nhost) on Github. Check our [contribution guide](https://github.com/nhost/nhost/blob/main/CONTRIBUTING.md) for more details about how to contribute. We're looking forward to your contribution!
## Security
### Contributors
If you discover a security vulnerability within Nhost, please e-mail [security@nhost.io](mailto:security@nhost.io). All security vulnerabilities will be promptly addressed.
<!-- readme: contributors -start -->
<table>
<tr>
<td align="center">
<a href="https://github.com/plmercereau">
<img src="https://avatars.githubusercontent.com/u/24897252?v=4" width="100;" alt="plmercereau"/>
<br />
<sub><b>Pilou</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/elitan">
<img src="https://avatars.githubusercontent.com/u/331818?v=4" width="100;" alt="elitan"/>
<br />
<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/nunopato">
<img src="https://avatars.githubusercontent.com/u/1523504?v=4" width="100;" alt="nunopato"/>
<br />
<sub><b>Nuno Pato</b></sub>
</a>
</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 align="center">
<a href="https://github.com/guicurcio">
<img src="https://avatars.githubusercontent.com/u/20285232?v=4" width="100;" alt="guicurcio"/>
<br />
<sub><b>Guido Curcio</b></sub>
</a>
</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"/>
<br />
<sub><b>Sebagudelo</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/mrinalwahal">
<img src="https://avatars.githubusercontent.com/u/9859731?v=4" width="100;" alt="mrinalwahal"/>
<br />
<sub><b>Mrinal Wahal</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/gdangelo">
<img src="https://avatars.githubusercontent.com/u/4352286?v=4" width="100;" alt="gdangelo"/>
<br />
<sub><b>Grégory D'Angelo</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/FuzzyReason">
<img src="https://avatars.githubusercontent.com/u/62517920?v=4" width="100;" alt="FuzzyReason"/>
<br />
<sub><b>Vadim Smirnov</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/subhendukundu">
<img src="https://avatars.githubusercontent.com/u/20059141?v=4" width="100;" alt="subhendukundu"/>
<br />
<sub><b>Subhendu Kundu</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/chrtze">
<img src="https://avatars.githubusercontent.com/u/3797215?v=4" width="100;" alt="chrtze"/>
<br />
<sub><b>Christopher Möller</b></sub>
</a>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/jerryjappinen">
<img src="https://avatars.githubusercontent.com/u/1101002?v=4" width="100;" alt="jerryjappinen"/>
<br />
<sub><b>Jerry Jäppinen</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/mustafa-hanif">
<img src="https://avatars.githubusercontent.com/u/30019262?v=4" width="100;" alt="mustafa-hanif"/>
<br />
<sub><b>Mustafa Hanif</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/Savinvadim1312">
<img src="https://avatars.githubusercontent.com/u/16936043?v=4" width="100;" alt="Savinvadim1312"/>
<br />
<sub><b>Savin Vadim</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/ahmic">
<img src="https://avatars.githubusercontent.com/u/13452362?v=4" width="100;" alt="ahmic"/>
<br />
<sub><b>Amir Ahmic</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/akd-io">
<img src="https://avatars.githubusercontent.com/u/30059155?v=4" width="100;" alt="akd-io"/>
<br />
<sub><b>Anders Kjær Damgaard</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/rustyb">
<img src="https://avatars.githubusercontent.com/u/53086?v=4" width="100;" alt="rustyb"/>
<br />
<sub><b>Colin Broderick</b></sub>
</a>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/dohomi">
<img src="https://avatars.githubusercontent.com/u/489221?v=4" width="100;" alt="dohomi"/>
<br />
<sub><b>Dominic Garms</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/alveshelio">
<img src="https://avatars.githubusercontent.com/u/8176422?v=4" width="100;" alt="alveshelio"/>
<br />
<sub><b>Helio Alves</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/nkhdo">
<img src="https://avatars.githubusercontent.com/u/26102306?v=4" width="100;" alt="nkhdo"/>
<br />
<sub><b>Hoang Do</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"/>
<br />
<sub><b>Nirmalya Ghosh</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/timpratim">
<img src="https://avatars.githubusercontent.com/u/32492961?v=4" width="100;" alt="timpratim"/>
<br />
<sub><b>Pratim</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/quentin-decre">
<img src="https://avatars.githubusercontent.com/u/1137511?v=4" width="100;" alt="quentin-decre"/>
<br />
<sub><b>Quentin Decré</b></sub>
</a>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/komninoschat">
<img src="https://avatars.githubusercontent.com/u/29049104?v=4" width="100;" alt="komninoschat"/>
<br />
<sub><b>Komninos</b></sub>
</a>
</td></tr>
</table>
<!-- readme: contributors -end -->

View File

@@ -33,8 +33,10 @@ export const orderTwo = {
},
reference: {
sdk: ['index', 'graphql', 'authentication', 'storage', 'functions'],
react: ['index', 'hooks', 'protecting-routes', 'apollo'],
nextjs: ['index', 'configuration', 'protecting-routes', ],
cli: ['index'],
'supporting-libraries': ['react-apollo', 'react-auth']
'hasura-auth': ['index', 'installation', 'configuration', 'environment-variables', 'schema', 'api-reference']
}
};
```

View File

@@ -2,15 +2,15 @@ import { lightNhostTheme } from '@/data/lightTheme'
import { useState } from 'react'
import { Light as SyntaxHighlighter } from 'react-syntax-highlighter'
import js from 'react-syntax-highlighter/dist/cjs/languages/hljs/javascript'
import ts from 'react-syntax-highlighter/dist/cjs/languages/hljs/typescript'
import Check from '../icons/Check'
import Copy from '../icons/Copy'
// @ts-ignore -> add to types
// @ts-ignore -> add to types
SyntaxHighlighter.registerLanguage('js', js)
SyntaxHighlighter.registerLanguage('language-js', js)
SyntaxHighlighter.registerLanguage('language-ts', ts)
// TODO highlight JSX
SyntaxHighlighter.registerLanguage('jsx', js)
SyntaxHighlighter.registerLanguage('language-jsx', js)
export interface CodeEditorProps {
code: string
@@ -24,7 +24,7 @@ export interface CodeEditorProps {
}
const CodeEditor = (props: CodeEditorProps) => {
const { children, url } = props
const { children, className } = props
const [copied, setCopied] = useState(false)
return (
@@ -53,6 +53,7 @@ const CodeEditor = (props: CodeEditorProps) => {
</button>
</div>
<SyntaxHighlighter
language={className}
style={lightNhostTheme}
wrapLongLines={true}
wrapLines={true}

View File

@@ -8,6 +8,7 @@ import React, { DetailedHTMLProps, HTMLProps, PropsWithChildren } from 'react'
import Command from '../Command'
import Divider from '../Divider'
import { Swagger } from '../Swagger'
function Note({ children }: PropsWithChildren<unknown>) {
return (
@@ -135,6 +136,7 @@ const components = {
}: DetailedHTMLProps<HTMLProps<HTMLTableCellElement>, HTMLTableCellElement>) => {
return <td className={clsx('font-display', className)} {...props} />
},
Swagger,
Mermaid: ({ chart }) => {
const [html, setHtml] = React.useState('')
React.useEffect(() => {

View File

@@ -0,0 +1,29 @@
import SwaggerUI from 'swagger-ui-react'
import 'swagger-ui-react/swagger-ui.css'
const OperationsLayout = (props) => {
const { getComponent } = props
const Operations = getComponent('operations', true)
let SvgAssets = getComponent('SvgAssets')
return (
<div className="swagger-ui">
<SvgAssets />
<Operations />
</div>
)
}
const OperationsLayoutPlugin = () => ({
components: {
OperationsLayout
}
})
export const Swagger: React.FC<{ spec: string }> = ({ spec }) => (
<SwaggerUI
url={`/openapi/${spec}`}
plugins={[OperationsLayoutPlugin]}
layout="OperationsLayout"
supportedSubmitMethods={[]}
/>
)

View File

@@ -18,9 +18,14 @@ In this guide, we'll keep the example simple. We're not using a frontend framewo
Create a new folder called `nhost-todos`, and initialize a new JavaScript app there:
Using npm package manager
```sh
npm init -y
# or
```
or
Using Yarn package manager
```sh
yarn init -y
```
@@ -28,9 +33,13 @@ yarn init -y
Install Nhost JavaScript SDK:
Using npm package manager
```sh
npm install @nhost/nhost-js
# or
```
or
Using Yarn package manager
```sh
yarn add @nhost/nhost-js
```

View File

@@ -0,0 +1,6 @@
---
title: 'API Reference'
subtitle: 'Hasura Auth'
---
<Swagger spec="hasura-auth.json" />

View File

@@ -0,0 +1,221 @@
---
title: Configuration
---
## Email configuration
Hasura Auth automatically sends transactional emails to manage the following operations:
- Sign up
- Password reset
- Email change
- Passwordless with emails
### SMTP settings
```bash
AUTH_SMTP_HOST=smtp.example.com
AUTH_SMTP_PORT=1025
AUTH_SMTP_USER=user
AUTH_SMTP_PASS=password
AUTH_SMTP_SENDER=hasura-auth@example.com
```
See the [environment variables](/reference/hasura-auth/environment-variables) for additional information about how to connnect to an SMTP server.
### Email templates
You can create your own templates to customize the emails that will be sent to the users. You can have a look at the [official email templates](https://github.com/nhost/hasura-auth/tree/main/email-templates) to understand how they are structured.
#### With Docker
When using Docker, you can mount your own email templates from the local file system. You can have a look at this [docker-compose example](https://github.com/nhost/hasura-auth/blob/16df3e84b6c9a4f888b2ff07bd85afc34f8ed051/docker-compose-example.yaml#L41) to see how to set it up.
#### Remote email templates
When running Hasura Auth in its own infrastructure, it is possible to mount a volume with custom `email-templates` directory. However, in some cases, we may want to fetch templates from an external HTTP endpoint. Hence the introduction of a new `AUTH_EMAIL_TEMPLATE_FETCH_URL` environment variable:
```bash
AUTH_EMAIL_TEMPLATE_FETCH_URL=https://github.com/nhost/nhost/tree/custom-email-templates-example/examples/custom-email-templates
```
In the above example, on every email creation, the server will use this URL to fetch its templates, depending on the locale, email type and field.
For instance, the template for english verification email body will the fetched in [https://raw.githubusercontent.com/nhost/nhost/main/examples/custom-email-templates/en/email-verify/body.html](https://raw.githubusercontent.com/nhost/nhost/main/examples/custom-email-templates/en/email-verify/body.html).
See the [example in the main nhost/nhost repository](https://github.com/nhost/nhost/tree/main/examples/custom-email-templates).
The context variables in email templates have been simplified: the `${link}` variable contains the entire redirection url the recipient needs to follow.
---
## Redirections
Some authentication operations redirects the users to the frontend application:
- After an OAuth provider completes or fails authentication, the user is redirected to the frontend
- Every email sent to the user (passwordless with email, password/email change, password reset) contains a link, that redirects the user to the frontend
In order to achieve that, you need to set the `AUTH_CLIENT_URL` environment variable, for instance:
```bash
AUTH_CLIENT_URL=https://my-app.vercel.com
```
---
## Email + password authentication
### Email checks
You can specify a list of allowed emails or domains with `AUTH_ACCESS_CONTROL_ALLOWED_EMAILS` and `AUTH_ACCESS_CONTROL_ALLOWED_EMAIL_DOMAINS`.
As an example, the following environment variables will only allow `@nhost.io`, `@example.com` and `bob@smith.com` to register to the application:
```bash
AUTH_ACCESS_CONTROL_ALLOWED_EMAILS=bob@smith.com
AUTH_ACCESS_CONTROL_ALLOWED_EMAIL_DOMAINS=nhost.io,example.com
```
In the above example, users with the following emails would be able to register `bob@smith.com`, `emma@example.com`, `john@nhost.io`, whereas `mary@firebase.com` won't.
Similarly, it is possible to provide a list of forbidden emails or domains with `AUTH_ACCESS_CONTROL_BLOCKED_EMAILS` and `AUTH_ACCESS_CONTROL_BLOCKED_EMAIL_DOMAINS`.
### Password checks
Hasura auth does not accepts passwords with less than three characters. This limit can be changed in changing the `AUTH_PASSWORD_MIN_LENGTH` environment variable.
It is also possible to only allow [passwords that have not been pwned](https://haveibeenpwned.com/) in setting `AUTH_PASSWORD_HIBP_ENABLED` to `true`.
<!-- TODO ### Change -->
<!-- TODO ### Reset email -->
<!-- TODO ### Reset password -->
<!-- ---
TODO ## Anonymous users -->
---
## Multi-factor authentication
Hasura Auth supports different types of Multi-Factor Authentication (MFA): passwordless with emails (magic links), passwordless with SMS, and Time-based one-time passwords.
### Passwordless with emails (magic links)
Hasura Auth supports email [passwordless authentication](https://en.wikipedia.org/wiki/Passwordless_authentication). It requires [SMTP](#email-configuration) to be configured properly.
Set `AUTH_EMAIL_PASSWORDLESS_ENABLED` to `true` to enable passwordless authentication.
<!-- TODO ### Passwordless with SMS -->
### Time-based one-time password (TOTP)
It is possible to add a step to authentication with email and password authentication. Once users registered, they can activate MFA TOTP:
1. Users generate a QR Code, that is then scanned in an authentication app such as [Authy](https://authy.com/) or [Google Authenticator](https://en.wikipedia.org/wiki/Google_Authenticator).
2. They then send the TOTP code to Hasura Auth. MFA is now activated
3. Next time they authenticate, Hasura Auth will first expect their email and password, but then, instead of completing authentication, Hasura Auth will expect the TOTP in order to return the refresh and the access tokens.
In order for users to be able to activate MFA TOTP, `AUTH_MFA_ENABLED` must be set to `true`.
<!-- ---
TODO ## OAuth authentication -->
---
## Gravatar
Hasura Auth stores the avatar URL of users in `auth.users.avatar_url`. By default, it will look for the Gravatar linked to the email, and store it into this field.
It is possible to deactivate the use of Gravatar in setting the `AUTH_GRAVATAR_ENABLED` environment variable to `false`.
---
## Extending user schema
Adding columns to the user tables may be tempting. However, all the tables and columns have a specific purpose, and changing the structure of the `auth` schema will very likely end in breaking the functionning of Hasura Auth. It's, therefore, **highly recommended** not to modify the database schema for any tables in the `auth` schema.
Instead, we recommend adding extra user information in the following ways:
- to store information in the `auth.users.metadata` column
- to store information in a separate table located in the `public` PostgreSQL schema, and to point to `auth.users.id` through a foreign key.
### `metadata` user field
The `auth.users.metadata` field is a JSON column, that can be used as an option on registration:
```json
{
"email": "bob@bob.com",
"passord": "12345678",
"options": {
"metadata": {
"first_name": "Bob"
}
}
}
```
### Additional user information in the `public` schema
As previously explained, the alteration of the `auth` schema may seriously hamper the functionning of Hasura Auth. The `metadata` field in the `auth.users` table may tackle some use cases, but in some other cases, we want to keep a certain level of structure in the way data is structured.
In that case, it is possible to create a dedicated table in the `public` schema, with a `user_id` foreign key column that would point to the `auth.users.id` column. It is then possible to add an Hasura object relationship that would join the two tables together.
<!-- TODO hooks on the metadata field -->
---
## Custom Hasura JWT claims
Hasura comes with a [powerful authorisation system](https://hasura.io/docs/latest/graphql/core/auth/authorization/index.html). Hasura Auth is already configured to add `x-hasura-user-id`, `x-hasura-allowed-roles`, and `x-hasura-user-isAnonymous` to the JSON Web Tokens it generates.
In Hasura Auth, it is possible to define custom claims to add to the JWT, so they can be used by Hasura to determine the permissions of the received GraphQL operation.
Each custom claim is defined by a pair of a key and a value:
- The key determines the name of the claim, prefixed by `x-hasura`. For instance, `organisation-id` will become `x-hasura-organisation-id`.
- The value is a representation of the path to look at to determine the value of the claim. For instance `profile.organisation.id` will look for the `user.profile` Hasura relationship, and the `profile.organisation` Hasura relationship. Array values are transformed into Postgres syntax so Hasura can interpret them. See the official Hasura documentation to understand the [session variables format](https://hasura.io/docs/latest/graphql/core/auth/authorization/roles-variables.html#format-of-session-variables).
```bash
AUTH_JWT_CUSTOM_CLAIMS={"organisation-id":"profile.organisation.id", "project-ids":"profile.contributesTo.project.id"}
```
Will automatically generate and fetch the following GraphQL query:
```graphql
{
user(id: "<user-id>") {
profile {
organisation {
id
}
contributesTo {
project {
id
}
}
}
}
}
```
It will then use the same expressions e.g. `profile.contributesTo.project.id` to evaluate the result with [JSONata](https://jsonata.org/), and possibly transform arrays into Hasura-readable, PostgreSQL arrays.Finally, it adds the custom claims to the JWT in the `https://hasura.io/jwt/claims` namespace:
```json
{
"https://hasura.io/jwt/claims": {
"x-hasura-organisation-id": "8bdc4f57-7d64-4146-a663-6bcb05ea2ac1",
"x-hasura-project-ids": "{\"3af1b33f-fd0f-425e-92e2-0db09c8b2e29\",\"979cb94c-d873-4d5b-8ee0-74527428f58f\"}",
"x-hasura-allowed-roles": [ "me", "user" ],
"x-hasura-default-role": "user",
"x-hasura-user-id": "121bbea4-908e-4540-ac5d-52c7f6f93bec",
"x-hasura-user-isAnonymous": "false"
}
"sub": "f8776768-4bbd-46f8-bae1-3c40da4a89ff",
"iss": "hasura-auth",
"iat": 1643040189,
"exp": 1643041089
}
```

View File

@@ -0,0 +1,107 @@
---
title: Environment Variables
---
## General environment variables
| Name (a star**\*** means the variable is required) | Description | Default value |
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------- |
| HASURA_GRAPHQL_JWT_SECRET**\*** | Key used for generating JWTs. Must be `HMAC-SHA`-based and the same as configured in Hasura. [More info](https://hasura.io/docs/latest/graphql/core/auth/authentication/jwt.html#running-with-jwt) | |
| HASURA_GRAPHQL_DATABASE_URL**\*** | [PostgreSQL connection URI](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING). Required to inject the `auth` schema into the database. | |
| HASURA_GRAPHQL_GRAPHQL_URL**\*** | Hasura GraphQL endpoint. Required to manipulate account data. For instance: `https://graphql-engine:8080/v1/graphql` | |
| HASURA_GRAPHQL_ADMIN_SECRET**\*** | Hasura GraphQL Admin Secret. Required to manipulate account data. | |
| AUTH_HOST | Server host. [Docs](http://expressjs.com/en/5x/api.html#app.listen) | `0.0.0.0` |
| AUTH_PORT | Server port. [Docs](http://expressjs.com/en/5x/api.html#app.listen) | `4000` |
| AUTH_SERVER_URL | Server URL of where Hasura Backend Plus is running. This value is to used as a callback in email templates and for the OAuth authentication process. | |
| AUTH_CLIENT_URL | URL of your frontend application. Used to redirect users to the right page once actions based on emails or OAuth succeed. | |
| AUTH_SMTP_HOST | SMTP server hostname used for sending emails | |
| AUTH_SMTP_PORT | SMTP port | `587` |
| AUTH_SMTP_USER | Username to use to authenticate on the SMTP server | |
| AUTH_SMTP_PASS | Password to use to authenticate on the SMTP server | |
| AUTH_SMTP_SENDER | Email to use in the `From` field of the email | |
| AUTH_SMTP_AUTH_METHOD | SMTP authentication method | `PLAIN` |
| AUTH_SMTP_SECURE | Enables SSL. [More info](https://nodemailer.com/smtp/#tls-options). | `false` |
| AUTH_GRAVATAR_ENABLED | | `true` |
| AUTH_GRAVATAR_DEFAULT | | `blank` |
| AUTH_GRAVATAR_RATING | | `g` |
| AUTH_ANONYMOUS_USERS_ENABLED | Enables users to register as an anonymous user. | `false` |
| AUTH_DISABLE_NEW_USERS | If set, new users will be disabled after finishing registration and won't be able to connect. | `false` |
| AUTH_ACCESS_CONTROL_ALLOWED_EMAILS | Comma-separated list of emails that are allowed to register. | |
| AUTH_ACCESS_CONTROL_ALLOWED_EMAIL_DOMAINS | Comma-separated list of email domains that are allowed to register. If `ALLOWED_EMAIL_DOMAINS` is `tesla.com,ikea.se`, only emails from tesla.com and ikea.se would be allowed to register an account. | `` (allow all email domains) |
| AUTH_ACCESS_CONTROL_BLOCKED_EMAILS | Comma-separated list of emails that cannot register. | |
| AUTH_ACCESS_CONTROL_BLOCKED_EMAIL_DOMAINS | Comma-separated list of email domains that cannot register. | |
| AUTH_PASSWORD_MIN_LENGTH | Minimum password length. | `3` |
| AUTH_PASSWORD_HIBP_ENABLED | User's password is checked against [Pwned Passwords](https://haveibeenpwned.com/Passwords). | `false` |
| AUTH_USER_DEFAULT_ROLE | Default user role for registered users. | `user` |
| AUTH_USER_DEFAULT_ALLOWED_ROLES | Comma-separated list of default allowed user roles. | `me,$AUTH_USER_DEFAULT_ROLE` |
| AUTH_LOCALE_DEFAULT | | `en` |
| AUTH_LOCALE_ALLOWED_LOCALES | | `en` |
| AUTH_EMAIL_PASSWORDLESS_ENABLED | Enables passwordless authentication by email. The SMTP server must then be configured. | `false` |
| AUTH_SMS_PASSWORDLESS_ENABLED | Enables passwordless authentication by SMS. An SMS provider must then be configured. | `false` |
| AUTH_SMS_PROVIDER | SMS provider name. Only `twilio` is possible as an option for now. | |
| AUTH_SMS_TWILIO_ACCOUNT_SID | | |
| AUTH_SMS_TWILIO_AUTH_TOKEN | | |
| AUTH_SMS_TWILIO_MESSAGING_SERVICE_ID | | |
| AUTH_SMS_TWILIO_FROM | | |
| AUTH_EMAIL_SIGNIN_EMAIL_VERIFIED_REQUIRED | When enabled, any email-based authentication requires emails to be verified by a link sent to this email. | `true` |
| AUTH_ACCESS_CONTROL_ALLOWED_REDIRECT_URLS | | |
| AUTH_MFA_ENABLED | Enables users to use Multi Factor Authentication. | `false` |
| AUTH_MFA_TOTP_ISSUER | The name of the One Time Password (OTP) issuer. Probably your app's name. | `hasura-auth` |
| AUTH_ACCESS_TOKEN_EXPIRES_IN | Number of seconds before the access token (JWT) expires. | `900`(15 minutes) |
| AUTH_REFRESH_TOKEN_EXPIRES_IN | Number of seconds before the refresh token expires. | `2592000` (30 days) |
| AUTH_EMAIL_TEMPLATE_FETCH_URL | | |
| AUTH_JWT_CUSTOM_CLAIMS | | |
## OAuth environment variables
| Name (a star**\*** means the variable is required when the provider is enabled) | Default value |
| ------------------------------------------------------------------------------- | ----------------------------------- |
| AUTH_PROVIDER_GITHUB_ENABLED | `false` |
| AUTH_PROVIDER_GITHUB_CLIENT_ID**\*** | |
| AUTH_PROVIDER_GITHUB_CLIENT_SECRET**\*** | |
| AUTH_PROVIDER_GITHUB_AUTHORIZATION_URL | |
| AUTH_PROVIDER_GITHUB_TOKEN_URL | |
| AUTH_PROVIDER_GITHUB_USER_PROFILE_URL | |
| AUTH_PROVIDER_GITHUB_SCOPE | `user:email ` |
| AUTH_PROVIDER_GOOGLE_ENABLED | `false` |
| AUTH_PROVIDER_GOOGLE_CLIENT_ID**\*** | |
| AUTH_PROVIDER_GOOGLE_CLIENT_SECRET**\*** | |
| AUTH_PROVIDER_GOOGLE_SCOPE | `email,profile` |
| AUTH_PROVIDER_FACEBOOK_ENABLED | `false` |
| AUTH_PROVIDER_FACEBOOK_CLIENT_ID**\*** | |
| AUTH_PROVIDER_FACEBOOK_CLIENT_SECRET**\*** | |
| AUTH_PROVIDER_FACEBOOK_PROFILE_FIELDS | `email,photos,displayName` |
| AUTH_PROVIDER_FACEBOOK_SCOPE | `email` |
| AUTH_PROVIDER_TWITTER_ENABLED | `false` |
| AUTH_PROVIDER_TWITTER_CONSUMER_KEY**\*** | |
| AUTH_PROVIDER_TWITTER_CONSUMER_SECRET**\*** | |
| AUTH_PROVIDER_LINKEDIN_ENABLED | |
| AUTH_PROVIDER_LINKEDIN_CLIENT_ID**\*** | |
| AUTH_PROVIDER_LINKEDIN_CLIENT_SECRET**\*** | |
| AUTH_PROVIDER_LINKEDIN_SCOPE | `r_emailaddress,r_liteprofile` |
| AUTH_PROVIDER_APPLE_ENABLED | `false` |
| AUTH_PROVIDER_APPLE_CLIENT_ID**\*** | |
| AUTH_PROVIDER_APPLE_TEAM_ID**\*** | |
| AUTH_PROVIDER_APPLE_KEY_ID**\*** | |
| AUTH_PROVIDER_APPLE_PRIVATE_KEY**\*** | Base64 format |
| AUTH_PROVIDER_APPLE_SCOPE | `name,email` |
| AUTH_PROVIDER_WINDOWS_LIVE_ENABLED | `false` |
| AUTH_PROVIDER_WINDOWS_LIVE_CLIENT_ID**\*** | |
| AUTH_PROVIDER_WINDOWS_LIVE_CLIENT_SECRET**\*** | |
| AUTH_PROVIDER_WINDOWS_LIVE_SCOPE | `wl.basic,wl.emails` |
| AUTH_PROVIDER_SPOTIFY_ENABLED | `false` |
| AUTH_PROVIDER_SPOTIFY_CLIENT_ID**\*** | |
| AUTH_PROVIDER_SPOTIFY_CLIENT_SECRET**\*** | |
| AUTH_PROVIDER_SPOTIFY_SCOPE | `user-read-email,user-read-private` |
| AUTH_PROVIDER_GITLAB_ENABLED | `false` |
| AUTH_PROVIDER_GITLAB_CLIENT_ID**\*** | |
| AUTH_PROVIDER_GITLAB_CLIENT_SECRET**\*** | |
| AUTH_PROVIDER_GITLAB_BASE_URL | |
| AUTH_PROVIDER_GITLAB_SCOPE | `read_user` |
| AUTH_PROVIDER_BITBUCKET_ENABLED | `false` |
| AUTH_PROVIDER_BITBUCKET_CLIENT_ID**\*** | |
| AUTH_PROVIDER_BITBUCKET_CLIENT_SECRET**\*** | |
| AUTH_PROVIDER_STRAVA_ENABLED | `false` |
| AUTH_PROVIDER_STRAVA_CLIENT_ID**\*** | |
| AUTH_PROVIDER_STRAVA_CLIENT_SECRET**\*** | |
| AUTH_PROVIDER_STRAVA_SCOPE | `profile:read_all` |

View File

@@ -0,0 +1,41 @@
---
title: 'Overview'
---
Hasura Auth handles **authentication** for [Hasura](https://github.com/hasura/graphql-engine).
Hasura Auth runs in a separate Docker container alongside Postgres and Hasura.
## Features
- 🧑‍🤝‍🧑 Users are stored in Postgres and accessed via GraphQL
- 🔑 Multiple sign-in methods
- ✨ Integrates with GraphQL and Hasura Permissions
- 🔐 JWT tokens and Refresh Tokens.
- ✉️ Emails sent on various operations
<!-- - ✅ Optional checking for Pwned Passwords. -->
- 🛡️ Two-factor authentication support.
- 👨‍💻 Written 100% in TypeScript.
### Authentication methods
- **Email and Password**: simple email and password method.
- **Email**, also called **passwordless email** or **magic link**.
- **SMS**, also called **passwordless sms**.
- **Anonymous**: sign in users without any method. Anonymous users can be
converted to _regular_ users at a later stage.
- **OAuth providers**: Facebook, Google, GitHub, Twitter, Apple, LinkedIn, Windows Live, Spotify, Strave, GitLab, BitBucket
## Integration with Hasura
Hasura Auth's final purpose is to securely provide a JSON Web Token that can be added as an authorization header to GraphQL operation sent to Hasura.
Hasura auth automatically generates and manages two kinds of tokens:
- An access token (JWT), that will be used to authenticate the GraphQL operations in Hasura, and that has a limited expiration limit (15 minutes by default)
- A refresh token, that is used to ask Hasura Auth for a new access token, and that can be consummed only once.
Access tokens generated by Hasura Auth contains information and user id, its default role, and the roles they actually have. In addition, it is possible since version `0.2.0` to extend JWT claims with custom information such as organisation or project ownership, so your application can leverage the capabilities of the [Hasura permissions layer](https://hasura.io/docs/latest/graphql/core/auth/authorization/index.html).
<!-- - Users and accounts are saved in the database. -->
You can read further information about JWT and Hasura in the [official Hasura documentation](https://hasura.io/docs/latest/graphql/core/auth/authentication/jwt.html).

View File

@@ -0,0 +1,24 @@
---
title: Installation
---
Hasura Auth runs in a container alongside Postgres and Hasura.
## Nhost (recommended)
The recommended way to start using Hasura Auth is by using Nhost. With Nhost, you will get a complete backend ready in seconds with Hasura, authentication, storage and serverless functions.
Go to [Nhost](https://nhost.io) and start building your app now.
## Docker-compose
```sh
git clone https://github.com/nhost/hasura-auth.git
cd hasura-auth
cp .env.example .env
docker-compose -f docker-compose-example.yaml up
```
Hasura Auth comes with plenty of options. They are explained in the [configuration section](/reference/hasura-auth/configuration).
If you are already familiar with the application, you can also have a look at the [environment variables](/reference/hasura-auth/environment-variables) that can be passed on to your docker container.

View File

@@ -0,0 +1,85 @@
---
title: 'Schema'
---
Hasura Auth stores all its data in a dedicated `auth` PostgreSQL schema. When Hasura Auth starts, it checks if the `auth` schema exists, then automatically syncs the following tables and their corresponding Hasura metadata:
```mermaid
erDiagram
migrations {
integer id PK
varchar name
varchar hash
timestamp executed_at "CURRENT_TIMESTAMP"
}
users ||--o{ user_roles : roles
user_roles }o--|| roles: role
users }o--|| roles: role
users ||--o{ refresh_tokens: refreshTokens
users ||--o{ user_providers: provider
providers ||--o{ user_providers: user
provider_requests {
uuid id PK "gen_random_uuid()"
test redirect_url
}
refresh_tokens {
uuid refresh_token PK
uuid user_id FK
timestamptz created_at "now()"
timestamptz expires_at
}
providers {
text id PK
}
user_providers {
uuid id PK "gen_random_uuid()"
timestamptz created_at "now()"
timestamptz updated_at "now()"
uuid user_id FK
text access_token
text refresh_token
text provider_id FK
text provider_user_id
}
user_roles {
uuid id PK "gen_random_uuid()"
timestamptz created_at "now()"
uuid user_id FK
text role FK
}
users {
uuid id PK "gen_random_uuid()"
timestamptz created_at "now()"
timestamptz updated_at "now()"
timestamptz last_seen "nullable"
boolean disabled "false"
text display_name "''"
text avatar_url "''"
varchar locale
email email "nullable"
text phone_number "nullable"
text password_hash "nullable"
boolean email_verified "false"
boolean phone_number_verified "false"
email new_email "nullable"
text otp_method_last_used "nullable"
text otp_hash "nullable"
timestamptz opt_hash_expires_at "now()"
text default_role FK "user"
boolean is_anonymous "false"
text totp_secret "nullable"
text active_mfa_type "nullable"
text ticket "nullable"
timestamptz ticket_expires_at "now()"
jsonb metadata "nullable"
}
roles {
text roles PK
}
```

View File

@@ -28,3 +28,11 @@ In this section:
### Nhost CLI
- [CLI overview](/reference/cli)
### Hasura Auth
- [Overview](./reference/hasura-auth)
- [Installation](./reference/hasura-auth/installation)
- [Configuration](./reference/hasura-auth/configuration)
- [Environment variables](./reference/hasura-auth/environment-variables)
- [API](./reference/hasura-auth/api-reference)
- [Schema](./reference/hasura-auth/api-reference)

View File

@@ -8,23 +8,25 @@ title: 'Hooks'
```js
const { signUpEmailPassword, isLoading, isSuccess, needsEmailVerification, isError, error } =
useSignUpEmailPassword(email?: string, password?: string, options?: Options )
useSignUpEmailPassword(options?: Options)
```
| Name | Type | Notes |
| ------------------------ | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `signUpEmailPassword` | (email?: string, password?: string) => void | Used for a new user to sign up. The email/password arguments will take precedence over the possible state values used when creating the hook. |
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
| `needsEmailVerification` | boolean | Returns `true` if the sign-up has been accepted, but a verificaiton email has been sent and is awaiting. |
| `isSuccess` | boolean | Returns `true` if the sign-up suceeded. Returns `false` if the new email needs to be verified first, or if an error occurred. |
| `isError` | boolean | Returns `true` if an error occurred. |
| `error` | {status: number, error: string, message: string} \| undefined | Provides details about the error. |
| `options.locale` | string \| undefined | Locale of the user, in two digits, for instance `en`. |
| `options.allowedRoles` | string[] \| undefined | Allowed roles of the user. Must be a subset of the default allowed roles defined in Hasura Auth. |
| `options.defaultRole` | string \| undefined | Default role of the user. Must be part of the default allowed roles defined in Hasura Auth. |
| `options.displayName` | string \| undefined | |
| `options.metadata` | Record<string, unknown> \| undefined | Custom additional user information stored in the `metadata` column. Can be any JSON object. |
| `options.redirectTo` | string \| undefined | redirection path in the client application that will be used in the link in the verification email. For instance, if you want to redirect to `https://myapp.com/success`, the `redirectTo` value is `'/success'`. |
| Name | Type | Notes |
| ------------------------ | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `signUpEmailPassword` | (email?: string, password?: string) => void | Used for a new user to sign up. Returns a promise with the current context |
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
| `needsEmailVerification` | boolean | Returns `true` if the sign-up has been accepted, but a verificaiton email has been sent and is awaiting. |
| `isSuccess` | boolean | Returns `true` if the sign-up suceeded. Returns `false` if the new email needs to be verified first, or if an error occurred. |
| `isError` | boolean | Returns `true` if an error occurred. |
| `error` | {status: number, error: string, message: string} \| null | Provides details about the error. |
| `user` | User \| null | User information |
| `accessToken` | string \| null | Access token (JWT) |
| `options.locale` | string \| undefined | Locale of the user, in two digits, for instance `en`. |
| `options.allowedRoles` | string[] \| undefined | Allowed roles of the user. Must be a subset of the default allowed roles defined in Hasura Auth. |
| `options.defaultRole` | string \| undefined | Default role of the user. Must be part of the default allowed roles defined in Hasura Auth. |
| `options.displayName` | string \| undefined | |
| `options.metadata` | Record<string, unknown> \| undefined | Custom additional user information stored in the `metadata` column. Can be any JSON object. |
| `options.redirectTo` | string \| undefined | redirection path in the client application that will be used in the link in the verification email. For instance, if you want to redirect to `https://myapp.com/success`, the `redirectTo` value is `'/success'`. |
#### Usage
@@ -36,7 +38,7 @@ const Component = () => {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const { signUpEmailPassword, isLoading, isSuccess, needsEmailVerification, isError, error } =
useSignUpEmailPassword(email, password)
useSignUpEmailPassword()
return (
<div>
<input value={email} onChange={(event) => setEmail(event.target.value)} placeholder="Email" />
@@ -45,7 +47,7 @@ const Component = () => {
onChange={(event) => setPassword(event.target.value)}
placeholder="Password"
/>
<button onClick={signUpEmailPassword}>Register</button>
<button onClick={() => signUpEmailPassword(email, password)}>Register</button>
{isSuccess && <div>Your account have beed created! You are now authenticated</div>}
{needsEmailVerification && (
<div>Please check your mailbox and follow the verification link to verify your email</div>
@@ -58,20 +60,31 @@ const Component = () => {
### Email and Password Sign-In
```js
const { signInEmailPassword, isLoading, needsEmailVerification, needsMfaOtp, sendMfaOtp, isSuccess, isError, error } =
useSignInEmailPassword(email?: string, password?: string)
const {
signInEmailPassword,
isLoading,
needsEmailVerification,
needsMfaOtp,
sendMfaOtp,
isSuccess,
isError,
error,
user
} = useSignInEmailPassword()
```
| Name | Type | Notes |
| ------------------------ | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `signInEmailPassword` | (email?: string, password?: string) => void | Will try to authenticate. The email/password arguments will take precedence over the possible state values used when creating the hook. |
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
| `needsEmailVerification` | boolean | Returns `true` if the user email is still pending email verification. |
| `needsMfaOtp` | boolean | Returns `true` if the server is awaiting an MFA one-time password to complete the authentication. |
| `sendMfaOtp` | (otp: string) => void | Sends MFA One-time password. Will turn either `isSuccess` or `isError` to true, and store potential error in `error`. |
| `isSuccess` | boolean | Returns `true` if the user has successfully authenticated. Returns `false` in case or error or if the new email needs to be verified first. |
| `isError` | boolean | Returns `true` if an error occurred. |
| `error` | {status: number, error: string, message: string} \| undefined | Provides details about the error. |
| Name | Type | Notes |
| ------------------------ | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `signInEmailPassword` | (email?: string, password?: string) | Will try to authenticate. Returns a promise with the current context |
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
| `needsEmailVerification` | boolean | Returns `true` if the user email is still pending email verification. |
| `needsMfaOtp` | boolean | Returns `true` if the server is awaiting an MFA one-time password to complete the authentication. |
| `sendMfaOtp` | (otp: string) => void | Sends MFA One-time password. Will turn either `isSuccess` or `isError` to true, and store potential error in `error`. |
| `isSuccess` | boolean | Returns `true` if the user has successfully authenticated. Returns `false` in case or error or if the new email needs to be verified first. |
| `isError` | boolean | Returns `true` if an error occurred. |
| `error` | {status: number, error: string, message: string} \| null | Provides details about the error. |
| `user` | User \| null | User information |
| `accessToken` | string \| null | Access token (JWT) |
#### Usage
@@ -83,7 +96,7 @@ const Component = () => {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const { signInEmailPassword, isLoading, isSuccess, needsEmailVerification, isError, error } =
useSignInEmailPassword(email, password)
useSignInEmailPassword()
return (
<div>
<input value={email} onChange={(event) => setEmail(event.target.value)} placeholder="Email" />
@@ -92,7 +105,7 @@ const Component = () => {
onChange={(event) => setPassword(event.target.value)}
placeholder="Password"
/>
<button onClick={signInEmailPassword}>Register</button>
<button onClick={() => signInEmailPassword(email, password)}>Register</button>
{isSuccess && <div>Authentication suceeded</div>}
{needsEmailVerification && (
<div>
@@ -139,12 +152,12 @@ const Component = () => {
```js
const { signInEmailPasswordless, isLoading, isSuccess, isError, error } =
useSignInEmailPasswordless(email?: string, options?: Options)
useSignInEmailPasswordless(options?: Options)
```
| Name | Type | Notes |
| ------------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `signInEmailPasswordless` | (email?: string) => void | Sends a magic link to the given email The email argument will take precedence over the the possible state value used when creating the hook. |
| `signInEmailPasswordless` | (email?: string) => void | Sends a magic link to the given email. |
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
| `isSuccess` | boolean | Returns `true` if the magic link email user has successfully send. |
| `isError` | boolean | Returns `true` if an error occurred. |
@@ -165,11 +178,11 @@ import { useSignInEmailPasswordless } from '@nhost/react'
const Component = () => {
const [email, setEmail] = useState('')
const { signInEmailPasswordless, isLoading, isSuccess, isError, error } =
useSignInEmailPasswordless(email)
useSignInEmailPasswordless()
return (
<div>
<input value={email} onChange={(event) => setEmail(event.target.value)} placeholder="Email" />
<button onClick={signInEmailPasswordless}>Authenticate</button>
<button onClick={() => signInEmailPasswordless(email)}>Authenticate</button>
{isSuccess && (
<div>
An email has been sent to {email}. Please check your mailbox and click on the
@@ -253,17 +266,17 @@ const accessToken = useAccessToken()
```js
const { changeEmail, isLoading, isSuccess, needsEmailVerification, isError, error } =
useChangeEmail(email?: string, options?: { redirectTo?: string })
useChangeEmail(options?: { redirectTo?: string })
```
| Name | Type | Notes |
| ------------------------ | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `changeEmail` | (email?: string) => void | Requests the email change. The arguement password will take precedence over the the possible state value used when creating the hook. |
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
| `needsEmailVerification` | boolean | Returns `true` if the email change has been requested, but that a email has been sent to the user to verify the new email. |
| `isError` | boolean | Returns `true` if an error occurred. |
| `error` | {status: number, error: string, message: string} \| undefined | Provides details about the error. |
| `redirectTo` | string \| undefined | Redirection path in the client application that will be used in the link in the verification email. For instance, if you want to redirect to `https://myapp.com/success`, the `redirectTo` value is `'/success'`. |
| Name | Type | Notes |
| ------------------------ | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `changeEmail` | (email?: string) => void | Requests the email change. Returns a promise with the current context |
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
| `needsEmailVerification` | boolean | Returns `true` if the email change has been requested, but that a email has been sent to the user to verify the new email. |
| `isError` | boolean | Returns `true` if an error occurred. |
| `error` | {status: number, error: string, message: string} \| null | Provides details about the error. |
| `redirectTo` | string \| undefined | Redirection path in the client application that will be used in the link in the verification email. For instance, if you want to redirect to `https://myapp.com/success`, the `redirectTo` value is `'/success'`. |
#### Usage
@@ -273,12 +286,11 @@ import { useChangeEmail } from '@nhost/react'
const Component = () => {
const [email, setEmail] = useState('')
const { changeEmail, isLoading, needsEmailVerification, isError, error } =
useChangeEmail(password)
const { changeEmail, isLoading, needsEmailVerification, isError, error } = useChangeEmail()
return (
<div>
<input value={email} onChange={(event) => setEmail(event.target.value)} />
<button onClick={changeEmail}>Change password</button>
<button onClick={() => changeEmail(email)}>Change email</button>
{needsEmailVerification && (
<div>
Please check your mailbox and follow the verification link to confirm your new email
@@ -292,16 +304,16 @@ const Component = () => {
### Change password
```js
const { changePassword, isLoading, isSuccess, isError, error } = useChangePassword(password?: string)
const { changePassword, isLoading, isSuccess, isError, error } = useChangePassword()
```
| Name | Type | Notes |
| ---------------- | ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `changePassword` | (password?: string) => void | Requests the password change. The arguement password will take precedence over the the possible state value used when creating the hook. |
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
| `isSuccess` | boolean | Returns `true` if the password has beed successfully changed. |
| `isError` | boolean | Returns `true` if an error occurred. |
| `error` | {status: number, error: string, message: string} \| undefined | Provides details about the error. |
| Name | Type | Notes |
| ---------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| `changePassword` | (password?: string) | Requests the password change. Returns a promise with the current context |
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
| `isSuccess` | boolean | Returns `true` if the password has beed successfully changed. |
| `isError` | boolean | Returns `true` if an error occurred. |
| `error` | {status: number, error: string, message: string} \| null | Provides details about the error. |
#### Usage
@@ -311,11 +323,11 @@ import { useChangePassword } from '@nhost/react'
const Component = () => {
const [password, setPassword] = useState('')
const { changePassword, isLoading, isSuccess, isError, error } = useChangePassword(password)
const { changePassword, isLoading, isSuccess, isError, error } = useChangePassword()
return (
<div>
<input value={password} onChange={(event) => setPassword(event.target.value)} />
<button onClick={changePassword}>Change password</button>
<button onClick={() => changePassword(password)}>Change password</button>
</div>
)
}
@@ -326,17 +338,17 @@ const Component = () => {
If a user loses their password, we can resend them an email to authenticate so that they can change it to a new one:
```js
const { resetPassword, isLoading, isSent, isError, error } = useResetPassword(email?: string, options?: { redirectTo?: string })
const { resetPassword, isLoading, isSent, isError, error } = useResetPassword(options?: { redirectTo?: string })
```
| Name | Type | Notes |
| --------------- | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `resetPassword` | (email?: string) => void | Sends an email with a temporary connection link. The arguement email will take precedence over the the possible state value used when creating the hook. |
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
| `isSent` | boolean | Returns `true` when the email has been successfully sent. |
| `isError` | boolean | Returns `true` if an error occurred. |
| `error` | {status: number, error: string, message: string} \| undefined | Provides details about the error. |
| `redirectTo` | string \| undefined | Redirection path in the client application that will be used in the link in the verification email. For instance, if you want to redirect to `https://myapp.com/success`, the `redirectTo` value is `'/success'`. |
| Name | Type | Notes |
| --------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `resetPassword` | (email?: string) | Sends an email with a temporary connection link. Returns a promise with the current context |
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
| `isSent` | boolean | Returns `true` when the email has been successfully sent. |
| `isError` | boolean | Returns `true` if an error occurred. |
| `error` | {status: number, error: string, message: string} \| null | Provides details about the error. |
| `redirectTo` | string \| undefined | Redirection path in the client application that will be used in the link in the verification email. For instance, if you want to redirect to `https://myapp.com/success`, the `redirectTo` value is `'/success'`. |
#### Usage
@@ -345,12 +357,12 @@ import { useState } from 'react'
import { useResetPassword } from '@nhost/react'
const Component = () => {
const [email, setEamil] = useState('')
const { resetPassword, isLoading, isSent, isError, error } = useResetPassword(email?: string)
const [email, setEmail] = useState('')
const { resetPassword, isLoading, isSent, isError, error } = useResetPassword()
return (
<div>
<input value={email} onChange={(event) => setEmail(event.target.value)} />
<button onClick={resetPassword}>Send reset link</button>
<button onClick={() => resetPassword(email)}>Send reset link</button>
</div>
)
}
@@ -360,31 +372,31 @@ const Component = () => {
```js
const { sendEmail, isLoading, isSent, isError, error } =
useSendVerificationEmail(email?: string, options?: { redirectTo?: string })
useSendVerificationEmail(options?: { redirectTo?: string })
```
| Name | Type | Notes |
| ------------ | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `sendEmail` | (email?: string) => void | Requests the email change. The arguement password will take precedence over the the possible state value used when creating the hook. |
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
| `isSent` | boolean | Returns `true` if the verification email has been sent |
| `isError` | boolean | Returns `true` if an error occurred. |
| `error` | {status: number, error: string, message: string} \| undefined | Provides details about the error. |
| `redirectTo` | string \| undefined | Redirection path in the client application that will be used in the link in the verification email. For instance, if you want to redirect to `https://myapp.com/success`, the `redirectTo` value is `'/success'`. |
| Name | Type | Notes |
| ------------ | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `sendEmail` | (email?: string) | Resend the verification email. Returns a promise with the current context |
| `isLoading` | boolean | Returns `true` when the action is executing, `false` when it finished its execution. |
| `isSent` | boolean | Returns `true` if the verification email has been sent |
| `isError` | boolean | Returns `true` if an error occurred. |
| `error` | {status: number, error: string, message: string} \| null | Provides details about the error. |
| `redirectTo` | string \| undefined | Redirection path in the client application that will be used in the link in the verification email. For instance, if you want to redirect to `https://myapp.com/success`, the `redirectTo` value is `'/success'`. |
#### Usage
```jsx
import { useState } from 'react'
import { useChangeEmail } from '@nhost/react'
import { useSendVerificationEmail } from '@nhost/react'
const Component = () => {
const [email, setEmail] = useState('')
const { sendEmail, isLoading, isSent, isError, error } = useChangeEmail(password)
const { sendEmail, isLoading, isSent, isError, error } = useSendVerificationEmail()
return (
<div>
<input value={email} onChange={(event) => setEmail(event.target.value)} />
<button onClick={sendEmail}>Send email verification</button>
<button onClick={() => sendEmail(email)}>Send email verification</button>
{isSent && (
<div>Please check your mailbox and follow the verification link to confirm your email</div>
)}
@@ -397,10 +409,41 @@ const Component = () => {
## User data
<!-- TODO ellaborate -->
```js
const userData = useUserData()
const { id, email, displayName, avatarUrl, isAnonymous, locale, defaultRole, roles, metadata, createdAt } = useUserData()
```
| Name | Type | Default | Notes |
| ------------- | ------------- | ---------------- | ------------------------------------------------------ |
| `id` | string | | User's unique identifier (uuid) |
| `email` | string | | User's email address |
| `displayName` | string | `""` | User's display name |
| `avatarUrl` | string | `""` | The URL to the user's profile picture |
| `isAnonymous` | boolean | `false` | Whether or not the user is anonymous |
| `locale` | string | `"en"` | A two-characters locale |
| `defaultRole` | string | `"user"` | The default role of the user |
| `roles` | string[] | `["me", "user"]` | The roles assigned to the user |
| `metadata` | JSON object | `null` | Additional attributes used for user information |
| `createdAt` | string | | The date-time when the user has been created |
Example of an authenticated user:
```json
{
"avatarUrl": "https://s.gravatar.com/avatar/3020737ed9d932c6665111a5550454d2?r=g&default=blank",
"createdAt": "2022-04-11T16:33:14.780439+00:00",
"defaultRole": "user",
"displayName": "Grégory D'Angelo",
"email": "greg@nhost.io",
"id": "05e054c7-a722-42e7-90a6-3f77a2f118c8",
"isAnonymous": false,
"locale": "en",
"metadata": {
"lastName": "D'Angelo",
"firstName": "Grégory"
},
"roles": ["user", "me"]
}
```
### Avatar
@@ -433,7 +476,7 @@ const Avatar = () => {
### Display name
```jsx
import { displayName } from '@nhost/react'
import { useDisplayName } from '@nhost/react'
const Avatar = () => {
const displayName = useDisplayName()

View File

@@ -64,5 +64,5 @@ const nhost = new NhostClient({
| `autoLogin` | boolean | `true` | If set to `true`, the client will detect credentials in the current URL that could have been sent during an email verification or an Oauth authentication. It will also automatically authenticate all the active tabs in the current browser. |
| `autoRefreshToken` | boolean | `true` | If set to `true`, the JWT (access token) will be automatically refreshed before it expires. |
| `clientStorageGetter` | (key:string) => string \| null | use localStorage | Nhost stores a refresh token in `localStorage` so the session can be restored when starting the browser. |
| `clientStorageGetter` | (key: string, value: string \| null | use localStorage | |
| `clientStorageSetter` | (key: string, value: string \| null | use localStorage | |
| `refreshIntervalTime` | | |

View File

@@ -4,40 +4,67 @@ title: 'Protecting routes'
## React Router
You can protect routes by creating an `AuthGate` component when using `@nhost/react` with [React Router](https://reactrouter.com/web/guides/quick-start).
> This example uses the latest version of [React Router (v6)](https://reactrouter.com/docs/en/v6).
You can protect routes by creating a wrapper component, `ProtectedRoute`, to implement the authentication logic using `@nhost/react`.
```jsx
import { Redirect } from 'react-router-dom'
import { useAuthenticationStatus } from '@nhost/react'
// src/components/ProtectedRoute.js
export function AuthGate(children) {
const { isLoading, isAuthenticated } = useAuthenticationStatus()
import { useAuthenticationStatus } from '@nhost/react';
import { Navigate, Outlet, useLocation } from 'react-router-dom';
const ProtectedRoute = () => {
const { isAuthenticated, isLoading } = useAuthenticationStatus();
const location = useLocation();
if (isLoading) {
return <div>Loading...</div>
return <div>Loading...</div>;
}
if (!isAuthenticated) {
return <Redirect to="/login" />
return <Navigate to="/login" />;
}
return children
}
return <Outlet />;
};
export default ProtectedRoute;
```
Then, in your React Router, wrap the `AuthGate` component around the routes you want to protect:
So, if the user is not authenticated, we redirect him to the `/login` route using the [`Navigate`](https://reactrouter.com/docs/en/v6/api#navigate) component from React Router. Otherwise, we render the [`Outlet`](https://reactrouter.com/docs/en/v6/api#outlet) component, also provided by React Router, to render the `ProtectedRoute` child route elements.
Then, in your `App.js` file, you can use a [layout route](https://reactrouter.com/docs/en/v6/getting-started/concepts#layout-route) to wrap the `ProtectedRoute` component around the routes you want to protect:
```jsx
<Router>
<Switch>
<Route path="/login">
<Login />
</Route>
<Route path="/" exact>
<AuthGate> // <--- Use AuthGate component like this
<div>My protected dashboard</div>
</AuthGate>
</Route>
</Switch>
</Router>
// src/App.js
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { NhostReactProvider } from '@nhost/react';
import ProtectedRoute from './components/ProtectedRoute';
import Home from './pages/Home';
import Login from './pages/Login';
import Dashboard from './pages/Dashboard';
import Profile from './pages/Profile';
import { nhost } from './lib/nhost';
export function App() {
return (
<NhostReactProvider nhost={nhost}>
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="/dashboard" element={<ProtectedRoute />}>
<Route index element={<Dashboard />} />
<Route path="profile" element={<Profile />} />
</Route>
</Routes>
</BrowserRouter>
</NhostReactProvider>
);
}
```

View File

@@ -33,6 +33,7 @@ export const orderTwo = {
sdk: ['index', 'graphql', 'authentication', 'storage', 'functions'],
react: ['index', 'hooks', 'protecting-routes', 'apollo'],
nextjs: ['index', 'configuration', 'protecting-routes', ],
cli: ['index']
cli: ['index'],
'hasura-auth': ['index', 'installation', 'configuration', 'environment-variables', 'schema', 'api-reference']
}
}

View File

@@ -2,7 +2,6 @@
"name": "nhost-documentation",
"private": true,
"version": "0.0.1",
"scripts": {
"dev": "next",
"build:next": "next build",
@@ -34,9 +33,11 @@
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-merge-refs": "^1.1.0",
"react-syntax-highlighter": "^15.4.5"
"react-syntax-highlighter": "^15.4.5",
"swagger-ui-react": "^4.5.2"
},
"devDependencies": {
"@types/node": "^17.0.21",
"@types/react": "^17.0.37",
"autoprefixer": "^10.4.0",
"next-sitemap": "^1.6.203",

File diff suppressed because it is too large Load Diff

View File

@@ -1,46 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
<url><loc>https://docs.nhost.io</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/get-started</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/get-started/authentication</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/get-started/cli-workflow</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/get-started/quick-start</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/get-started/upgrade</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/authentication</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/database</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/nhost</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/serverless-functions</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/storage</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/cli</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/nextjs</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/react</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/sdk</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/supporting-libraries</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/get-started/cli-workflow/install-cli</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/get-started/cli-workflow/local-changes</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/get-started/cli-workflow/metadata-and-serverless-functions</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/get-started/cli-workflow/workflow-setup</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/get-started/quick-start/javascript-client</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/get-started/quick-start/permissions</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/get-started/quick-start/schema</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/authentication/sign-in-methods</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/authentication/social-login</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/authentication/user-management</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/database/graphql</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/database/permissions</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/nhost/environment-variables</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/nhost/github-integration</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/nhost/local-development</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/serverless-functions/event-triggers</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/nextjs/server-side</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/react/apollo</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/react/hooks</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/sdk/authentication</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/sdk/functions</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/sdk/graphql</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/sdk/storage</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/supporting-libraries/react-apollo</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/supporting-libraries/react-auth</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-02-21T10:17:26.089Z</lastmod></url>
<url><loc>https://docs.nhost.io</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.648Z</lastmod></url>
<url><loc>https://docs.nhost.io/get-started</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.648Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.648Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.648Z</lastmod></url>
<url><loc>https://docs.nhost.io/get-started/authentication</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.648Z</lastmod></url>
<url><loc>https://docs.nhost.io/get-started/cli-workflow</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.648Z</lastmod></url>
<url><loc>https://docs.nhost.io/get-started/quick-start</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.648Z</lastmod></url>
<url><loc>https://docs.nhost.io/get-started/upgrade</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.648Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/authentication</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.648Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/database</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.648Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/nhost</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.648Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/serverless-functions</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.648Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/storage</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.648Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/cli</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.648Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/hasura-auth</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.648Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/nextjs</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.648Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/react</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/sdk</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/get-started/cli-workflow/install-cli</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/get-started/cli-workflow/local-changes</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/get-started/cli-workflow/metadata-and-serverless-functions</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/get-started/cli-workflow/workflow-setup</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/get-started/quick-start/javascript-client</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/get-started/quick-start/permissions</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/get-started/quick-start/schema</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/authentication/email-templates</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/authentication/sign-in-methods</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/authentication/sign-in-with-facebook</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/authentication/sign-in-with-github</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/authentication/sign-in-with-google</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/authentication/sign-in-with-linkedin</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/authentication/sign-in-with-spotify</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/authentication/social-sign-in</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/authentication/user-management</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/database/graphql</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/database/permissions</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/nhost/environment-variables</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/nhost/github-integration</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/nhost/local-development</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/platform/serverless-functions/event-triggers</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/hasura-auth/api-reference</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/hasura-auth/configuration</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/hasura-auth/environment-variables</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/hasura-auth/installation</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/hasura-auth/schema</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/nextjs/configuration</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/nextjs/protecting-routes</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/react/apollo</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/react/hooks</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/react/protecting-routes</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/sdk/authentication</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/sdk/functions</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/sdk/graphql</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
<url><loc>https://docs.nhost.io/reference/sdk/storage</loc><changefreq>daily</changefreq><priority>0.7</priority><lastmod>2022-04-08T13:10:11.649Z</lastmod></url>
</urlset>

View File

@@ -10,9 +10,9 @@
},
"dependencies": {
"@apollo/client": "^3.5.10",
"@nhost/nextjs": "^1.0.0",
"@nhost/react": "^0.3.0",
"@nhost/react-apollo": "^4.0.0",
"@nhost/nextjs": "^1.0.10",
"@nhost/react": "^0.5.0",
"@nhost/react-apollo": "^4.0.10",
"graphql": "^16.3.0",
"next": "12.1.0",
"react": "17.0.2",

View File

@@ -25,11 +25,11 @@ const Home: NextPage = () => {
const [newPassword, setNewPassword] = useState('')
const accessToken = useAccessToken()
const { signOut } = useSignOut()
const { signUpEmailPassword, ...signUpResult } = useSignUpEmailPassword(email, password)
const { signInEmailPassword } = useSignInEmailPassword(email, password)
const { signInEmailPasswordless } = useSignInEmailPasswordless(email)
const { changeEmail, ...changeEmailResult } = useChangeEmail(newEmail)
const { changePassword, ...changePasswordResult } = useChangePassword(newPassword)
const { signUpEmailPassword, ...signUpResult } = useSignUpEmailPassword()
const { signInEmailPassword } = useSignInEmailPassword()
const { signInEmailPasswordless } = useSignInEmailPasswordless()
const { changeEmail, ...changeEmailResult } = useChangeEmail()
const { changePassword, ...changePasswordResult } = useChangePassword()
const { loading, data, error } = useAuthQuery(BOOKS_QUERY)
return (
<div>
@@ -37,20 +37,24 @@ const Home: NextPage = () => {
<>
<button onClick={signOut}>Logout</button>
<input value={newEmail} onChange={(e) => setNewEmail(e.target.value)} />
<button onClick={changeEmail}>Change email</button>
<button onClick={() => changeEmail(email)}>Change email</button>
<div>{JSON.stringify(changeEmailResult)}</div>
<button onClick={changePassword}>Change password</button>
<button onClick={() => changePassword(password)}>Change password</button>
<input value={newPassword} onChange={(e) => setNewPassword(e.target.value)} />
<div>{JSON.stringify(changePasswordResult)}</div>
</>
) : (
<>
<input value={email} onChange={(e) => setEmail(e.target.value)} />
<button onClick={signInEmailPasswordless}>Passwordless signin</button>
<button onClick={() => signInEmailPasswordless(email)}>Passwordless signin</button>
<div>{JSON.stringify(signUpResult)}</div>
<input value={password} onChange={(e) => setPassword(e.target.value)} type="password" />
<button onClick={signUpEmailPassword}>Email + password sign-up</button>
<button onClick={signInEmailPassword}>Email + password sign-in</button>
<button onClick={() => signUpEmailPassword(email, password)}>
Email + password sign-up
</button>
<button onClick={() => signInEmailPassword(email, password)}>
Email + password sign-in
</button>
</>
)}

View File

@@ -136,71 +136,71 @@
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.0.tgz#d27e7e76c87a460a4da99c5bfdb1618dcd6cd064"
integrity sha512-aBvcbMwuanDH4EMrL2TthNJy+4nP59Bimn8egqv6GHMVj0a44cU6Au4PjOhLNqEh9l+IpRGBqMTzec94UdC5xg==
"@nhost/apollo@0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@nhost/apollo/-/apollo-0.3.0.tgz#89a66e97aa6af4de6045bf0c780e8b9590c06d9b"
integrity sha512-97DSycgPEnQQtzAWPB36yENAuQFDEl8c7qLB9xOzSnplImv5NGces40XMAkTDEWam0eD//PtXP9zi+TYNeMNjw==
"@nhost/apollo@^0.3.7":
version "0.3.7"
resolved "https://registry.yarnpkg.com/@nhost/apollo/-/apollo-0.3.7.tgz#761d3d60519df60caaa7220909ab11bd2c629e3a"
integrity sha512-NH1WCC5D6K/Ft8/EXYIgeAhOBq5Gt1OtX9U9RzV2IqmVRGigDw+YlXr8P5GRPAzBeZUVWrM1wvBt+oBk8zw/7g==
dependencies:
"@nhost/core" "0.3.0"
"@nhost/core" "^0.3.8"
graphql "16"
subscriptions-transport-ws "^0.11.0"
"@nhost/core@0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@nhost/core/-/core-0.3.0.tgz#fa630afef50840cd7b8415e17894c7765cda273f"
integrity sha512-wEdq+BLOHH7bOhBvF5gql9vtWuEtlLWvw65AtpstfX8pAUY8ce2yqamV6Z8kxr/RSYXZA+aLsKwig50qSZa99w==
"@nhost/core@^0.3.8":
version "0.3.8"
resolved "https://registry.yarnpkg.com/@nhost/core/-/core-0.3.8.tgz#0269ab5daa36b1bdd2b2864c174809a86d4d2a7a"
integrity sha512-6mOv23H16n0YN0voXdXSGS18rUELe1YI2+HXMRlaeksCib4BvSf28lsideEOjFnyfHA3Y4wAX1SMxnyaEj1qaQ==
dependencies:
axios "^0.25.0"
broadcast-channel "^4.10.0"
js-cookie "^3.0.1"
xstate "^4.30.5"
"@nhost/hasura-auth-js@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@nhost/hasura-auth-js/-/hasura-auth-js-1.0.0.tgz#0f3c267614ca328c944797f33a1921c8103dd3e5"
integrity sha512-hENPB1aMdekYxfDejthPAdoj9JarqaVkBKNRa+jun247Un1X6eFGDPo52Y2tZfP44pJEUK4EqTqkWH3DwT4uXg==
"@nhost/hasura-auth-js@^1.0.9":
version "1.0.9"
resolved "https://registry.yarnpkg.com/@nhost/hasura-auth-js/-/hasura-auth-js-1.0.9.tgz#7e5cfe7a59b18778352dd6d2bef368c765ce9886"
integrity sha512-d0UDfakzUO9N0/4RRy9NptoOLgpcRmr2F5XxVVzqLYX67+XzZoqT+LMhOF8spKP4+JqFlKFgqbNulmuRRc5FfA==
dependencies:
"@nhost/core" "0.3.0"
"@nhost/core" "^0.3.8"
"@nhost/hasura-storage-js@0.2.0":
"@nhost/hasura-storage-js@^0.2.0":
version "0.2.0"
resolved "https://registry.yarnpkg.com/@nhost/hasura-storage-js/-/hasura-storage-js-0.2.0.tgz#e8c127d883d231313cd262553732da3b0dccb858"
integrity sha512-JumgUhnScU6Bv8SBmN2F4sY+LbrD3i25Ppr30Zjbv4MvbUguBclx9zzAwqub/P2n/azc7bjjRvYl2n2/jjKRXw==
dependencies:
axios "^0.21.1"
"@nhost/nextjs@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@nhost/nextjs/-/nextjs-1.0.0.tgz#2e91cce4352ec7c521099c8f9fccd5fef94ec902"
integrity sha512-yrRXd3796wcLjabeqIbBgZ/IdD40xpC9LhBA9LoXHqHfNaqZ4ujtcMnSc7IZWJv45P5rDO3T8kKKk+Sm6vTAvQ==
"@nhost/nextjs@^1.0.10":
version "1.0.10"
resolved "https://registry.yarnpkg.com/@nhost/nextjs/-/nextjs-1.0.10.tgz#ac78e1b32b6a89e6379179108c49d71cf23aeed8"
integrity sha512-BTNe4KHhWLbRKd8XfppYncLIohXZ0C+oCTZApVwwgVexqdQ5dxhObw0nQin2K7TlP2Mis+Ldzjjn3SO/hcb3xw==
dependencies:
"@nhost/nhost-js" "1.0.0"
"@nhost/nhost-js" "^1.0.9"
cookies "^0.8.0"
"@nhost/nhost-js@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@nhost/nhost-js/-/nhost-js-1.0.0.tgz#d57aa66c889922926b9bde6278d35000729f884c"
integrity sha512-ve5+TqYGcQbRwDqxVDMCJKZQlj5BFCsTzqEhIAUnLP6Gu8YlNVeUQL3Bbc19j71OkHDNhw8TAJbE2zcFUBT2Fw==
"@nhost/nhost-js@^1.0.9":
version "1.0.9"
resolved "https://registry.yarnpkg.com/@nhost/nhost-js/-/nhost-js-1.0.9.tgz#a1b0bc0c35e15ade2867da4d211b1f81f3bc5e28"
integrity sha512-/SZLk3Be560scVAbUswcRSE4RMwf6M7xanbNLqGUuI/sr1Ir253WPhaD2YWXZChP1v2LBzONhdJNI2g7u1NzoA==
dependencies:
"@nhost/hasura-auth-js" "1.0.0"
"@nhost/hasura-storage-js" "0.2.0"
"@nhost/hasura-auth-js" "^1.0.9"
"@nhost/hasura-storage-js" "^0.2.0"
axios "^0.23.0"
jwt-decode "^3.1.2"
query-string "^7.0.1"
"@nhost/react-apollo@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@nhost/react-apollo/-/react-apollo-4.0.0.tgz#08be35946eadbb746f27435c3fc72cd092a97b61"
integrity sha512-ZmFgBgHFJE2Z2ZBYx3U4Gry9TprUOb4NXw/K5lSKv11zPeEaclfpqn+aeQbtCj02oCnzRe+MJLsJenpcuhQRuw==
"@nhost/react-apollo@^4.0.10":
version "4.0.10"
resolved "https://registry.yarnpkg.com/@nhost/react-apollo/-/react-apollo-4.0.10.tgz#d28819019f35aff7fb69a3b485489ab0492643e1"
integrity sha512-MTIBk9aQVCIfVR17eEKM6ssELadpDhIAh2ERjaZY8+i9KMgVyjEt0s4842nl1Bwq7OFIXf5GRykr3RtTjuT/Ug==
dependencies:
"@nhost/apollo" "0.3.0"
"@nhost/apollo" "^0.3.7"
"@nhost/react@^0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@nhost/react/-/react-0.3.0.tgz#5401922dce91bb66db5d575de1869df00fabbb8e"
integrity sha512-jxyt4dYfphgv3bf6jvV7qDKnV5qUArFvdTYExKlBA9tsBQYta0heawMsJk0rEarEZGUw1iioiUYFKdZyl2Qi5Q==
"@nhost/react@^0.5.0":
version "0.5.0"
resolved "https://registry.yarnpkg.com/@nhost/react/-/react-0.5.0.tgz#5276ae7e13691f32ceaa0e6ca2460ef2605820f6"
integrity sha512-d89I3Q1Y6+9QJ6jP9yU9xrEJv8dCvTwll7tctd7emqZyPWGgInLpmZ9OA+/xrannowck5MsgaBdz0zxQ9bjJBA==
dependencies:
"@nhost/nhost-js" "1.0.0"
"@nhost/nhost-js" "^1.0.9"
"@xstate/react" "^2.0.1"
immer "^9.0.12"

View File

@@ -1,16 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<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>Nhost React+Apollo demo</title>
</head>
<body>
<title>Vite App</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
</body>
</html>

View File

@@ -2,8 +2,6 @@ table:
name: provider_requests
schema: auth
configuration:
custom_column_names:
redirect_url: redirectUrl
custom_name: authProviderRequests
custom_root_fields:
delete: deleteAuthProviderRequests

View File

@@ -1,19 +1,21 @@
{
"name": "@nhost-examples/react-apollo",
"version": "0.2.0",
"version": "0.0.1",
"private": true,
"dependencies": {
"@apollo/client": "^3.5.10",
"@nhost/react": "^0.3.0",
"@nhost/react-apollo": "^4.0.0",
"@nhost/react": "^0.5.0",
"@nhost/react-apollo": "^4.0.10",
"@rsuite/icons": "^1.0.2",
"jwt-decode": "^3.1.2",
"less": "^4.1.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-icons": "^4.3.1",
"react-json-view": "^1.21.3",
"react-router-dom": "^6.2.1",
"rsuite": "^5.6.2"
"react-router": "^6.3.0",
"react-router-dom": "^6.3.0",
"rsuite": "^5.7.1"
},
"scripts": {
"dev": "vite",
@@ -38,14 +40,10 @@
]
},
"devDependencies": {
"@types/react": "^17.0.39",
"@types/react-dom": "^17.0.11",
"@vitejs/plugin-react": "^1.2.0",
"@xstate/inspect": "^0.6.2",
"graphql": "15.7.2",
"less": "^4.1.2",
"typescript": "^4.5.5",
"vite": "^2.8.5",
"ws": "^8.5.0"
"@types/react": "^17.0.43",
"@types/react-dom": "^17.0.14",
"@vitejs/plugin-react": "^1.3.0",
"typescript": "^4.6.3",
"vite": "^2.9.1"
}
}

View File

@@ -1,3 +1,4 @@
import React from 'react'
import { Link } from 'react-router-dom'
import { Panel } from 'rsuite'
@@ -19,11 +20,11 @@ export const AboutPage: React.FC = () => (
<li>React</li>
<li>React-router</li>
<li>RSuite</li>
<li>...and of course, the Nhost React client</li>
<li>and of course, the Nhost React client</li>
</ul>
</div>
<div>
Noew let's go to the <Link to="/">index page</Link>
Noew let&apos;s go to the <Link to="/">index page</Link>
</div>
</Panel>
)

View File

@@ -1,17 +1,20 @@
import './App.css'
/* eslint-disable react/react-in-jsx-scope */
import { useEffect } from 'react'
import { Link, Route, Routes, useLocation, useNavigate } from 'react-router-dom'
import { Container, Content, Header, Nav, Navbar } from 'rsuite'
import { useAuthenticated, useSignOut } from '@nhost/react'
import ExitIcon from '@rsuite/icons/Exit'
import { Routes, Route, Link, useNavigate, useLocation } from 'react-router-dom'
import { Container, Header, Navbar, Content, Nav } from 'rsuite'
import { useEffect } from 'react'
import { SignInPage } from './sign-in'
import { AuthGate, PublicGate } from './components/auth-gates'
import { AboutPage } from './About'
import { ApolloPage } from './apollo'
import Home from './Home'
import { ProfilePage } from './profile'
import { ApolloPage } from './apollo'
import { SignInPage } from './sign-in'
import { SignUpPage } from './sign-up'
import { AboutPage } from './About'
import './App.css'
function App() {
const isAuthenticated = useAuthenticated()

View File

@@ -1,3 +1,4 @@
import React from 'react'
import { Panel } from 'rsuite'
const HomePage: React.FC = () => {

View File

@@ -1,5 +1,7 @@
import { gql } from '@apollo/client'
import React from 'react'
import { Panel, Table } from 'rsuite'
import { gql } from '@apollo/client'
import { useAuthQuery } from '@nhost/react-apollo'
const GET_BOOKS = gql`

View File

@@ -1,4 +1,6 @@
import React from 'react'
import { Navigate, useLocation } from 'react-router-dom'
import { useAuthenticationStatus } from '@nhost/react'
export const AuthGate: React.FC = ({ children }) => {

View File

@@ -1,12 +1,13 @@
import { Button, Input, Message } from 'rsuite'
import React, { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { Button, Input, Message } from 'rsuite'
import { useSignInEmailPasswordless } from '@nhost/react'
import React, { useState, useEffect } from 'react'
export const EmailPasswordlessForm: React.FC = () => {
const [email, setEmail] = useState('')
const navigate = useNavigate()
const { signInEmailPasswordless, isError, isSuccess, error } = useSignInEmailPasswordless(email, {
const { signInEmailPasswordless, isError, isSuccess, error } = useSignInEmailPasswordless({
redirectTo: '/profile'
})
const [showError, setShowError] = useState(true)
@@ -42,7 +43,7 @@ export const EmailPasswordlessForm: React.FC = () => {
style={{ marginTop: '0.5em' }}
onClick={() => {
setShowError(true)
signInEmailPasswordless()
signInEmailPasswordless(email)
}}
>
Continue with email

View File

@@ -1,7 +1,9 @@
/* eslint-disable react/react-in-jsx-scope */
import { FaFacebook, FaGithub, FaGoogle } from 'react-icons/fa'
import { IconButton } from 'rsuite'
import { FaGithub, FaGoogle, FaFacebook } from 'react-icons/fa'
import { Icon } from '@rsuite/icons'
import { useProviderLink } from '@nhost/react'
import { Icon } from '@rsuite/icons'
export const OAuthLinks: React.FC = () => {
// TODO show how to use options

View File

@@ -1,10 +1,10 @@
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_NHOST_URL: string
// more env variables...
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
readonly VITE_NHOST_URL: string
// more env variables...
}
interface ImportMeta {
readonly env: ImportMetaEnv
}

View File

@@ -1,11 +1,13 @@
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import { BrowserRouter } from 'react-router-dom'
import { NhostClient, NhostReactProvider } from '@nhost/react'
import { NhostApolloProvider } from '@nhost/react-apollo'
import 'rsuite/styles/index.less' // or 'rsuite/dist/rsuite.min.css'
import { BrowserRouter } from 'react-router-dom'
import { NhostApolloProvider } from '@nhost/react-apollo'
import App from './App'
const nhost = new NhostClient({
backendUrl: import.meta.env.VITE_NHOST_URL || 'http://localhost:1337'

View File

@@ -1,11 +1,13 @@
import { useChangeEmail, useEmail } from '@nhost/react'
/* eslint-disable react/react-in-jsx-scope */
import { useEffect, useState } from 'react'
import { Button, FlexboxGrid, Input, Message, Panel, toaster, Notification } from 'rsuite'
import { Button, FlexboxGrid, Input, Message, Notification, Panel, toaster } from 'rsuite'
import { useChangeEmail, useEmail } from '@nhost/react'
export const ChangeEmail: React.FC = () => {
const [newEmail, setNewEmail] = useState('')
const email = useEmail()
const { changeEmail, error, needsEmailVerification } = useChangeEmail(newEmail, {
const { changeEmail, error, needsEmailVerification } = useChangeEmail({
redirectTo: '/profile'
})
const [errorMessage, setErrorMessage] = useState('')
@@ -45,7 +47,7 @@ export const ChangeEmail: React.FC = () => {
<Input value={newEmail} onChange={setNewEmail} placeholder="New email" />
</FlexboxGrid.Item>
<FlexboxGrid.Item colspan={12}>
<Button onClick={changeEmail} block appearance="primary">
<Button onClick={() => changeEmail(email)} block appearance="primary">
Change
</Button>
</FlexboxGrid.Item>

View File

@@ -1,10 +1,12 @@
import { useChangePassword } from '@nhost/react'
import React from 'react'
import { useEffect, useState } from 'react'
import { Button, FlexboxGrid, Input, Message, Panel, toaster, Notification } from 'rsuite'
import { Button, FlexboxGrid, Input, Message, Notification, Panel, toaster } from 'rsuite'
import { useChangePassword } from '@nhost/react'
export const ChangePassword: React.FC = () => {
const [password, setPassword] = useState('')
const { changePassword, isSuccess, error } = useChangePassword(password)
const { changePassword, isSuccess, error } = useChangePassword()
const [errorMessage, setErrorMessage] = useState('')
// * See https://github.com/rsuite/rsuite/issues/2336
@@ -44,7 +46,7 @@ export const ChangePassword: React.FC = () => {
/>
</FlexboxGrid.Item>
<FlexboxGrid.Item colspan={12}>
<Button onClick={changePassword} block appearance="primary">
<Button onClick={() => changePassword(password)} block appearance="primary">
Change
</Button>
</FlexboxGrid.Item>

View File

@@ -1,6 +1,8 @@
import decode from 'jwt-decode'
import React from 'react'
import ReactJson from 'react-json-view'
import { Button, Col, Panel, Row } from 'rsuite'
import { useAccessToken, useNhostClient, useUserData } from '@nhost/react'
import { ChangeEmail } from './change-email'

View File

@@ -1,11 +1,12 @@
import { useConfigMfa } from '@nhost/react'
import React from 'react'
import { useState } from 'react'
import { Button, Input, Panel } from 'rsuite'
import { useConfigMfa } from '@nhost/react'
export const Mfa: React.FC = () => {
const [code, setCode] = useState('')
const { generateQrCode, activateMfa, isActivated, isGenerated, qrCodeDataUrl } =
useConfigMfa(code)
const { generateQrCode, activateMfa, isActivated, isGenerated, qrCodeDataUrl } = useConfigMfa()
return (
<Panel header="Activate 2-step verification" bordered>
@@ -18,7 +19,7 @@ export const Mfa: React.FC = () => {
<div>
<img alt="qrcode" src={qrCodeDataUrl} />
<Input value={code} onChange={setCode} placeholder="Enter activation code" />
<Button block appearance="primary" onClick={activateMfa}>
<Button block appearance="primary" onClick={() => activateMfa(code)}>
Activate
</Button>
</div>

View File

@@ -1,7 +1,8 @@
import { Button, Divider, Input, Message } from 'rsuite'
import { useSignInEmailPassword } from '@nhost/react'
import React, { useEffect, useState } from 'react'
import { NavLink } from 'react-router-dom'
import { Button, Divider, Input, Message } from 'rsuite'
import { useSignInEmailPassword } from '@nhost/react'
const Footer: React.FC = () => (
<div>
@@ -80,7 +81,14 @@ export const EmailPassword: React.FC = () => {
</Message>
)}
<Button appearance="primary" onClick={signInEmailPassword} block>
<Button
appearance="primary"
onClick={async () => {
const result = await signInEmailPassword(email, password)
console.log(result)
}}
block
>
Sign in
</Button>
<Button as={NavLink} block to="/sign-in/forgot-password">

View File

@@ -1,6 +1,7 @@
import { Button } from 'rsuite'
import { NavLink } from 'react-router-dom'
import React from 'react'
import { NavLink } from 'react-router-dom'
import { Button } from 'rsuite'
import { EmailPasswordlessForm } from '../components/email-passwordless-form'
export const EmailPasswordless: React.FC = () => {
return (

View File

@@ -1,11 +1,12 @@
import { Button, Divider, Input, Message, Notification, toaster } from 'rsuite'
import { useResetPassword } from '@nhost/react'
import React, { useEffect, useState } from 'react'
import { NavLink } from 'react-router-dom'
import { Button, Divider, Input, Message, Notification, toaster } from 'rsuite'
import { useResetPassword } from '@nhost/react'
export const ForgotPassword: React.FC = () => {
const [email, setEmail] = useState('')
const { resetPassword, isSent, error } = useResetPassword(email, { redirectTo: '/profile' })
const { resetPassword, isSent, error } = useResetPassword({ redirectTo: '/profile' })
const [errorMessage, setErrorMessage] = useState('')
// * Set error message from the authentication hook errors
@@ -16,16 +17,12 @@ export const ForgotPassword: React.FC = () => {
useEffect(() => {
setErrorMessage('')
}, [email])
// * See https://github.com/rsuite/rsuite/issues/2336
useEffect(() => {
toaster.push(<div />)
}, [])
useEffect(() => {
if (isSent) {
toaster.push(
<Notification type="info" header="Info" closable>
An email has been sent with a passwordless authentication link, so you'll be able to
An email has been sent with a passwordless authentication link, so you will be able to
authenticate and change your password.
</Notification>
)
@@ -48,7 +45,7 @@ export const ForgotPassword: React.FC = () => {
</Message>
)}
<Button appearance="primary" onClick={resetPassword} block>
<Button appearance="primary" onClick={() => resetPassword(email)} block>
Reset your password
</Button>
<Divider />

View File

@@ -1,14 +1,16 @@
/* eslint-disable jsx-a11y/anchor-is-valid */
import React from 'react'
import { FaLock } from 'react-icons/fa'
import { Link, NavLink, Route, Routes } from 'react-router-dom'
import { Button, Divider, FlexboxGrid, IconButton, Panel } from 'rsuite'
import { Icon } from '@rsuite/icons'
import { FaLock } from 'react-icons/fa'
import { OAuthLinks } from '../components'
import { VerificationEmailSent } from '../verification-email-sent'
import { EmailPassword } from './email-password'
import { ForgotPassword } from './forgot-password'
import { EmailPasswordless } from './email-passwordless'
import { ForgotPassword } from './forgot-password'
// import { useSignInAnonymous } from '@nhost/react'
const Index: React.FC = () => (
@@ -48,7 +50,7 @@ export const SignInPage: React.FC = () => {
</FlexboxGrid.Item>
</FlexboxGrid>
<Divider />
Don't have an account? <Link to="/sign-up">Sign up</Link>
Don&lsquo;t have an account? <Link to="/sign-up">Sign up</Link>
{/* or{' '}
<a href="#" onClick={signIn}>
enter the app anonymously

View File

@@ -1,7 +1,9 @@
import { Button, Input, Message } from 'rsuite'
import { useSignUpEmailPassword } from '@nhost/react'
/* eslint-disable react/react-in-jsx-scope */
import { useEffect, useMemo, useState } from 'react'
import { NavLink, useNavigate } from 'react-router-dom'
import { Button, Input, Message } from 'rsuite'
import { useSignUpEmailPassword } from '@nhost/react'
export const EmailPassword: React.FC = () => {
const [email, setEmail] = useState('')
@@ -14,11 +16,8 @@ export const EmailPassword: React.FC = () => {
)
const navigate = useNavigate()
const [confirmPassword, setConfirmPassword] = useState('')
const { signUpEmailPassword, error, needsEmailVerification, isSuccess } = useSignUpEmailPassword(
email,
password,
options
)
const { signUpEmailPassword, error, needsEmailVerification, isSuccess } =
useSignUpEmailPassword(options)
const [errorMessage, setErrorMessage] = useState('')
useEffect(() => {
if (needsEmailVerification) navigate('/sign-up/verification-email-sent')
@@ -89,9 +88,10 @@ export const EmailPassword: React.FC = () => {
<Button
appearance="primary"
onClick={() => {
onClick={async () => {
setErrorMessage('')
signUpEmailPassword()
const result = await signUpEmailPassword(email, password)
console.log(result)
}}
block
>

View File

@@ -1,6 +1,7 @@
import { Button } from 'rsuite'
import { NavLink } from 'react-router-dom'
import React from 'react'
import { NavLink } from 'react-router-dom'
import { Button } from 'rsuite'
import { EmailPasswordlessForm } from '../components/email-passwordless-form'
export const EmailPasswordless: React.FC = () => {
return (

View File

@@ -1,9 +1,13 @@
import { Icon } from '@rsuite/icons'
import React from 'react'
import { FaLock } from 'react-icons/fa'
import { Button, Divider, FlexboxGrid, IconButton, Panel } from 'rsuite'
import { Link, NavLink, Route, Routes } from 'react-router-dom'
import { Button, Divider, FlexboxGrid, IconButton, Panel } from 'rsuite'
import { Icon } from '@rsuite/icons'
import { OAuthLinks } from '../components'
import { VerificationEmailSent } from '../verification-email-sent'
import { EmailPassword } from './email-password'
import { EmailPasswordless } from './email-passwordless'

View File

@@ -1,7 +1,8 @@
import { useAuthenticated } from '@nhost/react'
import React, { useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
import { useAuthenticated } from '@nhost/react'
export const VerificationEmailSent: React.FC = () => {
const isAuthenticated = useAuthenticated()
const navigate = useNavigate()

View File

@@ -39,7 +39,7 @@
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.7.tgz#078d8b833fbbcc95286613be8c716cef2b519fa2"
integrity sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ==
"@babel/core@^7.16.12":
"@babel/core@^7.17.8":
version "7.17.8"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.8.tgz#3dac27c190ebc3a4381110d46c80e77efe172e1a"
integrity sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ==
@@ -217,7 +217,7 @@
dependencies:
"@babel/helper-plugin-utils" "^7.16.7"
"@babel/plugin-transform-react-jsx@^7.16.7":
"@babel/plugin-transform-react-jsx@^7.16.7", "@babel/plugin-transform-react-jsx@^7.17.3":
version "7.17.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.17.3.tgz#eac1565da176ccb1a715dae0b4609858808008c1"
integrity sha512-9tjBm4O07f7mzKSIlEmPdiE6ub7kfIe6Cd+w+oQebpATfTQMAgW+YOuWxogbKVTulA+MEO7byMeIUtQ1z+z+ZQ==
@@ -296,67 +296,67 @@
resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.3.1.tgz#b50a781709c81e10701004214340f25475a171a0"
integrity sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw==
"@nhost/apollo@0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@nhost/apollo/-/apollo-0.3.0.tgz#89a66e97aa6af4de6045bf0c780e8b9590c06d9b"
integrity sha512-97DSycgPEnQQtzAWPB36yENAuQFDEl8c7qLB9xOzSnplImv5NGces40XMAkTDEWam0eD//PtXP9zi+TYNeMNjw==
"@nhost/apollo@^0.3.7":
version "0.3.7"
resolved "https://registry.yarnpkg.com/@nhost/apollo/-/apollo-0.3.7.tgz#761d3d60519df60caaa7220909ab11bd2c629e3a"
integrity sha512-NH1WCC5D6K/Ft8/EXYIgeAhOBq5Gt1OtX9U9RzV2IqmVRGigDw+YlXr8P5GRPAzBeZUVWrM1wvBt+oBk8zw/7g==
dependencies:
"@nhost/core" "0.3.0"
"@nhost/core" "^0.3.8"
graphql "16"
subscriptions-transport-ws "^0.11.0"
"@nhost/core@0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@nhost/core/-/core-0.3.0.tgz#fa630afef50840cd7b8415e17894c7765cda273f"
integrity sha512-wEdq+BLOHH7bOhBvF5gql9vtWuEtlLWvw65AtpstfX8pAUY8ce2yqamV6Z8kxr/RSYXZA+aLsKwig50qSZa99w==
"@nhost/core@^0.3.8":
version "0.3.8"
resolved "https://registry.yarnpkg.com/@nhost/core/-/core-0.3.8.tgz#0269ab5daa36b1bdd2b2864c174809a86d4d2a7a"
integrity sha512-6mOv23H16n0YN0voXdXSGS18rUELe1YI2+HXMRlaeksCib4BvSf28lsideEOjFnyfHA3Y4wAX1SMxnyaEj1qaQ==
dependencies:
axios "^0.25.0"
broadcast-channel "^4.10.0"
js-cookie "^3.0.1"
xstate "^4.30.5"
"@nhost/hasura-auth-js@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@nhost/hasura-auth-js/-/hasura-auth-js-1.0.0.tgz#0f3c267614ca328c944797f33a1921c8103dd3e5"
integrity sha512-hENPB1aMdekYxfDejthPAdoj9JarqaVkBKNRa+jun247Un1X6eFGDPo52Y2tZfP44pJEUK4EqTqkWH3DwT4uXg==
"@nhost/hasura-auth-js@^1.0.9":
version "1.0.9"
resolved "https://registry.yarnpkg.com/@nhost/hasura-auth-js/-/hasura-auth-js-1.0.9.tgz#7e5cfe7a59b18778352dd6d2bef368c765ce9886"
integrity sha512-d0UDfakzUO9N0/4RRy9NptoOLgpcRmr2F5XxVVzqLYX67+XzZoqT+LMhOF8spKP4+JqFlKFgqbNulmuRRc5FfA==
dependencies:
"@nhost/core" "0.3.0"
"@nhost/core" "^0.3.8"
"@nhost/hasura-storage-js@0.2.0":
"@nhost/hasura-storage-js@^0.2.0":
version "0.2.0"
resolved "https://registry.yarnpkg.com/@nhost/hasura-storage-js/-/hasura-storage-js-0.2.0.tgz#e8c127d883d231313cd262553732da3b0dccb858"
integrity sha512-JumgUhnScU6Bv8SBmN2F4sY+LbrD3i25Ppr30Zjbv4MvbUguBclx9zzAwqub/P2n/azc7bjjRvYl2n2/jjKRXw==
dependencies:
axios "^0.21.1"
"@nhost/nhost-js@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@nhost/nhost-js/-/nhost-js-1.0.0.tgz#d57aa66c889922926b9bde6278d35000729f884c"
integrity sha512-ve5+TqYGcQbRwDqxVDMCJKZQlj5BFCsTzqEhIAUnLP6Gu8YlNVeUQL3Bbc19j71OkHDNhw8TAJbE2zcFUBT2Fw==
"@nhost/nhost-js@^1.0.9":
version "1.0.9"
resolved "https://registry.yarnpkg.com/@nhost/nhost-js/-/nhost-js-1.0.9.tgz#a1b0bc0c35e15ade2867da4d211b1f81f3bc5e28"
integrity sha512-/SZLk3Be560scVAbUswcRSE4RMwf6M7xanbNLqGUuI/sr1Ir253WPhaD2YWXZChP1v2LBzONhdJNI2g7u1NzoA==
dependencies:
"@nhost/hasura-auth-js" "1.0.0"
"@nhost/hasura-storage-js" "0.2.0"
"@nhost/hasura-auth-js" "^1.0.9"
"@nhost/hasura-storage-js" "^0.2.0"
axios "^0.23.0"
jwt-decode "^3.1.2"
query-string "^7.0.1"
"@nhost/react-apollo@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@nhost/react-apollo/-/react-apollo-4.0.0.tgz#08be35946eadbb746f27435c3fc72cd092a97b61"
integrity sha512-ZmFgBgHFJE2Z2ZBYx3U4Gry9TprUOb4NXw/K5lSKv11zPeEaclfpqn+aeQbtCj02oCnzRe+MJLsJenpcuhQRuw==
"@nhost/react-apollo@^4.0.10":
version "4.0.10"
resolved "https://registry.yarnpkg.com/@nhost/react-apollo/-/react-apollo-4.0.10.tgz#d28819019f35aff7fb69a3b485489ab0492643e1"
integrity sha512-MTIBk9aQVCIfVR17eEKM6ssELadpDhIAh2ERjaZY8+i9KMgVyjEt0s4842nl1Bwq7OFIXf5GRykr3RtTjuT/Ug==
dependencies:
"@nhost/apollo" "0.3.0"
"@nhost/apollo" "^0.3.7"
"@nhost/react@^0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@nhost/react/-/react-0.3.0.tgz#5401922dce91bb66db5d575de1869df00fabbb8e"
integrity sha512-jxyt4dYfphgv3bf6jvV7qDKnV5qUArFvdTYExKlBA9tsBQYta0heawMsJk0rEarEZGUw1iioiUYFKdZyl2Qi5Q==
"@nhost/react@^0.5.0":
version "0.5.0"
resolved "https://registry.yarnpkg.com/@nhost/react/-/react-0.5.0.tgz#5276ae7e13691f32ceaa0e6ca2460ef2605820f6"
integrity sha512-d89I3Q1Y6+9QJ6jP9yU9xrEJv8dCvTwll7tctd7emqZyPWGgInLpmZ9OA+/xrannowck5MsgaBdz0zxQ9bjJBA==
dependencies:
"@nhost/nhost-js" "1.0.0"
"@nhost/nhost-js" "^1.0.9"
"@xstate/react" "^2.0.1"
immer "^9.0.12"
"@rollup/pluginutils@^4.1.2":
"@rollup/pluginutils@^4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.0.tgz#a14bbd058fdbba0a5647143b16ed0d86fb60bd08"
integrity sha512-2WUyJNRkyH5p487pGnn4tWAsxhEFKN/pT8CMgHshd5H+IXkOnKvKZwsz5ZWz+YCXkleZRAU5kwbfgF8CPfDRqA==
@@ -394,7 +394,7 @@
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11"
integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==
"@types/react-dom@^17.0.11":
"@types/react-dom@^17.0.14":
version "17.0.14"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.14.tgz#c8f917156b652ddf807711f5becbd2ab018dea9f"
integrity sha512-H03xwEP1oXmSfl3iobtmQ/2dHF5aBHr8aUMwyGZya6OW45G+xtdzmq6HkncefiBt5JU8DVyaWl/nWZbjZCnzAQ==
@@ -409,7 +409,7 @@
"@types/prop-types" "*"
"@types/react" "*"
"@types/react@*", "@types/react@^17.0.39":
"@types/react@*", "@types/react@^17.0.43":
version "17.0.43"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.43.tgz#4adc142887dd4a2601ce730bc56c3436fdb07a55"
integrity sha512-8Q+LNpdxf057brvPu1lMtC5Vn7J119xrP1aq4qiaefNioQUYANF/CYeK4NsKorSZyUGJ66g0IM+4bbjwx45o2A==
@@ -423,17 +423,17 @@
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==
"@vitejs/plugin-react@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-1.2.0.tgz#4cfb4c0475e93885e56d66ff15e12ef4c34b0af0"
integrity sha512-Rywwt0IXXg6yQ0hv3cMT3mtdDcGIw31mGaa+MMMAT651LhoXLF2yFy4LrakiTs7UKs7RPBo9eNgaS8pgl2A6Qw==
"@vitejs/plugin-react@^1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-1.3.0.tgz#efd4b4383edc12780cd8d230c2daa9d266690bb9"
integrity sha512-H+yIupjUE4a+E4oeWUv4xUJIMR0DWBIMUG/DYgvj0J9Vu1rdHAlJ5JdbI+N1KDUD7Ee2fZ1DMPZ/NBg6mXtoCw==
dependencies:
"@babel/core" "^7.16.12"
"@babel/plugin-transform-react-jsx" "^7.16.7"
"@babel/core" "^7.17.8"
"@babel/plugin-transform-react-jsx" "^7.17.3"
"@babel/plugin-transform-react-jsx-development" "^7.16.7"
"@babel/plugin-transform-react-jsx-self" "^7.16.7"
"@babel/plugin-transform-react-jsx-source" "^7.16.7"
"@rollup/pluginutils" "^4.1.2"
"@rollup/pluginutils" "^4.2.0"
react-refresh "^0.11.0"
resolve "^1.22.0"
@@ -458,13 +458,6 @@
dependencies:
tslib "^2.3.0"
"@xstate/inspect@^0.6.2":
version "0.6.4"
resolved "https://registry.yarnpkg.com/@xstate/inspect/-/inspect-0.6.4.tgz#dd12abb30375dcb0471b81e8db3b81377cd00be6"
integrity sha512-2Gz5wu/RdpeLEpQ93qWQe/lDybJHQq8NzgWyB/EmDUBhOggCeZu4JqJCT7/RsQ7FNSEenZILFbNTftOY00Kg4A==
dependencies:
fast-safe-stringify "^2.0.7"
"@xstate/react@^2.0.1":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@xstate/react/-/react-2.0.1.tgz#2b4717369d419e78a6c67f2dfcd1a3be9abce2d9"
@@ -682,131 +675,131 @@ errno@^0.1.1:
dependencies:
prr "~1.0.1"
esbuild-android-64@0.14.27:
version "0.14.27"
resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.27.tgz#b868bbd9955a92309c69df628d8dd1945478b45c"
integrity sha512-LuEd4uPuj/16Y8j6kqy3Z2E9vNY9logfq8Tq+oTE2PZVuNs3M1kj5Qd4O95ee66yDGb3isaOCV7sOLDwtMfGaQ==
esbuild-android-64@0.14.32:
version "0.14.32"
resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.32.tgz#cf23a9c6052bb48901f5541c7e5a4168495fca36"
integrity sha512-q1qjB2UcoWehR9Yp9dO2RdJUeLLrXAYsbOU4tkYa+GmJzxTwuvOrMdvaemsXYqb7F4STVTca9KpfqGicEChtUg==
esbuild-android-arm64@0.14.27:
version "0.14.27"
resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.27.tgz#e7d6430555e8e9c505fd87266bbc709f25f1825c"
integrity sha512-E8Ktwwa6vX8q7QeJmg8yepBYXaee50OdQS3BFtEHKrzbV45H4foMOeEE7uqdjGQZFBap5VAqo7pvjlyA92wznQ==
esbuild-android-arm64@0.14.32:
version "0.14.32"
resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.32.tgz#5840407c8d8b577eea847eecce8df9610c0f58fd"
integrity sha512-bs1uu+RuM15f8yjFc0FhPDE/6NID4fKl7beDVsGCme6Q8ld2IzRXmp5QaHurlcH93PFyQnUgVvdahIWgtK2QZw==
esbuild-darwin-64@0.14.27:
version "0.14.27"
resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.27.tgz#4dc7484127564e89b4445c0a560a3cb50b3d68e1"
integrity sha512-czw/kXl/1ZdenPWfw9jDc5iuIYxqUxgQ/Q+hRd4/3udyGGVI31r29LCViN2bAJgGvQkqyLGVcG03PJPEXQ5i2g==
esbuild-darwin-64@0.14.32:
version "0.14.32"
resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.32.tgz#c6defc12a60f27408f1a30bb233c9d0e66ea2a55"
integrity sha512-6MekflAld28wYtzanwZTxQlxMPeYw/yv1ToFG2hpo3LGxOIE2mBD5IJaMCcyy1//EYvGnGToO3p6XKdbS8E1QQ==
esbuild-darwin-arm64@0.14.27:
version "0.14.27"
resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.27.tgz#469e59c665f84a8ed323166624c5e7b9b2d22ac1"
integrity sha512-BEsv2U2U4o672oV8+xpXNxN9bgqRCtddQC6WBh4YhXKDcSZcdNh7+6nS+DM2vu7qWIWNA4JbRG24LUUYXysimQ==
esbuild-darwin-arm64@0.14.32:
version "0.14.32"
resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.32.tgz#fc878496516a90fc4982ee7cf8f2d2f484dbd64a"
integrity sha512-BHYIjiPDYQTD+4zwqdqRo+I2bbg3fn9mah/gZm4SCCy+7uwTTYOYobIunHT7wVCgxnFCr50PJUdaMrEoCImRbw==
esbuild-freebsd-64@0.14.27:
version "0.14.27"
resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.27.tgz#895df03bf5f87094a56c9a5815bf92e591903d70"
integrity sha512-7FeiFPGBo+ga+kOkDxtPmdPZdayrSzsV9pmfHxcyLKxu+3oTcajeZlOO1y9HW+t5aFZPiv7czOHM4KNd0tNwCA==
esbuild-freebsd-64@0.14.32:
version "0.14.32"
resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.32.tgz#c136e8e8bab8e7ea95a7fbe4b689d2c940bf48f2"
integrity sha512-6BOBhtfAf9AlfjL1AvtfVOxwY82tHPfYrA0lskJpFjfiEMGTLU6e0vdOwb4+4x++gGz49azuGK0woYqdfL03uw==
esbuild-freebsd-arm64@0.14.27:
version "0.14.27"
resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.27.tgz#0b72a41a6b8655e9a8c5608f2ec1afdcf6958441"
integrity sha512-8CK3++foRZJluOWXpllG5zwAVlxtv36NpHfsbWS7TYlD8S+QruXltKlXToc/5ZNzBK++l6rvRKELu/puCLc7jA==
esbuild-freebsd-arm64@0.14.32:
version "0.14.32"
resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.32.tgz#46668a10e5a51665ed800b10a02b757bf6bc6fbf"
integrity sha512-zIRR4gKQW56p/xLM8TlpxVBNiX0w3VoR9ZxfH4nrfJ7QiL0SYHRy8YPL5C7zMWRjSze2WxQRHfS9bHKdVrVXBw==
esbuild-linux-32@0.14.27:
version "0.14.27"
resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.27.tgz#43b8ba3803b0bbe7f051869c6a8bf6de1e95de28"
integrity sha512-qhNYIcT+EsYSBClZ5QhLzFzV5iVsP1YsITqblSaztr3+ZJUI+GoK8aXHyzKd7/CKKuK93cxEMJPpfi1dfsOfdw==
esbuild-linux-32@0.14.32:
version "0.14.32"
resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.32.tgz#ac51a64f26f638618ff62a1a966babe065bc54cc"
integrity sha512-kn0AkGtPvzA6xiv93/mavvZ7DVinu/ewh2F2S0/8mE8/PXi3D4+svZ6V3beV5DIH7vcHVuGhoooWav8HPF04tg==
esbuild-linux-64@0.14.27:
version "0.14.27"
resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.27.tgz#dc8072097327ecfadba1735562824ce8c05dd0bd"
integrity sha512-ESjck9+EsHoTaKWlFKJpPZRN26uiav5gkI16RuI8WBxUdLrrAlYuYSndxxKgEn1csd968BX/8yQZATYf/9+/qg==
esbuild-linux-64@0.14.32:
version "0.14.32"
resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.32.tgz#a3dfeb772f339fb34f0ff61df753a70a01be243a"
integrity sha512-Ie+PMvrPj/HCOmSc0QubKttDxP2iBtPzDu+b+V3HGDGwkGmVpDkyXx1NXp5LjkIphIay2QekMwy1dSw3KDqCew==
esbuild-linux-arm64@0.14.27:
version "0.14.27"
resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.27.tgz#c52b58cbe948426b1559910f521b0a3f396f10b8"
integrity sha512-no6Mi17eV2tHlJnqBHRLekpZ2/VYx+NfGxKcBE/2xOMYwctsanCaXxw4zapvNrGE9X38vefVXLz6YCF8b1EHiQ==
esbuild-linux-arm64@0.14.32:
version "0.14.32"
resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.32.tgz#df2fead5c0d9228eede866359f35b3e0eef4e192"
integrity sha512-ykoqKaxX95nB+lk2K/+qxr0ke+BxkeVi0yKOnymCR5Ive7IZDHa4BJX53NEGSBKLfWPwKE6SXTz8qcEewSntoA==
esbuild-linux-arm@0.14.27:
version "0.14.27"
resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.27.tgz#df869dbd67d4ee3a04b3c7273b6bd2b233e78a18"
integrity sha512-JnnmgUBdqLQO9hoNZQqNHFWlNpSX82vzB3rYuCJMhtkuaWQEmQz6Lec1UIxJdC38ifEghNTBsF9bbe8dFilnCw==
esbuild-linux-arm@0.14.32:
version "0.14.32"
resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.32.tgz#64633aa6491e91d935324cf041795ebce18c071b"
integrity sha512-R/Bvn/YQNDyvfN0SERh/I7hKPqN+nSSruQdVeiYEJ+jc3fUi73jXYAscpTQgIBeER/yXnEsgJGU/UQ9+sscr7A==
esbuild-linux-mips64le@0.14.27:
version "0.14.27"
resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.27.tgz#a2b646d9df368b01aa970a7b8968be6dd6b01d19"
integrity sha512-NolWP2uOvIJpbwpsDbwfeExZOY1bZNlWE/kVfkzLMsSgqeVcl5YMen/cedRe9mKnpfLli+i0uSp7N+fkKNU27A==
esbuild-linux-mips64le@0.14.32:
version "0.14.32"
resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.32.tgz#f0a7a083e8fdfb6e4edffb93ec27de2c5d732f01"
integrity sha512-IilnlBexpHpt/5po0cle/L/S6CYnwaq23UuAqWzxp+opHLOCNnyANpC1jOoP551aRx4JuZ7z3xZZ7bYQZB147w==
esbuild-linux-ppc64le@0.14.27:
version "0.14.27"
resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.27.tgz#9a21af766a0292578a3009c7408b8509cac7cefd"
integrity sha512-/7dTjDvXMdRKmsSxKXeWyonuGgblnYDn0MI1xDC7J1VQXny8k1qgNp6VmrlsawwnsymSUUiThhkJsI+rx0taNA==
esbuild-linux-ppc64le@0.14.32:
version "0.14.32"
resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.32.tgz#dc22b766dd4ddd20c28febe36e8b92b9c11faa63"
integrity sha512-TR6l5nWZbfq7jSY+1vsiQjT4m67NWplNhbX6GBieZq6DBt0nTx1XgTZAdKROF7jTuaK7YrCYlPXtfO3w86Mysw==
esbuild-linux-riscv64@0.14.27:
version "0.14.27"
resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.27.tgz#344a27f91568056a5903ad5841b447e00e78d740"
integrity sha512-D+aFiUzOJG13RhrSmZgrcFaF4UUHpqj7XSKrIiCXIj1dkIkFqdrmqMSOtSs78dOtObWiOrFCDDzB24UyeEiNGg==
esbuild-linux-riscv64@0.14.32:
version "0.14.32"
resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.32.tgz#0ae09eee847de5993cbe1529591d5ca17c7303c5"
integrity sha512-aSOcUzTeIAslfri8e+bMpyzQuxhcIiNhWyuCGGXum2PtxwYiUqR8/UCMYfwYtYkhr1yABOFOfs83mm9KBy5qCQ==
esbuild-linux-s390x@0.14.27:
version "0.14.27"
resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.27.tgz#73a7309bd648a07ef58f069658f989a5096130db"
integrity sha512-CD/D4tj0U4UQjELkdNlZhQ8nDHU5rBn6NGp47Hiz0Y7/akAY5i0oGadhEIg0WCY/HYVXFb3CsSPPwaKcTOW3bg==
esbuild-linux-s390x@0.14.32:
version "0.14.32"
resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.32.tgz#1297f9f130cd93495e7ce25c63a79dab223b89de"
integrity sha512-dNlip+EvexxKjRZitFCWCd7DVk64c7R5ySr8aFEMHCb/RriNiyDxYJGzYWm4EMJsMRMupMUHlMY64BAa3Op9FA==
esbuild-netbsd-64@0.14.27:
version "0.14.27"
resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.27.tgz#482a587cdbd18a6c264a05136596927deb46c30a"
integrity sha512-h3mAld69SrO1VoaMpYl3a5FNdGRE/Nqc+E8VtHOag4tyBwhCQXxtvDDOAKOUQexBGca0IuR6UayQ4ntSX5ij1Q==
esbuild-netbsd-64@0.14.32:
version "0.14.32"
resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.32.tgz#902bf5ba7c54db9c7274f019c4d006b1b963fb7d"
integrity sha512-Pa3QByYqxzlBFQQQhjYBPg3WUfSjwibqzh1hC6mPDRUHnCeUcrLoBuIiG4xqOYEpQM9/kDowIBsrGIQEVWWdQA==
esbuild-openbsd-64@0.14.27:
version "0.14.27"
resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.27.tgz#e99f8cdc63f1628747b63edd124d53cf7796468d"
integrity sha512-xwSje6qIZaDHXWoPpIgvL+7fC6WeubHHv18tusLYMwL+Z6bEa4Pbfs5IWDtQdHkArtfxEkIZz77944z8MgDxGw==
esbuild-openbsd-64@0.14.32:
version "0.14.32"
resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.32.tgz#0fbfbdf555deeb05a8915daf0b71168d09773437"
integrity sha512-uWKKqpCjkMY8TCIobFvaSETonQY3OrmgnoTCC3tF+lvMoneYjppB6akx7L5Xv0kP+1tnSbrIof1ca8PfqGUyjw==
esbuild-sunos-64@0.14.27:
version "0.14.27"
resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.27.tgz#8611d825bcb8239c78d57452e83253a71942f45c"
integrity sha512-/nBVpWIDjYiyMhuqIqbXXsxBc58cBVH9uztAOIfWShStxq9BNBik92oPQPJ57nzWXRNKQUEFWr4Q98utDWz7jg==
esbuild-sunos-64@0.14.32:
version "0.14.32"
resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.32.tgz#d493ca5222703dd0b8c489324d1517cd622618e8"
integrity sha512-Ar+u3mBk0oVV4Fwv/qlinJZNIPPtTBSG+1W42o8lOaVxJ+rJgecDoeUN+5uyd9at0BK1SVrQ1qZ4wjHKB0qFpQ==
esbuild-windows-32@0.14.27:
version "0.14.27"
resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.27.tgz#c06374206d4d92dd31d4fda299b09f51a35e82f6"
integrity sha512-Q9/zEjhZJ4trtWhFWIZvS/7RUzzi8rvkoaS9oiizkHTTKd8UxFwn/Mm2OywsAfYymgUYm8+y2b+BKTNEFxUekw==
esbuild-windows-32@0.14.32:
version "0.14.32"
resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.32.tgz#c6b0f4cf952c6f562a32fe763acab9fb8cb3912a"
integrity sha512-rLMsbflMY6Hjh3rmQnCDVZahJQ7n+XfT6o1+no5pHRpDlMh38MHthgGh35q+EcOMgrGP3ppnw70rhJq80SaYTQ==
esbuild-windows-64@0.14.27:
version "0.14.27"
resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.27.tgz#756631c1d301dfc0d1a887deed2459ce4079582f"
integrity sha512-b3y3vTSl5aEhWHK66ngtiS/c6byLf6y/ZBvODH1YkBM+MGtVL6jN38FdHUsZasCz9gFwYs/lJMVY9u7GL6wfYg==
esbuild-windows-64@0.14.32:
version "0.14.32"
resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.32.tgz#2ad9322a963fd26bb4818ad1c0ee7acde63ebb81"
integrity sha512-OHnMMxYufVgLXIMnwLynLMKguHMrsVnWcehieSP9i6ZX31KEsOFYWrorcnTWOn4rbZVLSL10ofxLuVIgRW3SWw==
esbuild-windows-arm64@0.14.27:
version "0.14.27"
resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.27.tgz#ad7e187193dcd18768b16065a950f4441d7173f4"
integrity sha512-I/reTxr6TFMcR5qbIkwRGvldMIaiBu2+MP0LlD7sOlNXrfqIl9uNjsuxFPGEG4IRomjfQ5q8WT+xlF/ySVkqKg==
esbuild-windows-arm64@0.14.32:
version "0.14.32"
resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.32.tgz#bb589106c0fd5d582cce62bd7995a6e5db52e7b4"
integrity sha512-ddavy6IPUBySMfqDfG243TgtuqwQBNJQJPVaA4DaavmMfpBsUxFrSV+HzBWXTKU3I9EcuoEvIATLuQ7NJKxjwg==
esbuild@^0.14.14:
version "0.14.27"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.27.tgz#41fe0f1b6b68b9f77cac025009bc54bb96e616f1"
integrity sha512-MZQt5SywZS3hA9fXnMhR22dv0oPGh6QtjJRIYbgL1AeqAoQZE+Qn5ppGYQAoHv/vq827flj4tIJ79Mrdiwk46Q==
esbuild@^0.14.27:
version "0.14.32"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.32.tgz#f55245ccd4b820707147ac4cc69a2c3e1a76af03"
integrity sha512-RuzVUP/bkStmnVHK6Gh3gjaMjfXNLqBqvYVDiS9JKl5KdRdRLUeW5Wo8NrbL7cL6CW7Cyak7SvACqyPOBuA8vA==
optionalDependencies:
esbuild-android-64 "0.14.27"
esbuild-android-arm64 "0.14.27"
esbuild-darwin-64 "0.14.27"
esbuild-darwin-arm64 "0.14.27"
esbuild-freebsd-64 "0.14.27"
esbuild-freebsd-arm64 "0.14.27"
esbuild-linux-32 "0.14.27"
esbuild-linux-64 "0.14.27"
esbuild-linux-arm "0.14.27"
esbuild-linux-arm64 "0.14.27"
esbuild-linux-mips64le "0.14.27"
esbuild-linux-ppc64le "0.14.27"
esbuild-linux-riscv64 "0.14.27"
esbuild-linux-s390x "0.14.27"
esbuild-netbsd-64 "0.14.27"
esbuild-openbsd-64 "0.14.27"
esbuild-sunos-64 "0.14.27"
esbuild-windows-32 "0.14.27"
esbuild-windows-64 "0.14.27"
esbuild-windows-arm64 "0.14.27"
esbuild-android-64 "0.14.32"
esbuild-android-arm64 "0.14.32"
esbuild-darwin-64 "0.14.32"
esbuild-darwin-arm64 "0.14.32"
esbuild-freebsd-64 "0.14.32"
esbuild-freebsd-arm64 "0.14.32"
esbuild-linux-32 "0.14.32"
esbuild-linux-64 "0.14.32"
esbuild-linux-arm "0.14.32"
esbuild-linux-arm64 "0.14.32"
esbuild-linux-mips64le "0.14.32"
esbuild-linux-ppc64le "0.14.32"
esbuild-linux-riscv64 "0.14.32"
esbuild-linux-s390x "0.14.32"
esbuild-netbsd-64 "0.14.32"
esbuild-openbsd-64 "0.14.32"
esbuild-sunos-64 "0.14.32"
esbuild-windows-32 "0.14.32"
esbuild-windows-64 "0.14.32"
esbuild-windows-arm64 "0.14.32"
escalade@^3.1.1:
version "3.1.1"
@@ -833,11 +826,6 @@ eventemitter3@^4.0.4:
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
fast-safe-stringify@^2.0.7:
version "2.1.1"
resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884"
integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==
fbemitter@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/fbemitter/-/fbemitter-3.0.0.tgz#00b2a1af5411254aab416cd75f9e6289bee4bff3"
@@ -930,11 +918,6 @@ graphql-tag@^2.12.3:
dependencies:
tslib "^2.1.0"
graphql@15.7.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.7.2.tgz#85ab0eeb83722977151b3feb4d631b5f2ab287ef"
integrity sha512-AnnKk7hFQFmU/2I9YSQf3xw44ctnSFCfp3zE0N6W174gqe9fWG/2rKaKxROK7CcI3XtERpjEKFqts8o319Kf7A==
graphql@16:
version "16.3.0"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.3.0.tgz#a91e24d10babf9e60c706919bb182b53ccdffc05"
@@ -1225,7 +1208,7 @@ pify@^4.0.1:
resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==
postcss@^8.4.6:
postcss@^8.4.12:
version "8.4.12"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.12.tgz#1e7de78733b28970fa4743f7da6f3763648b1905"
integrity sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==
@@ -1324,18 +1307,18 @@ react-refresh@^0.11.0:
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.11.0.tgz#77198b944733f0f1f1a90e791de4541f9f074046"
integrity sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==
react-router-dom@^6.2.1:
version "6.2.2"
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.2.2.tgz#f1a2c88365593c76b9612ae80154a13fcb72e442"
integrity sha512-AtYEsAST7bDD4dLSQHDnk/qxWLJdad5t1HFa1qJyUrCeGgEuCSw0VB/27ARbF9Fi/W5598ujvJOm3ujUCVzuYQ==
react-router-dom@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.3.0.tgz#a0216da813454e521905b5fa55e0e5176123f43d"
integrity sha512-uaJj7LKytRxZNQV8+RbzJWnJ8K2nPsOOEuX7aQstlMZKQT0164C+X2w6bnkqU3sjtLvpd5ojrezAyfZ1+0sStw==
dependencies:
history "^5.2.0"
react-router "6.2.2"
react-router "6.3.0"
react-router@6.2.2:
version "6.2.2"
resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.2.2.tgz#495e683a0c04461eeb3d705fe445d6cf42f0c249"
integrity sha512-/MbxyLzd7Q7amp4gDOGaYvXwhEojkJD5BtExkuKmj39VEE0m3l/zipf6h2WIB2jyAO0lI6NGETh4RDcktRm4AQ==
react-router@6.3.0, react-router@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.3.0.tgz#3970cc64b4cb4eae0c1ea5203a80334fdd175557"
integrity sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ==
dependencies:
history "^5.2.0"
@@ -1409,10 +1392,10 @@ rsuite-table@^5.3.6:
lodash "^4.17.21"
react-is "^17.0.2"
rsuite@^5.6.2:
version "5.6.6"
resolved "https://registry.yarnpkg.com/rsuite/-/rsuite-5.6.6.tgz#03b97ec32a24212aaa95e3d14e5e85db2255175a"
integrity sha512-N4xnfnOpbxkEQ4+6GP/ll76XC8motkCQUNy1WL5wayZGgmOjzbVLbOUUHn9iGN32sBLyH8/d3Lo/WxfAjprj3g==
rsuite@^5.7.1:
version "5.7.1"
resolved "https://registry.yarnpkg.com/rsuite/-/rsuite-5.7.1.tgz#2c50161e568cbf0074b42e7b65592b25a3b9412d"
integrity sha512-vvqBadf9vJ49CW4gboFpj+Ol7M5sK7a72irwQxgxBxHBD2YEWUx9LQp137RIJV6w/nXg1P5yaObZULb5n77QoA==
dependencies:
"@babel/runtime" "^7.8.4"
"@juggle/resize-observer" "^3.3.1"
@@ -1555,7 +1538,7 @@ tslib@^2.1.0, tslib@^2.3.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01"
integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==
typescript@^4.5.5:
typescript@^4.6.3:
version "4.6.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.3.tgz#eefeafa6afdd31d725584c67a0eaba80f6fc6c6c"
integrity sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==
@@ -1597,13 +1580,13 @@ use-subscription@^1.3.0:
dependencies:
object-assign "^4.1.1"
vite@^2.8.5:
version "2.8.6"
resolved "https://registry.yarnpkg.com/vite/-/vite-2.8.6.tgz#32d50e23c99ca31b26b8ccdc78b1d72d4d7323d3"
integrity sha512-e4H0QpludOVKkmOsRyqQ7LTcMUDF3mcgyNU4lmi0B5JUbe0ZxeBBl8VoZ8Y6Rfn9eFKYtdXNPcYK97ZwH+K2ug==
vite@^2.9.1:
version "2.9.1"
resolved "https://registry.yarnpkg.com/vite/-/vite-2.9.1.tgz#84bce95fae210a7beb566a0af06246748066b48f"
integrity sha512-vSlsSdOYGcYEJfkQ/NeLXgnRv5zZfpAsdztkIrs7AZHV8RCMZQkwjo4DS5BnrYTqoWqLoUe1Cah4aVO4oNNqCQ==
dependencies:
esbuild "^0.14.14"
postcss "^8.4.6"
esbuild "^0.14.27"
postcss "^8.4.12"
resolve "^1.22.0"
rollup "^2.59.0"
optionalDependencies:
@@ -1632,11 +1615,6 @@ wrappy@1:
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.7.tgz#9e0ac77ee50af70d58326ecff7e85eb3fa375e67"
integrity sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==
ws@^8.5.0:
version "8.5.0"
resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f"
integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==
xstate@^4.30.5:
version "4.30.6"
resolved "https://registry.yarnpkg.com/xstate/-/xstate-4.30.6.tgz#62b6dea37a500e0e1c0ff7c553a801eea5119554"

View File

@@ -28,11 +28,11 @@
"prettier:fix": "prettier --write .",
"lint": "pnpm turbo run lint --stream",
"lint:fix": "pnpm turbo run lint:fix --stream",
"test": "pnpm turbo run test --scope='@nhost/*' --no-deps --include-dependencies",
"prerelease": "pnpm clean && pnpm install && pnpm build",
"release": "pnpm run prerelease && changeset publish && git push --follow-tags && git status && pnpm -r publish",
"changeset": "changeset",
"release": "pnpm run prerelease && changeset publish",
"snapshot": "pnpm prerelease && changeset version --snapshot preview && pnpm install && changeset publish --tag preview",
"test": "pnpm turbo run test --scope='@nhost/*' --no-deps --include-dependencies",
"changeset": "changeset",
"wait": "wait-on http://localhost:1337/v1/auth/healthz -i 500 -t 120000"
},
"workspaces": [

View File

@@ -1,5 +1,57 @@
# @nhost/apollo
## 0.3.9
### Patch Changes
- Updated dependencies [63d6059]
- Updated dependencies [63d6059]
- @nhost/core@0.3.10
## 0.3.8
### Patch Changes
- Updated dependencies [2c97db6]
- @nhost/core@0.3.9
## 0.3.7
### Patch Changes
- Updated dependencies [058956b]
- Updated dependencies [7cf875f]
- @nhost/core@0.3.8
## 0.3.5
### Patch Changes
- Updated dependencies [16a6c50]
- @nhost/core@0.3.4
## 0.3.3
### Patch Changes
- correct dependencies
See this related issues:
- [nhost](https://github.com/nhost/nhost/issues/326)
- [pnpm](https://github.com/pnpm/pnpm/issues/4348)
- Updated dependencies
- @nhost/core@0.3.2
## 0.3.1
### Patch Changes
- 113beed: fix: Refetched queries and leaking subscriptions [#301](https://github.com/nhost/nhost/issues/301)
- Updated dependencies [4420c0e]
- @nhost/core@0.3.1
## 0.3.0
### Minor Changes
@@ -10,7 +62,6 @@
### Patch Changes
- Updated dependencies [744fd69]
- Updated dependencies [744fd69]
- @nhost/core@0.3.0

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/apollo",
"version": "0.3.0",
"version": "0.3.9",
"description": "Nhost Apollo Client library",
"license": "MIT",
"keywords": [

View File

@@ -131,26 +131,22 @@ export const createApolloClient = ({
if (token !== newToken) {
token = newToken
client.reFetchObservableQueries()
if (isBrowser && webSocketClient) {
if (newToken) {
if (webSocketClient.status === 1) {
// @ts-expect-error
webSocketClient.tryReconnect()
}
} else {
if (webSocketClient.status === 1) {
// must close first to avoid race conditions
webSocketClient.close()
// reconnect
// @ts-expect-error
webSocketClient.tryReconnect()
}
if (event.type === 'SIGNOUT') {
await client.resetStore().catch((error) => {
console.error('Error resetting Apollo client cache')
console.error(error)
})
if (webSocketClient.status === 1) {
// must close first to avoid race conditions
webSocketClient.close()
// @ts-expect-error
webSocketClient.tryReconnect()
}
if (!newToken && event.type === 'SIGNOUT') {
try {
await client.resetStore()
} catch (error) {
console.error('Error resetting Apollo client cache')
console.error(error)
}
}
}

View File

@@ -1,5 +1,60 @@
# @nhost/core
## 0.3.10
### Patch Changes
- 63d6059: Set onTokenChanged before the state interpreter started
Fixes [#384](https://github.com/nhost/nhost/issues/384), thanks [@noverby](https://github.com/noverby)
- 63d6059: Trigger onTokenChanged when token changes
Fixes [#373](https://github.com/nhost/nhost/issues/373), thanks [@yureckey](https://github.com/yureckey)
## 0.3.9
### Patch Changes
- 2c97db6: Keep authentication status and access token in sync
The authentication events where not set correctly, leading the main Nhost client not to update internal states of storage/graphql/functions sub-clients when using non-react clients.
The use of private fields (`#`) is also avoided as they conflict with the use of proxies in Vue, leading to errors in the upcoming Vue library.
Fixes #373 and #378
## 0.3.8
### Patch Changes
- 058956b: Add missing provider types
`strava`, `gitlab`, and `bitbucket` were missing from the list of providers in Typescript and are now available.
- 058956b: Add `emailVerified`, `phoneNumber`, `phoneNumberVerified`, and `activeMfaType` to User type
Some information is missing in the `User` payload (see [this issue](https://github.com/nhost/nhost/issues/306)). The above properties have been added in the Typescript `User` type and are available when using Hasura Auth versions from [this pull request](https://github.com/nhost/hasura-auth/pull/128) (tentative version number: `0.5.1`)
- 7cf875f: Export error code payloads and type
## 0.3.7
### Patch Changes
- 16a6c50: Correct autoSignIn
## 0.3.3
### Patch Changes
- correct dependencies
See this related issues:
- [nhost](https://github.com/nhost/nhost/issues/326)
- [pnpm](https://github.com/pnpm/pnpm/issues/4348)
## 0.3.1
### Patch Changes
- 4420c0e: Check if `window.location` exists
When using [Expo](https://expo.dev/), `window` can be an object while `window.location` is `undefined`. It lead to [this issue](https://github.com/nhost/nhost/issues/309).
## 0.3.0
### Minor Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/core",
"version": "0.3.0",
"version": "0.3.10",
"description": "Nhost core client library",
"license": "MIT",
"keywords": [

View File

@@ -12,13 +12,13 @@ export class AuthClient {
readonly backendUrl: string
readonly clientUrl: string
readonly machine: AuthMachine
#interpreter?: AuthInterpreter
#channel?: BroadcastChannel
#subscriptions: Set<(client: AuthClient) => void> = new Set()
private _interpreter?: AuthInterpreter
private _channel?: BroadcastChannel
private _subscriptions: Set<(client: AuthClient) => void> = new Set()
constructor({
backendUrl,
clientUrl = typeof window !== 'undefined' ? window.location.origin : '',
clientUrl = (typeof window !== 'undefined' && window.location?.origin) || '',
clientStorageGetter = defaultClientStorageGetter,
clientStorageSetter = defaultClientStorageSetter,
refreshIntervalTime = MIN_TOKEN_REFRESH_INTERVAL,
@@ -45,8 +45,8 @@ export class AuthClient {
}
if (typeof window !== 'undefined' && autoSignIn) {
this.#channel = new BroadcastChannel<string>('nhost')
this.#channel.addEventListener('message', (token) => {
this._channel = new BroadcastChannel<string>('nhost')
this._channel.addEventListener('message', (token) => {
const existingToken = this.interpreter?.state.context.refreshToken
if (this.interpreter && token !== existingToken) {
this.interpreter.send({ type: 'TRY_TOKEN', token })
@@ -56,16 +56,23 @@ export class AuthClient {
}
get interpreter(): AuthInterpreter | undefined {
return this.#interpreter
return this._interpreter
}
set interpreter(interpreter: AuthInterpreter | undefined) {
this.#interpreter = interpreter
this._interpreter = interpreter
if (interpreter) {
this.#subscriptions.forEach((fn) => fn(this))
this._subscriptions.forEach((fn) => fn(this))
}
}
onStart(fn: (interpreter: AuthClient) => void) {
this.#subscriptions.add(fn)
onStart(fn: (client: AuthClient) => void) {
if (this.interpreter) {
// * The interpreter is already available: we can add the listener straight ahead
fn(this)
} else {
// * The interpreter is not yet available: we add the listener to a queue that will be started when setting the interpreter
// * Note: in React, the Xstate interpreter does not start from the global state, but from the root component
this._subscriptions.add(fn)
}
}
}

View File

@@ -2,6 +2,7 @@ export type { NhostClientOptions } from './client'
export { AuthClient } from './client'
export * from './constants'
export { AuthClientSSR } from './coookie-client'
export * from './errors'
export * from './machines'
export * from './storage'
export * from './types'

View File

@@ -71,6 +71,7 @@ export const createChangeEmailMachine = ({ backendUrl, clientUrl, interpreter }:
error: (_, { data: { error } }: any) => error
}),
reportError: send((ctx) => ({ type: 'ERROR', error: ctx.error })),
// TODO change email in the main machine (context.user.email)
reportSuccess: send('SUCCESS')
},
guards: {

View File

@@ -401,7 +401,12 @@ export const createAuthMachine = ({
src: 'refreshToken',
id: 'refreshToken',
onDone: {
actions: ['saveSession', 'persist', 'resetTimer'],
actions: [
'saveSession',
'persist',
'resetTimer',
'reportTokenChanged'
],
target: 'pending'
},
onError: [
@@ -634,28 +639,31 @@ export const createAuthMachine = ({
options: rewriteRedirectTo(clientUrl, options)
}),
/**
* If autoSignIn is enabled, attempts to get the refreshToken from the current location's hash
* @returns
*/
autoSignIn: async () => {
if (typeof window !== 'undefined') {
const location = window.location
if (location.hash) {
const params = new URLSearchParams(location.hash.slice(1))
const refreshToken = params.get('refreshToken')
if (refreshToken) {
const session = await postRequest('/token', {
refreshToken
})
// * remove hash from the current url after consumming the token
// TODO remove the hash. For the moment, it is kept to avoid regression from the current SDK.
// * Then, only `refreshToken` will be in the hash, while `type` will be sent by hasura-auth as a query parameter
// window.history.pushState({}, '', location.pathname)
const channel = new BroadcastChannel('nhost')
// TODO broadcat session instead of token
channel.postMessage(refreshToken)
return { session }
}
}
}
throw Error()
// TODO throwing errors is not really important as they are captured by the xstate invoker
// * Still, keep them for the moment as it needs to be tested in every environemnt e.g. nodejs, expo, react-native...
if (typeof window === 'undefined' || !window.location)
throw Error('window is undefined or location does not exist')
const { hash } = window.location
if (!hash) throw Error('No hash in window.location')
const params = new URLSearchParams(hash.slice(1))
const refreshToken = params.get('refreshToken')
if (!refreshToken) throw Error('No refresh token in the location hash')
const session = await postRequest('/token', {
refreshToken
})
// * remove hash from the current url after consumming the token
// TODO remove the hash. For the moment, it is kept to avoid regression from the current SDK.
// * Then, only `refreshToken` will be in the hash, while `type` will be sent by hasura-auth as a query parameter
// window.history.pushState({}, '', location.pathname)
const channel = new BroadcastChannel('nhost')
// ? broadcat session instead of token ?
channel.postMessage(refreshToken)
return { session }
},
importRefreshToken: async () => {
const stringExpiresAt = await clientStorageGetter(NHOST_JWT_EXPIRES_AT_KEY)

View File

@@ -32,6 +32,7 @@ export interface Typegen0 {
| 'done.invoke.authenticateAnonymously'
| 'done.invoke.signInMfaTotp'
| 'done.invoke.registerUser'
| 'done.invoke.refreshToken'
| 'done.invoke.authenticateWithToken'
saveRefreshToken: 'done.invoke.importRefreshToken'
saveInvalidEmail: 'SIGNIN_PASSWORD' | 'SIGNIN_PASSWORDLESS_EMAIL'

View File

@@ -14,7 +14,7 @@ type RegistrationOptions = {
metadata?: Record<string, unknown>
}
type RedirectOption = {
export type RedirectOption = {
redirectTo?: string
}
@@ -26,6 +26,7 @@ export type SendVerificationEmailOptions = RedirectOption
export type DeanonymizeOptions = { email?: string; password?: string } & RegistrationOptions
export type ProviderOptions = RegistrationOptions & RedirectOption
// TODO share with hasura-auth
export type User = {
id: string
createdAt: string
@@ -37,9 +38,13 @@ export type User = {
defaultRole: string
roles: string[]
metadata: Record<string, unknown>
emailVerified: boolean
phoneNumber: string | null
phoneNumberVerified: boolean
activeMfaType: 'totp' | null
}
// ! copy-paste from hasura-auth
// TODO share with hasura-auth
export type NhostSession = {
accessToken: string
accessTokenExpiresIn: number
@@ -51,6 +56,7 @@ export type Mfa = {
ticket: string
}
// TODO share with hasura-auth
export type Provider =
| 'apple'
| 'facebook'
@@ -60,3 +66,6 @@ export type Provider =
| 'spotify'
| 'twitter'
| 'windowslive'
| 'strava'
| 'gitlab'
| 'bitbucket'

View File

@@ -1,5 +1,80 @@
# @nhost/hasura-auth-js
## 1.0.11
### Patch Changes
- 63d6059: Add TSDoc information about Nhost client options
- 63d6059: Set onTokenChanged before the state interpreter started
Fixes [#384](https://github.com/nhost/nhost/issues/384), thanks [@noverby](https://github.com/noverby)
- 63d6059: Trigger onTokenChanged when token changes
Fixes [#373](https://github.com/nhost/nhost/issues/373), thanks [@yureckey](https://github.com/yureckey)
- Updated dependencies [63d6059]
- Updated dependencies [63d6059]
- @nhost/core@0.3.10
## 1.0.10
### Patch Changes
- 2c97db6: Keep authentication status and access token in sync
The authentication events where not set correctly, leading the main Nhost client not to update internal states of storage/graphql/functions sub-clients when using non-react clients.
The use of private fields (`#`) is also avoided as they conflict with the use of proxies in Vue, leading to errors in the upcoming Vue library.
Fixes #373 and #378
- Updated dependencies [2c97db6]
- @nhost/core@0.3.9
## 1.0.9
### Patch Changes
- 058956b: Add missing provider types
`strava`, `gitlab`, and `bitbucket` were missing from the list of providers in Typescript and are now available.
- 058956b: Add `emailVerified`, `phoneNumber`, `phoneNumberVerified`, and `activeMfaType` to User type
Some information is missing in the `User` payload (see [this issue](https://github.com/nhost/nhost/issues/306)). The above properties have been added in the Typescript `User` type and are available when using Hasura Auth versions from [this pull request](https://github.com/nhost/hasura-auth/pull/128) (tentative version number: `0.5.1`)
- Updated dependencies [058956b]
- Updated dependencies [7cf875f]
- @nhost/core@0.3.8
## 1.0.8
### Patch Changes
- 6be3758: bug: Correct OAuth provider link.
## 1.0.7
### Patch Changes
- Updated dependencies [16a6c50]
- @nhost/core@0.3.4
## 1.0.4
### Patch Changes
- correct dependencies
See this related issues:
- [nhost](https://github.com/nhost/nhost/issues/326)
- [pnpm](https://github.com/pnpm/pnpm/issues/4348)
- Updated dependencies
- @nhost/core@0.3.2
## 1.0.2
### Patch Changes
- 6eeb9d2: Wait for the authentication status to be known before executing auth actions
The auth client was able to start actions such as signUp or signIn before the authentication state was ready (e.g. before initial refresh token could be processed).
This patch solves the problem in waiting for the authentication status to be known before running these actions.
- Updated dependencies [4420c0e]
- @nhost/core@0.3.1
## 1.0.1
### Patch Changes
@@ -31,7 +106,6 @@
2. hasura-auth validates the link, attaches the token and redirects to the frontend
3. the sdk gets the refresh token from the url
4. the sdk consumes the refresh token
- Updated dependencies [744fd69]
- Updated dependencies [744fd69]
- @nhost/core@0.3.0

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/hasura-auth-js",
"version": "1.0.1",
"version": "1.0.11",
"description": "Hasura-auth client",
"license": "MIT",
"keywords": [

View File

@@ -33,6 +33,7 @@ import {
SignUpParams,
SignUpResponse
} from './utils/types'
const USER_ALREADY_SIGNED_IN: ApiError = {
message: 'User is already signed in',
status: 100
@@ -52,9 +53,7 @@ const EMAIL_NEEDS_VERIFICATION: ApiError = {
status: 102
}
export class HasuraAuthClient {
#client: AuthClient
private onTokenChangedSubscriptions: Set<AuthInterpreter> = new Set()
private onAuthStateChangedSubscriptions: Set<AuthInterpreter> = new Set()
private _client: AuthClient
constructor({
url,
@@ -68,7 +67,7 @@ export class HasuraAuthClient {
start = true,
Client = AuthClient
}: NhostAuthConstructorParams) {
this.#client = new Client({
this._client = new Client({
backendUrl: url,
autoRefreshToken,
autoSignIn: autoLogin,
@@ -93,10 +92,7 @@ export class HasuraAuthClient {
* @docs https://docs.nhost.io/reference/sdk/authentication#nhost-auth-signup
*/
async signUp(params: SignUpParams): Promise<SignUpResponse> {
const interpreter = this.#client.interpreter
if (!interpreter) {
throw Error('Auth interpreter not set')
}
const interpreter = await this.waitUntilReady()
const { email, password, options } = params
@@ -145,8 +141,7 @@ export class HasuraAuthClient {
providerUrl?: string
provider?: string
}> {
const interpreter = this.#client.interpreter
if (!interpreter) throw Error('Auth interpreter not set')
const interpreter = await this.waitUntilReady()
// * Raise an error if the user is already authenticated
if (this.isAuthenticated()) {
@@ -160,8 +155,8 @@ export class HasuraAuthClient {
if ('provider' in params) {
const { provider, options } = params
const providerUrl = encodeQueryParameters(
`${this.#client.backendUrl}/v1/auth/signin/provider/${provider}`,
rewriteRedirectTo(this.#client.clientUrl, options)
`${this._client.backendUrl}/signin/provider/${provider}`,
rewriteRedirectTo(this._client.clientUrl, options)
)
if (isBrowser()) {
window.location.href = providerUrl
@@ -282,8 +277,7 @@ export class HasuraAuthClient {
* @docs https://docs.nhost.io/reference/sdk/authentication#nhost-auth-signout
*/
async signOut(params?: { all?: boolean }): Promise<ApiSignOutResponse> {
const interpreter = this.#client.interpreter
if (!interpreter) throw Error('Auth interpreter not set')
const interpreter = await this.waitUntilReady()
if (!this.isAuthenticated()) return { error: USER_UNAUTHENTICATED }
return new Promise((resolve) => {
interpreter.send({ type: 'SIGNOUT', all: params?.all })
@@ -305,7 +299,7 @@ export class HasuraAuthClient {
*/
async resetPassword({ email, options }: ResetPasswordParams): Promise<ApiResetPasswordResponse> {
return new Promise((resolve) => {
const service = interpret(createResetPasswordMachine(this.#client))
const service = interpret(createResetPasswordMachine(this._client))
service.onTransition(({ event }) => {
if (event.type === 'ERROR') return resolve({ error: event.error })
else if (event.type === 'SUCCESS') return resolve({ error: null })
@@ -325,7 +319,7 @@ export class HasuraAuthClient {
*/
async changePassword(params: ChangePasswordParams): Promise<ApiChangePasswordResponse> {
return new Promise((resolve) => {
const service = interpret(createChangePasswordMachine(this.#client))
const service = interpret(createChangePasswordMachine(this._client))
service.onTransition(({ event }) => {
if (event.type === 'ERROR') return resolve({ error: event.error })
else if (event.type === 'SUCCESS') return resolve({ error: null })
@@ -348,7 +342,7 @@ export class HasuraAuthClient {
params: SendVerificationEmailParams
): Promise<ApiSendVerificationEmailResponse> {
return new Promise((resolve) => {
const service = interpret(createSendVerificationEmailMachine(this.#client))
const service = interpret(createSendVerificationEmailMachine(this._client))
service.onTransition(({ event }) => {
if (event.type === 'ERROR') return resolve({ error: event.error })
else if (event.type === 'SUCCESS') return resolve({ error: null })
@@ -368,7 +362,7 @@ export class HasuraAuthClient {
*/
async changeEmail({ newEmail, options }: ChangeEmailParams): Promise<ApiChangeEmailResponse> {
return new Promise((resolve) => {
const service = interpret(createChangeEmailMachine(this.#client))
const service = interpret(createChangeEmailMachine(this._client))
service.onTransition(({ event }) => {
if (event.type === 'ERROR') return resolve({ error: event.error })
else if (event.type === 'SUCCESS') return resolve({ error: null })
@@ -387,9 +381,8 @@ export class HasuraAuthClient {
* @docs https://docs.nhost.io/TODO
*/
async deanonymize(params: DeanonymizeParams): Promise<ApiDeanonymizeResponse> {
const interpreter = await this.waitUntilReady()
return new Promise((resolve) => {
const interpreter = this.#client.interpreter
if (!interpreter) throw Error('Auth interpreter not set')
if (!this.isAuthenticated() || !interpreter.state.context.user?.isAnonymous)
return { error: USER_NOT_ANONYMOUS }
interpreter.onTransition((state) => {
@@ -419,17 +412,23 @@ export class HasuraAuthClient {
* @docs https://docs.nhost.io/TODO
*/
onTokenChanged(fn: OnTokenChangedFunction): Function {
if (this.#client.interpreter)
this.onTokenChangedSubscriptions.add(
this.#client.interpreter?.onTransition(({ event, context }) => {
if (event.type === 'TOKEN_CHANGED') fn(getSession(context))
})
)
else {
console.log('onTokenChanged: no interpreter is set yet', fn)
}
return () => {
this.onTokenChangedSubscriptions.forEach((subscription) => subscription.stop())
const listen = (interpreter: AuthInterpreter) =>
interpreter.onTransition(({ event, context }) => {
if (event.type === 'TOKEN_CHANGED') fn(getSession(context))
})
if (this._client.interpreter) {
const subscription = listen(this._client.interpreter)
return () => subscription.stop()
} else {
this._client.onStart((client) => {
listen(client.interpreter as AuthInterpreter)
})
return () => {
console.log(
'onTokenChanged was added before the interpreter started. Cannot unsubscribe listener.'
)
}
}
}
@@ -446,18 +445,23 @@ export class HasuraAuthClient {
* @docs https://docs.nhost.io/reference/sdk/authentication#nhost-auth-onauthstatechangedevent,-session
*/
onAuthStateChanged(fn: AuthChangedFunction): Function {
if (this.#client.interpreter)
this.onAuthStateChangedSubscriptions.add(
this.#client.interpreter?.onTransition(({ event, context }) => {
if (event.type === 'SIGNED_IN') fn('SIGNED_IN', getSession(context))
else if (event.type === 'SIGNED_OUT') fn('SIGNED_OUT', getSession(context))
})
)
else {
console.log('onAuthStateChanged: no interpreter is set yet', fn)
}
return () => {
this.onAuthStateChangedSubscriptions.forEach((subscription) => subscription.stop())
const listen = (interpreter: AuthInterpreter) =>
interpreter.onTransition(({ event, context }) => {
if (event.type === 'SIGNED_IN' || event.type === 'SIGNED_OUT')
fn(event.type, getSession(context))
})
if (this._client.interpreter) {
const subscription = listen(this._client.interpreter)
return () => subscription.stop()
} else {
this._client.onStart((client) => {
listen(client.interpreter as AuthInterpreter)
})
return () => {
console.log(
'onAuthStateChanged was added before the interpreter started. Cannot unsubscribe listener.'
)
}
}
}
@@ -479,7 +483,7 @@ export class HasuraAuthClient {
* @docs https://docs.nhost.io/TODO
*/
isAuthenticated(): boolean {
return !!this.#client.interpreter?.state.matches({ authentication: 'signedIn' })
return !!this._client.interpreter?.state.matches({ authentication: 'signedIn' })
}
/**
@@ -496,15 +500,8 @@ export class HasuraAuthClient {
* @docs https://docs.nhost.io/TODO
*/
async isAuthenticatedAsync(): Promise<boolean> {
return new Promise((resolve) => {
// if init auth loading is already completed, we can return the value of `isAuthenticated`.
if (this.isReady()) resolve(this.isAuthenticated())
const interpreter = this.#client.interpreter
if (!interpreter) resolve(false)
interpreter?.onTransition((state) => {
if (state.hasTag('ready')) resolve(state.matches({ authentication: 'signedIn' }))
})
})
const interpreter = await this.waitUntilReady()
return interpreter.state.matches({ authentication: 'signedIn' })
}
/**
@@ -555,7 +552,7 @@ export class HasuraAuthClient {
* @docs https://docs.nhost.io/TODO
*/
getAccessToken(): string | undefined {
return this.#client.interpreter?.state.context.accessToken.value ?? undefined
return this._client.interpreter?.state.context.accessToken.value ?? undefined
}
/**
@@ -571,20 +568,24 @@ export class HasuraAuthClient {
* @docs https://docs.nhost.io/TODO
*/
async refreshSession(refreshToken?: string): Promise<void> {
return new Promise((resolve) => {
const interpreter = this.#client.interpreter
if (!interpreter || !interpreter.state.matches({ token: 'idle' })) return resolve()
const token = refreshToken || interpreter.state.context.refreshToken.value
if (!token) return resolve()
interpreter?.onTransition((state) => {
if (state.matches({ token: { idle: 'error' } })) resolve()
else if (state.event.type === 'TOKEN_CHANGED') resolve()
try {
const interpreter = await this.waitUntilReady()
if (interpreter.state.matches({ token: 'idle' })) return
return new Promise((resolve) => {
const token = refreshToken || interpreter.state.context.refreshToken.value
if (!token) return resolve()
interpreter?.onTransition((state) => {
if (state.matches({ token: { idle: 'error' } })) resolve()
else if (state.event.type === 'TOKEN_CHANGED') resolve()
})
interpreter.send({
type: 'TRY_TOKEN',
token
})
})
interpreter.send({
type: 'TRY_TOKEN',
token
})
})
} catch {
return
}
}
/**
@@ -598,7 +599,7 @@ export class HasuraAuthClient {
* @docs https://docs.nhost.io/TODO
*/
getSession() {
return getSession(this.#client.interpreter?.state?.context)
return getSession(this._client.interpreter?.state?.context)
}
/**
@@ -612,14 +613,39 @@ export class HasuraAuthClient {
* @docs https://docs.nhost.io/reference/sdk/authentication#nhost-auth-getuser
*/
getUser() {
return this.#client.interpreter?.state?.context?.user || null
return this._client.interpreter?.state?.context?.user || null
}
/**
* Make sure the state machine is set, and wait for it to be ready
* @returns
*/
private waitUntilReady(): Promise<AuthInterpreter> {
const TIMEOUT_IN_SECONS = 15
const interpreter = this._client.interpreter
if (!interpreter) {
throw Error('Auth interpreter not set')
}
if (interpreter.state.hasTag('ready')) return Promise.resolve(interpreter)
return new Promise((resolve, reject) => {
let timer: ReturnType<typeof setTimeout> = setTimeout(
() => reject(`The state machine is not yet ready after ${TIMEOUT_IN_SECONS} seconds.`),
TIMEOUT_IN_SECONS * 1_000
)
interpreter.onTransition((state) => {
if (state.hasTag('ready')) {
clearTimeout(timer)
return resolve(interpreter)
}
})
})
}
private isReady() {
return !!this.#client.interpreter?.state?.hasTag('ready')
return !!this._client.interpreter?.state?.hasTag('ready')
}
get client() {
return this.#client
return this._client
}
}

View File

@@ -1,15 +1,30 @@
import { AuthClient, StorageGetter, StorageSetter, User } from '@nhost/core'
import {
AuthClient,
PasswordlessOptions,
Provider,
ProviderOptions,
RedirectOption,
SignUpOptions,
StorageGetter,
StorageSetter,
User
} from '@nhost/core'
export type { AuthClient, Provider, StorageGetter, StorageSetter, User }
export interface NhostAuthConstructorParams {
url: string
/** Time interval until token refreshes, in seconds */
refreshIntervalTime?: number
/** @deprecated Use clientStorageGetter and clientStorageSetter options instead */
clientStorage?: ClientStorage
/** @deprecated Use clientStorageGetter and clientStorageSetter options instead */
clientStorageType?: ClientStorageType
/** Define a way to get information about the refresh token and its exipration date */
clientStorageGetter?: StorageGetter
/** Define a way to set information about the refresh token and its exipration date */
clientStorageSetter?: StorageSetter
/** When set to true, will automatically refresh token before it expires */
autoRefreshToken?: boolean
/** When set to true, will parse the url on startup to check if it contains a refresh token to start the session with */
autoLogin?: boolean
start?: boolean
Client?: typeof AuthClient
@@ -30,14 +45,7 @@ export interface ApiError {
export interface SignUpEmailPasswordParams {
email: string
password: string
options?: {
locale?: string
allowedRoles?: string[]
defaultRole?: string
displayName?: string
redirectTo?: string
metadata?: Record<string, unknown>
}
options?: SignUpOptions
}
export type SignUpParams = SignUpEmailPasswordParams
@@ -54,55 +62,21 @@ export interface SignInEmailPasswordParams {
export interface SignInPasswordlessEmailParams {
email: string
options?: {
locale?: string
allowedRoles?: string[]
defaultRole?: string
displayName?: string
redirectTo?: string
metadata?: Record<string, unknown>
}
options?: PasswordlessOptions
}
export interface SignInPasswordlessSmsParams {
phoneNumber: string
options?: {
locale?: string
allowedRoles?: string[]
defaultRole?: string
displayName?: string
redirectTo?: string
metadata?: Record<string, unknown>
}
options?: PasswordlessOptions
}
export interface SignInPasswordlessSmsOtpParams {
phoneNumber: string
otp: string
}
export type Provider =
| 'facebook'
| 'github'
| 'google'
| 'linkedin'
| 'spotify'
| 'discord'
| 'twitch'
| 'apple'
| 'twitter'
| 'windowslive'
export interface SignInWithProviderOptions {
provider: Provider
options?: {
locale?: string
allowedRoles?: string[]
defaultRole?: string
displayName?: string
redirectTo?: string
metadata?: Record<string, unknown>
}
options?: ProviderOptions
}
export type SignInParams =
@@ -125,18 +99,15 @@ export interface ChangePasswordParams {
export interface SendVerificationEmailParams {
email: string
options?: {
redirectTo?: string
}
options?: RedirectOption
}
export interface ChangeEmailParams {
newEmail: string
options?: {
redirectTo?: string
}
options?: RedirectOption
}
// TODO define type in @nhost/core
export interface DeanonymizeParams {
signInMethod: 'email-password' | 'passwordless'
email: string

View File

@@ -1,6 +1,67 @@
# @nhost/nextjs
## 2.0.0
## 1.0.12
### Patch Changes
- @nhost/nhost-js@1.0.11
- @nhost/react@0.5.2
## 1.0.11
### Patch Changes
- Updated dependencies [2c97db6]
- @nhost/nhost-js@1.0.10
- @nhost/react@0.5.1
## 1.0.10
### Patch Changes
- Updated dependencies [7cf875f]
- Updated dependencies [7135aee]
- Updated dependencies [587eaff]
- @nhost/react@0.5.0
- @nhost/nhost-js@1.0.9
## 1.0.9
### Patch Changes
- @nhost/nhost-js@1.0.8
- @nhost/react@0.4.7
## 1.0.8
### Patch Changes
- @nhost/nhost-js@1.0.5
- @nhost/react@0.4.4
## 1.0.5
### Patch Changes
- correct dependencies
See this related issues:
- [nhost](https://github.com/nhost/nhost/issues/326)
- [pnpm](https://github.com/pnpm/pnpm/issues/4348)
- Updated dependencies
- @nhost/nhost-js@1.0.3
- @nhost/react@0.4.2
## 1.0.3
### Patch Changes
- @nhost/nhost-js@1.0.2
- @nhost/react@0.4.1
## 1.0.2
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/nextjs",
"version": "2.0.0",
"version": "1.0.12",
"description": "Nhost NextJS library",
"license": "MIT",
"keywords": [

View File

@@ -1,5 +1,66 @@
# @nhost/nhost-js
## 1.0.11
### Patch Changes
- Updated dependencies [63d6059]
- Updated dependencies [63d6059]
- Updated dependencies [63d6059]
- @nhost/hasura-auth-js@1.0.11
## 1.0.10
### Patch Changes
- 2c97db6: Keep authentication status and access token in sync
The authentication events where not set correctly, leading the main Nhost client not to update internal states of storage/graphql/functions sub-clients when using non-react clients.
The use of private fields (`#`) is also avoided as they conflict with the use of proxies in Vue, leading to errors in the upcoming Vue library.
Fixes #373 and #378
- Updated dependencies [2c97db6]
- @nhost/hasura-auth-js@1.0.10
## 1.0.9
### Patch Changes
- Updated dependencies [058956b]
- @nhost/hasura-auth-js@1.0.9
## 1.0.8
### Patch Changes
- Updated dependencies [6be3758]
- @nhost/hasura-auth-js@1.0.8
## 1.0.7
### Patch Changes
- @nhost/hasura-auth-js@1.0.5
## 1.0.4
### Patch Changes
- correct dependencies
See this related issues:
- [nhost](https://github.com/nhost/nhost/issues/326)
- [pnpm](https://github.com/pnpm/pnpm/issues/4348)
- Updated dependencies
- @nhost/hasura-auth-js@1.0.3
## 1.0.2
### Patch Changes
- Updated dependencies [6eeb9d2]
- @nhost/hasura-auth-js@1.0.2
## 1.0.1
### Patch Changes
@@ -25,8 +86,6 @@
### Patch Changes
- Updated dependencies [744fd69]
- Updated dependencies [744fd69]
- Updated dependencies [744fd69]
- @nhost/hasura-auth-js@1.0.0
- @nhost/hasura-storage-js@0.2.0
@@ -46,7 +105,6 @@
Some systems based on older versions of Webpack or Babel don't support the current esbuild configuration e.g, [this issue](https://github.com/nhost/nhost/issues/275).
- Updated dependencies [e688600]
- Updated dependencies [8f7643a]
- Updated dependencies [e688600]
- Updated dependencies [50b9d76]
- @nhost/hasura-auth-js@0.1.15
- @nhost/hasura-storage-js@0.0.12

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/nhost-js",
"version": "1.0.1",
"version": "1.0.11",
"description": "Nhost JavaScript SDK",
"license": "MIT",
"keywords": [

View File

@@ -60,20 +60,22 @@ export class NhostClient {
url: `${backendUrl}/v1/graphql`
})
// set current token if token is already accessable
// * Set current token if token is already accessable
this.storage.setAccessToken(this.auth.getAccessToken())
this.functions.setAccessToken(this.auth.getAccessToken())
this.graphql.setAccessToken(this.auth.getAccessToken())
this.auth.client.onStart(() => {
// update access token for clients
// * Set access token when signing out
this.auth.onAuthStateChanged((_event, session) => {
this.storage.setAccessToken(session?.accessToken)
this.functions.setAccessToken(session?.accessToken)
this.graphql.setAccessToken(session?.accessToken)
if (_event === 'SIGNED_OUT') {
this.storage.setAccessToken(undefined)
this.functions.setAccessToken(undefined)
this.graphql.setAccessToken(undefined)
}
})
// update access token for clients
// * Update access token for clients, including when signin in
this.auth.onTokenChanged((session) => {
this.storage.setAccessToken(session?.accessToken)
this.functions.setAccessToken(session?.accessToken)

View File

@@ -1,6 +1,68 @@
# @nhost/react-apollo
## 5.0.0
## 4.0.12
### Patch Changes
- @nhost/react@0.5.2
- @nhost/apollo@0.3.9
## 4.0.11
### Patch Changes
- 8583af8: correct documentation link in readme
- @nhost/apollo@0.3.8
- @nhost/react@0.5.1
## 4.0.10
### Patch Changes
- Updated dependencies [7cf875f]
- Updated dependencies [7135aee]
- Updated dependencies [587eaff]
- @nhost/react@0.5.0
- @nhost/apollo@0.3.7
## 4.0.9
### Patch Changes
- @nhost/react@0.4.7
- @nhost/apollo@0.3.6
## 4.0.8
### Patch Changes
- @nhost/apollo@0.3.4
- @nhost/react@0.4.4
## 4.0.5
### Patch Changes
- correct dependencies
See this related issues:
- [nhost](https://github.com/nhost/nhost/issues/326)
- [pnpm](https://github.com/pnpm/pnpm/issues/4348)
- Updated dependencies
- @nhost/apollo@0.3.2
- @nhost/react@0.4.2
## 4.0.3
### Patch Changes
- Updated dependencies [113beed]
- @nhost/apollo@0.3.1
- @nhost/react@0.4.1
## 4.0.2
### Patch Changes

View File

@@ -38,4 +38,4 @@ ReactDOM.render(
## Documentation
[https://docs.nhost.io/reference/supporting-libraries/react-apollo](https://docs.nhost.io/reference/supporting-libraries/react-apollo)
[https://docs.nhost.io/reference/react/apollo](https://docs.nhost.io/reference/react/apollo)

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/react-apollo",
"version": "5.0.0",
"version": "4.0.12",
"description": "Nhost React Apollo client",
"license": "MIT",
"keywords": [

View File

@@ -1,5 +1,102 @@
# @nhost/react
## 0.5.2
### Patch Changes
- @nhost/nhost-js@1.0.11
## 0.5.1
### Patch Changes
- Updated dependencies [2c97db6]
- @nhost/nhost-js@1.0.10
## 0.5.0
### Minor Changes
- 7135aee: Add user and accessToken to authentication hooks
Hooks that can complete a successful authentication now have two additional `user` and `accessToken` exported states:
- `useSignInEmailPassword`
- `useSignInAnonymous`
- `useSignUpEmailPassword`
- 587eaff: Return a promise with the current context to hooks actions
It is now possible to get the result of an action. Hook handlers return the action context in a promise.
```jsx
const { signInEmailPasswordless, isError } = useSignInEmailPasswordless()
const MyComponent = () => {
return <div>
<button onClick={async () => {
const { isSuccess, isError, error } = await signInEmailPasswordless('johan@ikea.se')
if (isError) {
console.log(error)
}}}/>
{isError && <div>an error occurred</div>}
<div>
}
```
### Patch Changes
- 7cf875f: Deprecate the use of values sent as hook parameters
Although handlers parameters of authentication hooks can be given when creating the hook, it is recommended to use them when executing the handler. For instance, instead of:
```js
const { signInEmailPasswordless } = useSignInEmailPasswordless('nuno@fcporto.pt')
signInEmailPasswordless()
```
It is recommended to use the following syntax:
```js
const { signInEmailPasswordless } = useSignInEmailPasswordless()
signInEmailPasswordless('nuno@fcporto.pt')
```
No breaking change has been introduced. For instance, `useSignUpEmailPassword('szilard@brussels.be','1234', options)` will appear as deprecated but will work, while `useSignUpEmailPassword(options)` will work too.
- @nhost/nhost-js@1.0.9
## 0.4.7
### Patch Changes
- @nhost/nhost-js@1.0.8
## 0.4.6
### Patch Changes
- @nhost/nhost-js@1.0.5
## 0.4.3
### Patch Changes
- correct dependencies
See this related issues:
- [nhost](https://github.com/nhost/nhost/issues/326)
- [pnpm](https://github.com/pnpm/pnpm/issues/4348)
- Updated dependencies
- @nhost/nhost-js@1.0.3
## 0.4.1
### Patch Changes
- @nhost/nhost-js@1.0.2
## 0.4.0
### Minor Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/react",
"version": "0.4.0",
"version": "0.5.2",
"description": "Nhost React library",
"license": "MIT",
"keywords": [

View File

@@ -5,35 +5,123 @@ import {
PasswordlessOptions,
Provider,
ProviderOptions,
rewriteRedirectTo
rewriteRedirectTo,
User
} from '@nhost/core'
import { useSelector } from '@xstate/react'
import { NhostReactContext } from '../provider'
import { useAuthenticated, useAuthInterpreter } from './common'
import { ActionHookState, useAuthenticated, useAuthInterpreter } from './common'
export const useSignInEmailPassword = (
type SignInEmailPasswordHookState = ActionHookState & {
needsMfaOtp: boolean
needsEmailVerification: boolean
user: User | null
accessToken: string | null
}
type SignInEmailPasswordHandlerResult = Omit<SignInEmailPasswordHookState, 'isLoading'>
type SignInEmailPasswordHandler = {
(email: string, password: string): Promise<SignInEmailPasswordHandlerResult>
/** @deprecated */
(email?: unknown, password?: string): Promise<SignInEmailPasswordHandlerResult>
}
type SendMfaOtpHander = {
(otp: string): void
/** @deprecated */
(otp?: unknown): void
}
type SignInEmailPasswordHookResult = {
signInEmailPassword: SignInEmailPasswordHandler
sendMfaOtp: SendMfaOtpHander
} & SignInEmailPasswordHookState
type SignInEmailPasswordHook = {
(): SignInEmailPasswordHookResult
/** @deprecated */
(email?: string, password?: string, otp?: string): SignInEmailPasswordHookResult
}
export const useSignInEmailPassword: SignInEmailPasswordHook = (
stateEmail?: string,
statePassword?: string,
stateOtp?: string
) => {
const service = useAuthInterpreter()
const signInEmailPassword = (valueEmail?: string | unknown, valuePassword?: string | unknown) =>
service.send({
type: 'SIGNIN_PASSWORD',
email: typeof valueEmail === 'string' ? valueEmail : stateEmail,
password: typeof valuePassword === 'string' ? valuePassword : statePassword
const signInEmailPassword: SignInEmailPasswordHandler = (
valueEmail?: string | unknown,
valuePassword?: string
) =>
new Promise<SignInEmailPasswordHandlerResult>((resolve) => {
service.send({
type: 'SIGNIN_PASSWORD',
email: typeof valueEmail === 'string' ? valueEmail : stateEmail,
password: typeof valuePassword === 'string' ? valuePassword : statePassword
})
service.onTransition((state) => {
if (state.matches({ authentication: { signedOut: 'needsEmailVerification' } })) {
resolve({
accessToken: null,
error: null,
isError: false,
isSuccess: false,
needsEmailVerification: true,
needsMfaOtp: false,
user: null
})
} else if (state.matches({ authentication: { signedOut: 'needsMfa' } })) {
resolve({
accessToken: null,
error: null,
isError: false,
isSuccess: false,
needsEmailVerification: false,
needsMfaOtp: true,
user: null
})
} else if (state.matches({ authentication: { signedOut: 'failed' } })) {
resolve({
accessToken: null,
error: state.context.errors.authentication || null,
isError: true,
isSuccess: false,
needsEmailVerification: false,
needsMfaOtp: false,
user: null
})
} else if (state.matches({ authentication: 'signedIn' })) {
resolve({
accessToken: state.context.accessToken.value,
error: null,
isError: false,
isSuccess: true,
needsEmailVerification: false,
needsMfaOtp: false,
user: state.context.user
})
}
})
})
const sendMfaOtp = (valueOtp?: string | unknown) => {
const sendMfaOtp: SendMfaOtpHander = (valueOtp?: string | unknown) => {
service.send({
type: 'SIGNIN_MFA_TOTP',
otp: typeof valueOtp === 'string' ? valueOtp : stateOtp
})
}
const user = useSelector(
service,
(state) => state.context.user,
(a, b) => a?.id === b?.id
)
const accessToken = useSelector(service, (state) => state.context.accessToken.value)
const error = useSelector(
service,
(state) => state.context.errors.authentication,
(state) => state.context.errors.authentication || null,
(a, b) => a?.error === b?.error
)
const isSuccess = useAuthenticated()
@@ -59,32 +147,70 @@ export const useSignInEmailPassword = (
)
return {
signInEmailPassword,
accessToken,
error,
isError,
isLoading,
isSuccess,
needsEmailVerification,
needsMfaOtp,
sendMfaOtp,
isError,
error
signInEmailPassword,
user
}
}
export const useSignInEmailPasswordless = (
stateEmail?: string,
stateOptions?: PasswordlessOptions
type SignInEmailPasswordlessHandlerResult = Omit<ActionHookState, 'isLoading'>
type SignInEmailPasswordlessHandler = {
(email: string, options?: PasswordlessOptions): Promise<SignInEmailPasswordlessHandlerResult>
/** @deprecated */
(email?: unknown, options?: PasswordlessOptions): Promise<SignInEmailPasswordlessHandlerResult>
}
type SignInEmailPasswordlessHookResult = {
signInEmailPasswordless: SignInEmailPasswordlessHandler
} & ActionHookState
type SignInEmailPasswordlessdHook = {
(options?: PasswordlessOptions): SignInEmailPasswordlessHookResult
/** @deprecated */
(email?: string, options?: PasswordlessOptions): SignInEmailPasswordlessHookResult
}
export const useSignInEmailPasswordless: SignInEmailPasswordlessdHook = (
a?: string | PasswordlessOptions,
b?: PasswordlessOptions
) => {
const stateEmail = typeof a === 'string' ? a : undefined
const stateOptions = typeof a === 'string' ? b : a
const service = useAuthInterpreter()
const signInEmailPasswordless = (valueEmail?: string | unknown, valueOptions = stateOptions) =>
service.send({
type: 'SIGNIN_PASSWORDLESS_EMAIL',
email: typeof valueEmail === 'string' ? valueEmail : stateEmail,
options: valueOptions
const signInEmailPasswordless: SignInEmailPasswordlessHandler = (
valueEmail?: string | unknown,
valueOptions = stateOptions
) =>
new Promise<SignInEmailPasswordlessHandlerResult>((resolve) => {
service.send({
type: 'SIGNIN_PASSWORDLESS_EMAIL',
email: typeof valueEmail === 'string' ? valueEmail : stateEmail,
options: valueOptions
})
service.onTransition((state) => {
if (state.matches({ authentication: { signedOut: 'failed' } })) {
resolve({
error: state.context.errors.authentication || null,
isError: true,
isSuccess: false
})
} else if (state.matches({ authentication: { signedOut: 'needsEmailVerification' } })) {
resolve({ error: null, isError: false, isSuccess: true })
}
})
})
const error = useSelector(
service,
(state) => state.context.errors.authentication,
(state) => state.context.errors.authentication || null,
(a, b) => a?.error === b?.error
)
const isLoading =
@@ -93,9 +219,9 @@ export const useSignInEmailPasswordless = (
const isSuccess =
!!service.status &&
service.state.matches({ authentication: { signedOut: 'needsEmailVerification' } })
const isError =
!!service.status && service.state.matches({ authentication: { signedOut: 'failed' } })
return { signInEmailPasswordless, isLoading, isSuccess, isError, error }
}
@@ -115,7 +241,13 @@ export const useSignInAnonymous = () => {
const isSuccess = useAuthenticated()
const isError =
!!service.status && service.state.matches({ authentication: { signedOut: 'failed' } })
return { signInAnonymous, isLoading, isSuccess, isError, error }
const user = useSelector(
service,
(state) => state.context.user,
(a, b) => a?.id === b?.id
)
const accessToken = useSelector(service, (state) => state.context.accessToken.value)
return { accessToken, error, isError, isLoading, isSuccess, signInAnonymous, user }
}
export const useProviderLink = (options?: ProviderOptions) => {

View File

@@ -1,12 +1,19 @@
import { useContext, useEffect, useState } from 'react'
import { InterpreterFrom } from 'xstate'
import { AuthMachine } from '@nhost/core'
import { AuthMachine, ErrorPayload } from '@nhost/core'
import { NhostClient } from '@nhost/nhost-js'
import { useSelector } from '@xstate/react'
import { NhostReactContext } from '../provider'
export type ActionHookState<T extends string = 'isSuccess'> = {
isLoading: boolean
isError: boolean
error: ErrorPayload | null
} & Record<T, boolean>
export const useNhostClient = (): NhostClient => {
const nhost = useContext(NhostReactContext)
return nhost

View File

@@ -1,21 +1,55 @@
import { useMemo } from 'react'
import { SignUpOptions } from '@nhost/core'
import { SignUpOptions, User } from '@nhost/core'
import { useSelector } from '@xstate/react'
import { useAuthenticationStatus, useAuthInterpreter } from './common'
import { ActionHookState, useAuthenticationStatus, useAuthInterpreter } from './common'
export const useSignUpEmailPassword = (
stateEmail?: string,
statePassword?: string,
stateOptions?: SignUpOptions
type SignUpEmailPasswordHookState = ActionHookState & {
needsEmailVerification: boolean
user: User | null
accessToken: string | null
}
type SignUpEmailPasswordHandlerResult = Omit<SignUpEmailPasswordHookState, 'isLoading'>
type SignUpEmailPasswordHandler = {
(
email: string,
password: string,
options?: SignUpOptions
): Promise<SignUpEmailPasswordHandlerResult>
/** @deprecated */
(
email?: unknown,
password?: string,
options?: SignUpOptions
): Promise<SignUpEmailPasswordHandlerResult>
}
type SignUpEmailPasswordHookResult = {
signUpEmailPassword: SignUpEmailPasswordHandler
} & SignUpEmailPasswordHookState
type SignUpEmailPasswordHook = {
(options?: SignUpOptions): SignUpEmailPasswordHookResult
/** @deprecated */
(email?: string, password?: string, options?: SignUpOptions): SignUpEmailPasswordHookResult
}
export const useSignUpEmailPassword: SignUpEmailPasswordHook = (
a?: string | SignUpOptions,
b?: string,
c?: SignUpOptions
) => {
const stateEmail: string | undefined = typeof a === 'string' ? a : undefined
const statePassword: string | undefined = typeof b === 'string' ? b : undefined
const stateOptions = c || (typeof a !== 'string' ? a : undefined)
const service = useAuthInterpreter()
const isError =
!!service.status && service.state.matches({ authentication: { signedOut: 'failed' } })
const error = useSelector(
service,
(state) => state.context.errors.registration,
(state) => state.context.errors.registration || null,
(a, b) => a?.error === b?.error
)
const { isLoading: loading, isAuthenticated: isSuccess } = useAuthenticationStatus()
@@ -24,23 +58,65 @@ export const useSignUpEmailPassword = (
!!service.status &&
service.state.matches({ authentication: { signedOut: 'needsEmailVerification' } })
const signUpEmailPassword = (
const signUpEmailPassword: SignUpEmailPasswordHandler = (
valueEmail?: string | unknown,
valuePassword = statePassword,
valueOptions = stateOptions
) =>
service.send({
type: 'SIGNUP_EMAIL_PASSWORD',
email: typeof valueEmail === 'string' ? valueEmail : stateEmail,
password: valuePassword,
options: valueOptions
new Promise<SignUpEmailPasswordHandlerResult>((resolve) => {
service.send({
type: 'SIGNUP_EMAIL_PASSWORD',
email: typeof valueEmail === 'string' ? valueEmail : stateEmail,
password: valuePassword,
options: valueOptions
})
service.onTransition((state) => {
if (state.matches({ authentication: { signedOut: 'failed' } })) {
resolve({
accessToken: null,
error: state.context.errors.registration || null,
isError: true,
isSuccess: false,
needsEmailVerification: false,
user: null
})
} else if (state.matches({ authentication: { signedOut: 'needsEmailVerification' } })) {
resolve({
accessToken: null,
error: null,
isError: false,
isSuccess: false,
needsEmailVerification: true,
user: null
})
} else if (state.matches({ authentication: 'signedIn' })) {
resolve({
accessToken: state.context.accessToken.value,
error: null,
isError: false,
isSuccess: true,
needsEmailVerification: false,
user: state.context.user
})
}
})
})
const user = useSelector(
service,
(state) => state.context.user,
(a, b) => a?.id === b?.id
)
const accessToken = useSelector(service, (state) => state.context.accessToken.value)
return {
signUpEmailPassword,
accessToken,
error,
isError,
isLoading,
isSuccess,
isError,
error,
needsEmailVerification
needsEmailVerification,
signUpEmailPassword,
user
}
}

View File

@@ -1,4 +1,4 @@
import { useMemo } from 'react'
import { useMemo, useState } from 'react'
import {
ChangeEmailOptions,
@@ -7,64 +7,171 @@ import {
createEnableMfaMachine,
createResetPasswordMachine,
createSendVerificationEmailMachine,
ErrorPayload,
ResetPasswordOptions,
SendVerificationEmailOptions
} from '@nhost/core'
import { useMachine, useSelector } from '@xstate/react'
import { useAuthInterpreter, useNhostClient } from './common'
import { ActionHookState, useAuthInterpreter, useNhostClient } from './common'
export const useChangeEmail = (stateEmail?: string, stateOptions?: ChangeEmailOptions) => {
type ChangeEmailHookState = ActionHookState<'needsEmailVerification'>
type ChangeEmailHandlerResult = Omit<ChangeEmailHookState, 'isLoading'>
type ChangeEmailHandler = {
(email: string, options?: ChangeEmailOptions): Promise<ChangeEmailHandlerResult>
/** @deprecated */
(email?: unknown, options?: ChangeEmailOptions): Promise<ChangeEmailHandlerResult>
}
type ChangeEmailHookResult = {
changeEmail: ChangeEmailHandler
} & ChangeEmailHookState
type ChangeEmailHook = {
(options?: ChangeEmailOptions): ChangeEmailHookResult
/** @deprecated */
(email?: string, options?: ChangeEmailOptions): ChangeEmailHookResult
}
export const useChangeEmail: ChangeEmailHook = (
a?: string | ChangeEmailOptions,
b?: ChangeEmailOptions
) => {
const stateEmail = typeof a === 'string' ? a : undefined
const stateOptions = typeof a !== 'string' ? a : b
const nhost = useNhostClient()
const machine = useMemo(() => createChangeEmailMachine(nhost.auth.client), [nhost])
const [current, send] = useMachine(machine)
const isError = current.matches({ idle: 'error' })
const needsEmailVerification = current.matches({ idle: 'success' })
const error = current.context.error
const isLoading = current.matches('requesting')
const changeEmail = (valueEmail?: string | unknown, valueOptions = stateOptions) =>
send({
type: 'REQUEST',
email: typeof valueEmail === 'string' ? valueEmail : stateEmail,
options: valueOptions
const [, send, service] = useMachine(machine)
const [isError, setIsError] = useState(false)
const [needsEmailVerification, setNeedsEmailVerification] = useState(false)
const [error, setError] = useState<ErrorPayload | null>(null)
const [isLoading, setIsLoading] = useState(false)
const changeEmail: ChangeEmailHandler = async (
valueEmail?: string | unknown,
valueOptions = stateOptions
) =>
new Promise<ChangeEmailHandlerResult>((resolve) => {
send({
type: 'REQUEST',
email: typeof valueEmail === 'string' ? valueEmail : stateEmail,
options: valueOptions
})
service.onTransition((state) => {
if (state.matches({ idle: 'error' })) {
const error = state.context.error
setIsError(true)
setError(error)
setIsLoading(false)
resolve({ isError: true, error, needsEmailVerification })
} else if (state.matches('requesting')) {
setIsLoading(true)
} else if (state.matches({ idle: 'success' })) {
setIsError(false)
setError(null)
setIsLoading(false)
setNeedsEmailVerification(true)
resolve({ isError: false, error: null, needsEmailVerification: true })
}
})
})
return { changeEmail, isLoading, needsEmailVerification, isError, error }
}
export const useChangePassword = (statePassword?: string) => {
type ChangePasswordHandlerResult = Omit<ActionHookState, 'isLoading'>
type ChangePasswordHandler = {
(password: string): Promise<ChangePasswordHandlerResult>
/** @deprecated */
(password?: unknown): Promise<ChangePasswordHandlerResult>
}
type ChangePasswordHookResult = {
changePassword: ChangePasswordHandler
} & ActionHookState
type ChangePasswordHook = {
(): ChangePasswordHookResult
/** @deprecated */
(email?: string): ChangePasswordHookResult
}
export const useChangePassword: ChangePasswordHook = (statePassword?: string) => {
const nhost = useNhostClient()
const machine = useMemo(() => createChangePasswordMachine(nhost.auth.client), [nhost])
const [current, send] = useMachine(machine)
const [current, send, service] = useMachine(machine)
const isError = current.matches({ idle: 'error' })
const isSuccess = current.matches({ idle: 'success' })
const error = current.context.error
const isLoading = current.matches('requesting')
const changePassword = (valuePassword?: string | unknown) =>
send({
type: 'REQUEST',
password: typeof valuePassword === 'string' ? valuePassword : statePassword
const changePassword: ChangePasswordHandler = (valuePassword?: string | unknown) =>
new Promise<ChangePasswordHandlerResult>((resolve) => {
send({
type: 'REQUEST',
password: typeof valuePassword === 'string' ? valuePassword : statePassword
})
service.onTransition((state) => {
if (state.matches({ idle: 'error' })) {
resolve({ error: state.context.error, isError: true, isSuccess: false })
} else if (state.matches({ idle: 'success' })) {
resolve({ error: null, isError: false, isSuccess: true })
}
})
})
return { changePassword, isLoading, isSuccess, isError, error }
}
export const useResetPassword = (stateEmail?: string, stateOptions?: ResetPasswordOptions) => {
type ResetPasswordHandlerResult = Omit<ResetPasswordHookState, 'isLoading'>
type ResetPasswordHandler = {
(email: string, options?: ResetPasswordOptions): Promise<ResetPasswordHandlerResult>
/** @deprecated */
(email?: unknown, options?: ResetPasswordOptions): Promise<ResetPasswordHandlerResult>
}
type ResetPasswordHookState = ActionHookState<'isSent'>
type ResetPasswordHookResult = {
resetPassword: ResetPasswordHandler
} & ResetPasswordHookState
type ResetPasswordHook = {
(options?: ResetPasswordOptions): ResetPasswordHookResult
/** @deprecated */
(email?: string, options?: ResetPasswordOptions): ResetPasswordHookResult
}
export const useResetPassword: ResetPasswordHook = (
a?: string | ResetPasswordOptions,
b?: ResetPasswordOptions
) => {
const stateEmail = typeof a === 'string' ? a : undefined
const stateOptions = typeof a !== 'string' ? a : b
const nhost = useNhostClient()
const machine = useMemo(() => createResetPasswordMachine(nhost.auth.client), [nhost])
const [current, send] = useMachine(machine)
const [current, send, service] = useMachine(machine)
const isError = current.matches({ idle: 'error' })
const isSent = current.matches({ idle: 'success' })
const error = current.context.error
const isLoading = current.matches('requesting')
const resetPassword = (valueEmail?: string | unknown, valueOptions = stateOptions) =>
send({
type: 'REQUEST',
email: typeof valueEmail === 'string' ? valueEmail : stateEmail,
options: valueOptions
const resetPassword: ResetPasswordHandler = (
valueEmail?: string | unknown,
valueOptions = stateOptions
) =>
new Promise<ResetPasswordHandlerResult>((resolve) => {
send({
type: 'REQUEST',
email: typeof valueEmail === 'string' ? valueEmail : stateEmail,
options: valueOptions
})
service.onTransition((state) => {
if (state.matches({ idle: 'error' })) {
resolve({ error: state.context.error, isError: true, isSent: false })
} else if (state.matches({ idle: 'success' })) {
resolve({ error: null, isError: false, isSent: true })
}
})
})
return { resetPassword, isLoading, isSent, isError, error }
}
@@ -150,37 +257,103 @@ export const useUserRoles = () => {
)
}
export const useSendVerificationEmail = (
stateEmail?: string,
stateOptions?: SendVerificationEmailOptions
type SendVerificationEmailHandlerResult = Omit<SendVerificationEmailHookState, 'isLoading'>
type SendVerificationEmailHandler = {
(
email: string,
options?: SendVerificationEmailOptions
): Promise<SendVerificationEmailHandlerResult>
/** @deprecated */
(
email?: unknown,
options?: SendVerificationEmailOptions
): Promise<SendVerificationEmailHandlerResult>
}
type SendVerificationEmailHookState = ActionHookState<'isSent'>
type SendVerificationEmailHookResult = {
sendEmail: SendVerificationEmailHandler
} & SendVerificationEmailHookState
type SendVerificationEmailHook = {
(options?: SendVerificationEmailOptions): SendVerificationEmailHookResult
/** @deprecated */
(email?: string, options?: SendVerificationEmailOptions): SendVerificationEmailHookResult
}
export const useSendVerificationEmail: SendVerificationEmailHook = (
a?: string | SendVerificationEmailOptions,
b?: SendVerificationEmailOptions
) => {
const stateEmail = typeof a === 'string' ? a : undefined
const stateOptions = typeof a !== 'string' ? a : b
const nhost = useNhostClient()
const machine = useMemo(() => createSendVerificationEmailMachine(nhost.auth.client), [nhost])
const [current, send] = useMachine(machine)
const [current, send, service] = useMachine(machine)
const isError = current.matches({ idle: 'error' })
const isSent = current.matches({ idle: 'success' })
const error = current.context.error
const isLoading = current.matches('requesting')
const sendEmail = (valueEmail?: string | unknown, valueOptions = stateOptions) =>
send({
type: 'REQUEST',
email: typeof valueEmail === 'string' ? valueEmail : stateEmail,
options: valueOptions
const sendEmail: SendVerificationEmailHandler = (
valueEmail?: string | unknown,
valueOptions = stateOptions
) =>
new Promise<SendVerificationEmailHandlerResult>((resolve) => {
send({
type: 'REQUEST',
email: typeof valueEmail === 'string' ? valueEmail : stateEmail,
options: valueOptions
})
service.onTransition((state) => {
if (state.matches({ idle: 'error' })) {
resolve({ error: state.context.error, isError: true, isSent: false })
} else if (state.matches({ idle: 'success' })) {
resolve({ error: null, isError: false, isSent: true })
}
})
})
return { sendEmail, isLoading, isSent, isError, error }
}
type ActivateMfaHookState = {
isActivating: boolean
isActivated: boolean
isError: boolean
error: ErrorPayload | null
}
type GenerateQrCodeHookState = {
qrCodeDataUrl: string
isGenerating: boolean
isGenerated: boolean
isError: boolean
error: ErrorPayload | null
}
type ActivateMfaHandlerResult = Omit<ActivateMfaHookState, 'isActivating'>
type ActivateMfaHandler = (code: string) => Promise<ActivateMfaHandlerResult>
type GenerateQrCodeHandlerResult = Omit<GenerateQrCodeHookState, 'isGenerating'>
type GenerateQrCodeHandler = () => Promise<GenerateQrCodeHandlerResult>
type ConfigMfaHookState = ActivateMfaHookState &
GenerateQrCodeHookState & {
generateQrCode: GenerateQrCodeHandler
activateMfa: ActivateMfaHandler
}
type ConfigMfaHook = () => ConfigMfaHookState
// TODO documentation when available in Nhost Cloud - see changelog
export const useConfigMfa = (stateCode?: string) => {
export const useConfigMfa: ConfigMfaHook = () => {
const nhost = useNhostClient()
const machine = useMemo(() => createEnableMfaMachine(nhost.auth.client), [nhost])
const [current, send] = useMachine(machine)
const [current, send, service] = useMachine(machine)
const isError = useMemo(() => {
current.matches({ idle: 'error' }) || current.matches({ generated: { idle: 'error' } })
}, [current])
const isError = useMemo(
() => current.matches({ idle: 'error' }) || current.matches({ generated: { idle: 'error' } }),
[current]
)
const isGenerating = current.matches('generating')
const isGenerated = current.matches('generated')
const isActivating = current.matches({ generated: 'activating' })
@@ -188,12 +361,41 @@ export const useConfigMfa = (stateCode?: string) => {
const error = current.context.error
const qrCodeDataUrl = current.context.imageUrl || ''
const generateQrCode = () => send('GENERATE')
const activateMfa = (valueCode?: string | unknown) =>
send({
type: 'ACTIVATE',
activeMfaType: 'totp',
code: typeof valueCode === 'string' ? valueCode : stateCode
const generateQrCode: GenerateQrCodeHandler = () =>
new Promise<GenerateQrCodeHandlerResult>((resolve) => {
send('GENERATE')
service.onTransition((state) => {
if (state.matches('generated')) {
resolve({
error: null,
isError: false,
isGenerated: true,
qrCodeDataUrl: state.context.imageUrl || ''
})
} else if (state.matches({ idle: 'error' })) {
resolve({
error: state.context.error || null,
isError: true,
isGenerated: false,
qrCodeDataUrl: ''
})
}
})
})
const activateMfa: ActivateMfaHandler = (code: string) =>
new Promise<ActivateMfaHandlerResult>((resolve) => {
send({
type: 'ACTIVATE',
activeMfaType: 'totp',
code
})
service.onTransition((state) => {
if (state.matches({ generated: 'activated' })) {
resolve({ error: null, isActivated: true, isError: false })
} else if (state.matches({ generated: { idle: 'error' } })) {
resolve({ error: state.context.error, isActivated: false, isError: true })
}
})
})
return {
generateQrCode,

435
pnpm-lock.yaml generated
View File

@@ -83,6 +83,7 @@ importers:
specifiers:
'@heroicons/react': ^1.0.5
'@mailchimp/mailchimp_marketing': ^3.0.74
'@types/node': ^17.0.21
'@types/react': ^17.0.37
autoprefixer: ^10.4.0
axios: ^0.24.0
@@ -108,6 +109,7 @@ importers:
react-dom: ^17.0.2
react-merge-refs: ^1.1.0
react-syntax-highlighter: ^15.4.5
swagger-ui-react: ^4.5.2
tailwindcss: ^2.2.19
typescript: ^4.5.2
dependencies:
@@ -132,7 +134,9 @@ importers:
react-dom: 17.0.2_react@17.0.2
react-merge-refs: 1.1.0
react-syntax-highlighter: 15.4.5_react@17.0.2
swagger-ui-react: 4.8.0_react-dom@17.0.2+react@17.0.2
devDependencies:
'@types/node': 17.0.21
'@types/react': 17.0.40
autoprefixer: 10.4.2_postcss@8.4.8
next-sitemap: 1.9.12_next@12.1.0
@@ -1778,6 +1782,10 @@ packages:
deprecated: Potential XSS vulnerability patched in v6.0.0.
dev: false
/@braintree/sanitize-url/6.0.0:
resolution: {integrity: sha512-mgmE7XBYY/21erpzhexk4Cj1cyTQ9LzvnTxtzM17BJ7ERMNE6W72mQRo0I1Ud8eFJ+RVVIcBNhLFZ3GX4XFz5w==}
dev: false
/@changesets/apply-release-plan/5.0.5:
resolution: {integrity: sha512-CxL9dkhzjHiVmXCyHgsLCQj7i/coFTMv/Yy0v6BC5cIWZkQml+lf7zvQqAcFXwY7b54HxRWZPku02XFB53Q0Uw==}
dependencies:
@@ -2719,6 +2727,13 @@ packages:
'@types/unist': 2.0.6
dev: false
/@types/hoist-non-react-statics/3.3.1:
resolution: {integrity: sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==}
dependencies:
'@types/react': 17.0.40
hoist-non-react-statics: 3.3.2
dev: false
/@types/is-ci/3.0.0:
resolution: {integrity: sha512-Q0Op0hdWbYd1iahB+IFNQcWXFq4O0Q5MwQP7uN0souuQ4rPg1vEYcnIOfr1gY+M+6rc8FGoRaBO1mOOvL29sEQ==}
dependencies:
@@ -2791,7 +2806,15 @@ packages:
/@types/prop-types/15.7.4:
resolution: {integrity: sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==}
dev: true
/@types/react-redux/7.1.23:
resolution: {integrity: sha512-D02o3FPfqQlfu2WeEYwh3x2otYd2Dk1o8wAfsA0B1C2AJEFxE663Ozu7JzuWbznGgW248NaOF6wsqCGNq9d3qw==}
dependencies:
'@types/hoist-non-react-statics': 3.3.1
'@types/react': 17.0.40
hoist-non-react-statics: 3.3.2
redux: 4.1.2
dev: false
/@types/react/17.0.40:
resolution: {integrity: sha512-UrXhD/JyLH+W70nNSufXqMZNuUD2cXHu6UjCllC6pmOQgBX4SGXOH8fjRka0O0Ee0HrFxapDD8Bwn81Kmiz6jQ==}
@@ -2799,11 +2822,9 @@ packages:
'@types/prop-types': 15.7.4
'@types/scheduler': 0.16.2
csstype: 3.0.11
dev: true
/@types/scheduler/0.16.2:
resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==}
dev: true
/@types/semver/6.2.3:
resolution: {integrity: sha512-KQf+QAMWKMrtBMsB8/24w53tEsxllMj6TuA80TT/5igJalLI/zm0L3oXRbIAl4Ohfc85gyHX/jhMwsVkmhLU4A==}
@@ -3281,6 +3302,12 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/autolinker/3.15.0:
resolution: {integrity: sha512-N/5Dk5AZnqL9k6kkHdFIGLm/0/rRuSnJwqYYhLCJjU7ZtiaJwCBzNTvjzy1zzJADngv/wvtHYcrPHytPnASeFA==}
dependencies:
tslib: 2.3.1
dev: false
/autoprefixer/10.4.2_postcss@8.4.8:
resolution: {integrity: sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ==}
engines: {node: ^10 || ^12 || >=14}
@@ -3521,6 +3548,10 @@ packages:
/balanced-match/1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
/base64-js/1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
dev: false
/better-path-resolve/1.0.0:
resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==}
engines: {node: '>=4'}
@@ -3602,6 +3633,12 @@ packages:
node-int64: 0.4.0
dev: true
/btoa/1.2.1:
resolution: {integrity: sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==}
engines: {node: '>= 0.4.0'}
hasBin: true
dev: false
/buffer-from/1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
dev: true
@@ -3884,6 +3921,7 @@ packages:
/commander/2.20.3:
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
requiresBuild: true
dev: false
/commander/7.2.0:
@@ -3921,6 +3959,11 @@ packages:
dependencies:
safe-buffer: 5.1.2
/cookie/0.4.2:
resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==}
engines: {node: '>= 0.6'}
dev: false
/cookiejar/2.1.3:
resolution: {integrity: sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ==}
dev: false
@@ -3933,6 +3976,12 @@ packages:
keygrip: 1.1.0
dev: false
/copy-to-clipboard/3.3.1:
resolution: {integrity: sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw==}
dependencies:
toggle-selection: 1.0.6
dev: false
/core-js-compat/3.21.1:
resolution: {integrity: sha512-gbgX5AUvMb8gwxC7FLVWYT7Kkgu/y7+h/h1X43yJkNqhlK2fuYyQimqvKGNZFAY6CKii/GFKJ2cp/1/42TN36g==}
dependencies:
@@ -3959,6 +4008,14 @@ packages:
yaml: 1.10.2
dev: true
/cross-fetch/3.1.5:
resolution: {integrity: sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==}
dependencies:
node-fetch: 2.6.7
transitivePeerDependencies:
- encoding
dev: false
/cross-spawn/5.1.0:
resolution: {integrity: sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=}
dependencies:
@@ -4009,6 +4066,10 @@ packages:
engines: {node: '>= 6'}
dev: true
/css.escape/1.5.1:
resolution: {integrity: sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=}
dev: false
/cssesc/3.0.0:
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
engines: {node: '>=4'}
@@ -4036,7 +4097,6 @@ packages:
/csstype/3.0.11:
resolution: {integrity: sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==}
dev: true
/csv-generate/3.4.3:
resolution: {integrity: sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==}
@@ -4617,13 +4677,17 @@ packages:
resolution: {integrity: sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=}
dev: true
/deep-extend/0.6.0:
resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
engines: {node: '>=4.0.0'}
dev: false
/deep-is/0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
/deepmerge/4.2.2:
resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==}
engines: {node: '>=0.10.0'}
dev: true
/defaults/1.0.3:
resolution: {integrity: sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=}
@@ -4759,6 +4823,10 @@ packages:
domelementtype: 2.2.0
dev: true
/dompurify/2.3.3:
resolution: {integrity: sha512-dqnqRkPMAjOZE0FogZ+ceJNM2dZ3V/yNOuFB7+39qpO93hHhfRpHw3heYQC7DPK9FqbQTfBKUJhiSfz4MvXYwg==}
dev: false
/dompurify/2.3.5:
resolution: {integrity: sha512-kD+f8qEaa42+mjdOpKeztu9Mfx5bv9gVLO6K9jRx4uGvh6Wv06Srn4jr1wPNY2OOUGGSKHNFN+A8MA3v0E0QAQ==}
dev: false
@@ -4776,6 +4844,11 @@ packages:
engines: {node: '>=10'}
dev: false
/drange/1.1.1:
resolution: {integrity: sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA==}
engines: {node: '>=4'}
dev: false
/electron-to-chromium/1.4.82:
resolution: {integrity: sha512-Ks+ANzLoIrFDUOJdjxYMH6CMKB8UQo5modAwvSZTxgF+vEs/U7G5IbWFUp6dS4klPkTDVdxbORuk8xAXXhMsWw==}
dev: true
@@ -5723,6 +5796,10 @@ packages:
merge2: 1.4.1
micromatch: 4.0.4
/fast-json-patch/3.1.0:
resolution: {integrity: sha512-IhpytlsVTRndz0hU5t0/MGzS/etxLlfrpG5V5M9mVbuj9TrJLWaMfsox9REM5rkuGX0T+5qjpe8XA1o0gZ42nA==}
dev: false
/fast-json-stable-stringify/2.1.0:
resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
@@ -5819,6 +5896,10 @@ packages:
debug:
optional: true
/form-data-encoder/1.7.1:
resolution: {integrity: sha512-EFRDrsMm/kyqbTQocNvRXMLjc7Es2Vk+IQFx/YW7hkUH1eBl4J1fqiP34l74Yt0pFLCNpc06fkbVk00008mzjg==}
dev: false
/form-data/2.5.1:
resolution: {integrity: sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==}
engines: {node: '>= 0.12'}
@@ -5851,6 +5932,14 @@ packages:
engines: {node: '>=0.4.x'}
dev: false
/formdata-node/4.3.2:
resolution: {integrity: sha512-k7lYJyzDOSL6h917favP8j1L0/wNyylzU+x+1w4p5haGVHNlP58dbpdJhiCUsDbWsa9HwEtLp89obQgXl2e0qg==}
engines: {node: '>= 12.20'}
dependencies:
node-domexception: 1.0.0
web-streams-polyfill: 4.0.0-beta.1
dev: false
/formidable/1.2.6:
resolution: {integrity: sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==}
deprecated: 'Please upgrade to latest, formidable@v2 or formidable@v3! Check these notes: https://bit.ly/2ZEqIau'
@@ -6211,7 +6300,6 @@ packages:
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
dependencies:
react-is: 16.13.1
dev: true
/hosted-git-info/2.8.9:
resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==}
@@ -6347,6 +6435,10 @@ packages:
dependencies:
safer-buffer: 2.1.2
/ieee754/1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
dev: false
/ignore/4.0.6:
resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==}
engines: {node: '>= 4'}
@@ -6365,6 +6457,11 @@ packages:
resolution: {integrity: sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA==}
dev: false
/immutable/3.8.2:
resolution: {integrity: sha1-wkOZUUVbs5kT2vKBN28VMOEErfM=}
engines: {node: '>=0.10.0'}
dev: false
/import-fresh/3.3.0:
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
engines: {node: '>=6'}
@@ -6425,6 +6522,12 @@ packages:
engines: {node: '>=12'}
dev: false
/invariant/2.2.4:
resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==}
dependencies:
loose-envify: 1.4.0
dev: false
/ip-regex/4.3.0:
resolution: {integrity: sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==}
engines: {node: '>=8'}
@@ -6519,6 +6622,13 @@ packages:
resolution: {integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==}
dev: false
/is-dom/1.1.0:
resolution: {integrity: sha512-u82f6mvhYxRPKpw8V1N0W8ce1xXwOrQtgGcxl6UCL5zBmZu3is/18K0rR7uFCnMDuAsS/3W54mGL4vsaFUQlEQ==}
dependencies:
is-object: 1.0.2
is-window: 1.0.2
dev: false
/is-extendable/0.1.1:
resolution: {integrity: sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=}
engines: {node: '>=0.10.0'}
@@ -6566,6 +6676,10 @@ packages:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
/is-object/1.0.2:
resolution: {integrity: sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==}
dev: false
/is-plain-obj/1.1.0:
resolution: {integrity: sha1-caUMhCnfync8kqOQpKA7OfzVHT4=}
engines: {node: '>=0.10.0'}
@@ -6576,6 +6690,11 @@ packages:
engines: {node: '>=8'}
dev: false
/is-plain-object/5.0.0:
resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
engines: {node: '>=0.10.0'}
dev: false
/is-potential-custom-element-name/1.0.1:
resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
dev: true
@@ -6652,6 +6771,10 @@ packages:
resolution: {integrity: sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==}
dev: false
/is-window/1.0.2:
resolution: {integrity: sha1-LIlspT25feRdPDMTOmXYyfVjSA0=}
dev: false
/is-windows/1.0.2:
resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==}
engines: {node: '>=0.10.0'}
@@ -7207,6 +7330,10 @@ packages:
engines: {node: '>=12'}
dev: false
/js-file-download/0.4.12:
resolution: {integrity: sha512-rML+NkoD08p5Dllpjo0ffy4jRHeY6Zsapvr/W86N7E0yuzAO6qa5X9+xog6zQNlH102J7IXljNY2FtS6Lj3ucg==}
dev: false
/js-tokens/4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@@ -7468,7 +7595,6 @@ packages:
/lodash.debounce/4.0.8:
resolution: {integrity: sha1-gteb/zCmfEAF/9XiUVMArZyk168=}
dev: true
/lodash.memoize/4.1.2:
resolution: {integrity: sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=}
@@ -7973,12 +8099,29 @@ packages:
resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==}
dev: true
/node-domexception/1.0.0:
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
engines: {node: '>=10.5.0'}
dev: false
/node-emoji/1.11.0:
resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==}
dependencies:
lodash: 4.17.21
dev: true
/node-fetch/2.6.7:
resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==}
engines: {node: 4.x || >=6.0.0}
peerDependencies:
encoding: ^0.1.0
peerDependenciesMeta:
encoding:
optional: true
dependencies:
whatwg-url: 5.0.0
dev: false
/node-gyp/8.4.1:
resolution: {integrity: sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==}
engines: {node: '>= 10.12.0'}
@@ -8580,6 +8723,10 @@ packages:
resolution: {integrity: sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==}
dev: true
/punycode/1.3.2:
resolution: {integrity: sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=}
dev: false
/punycode/2.1.1:
resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==}
engines: {node: '>=6'}
@@ -8615,6 +8762,16 @@ packages:
strict-uri-encode: 2.0.0
dev: false
/querystring/0.2.0:
resolution: {integrity: sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=}
engines: {node: '>=0.4.x'}
deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead.
dev: false
/querystringify/2.2.0:
resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
dev: false
/queue-microtask/1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
@@ -8628,6 +8785,20 @@ packages:
engines: {node: '>=10'}
dev: true
/randexp/0.5.3:
resolution: {integrity: sha512-U+5l2KrcMNOUPYvazA3h5ekF80FHTUG+87SEAmHZmolh1M+i/WyTCxVzmi+tidIa1tM4BSe8g2Y/D3loWDjj+w==}
engines: {node: '>=4'}
dependencies:
drange: 1.1.1
ret: 0.2.2
dev: false
/randombytes/2.1.0:
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
dependencies:
safe-buffer: 5.2.1
dev: false
/re2/1.17.4:
resolution: {integrity: sha512-xyZ4h5PqE8I9tAxTh3G0UttcK5ufrcUxReFjGzfX61vtanNbS1XZHjnwRSyPcLgChI4KLxVgOT/ioZXnUAdoTA==}
requiresBuild: true
@@ -8639,6 +8810,26 @@ packages:
- supports-color
dev: true
/react-copy-to-clipboard/5.0.4_react@17.0.2:
resolution: {integrity: sha512-IeVAiNVKjSPeGax/Gmkqfa/+PuMTBhutEvFUaMQLwE2tS0EXrAdgOpWDX26bWTXF3HrioorR7lr08NqeYUWQCQ==}
peerDependencies:
react: ^15.3.0 || ^16.0.0 || ^17.0.0
dependencies:
copy-to-clipboard: 3.3.1
prop-types: 15.8.1
react: 17.0.2
dev: false
/react-debounce-input/3.2.4_react@17.0.2:
resolution: {integrity: sha512-fX70bNj0fLEYO2Zcvuh7eh9wOUQ29GIx6r8IxIJlc0i0mpUH++9ax0BhfAYfzndADli3RAMROrZQ014J01owrg==}
peerDependencies:
react: ^15.3.0 || ^16.0.0 || ^17.0.0
dependencies:
lodash.debounce: 4.0.8
prop-types: 15.8.1
react: 17.0.2
dev: false
/react-dom/17.0.2_react@17.0.2:
resolution: {integrity: sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==}
peerDependencies:
@@ -8649,17 +8840,70 @@ packages:
react: 17.0.2
scheduler: 0.20.2
/react-immutable-proptypes/2.2.0_immutable@3.8.2:
resolution: {integrity: sha512-Vf4gBsePlwdGvSZoLSBfd4HAP93HDauMY4fDjXhreg/vg6F3Fj/MXDNyTbltPC/xZKmZc+cjLu3598DdYK6sgQ==}
peerDependencies:
immutable: '>=3.6.2'
dependencies:
immutable: 3.8.2
invariant: 2.2.4
dev: false
/react-immutable-pure-component/2.2.2_bd1a0e68a5e0e4857c26400f3b5f7e9d:
resolution: {integrity: sha512-vkgoMJUDqHZfXXnjVlG3keCxSO/U6WeDQ5/Sl0GK2cH8TOxEzQ5jXqDXHEL/jqk6fsNxV05oH5kD7VNMUE2k+A==}
peerDependencies:
immutable: '>= 2 || >= 4.0.0-rc'
react: '>= 16.6'
react-dom: '>= 16.6'
dependencies:
immutable: 3.8.2
react: 17.0.2
react-dom: 17.0.2_react@17.0.2
dev: false
/react-inspector/5.1.1_react@17.0.2:
resolution: {integrity: sha512-GURDaYzoLbW8pMGXwYPDBIv6nqei4kK7LPRZ9q9HCZF54wqXz/dnylBp/kfE9XmekBhHvLDdcYeyIwSrvtOiWg==}
peerDependencies:
react: ^16.8.4 || ^17.0.0
dependencies:
'@babel/runtime': 7.17.2
is-dom: 1.1.0
prop-types: 15.8.1
react: 17.0.2
dev: false
/react-is/16.13.1:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
/react-is/17.0.2:
resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
dev: true
/react-merge-refs/1.1.0:
resolution: {integrity: sha512-alTKsjEL0dKH/ru1Iyn7vliS2QRcBp9zZPGoWxUOvRGWPUYgjo+V01is7p04It6KhgrzhJGnIj9GgX8W4bZoCQ==}
dev: false
/react-redux/7.2.6_react-dom@17.0.2+react@17.0.2:
resolution: {integrity: sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ==}
peerDependencies:
react: ^16.8.3 || ^17
react-dom: '*'
react-native: '*'
peerDependenciesMeta:
react-dom:
optional: true
react-native:
optional: true
dependencies:
'@babel/runtime': 7.17.2
'@types/react-redux': 7.1.23
hoist-non-react-statics: 3.3.2
loose-envify: 1.4.0
prop-types: 15.8.1
react: 17.0.2
react-dom: 17.0.2_react@17.0.2
react-is: 17.0.2
dev: false
/react-refresh/0.11.0:
resolution: {integrity: sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==}
engines: {node: '>=0.10.0'}
@@ -8786,6 +9030,20 @@ packages:
postcss-value-parser: 3.3.1
dev: true
/redux-immutable/4.0.0_immutable@3.8.2:
resolution: {integrity: sha1-Ohoy32Y2ZGK2NpHw4dw15HK7yfM=}
peerDependencies:
immutable: ^3.8.1 || ^4.0.0-rc.1
dependencies:
immutable: 3.8.2
dev: false
/redux/4.1.2:
resolution: {integrity: sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==}
dependencies:
'@babel/runtime': 7.17.2
dev: false
/refractor/3.6.0:
resolution: {integrity: sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==}
dependencies:
@@ -8894,6 +9152,15 @@ packages:
mdast-squeeze-paragraphs: 4.0.0
dev: false
/remarkable/2.0.1:
resolution: {integrity: sha512-YJyMcOH5lrR+kZdmB0aJJ4+93bEojRZ1HGDn9Eagu6ibg7aVZhc3OWbbShRid+Q5eAfsEqWxpe+g5W5nYNfNiA==}
engines: {node: '>= 6.0.0'}
hasBin: true
dependencies:
argparse: 1.0.10
autolinker: 3.15.0
dev: false
/repeat-string/1.6.1:
resolution: {integrity: sha1-jcrkcOHIirwtYA//Sndihtp15jc=}
engines: {node: '>=0.10'}
@@ -8908,6 +9175,14 @@ packages:
resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
dev: true
/requires-port/1.0.0:
resolution: {integrity: sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=}
dev: false
/reselect/4.1.5:
resolution: {integrity: sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ==}
dev: false
/resolve-cwd/3.0.0:
resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==}
engines: {node: '>=8'}
@@ -8943,6 +9218,11 @@ packages:
is-core-module: 2.8.1
path-parse: 1.0.7
/ret/0.2.2:
resolution: {integrity: sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==}
engines: {node: '>=4'}
dev: false
/retry/0.12.0:
resolution: {integrity: sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=}
engines: {node: '>= 4'}
@@ -8998,7 +9278,6 @@ packages:
/safe-buffer/5.2.1:
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
dev: true
/safer-buffer/2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
@@ -9044,10 +9323,25 @@ packages:
dependencies:
lru-cache: 6.0.0
/serialize-error/8.1.0:
resolution: {integrity: sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ==}
engines: {node: '>=10'}
dependencies:
type-fest: 0.20.2
dev: false
/set-blocking/2.0.0:
resolution: {integrity: sha1-BF+XgtARrppoA93TgrJDkrPYkPc=}
dev: true
/sha.js/2.4.11:
resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==}
hasBin: true
dependencies:
inherits: 2.0.4
safe-buffer: 5.2.1
dev: false
/shebang-command/1.2.0:
resolution: {integrity: sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=}
engines: {node: '>=0.10.0'}
@@ -9435,6 +9729,73 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
/swagger-client/3.18.4:
resolution: {integrity: sha512-Wj26oEctONq/u0uM+eSj18675YM5e2vFnx7Kr4neLeXEHKUsfceVQ/OdtrBXdrT3VbtdBbZfMTfl1JOBpix2MA==}
dependencies:
'@babel/runtime-corejs3': 7.17.2
btoa: 1.2.1
cookie: 0.4.2
cross-fetch: 3.1.5
deepmerge: 4.2.2
fast-json-patch: 3.1.0
form-data-encoder: 1.7.1
formdata-node: 4.3.2
is-plain-object: 5.0.0
js-yaml: 4.1.0
lodash: 4.17.21
qs: 6.10.3
traverse: 0.6.6
url: 0.11.0
transitivePeerDependencies:
- encoding
dev: false
/swagger-ui-react/4.8.0_react-dom@17.0.2+react@17.0.2:
resolution: {integrity: sha512-zumBDcwifJaM4/7DdMh76fHvlzT5t4f8/Fx8hSlZ25VhJycv+F+s23KzfhoXsgAy4qE8TeEDz2fDiODx/1XAWA==}
peerDependencies:
react: '>=17.0.0'
react-dom: '>=17.0.0'
dependencies:
'@babel/runtime-corejs3': 7.17.2
'@braintree/sanitize-url': 6.0.0
base64-js: 1.5.1
classnames: 2.3.1
css.escape: 1.5.1
deep-extend: 0.6.0
dompurify: 2.3.3
ieee754: 1.2.1
immutable: 3.8.2
js-file-download: 0.4.12
js-yaml: 4.1.0
lodash: 4.17.21
prop-types: 15.8.1
randexp: 0.5.3
randombytes: 2.1.0
react: 17.0.2
react-copy-to-clipboard: 5.0.4_react@17.0.2
react-debounce-input: 3.2.4_react@17.0.2
react-dom: 17.0.2_react@17.0.2
react-immutable-proptypes: 2.2.0_immutable@3.8.2
react-immutable-pure-component: 2.2.2_bd1a0e68a5e0e4857c26400f3b5f7e9d
react-inspector: 5.1.1_react@17.0.2
react-redux: 7.2.6_react-dom@17.0.2+react@17.0.2
react-syntax-highlighter: 15.4.5_react@17.0.2
redux: 4.1.2
redux-immutable: 4.0.0_immutable@3.8.2
remarkable: 2.0.1
reselect: 4.1.5
serialize-error: 8.1.0
sha.js: 2.4.11
swagger-client: 3.18.4
url-parse: 1.5.10
xml: 1.0.1
xml-but-prettier: 1.0.1
zenscroll: 4.0.2
transitivePeerDependencies:
- encoding
- react-native
dev: false
/symbol-observable/1.2.0:
resolution: {integrity: sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==}
engines: {node: '>=0.10.0'}
@@ -9569,6 +9930,10 @@ packages:
dependencies:
is-number: 7.0.0
/toggle-selection/1.0.6:
resolution: {integrity: sha1-bkWxJj8gF/oKzH2J14sVuL932jI=}
dev: false
/tough-cookie/4.0.0:
resolution: {integrity: sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==}
engines: {node: '>=6'}
@@ -9578,6 +9943,10 @@ packages:
universalify: 0.1.2
dev: true
/tr46/0.0.3:
resolution: {integrity: sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=}
dev: false
/tr46/2.1.0:
resolution: {integrity: sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==}
engines: {node: '>=8'}
@@ -9592,6 +9961,10 @@ packages:
punycode: 2.1.1
dev: true
/traverse/0.6.6:
resolution: {integrity: sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=}
dev: false
/trim-newlines/3.0.1:
resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==}
engines: {node: '>=8'}
@@ -10022,6 +10395,13 @@ packages:
dependencies:
punycode: 2.1.1
/url-parse/1.5.10:
resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
dependencies:
querystringify: 2.2.0
requires-port: 1.0.0
dev: false
/url-regex-safe/3.0.0_re2@1.17.4:
resolution: {integrity: sha512-+2U40NrcmtWFVjuxXVt9bGRw6c7/MgkGKN9xIfPrT/2RX0LTkkae6CCEDp93xqUN0UKm/rr821QnHd2dHQmN3A==}
engines: {node: '>= 10.12.0'}
@@ -10036,6 +10416,13 @@ packages:
tlds: 1.230.0
dev: true
/url/0.11.0:
resolution: {integrity: sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=}
dependencies:
punycode: 1.3.2
querystring: 0.2.0
dev: false
/use-isomorphic-layout-effect/1.1.1_react@17.0.2:
resolution: {integrity: sha512-L7Evj8FGcwo/wpbv/qvSfrkHFtOpCzvM5yl2KVyDJoylVuSvzphiiasmjgQPttIGBAy2WKiBNR98q8w7PiNgKQ==}
peerDependencies:
@@ -10203,6 +10590,15 @@ packages:
resolution: {integrity: sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==}
dev: false
/web-streams-polyfill/4.0.0-beta.1:
resolution: {integrity: sha512-3ux37gEX670UUphBF9AMCq8XM6iQ8Ac6A+DSRRjDoRBm1ufCkaCDdNVbaqq60PsEkdNlLKrGtv/YBP4EJXqNtQ==}
engines: {node: '>= 12'}
dev: false
/webidl-conversions/3.0.1:
resolution: {integrity: sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=}
dev: false
/webidl-conversions/5.0.0:
resolution: {integrity: sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==}
engines: {node: '>=8'}
@@ -10248,6 +10644,13 @@ packages:
webidl-conversions: 7.0.0
dev: true
/whatwg-url/5.0.0:
resolution: {integrity: sha1-lmRU6HZUYuN2RNNib2dCzotwll0=}
dependencies:
tr46: 0.0.3
webidl-conversions: 3.0.1
dev: false
/whatwg-url/8.7.0:
resolution: {integrity: sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==}
engines: {node: '>=10'}
@@ -10357,6 +10760,12 @@ packages:
optional: true
dev: true
/xml-but-prettier/1.0.1:
resolution: {integrity: sha1-9aMyZ+1CzNTjVcYlV6XjmwH7QPM=}
dependencies:
repeat-string: 1.6.1
dev: false
/xml-name-validator/3.0.0:
resolution: {integrity: sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==}
dev: true
@@ -10366,6 +10775,10 @@ packages:
engines: {node: '>=12'}
dev: true
/xml/1.0.1:
resolution: {integrity: sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=}
dev: false
/xmlchars/2.2.0:
resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
dev: true
@@ -10455,6 +10868,10 @@ packages:
resolution: {integrity: sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==}
dev: true
/zenscroll/4.0.2:
resolution: {integrity: sha1-6NV3TRwHOKR7z6hynzcS4t7d6yU=}
dev: false
/zwitch/1.0.5:
resolution: {integrity: sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==}
dev: false

View File

@@ -2,7 +2,7 @@
"compilerOptions": {
"declaration": true,
"noImplicitAny": false,
"removeComments": true,
"removeComments": false,
"noLib": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,