@aws-amplify/ui-react-core 2.1.20 → 2.1.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,29 @@
1
+ import { __awaiter } from '../../node_modules/tslib/tslib.es6.mjs';
1
2
  import React, { useContext, useMemo, useEffect } from 'react';
2
3
  import { useInterpret } from '@xstate/react';
3
- import { createAuthenticatorMachine, listenToAuthHub } from '@aws-amplify/ui';
4
+ import { Auth } from 'aws-amplify';
5
+ import { createAuthenticatorMachine, listenToAuthHub, defaultAuthHubHandler } from '@aws-amplify/ui';
4
6
  import { AuthenticatorContext } from './AuthenticatorContext.mjs';
5
7
 
8
+ const createHubHandler = (options) => (data, service) => __awaiter(void 0, void 0, void 0, function* () {
9
+ yield defaultAuthHubHandler(data, service, options);
10
+ });
6
11
  function AuthenticatorProvider({ children, }) {
12
+ // `authStatus` is exposed by `useAuthenticator` but should not be derived directly from the
13
+ // state machine as the machine only updates on `Authenticator` initiated events, which
14
+ // leads to scenarios where the state machine `authStatus` gets "stuck". For exmample,
15
+ // if a user was to sign in using `Auth.signIn` directly rather than using `Authenticator`
16
+ const [authStatus, setAuthStatus] = React.useState('configuring');
17
+ // only run on first render
18
+ React.useEffect(() => {
19
+ Auth.currentAuthenticatedUser()
20
+ .then(() => {
21
+ setAuthStatus('authenticated');
22
+ })
23
+ .catch(() => {
24
+ setAuthStatus('unauthenticated');
25
+ });
26
+ }, []);
7
27
  /**
8
28
  * Based on use cases, developer might already have added another Provider
9
29
  * outside Authenticator. In that case, we sync the two providers by just
@@ -13,10 +33,16 @@ function AuthenticatorProvider({ children, }) {
13
33
  */
14
34
  const parentProviderVal = useContext(AuthenticatorContext);
15
35
  const service = useInterpret(createAuthenticatorMachine);
16
- const value = useMemo(() => (!parentProviderVal ? { service } : parentProviderVal), [parentProviderVal, service]);
36
+ const value = useMemo(() => (!parentProviderVal ? { authStatus, service } : parentProviderVal), [authStatus, parentProviderVal, service]);
17
37
  const { service: activeService } = value;
18
38
  useEffect(() => {
19
- const unsubscribe = listenToAuthHub(activeService);
39
+ const onSignIn = () => {
40
+ setAuthStatus('authenticated');
41
+ };
42
+ const onSignOut = () => {
43
+ setAuthStatus('unauthenticated');
44
+ };
45
+ const unsubscribe = listenToAuthHub(activeService, createHubHandler({ onSignIn, onSignOut }));
20
46
  return unsubscribe;
21
47
  }, [activeService]);
22
48
  return (React.createElement(AuthenticatorContext.Provider, { value: value }, children));
@@ -2,6 +2,7 @@ import { __rest } from '../../../node_modules/tslib/tslib.es6.mjs';
2
2
  import React, { useCallback } from 'react';
3
3
  import { useSelector } from '@xstate/react';
4
4
  import { getServiceFacade } from '@aws-amplify/ui';
5
+ import 'aws-amplify';
5
6
  import { AuthenticatorContext } from '../../context/AuthenticatorContext.mjs';
6
7
  import { USE_AUTHENTICATOR_ERROR } from './constants.mjs';
7
8
  import { getQRFields, getMachineFields, getTotpSecretCodeCallback, getComparator, defaultComparator } from './utils.mjs';
@@ -18,6 +19,9 @@ function useAuthenticator(selector) {
18
19
  const { send } = service;
19
20
  const xstateSelector = useCallback((state) => (Object.assign({}, getServiceFacade({ send, state }))), [send]);
20
21
  const comparator = selector ? getComparator(selector) : defaultComparator;
22
+ // the purpose of `context.authStatus`is to intentionally override `facade.authStatus`. `facade.authStatus` does
23
+ // not update on external sign in events (for example when a user is not using the `Authenticator`).
24
+ const { authStatus } = context;
21
25
  const facade = useSelector(service, xstateSelector, comparator);
22
26
  const { route, totpSecretCode, unverifiedContactMethods, user } = facade, rest = __rest(facade, ["route", "totpSecretCode", "unverifiedContactMethods", "user"]);
23
27
  // do not memoize output. `service.getSnapshot` reference remains stable preventing
@@ -27,7 +31,8 @@ function useAuthenticator(selector) {
27
31
  const QRFields = route === 'setupTOTP' ? getQRFields(serviceSnapshot) : null;
28
32
  // legacy `formFields` values required until form state is removed from state machine
29
33
  const fields = getMachineFields(route, serviceSnapshot, unverifiedContactMethods);
30
- return Object.assign(Object.assign({}, rest), { route,
34
+ return Object.assign(Object.assign({}, rest), { authStatus,
35
+ route,
31
36
  totpSecretCode,
32
37
  unverifiedContactMethods,
33
38
  user,
package/dist/index.js CHANGED
@@ -4,8 +4,8 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var React = require('react');
6
6
  var react = require('@xstate/react');
7
- var ui = require('@aws-amplify/ui');
8
7
  var awsAmplify = require('aws-amplify');
8
+ var ui = require('@aws-amplify/ui');
9
9
  var notifications = require('@aws-amplify/notifications');
10
10
  var core = require('@aws-amplify/core');
11
11
 
@@ -13,32 +13,6 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
13
13
 
14
14
  var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
15
15
 
16
- /**
17
- * AuthenticatorContext serves static reference to the auth machine service.
18
- *
19
- * https://xstate.js.org/docs/recipes/react.html#context-provider
20
- */
21
- const AuthenticatorContext = React__default["default"].createContext(null);
22
-
23
- function AuthenticatorProvider({ children, }) {
24
- /**
25
- * Based on use cases, developer might already have added another Provider
26
- * outside Authenticator. In that case, we sync the two providers by just
27
- * passing the parent value.
28
- *
29
- * TODO(BREAKING): enforce only one provider in App tree
30
- */
31
- const parentProviderVal = React.useContext(AuthenticatorContext);
32
- const service = react.useInterpret(ui.createAuthenticatorMachine);
33
- const value = React.useMemo(() => (!parentProviderVal ? { service } : parentProviderVal), [parentProviderVal, service]);
34
- const { service: activeService } = value;
35
- React.useEffect(() => {
36
- const unsubscribe = ui.listenToAuthHub(activeService);
37
- return unsubscribe;
38
- }, [activeService]);
39
- return (React__default["default"].createElement(AuthenticatorContext.Provider, { value: value }, children));
40
- }
41
-
42
16
  /******************************************************************************
43
17
  Copyright (c) Microsoft Corporation.
44
18
 
@@ -76,6 +50,56 @@ function __awaiter(thisArg, _arguments, P, generator) {
76
50
  });
77
51
  }
78
52
 
53
+ /**
54
+ * AuthenticatorContext serves static reference to the auth machine service.
55
+ *
56
+ * https://xstate.js.org/docs/recipes/react.html#context-provider
57
+ */
58
+ const AuthenticatorContext = React__default["default"].createContext(null);
59
+
60
+ const createHubHandler = (options) => (data, service) => __awaiter(void 0, void 0, void 0, function* () {
61
+ yield ui.defaultAuthHubHandler(data, service, options);
62
+ });
63
+ function AuthenticatorProvider({ children, }) {
64
+ // `authStatus` is exposed by `useAuthenticator` but should not be derived directly from the
65
+ // state machine as the machine only updates on `Authenticator` initiated events, which
66
+ // leads to scenarios where the state machine `authStatus` gets "stuck". For exmample,
67
+ // if a user was to sign in using `Auth.signIn` directly rather than using `Authenticator`
68
+ const [authStatus, setAuthStatus] = React__default["default"].useState('configuring');
69
+ // only run on first render
70
+ React__default["default"].useEffect(() => {
71
+ awsAmplify.Auth.currentAuthenticatedUser()
72
+ .then(() => {
73
+ setAuthStatus('authenticated');
74
+ })
75
+ .catch(() => {
76
+ setAuthStatus('unauthenticated');
77
+ });
78
+ }, []);
79
+ /**
80
+ * Based on use cases, developer might already have added another Provider
81
+ * outside Authenticator. In that case, we sync the two providers by just
82
+ * passing the parent value.
83
+ *
84
+ * TODO(BREAKING): enforce only one provider in App tree
85
+ */
86
+ const parentProviderVal = React.useContext(AuthenticatorContext);
87
+ const service = react.useInterpret(ui.createAuthenticatorMachine);
88
+ const value = React.useMemo(() => (!parentProviderVal ? { authStatus, service } : parentProviderVal), [authStatus, parentProviderVal, service]);
89
+ const { service: activeService } = value;
90
+ React.useEffect(() => {
91
+ const onSignIn = () => {
92
+ setAuthStatus('authenticated');
93
+ };
94
+ const onSignOut = () => {
95
+ setAuthStatus('unauthenticated');
96
+ };
97
+ const unsubscribe = ui.listenToAuthHub(activeService, createHubHandler({ onSignIn, onSignOut }));
98
+ return unsubscribe;
99
+ }, [activeService]);
100
+ return (React__default["default"].createElement(AuthenticatorContext.Provider, { value: value }, children));
101
+ }
102
+
79
103
  const USE_AUTHENTICATOR_ERROR = '`useAuthenticator` must be used inside an `Authenticator.Provider`.';
80
104
 
81
105
  const COMPONENT_ROUTE_KEYS = [
@@ -193,6 +217,9 @@ function useAuthenticator(selector) {
193
217
  const { send } = service;
194
218
  const xstateSelector = React.useCallback((state) => (Object.assign({}, ui.getServiceFacade({ send, state }))), [send]);
195
219
  const comparator = selector ? getComparator(selector) : defaultComparator;
220
+ // the purpose of `context.authStatus`is to intentionally override `facade.authStatus`. `facade.authStatus` does
221
+ // not update on external sign in events (for example when a user is not using the `Authenticator`).
222
+ const { authStatus } = context;
196
223
  const facade = react.useSelector(service, xstateSelector, comparator);
197
224
  const { route, totpSecretCode, unverifiedContactMethods, user } = facade, rest = __rest(facade, ["route", "totpSecretCode", "unverifiedContactMethods", "user"]);
198
225
  // do not memoize output. `service.getSnapshot` reference remains stable preventing
@@ -202,7 +229,8 @@ function useAuthenticator(selector) {
202
229
  const QRFields = route === 'setupTOTP' ? getQRFields(serviceSnapshot) : null;
203
230
  // legacy `formFields` values required until form state is removed from state machine
204
231
  const fields = getMachineFields(route, serviceSnapshot, unverifiedContactMethods);
205
- return Object.assign(Object.assign({}, rest), { route,
232
+ return Object.assign(Object.assign({}, rest), { authStatus,
233
+ route,
206
234
  totpSecretCode,
207
235
  unverifiedContactMethods,
208
236
  user,
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { AuthInterpreter } from '@aws-amplify/ui';
2
+ import { AuthInterpreter, AuthStatus } from '@aws-amplify/ui';
3
3
  /**
4
4
  * Authenticator React.Context type
5
5
  */
@@ -11,5 +11,7 @@ type AuthenticatorContextType = {
11
11
  *
12
12
  * https://xstate.js.org/docs/recipes/react.html#context-provider
13
13
  */
14
- export declare const AuthenticatorContext: React.Context<AuthenticatorContextType | null>;
14
+ export declare const AuthenticatorContext: React.Context<(AuthenticatorContextType & {
15
+ authStatus: AuthStatus;
16
+ }) | null>;
15
17
  export {};
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "@aws-amplify/ui-react-core",
3
- "version": "2.1.20",
3
+ "version": "2.1.22",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/esm/index.mjs",
6
6
  "react-native": "dist/index.js",
7
7
  "exports": {
8
8
  ".": {
9
9
  "import": "./dist/esm/index.mjs",
10
- "require": "./dist/index.js"
10
+ "require": "./dist/index.js",
11
+ "types": "./dist/types/index.d.ts"
11
12
  },
12
13
  "./package.json": "./package.json"
13
14
  },
@@ -30,7 +31,7 @@
30
31
  "typecheck": "tsc --noEmit"
31
32
  },
32
33
  "dependencies": {
33
- "@aws-amplify/ui": "5.6.1",
34
+ "@aws-amplify/ui": "5.6.3",
34
35
  "@xstate/react": "3.0.1",
35
36
  "lodash": "4.17.21",
36
37
  "xstate": "^4.33.6"