@aws-amplify/ui-react-liveness 3.3.8 → 3.4.0

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.
Files changed (82) hide show
  1. package/README.md +15 -15
  2. package/dist/esm/components/FaceLivenessDetector/FaceLivenessDetectorCore.mjs +4 -2
  3. package/dist/esm/components/FaceLivenessDetector/LivenessCheck/CameraSelector.mjs +13 -0
  4. package/dist/esm/components/FaceLivenessDetector/LivenessCheck/LivenessCameraModule.mjs +50 -28
  5. package/dist/esm/components/FaceLivenessDetector/LivenessCheck/LivenessCheck.mjs +5 -4
  6. package/dist/esm/components/FaceLivenessDetector/service/machine/machine.mjs +247 -314
  7. package/dist/esm/components/FaceLivenessDetector/service/utils/ColorSequenceDisplay/ColorSequenceDisplay.mjs +140 -0
  8. package/dist/esm/components/FaceLivenessDetector/service/utils/StreamRecorder/StreamRecorder.mjs +171 -0
  9. package/dist/esm/components/FaceLivenessDetector/service/utils/TelemetryReporter/TelemetryReporter.mjs +27 -0
  10. package/dist/esm/components/FaceLivenessDetector/service/utils/constants.mjs +30 -7
  11. package/dist/esm/components/FaceLivenessDetector/service/utils/createRequestStreamGenerator/createRequestStreamGenerator.mjs +32 -0
  12. package/dist/esm/components/FaceLivenessDetector/service/utils/createRequestStreamGenerator/utils.mjs +148 -0
  13. package/dist/esm/components/FaceLivenessDetector/service/utils/createStreamingClient/Signer.mjs +2 -3
  14. package/dist/esm/components/FaceLivenessDetector/service/utils/createStreamingClient/createStreamingClient.mjs +36 -6
  15. package/dist/esm/components/FaceLivenessDetector/service/utils/createStreamingClient/resolveCredentials.mjs +7 -6
  16. package/dist/esm/components/FaceLivenessDetector/service/utils/getFaceMatchStateInLivenessOval.mjs +9 -5
  17. package/dist/esm/components/FaceLivenessDetector/service/utils/liveness.mjs +19 -34
  18. package/dist/esm/components/FaceLivenessDetector/service/utils/{eventUtils.mjs → responseStreamEvent.mjs} +2 -2
  19. package/dist/esm/components/FaceLivenessDetector/service/utils/sessionInformation.mjs +45 -0
  20. package/dist/esm/components/FaceLivenessDetector/shared/DefaultStartScreenComponents.mjs +3 -2
  21. package/dist/esm/components/FaceLivenessDetector/shared/FaceLivenessErrorModal.mjs +4 -2
  22. package/dist/esm/components/FaceLivenessDetector/shared/Hint.mjs +4 -7
  23. package/dist/esm/components/FaceLivenessDetector/types/classNames.mjs +3 -0
  24. package/dist/esm/components/FaceLivenessDetector/utils/device.mjs +12 -12
  25. package/dist/esm/index.mjs +12 -0
  26. package/dist/esm/version.mjs +1 -1
  27. package/dist/index.js +956 -775
  28. package/dist/styles.css +17 -2
  29. package/dist/types/components/FaceLivenessDetector/FaceLivenessDetector.d.ts +3 -3
  30. package/dist/types/components/FaceLivenessDetector/FaceLivenessDetectorCore.d.ts +3 -3
  31. package/dist/types/components/FaceLivenessDetector/LivenessCheck/CameraSelector.d.ts +8 -0
  32. package/dist/types/components/FaceLivenessDetector/LivenessCheck/LivenessCameraModule.d.ts +3 -2
  33. package/dist/types/components/FaceLivenessDetector/LivenessCheck/LivenessCheck.d.ts +2 -2
  34. package/dist/types/components/FaceLivenessDetector/displayText.d.ts +1 -1
  35. package/dist/types/components/FaceLivenessDetector/hooks/useLivenessSelector.d.ts +1 -1
  36. package/dist/types/components/FaceLivenessDetector/index.d.ts +6 -3
  37. package/dist/types/components/FaceLivenessDetector/providers/FaceLivenessDetectorProvider.d.ts +1 -1
  38. package/dist/types/components/FaceLivenessDetector/service/machine/machine.d.ts +1 -1
  39. package/dist/types/components/FaceLivenessDetector/service/types/credentials.d.ts +1 -1
  40. package/dist/types/components/FaceLivenessDetector/service/types/liveness.d.ts +2 -2
  41. package/dist/types/components/FaceLivenessDetector/service/types/machine.d.ts +40 -27
  42. package/dist/types/components/FaceLivenessDetector/service/utils/ColorSequenceDisplay/ColorSequenceDisplay.d.ts +55 -0
  43. package/dist/types/components/FaceLivenessDetector/service/utils/ColorSequenceDisplay/index.d.ts +2 -0
  44. package/dist/types/components/FaceLivenessDetector/service/utils/StreamRecorder/StreamRecorder.d.ts +15 -0
  45. package/dist/types/components/FaceLivenessDetector/service/utils/StreamRecorder/index.d.ts +1 -0
  46. package/dist/types/components/FaceLivenessDetector/service/utils/TelemetryReporter/TelemetryReporter.d.ts +8 -0
  47. package/dist/types/components/FaceLivenessDetector/service/utils/TelemetryReporter/index.d.ts +2 -0
  48. package/dist/types/components/FaceLivenessDetector/service/utils/blazefaceFaceDetection.d.ts +2 -1
  49. package/dist/types/components/FaceLivenessDetector/service/utils/constants.d.ts +27 -3
  50. package/dist/types/components/FaceLivenessDetector/service/utils/createRequestStreamGenerator/createRequestStreamGenerator.d.ts +15 -0
  51. package/dist/types/components/FaceLivenessDetector/service/utils/createRequestStreamGenerator/index.d.ts +2 -0
  52. package/dist/types/components/FaceLivenessDetector/service/utils/createRequestStreamGenerator/utils.d.ts +30 -0
  53. package/dist/types/components/FaceLivenessDetector/service/utils/createStreamingClient/CustomWebSocketFetchHandler.d.ts +3 -2
  54. package/dist/types/components/FaceLivenessDetector/service/utils/createStreamingClient/Signer.d.ts +1 -2
  55. package/dist/types/components/FaceLivenessDetector/service/utils/createStreamingClient/createStreamingClient.d.ts +28 -6
  56. package/dist/types/components/FaceLivenessDetector/service/utils/createStreamingClient/index.d.ts +1 -0
  57. package/dist/types/components/FaceLivenessDetector/service/utils/createStreamingClient/resolveCredentials.d.ts +1 -1
  58. package/dist/types/components/FaceLivenessDetector/service/utils/createStreamingClient/types.d.ts +1 -1
  59. package/dist/types/components/FaceLivenessDetector/service/utils/getFaceMatchStateInLivenessOval.d.ts +4 -4
  60. package/dist/types/components/FaceLivenessDetector/service/utils/index.d.ts +7 -4
  61. package/dist/types/components/FaceLivenessDetector/service/utils/liveness.d.ts +16 -26
  62. package/dist/types/components/FaceLivenessDetector/service/utils/{eventUtils.d.ts → responseStreamEvent.d.ts} +2 -2
  63. package/dist/types/components/FaceLivenessDetector/service/utils/sessionInformation.d.ts +7 -0
  64. package/dist/types/components/FaceLivenessDetector/service/utils/types.d.ts +21 -0
  65. package/dist/types/components/FaceLivenessDetector/shared/DefaultStartScreenComponents.d.ts +1 -1
  66. package/dist/types/components/FaceLivenessDetector/shared/FaceLivenessErrorModal.d.ts +2 -2
  67. package/dist/types/components/FaceLivenessDetector/shared/Hint.d.ts +1 -1
  68. package/dist/types/components/FaceLivenessDetector/shared/Overlay.d.ts +1 -1
  69. package/dist/types/components/FaceLivenessDetector/shared/Toast.d.ts +1 -1
  70. package/dist/types/components/FaceLivenessDetector/types/classNames.d.ts +3 -0
  71. package/dist/types/components/FaceLivenessDetector/utils/device.d.ts +1 -0
  72. package/dist/types/components/FaceLivenessDetector/utils/getDisplayText.d.ts +1 -1
  73. package/dist/types/index.d.ts +2 -1
  74. package/dist/types/version.d.ts +1 -1
  75. package/package.json +10 -10
  76. package/dist/esm/components/FaceLivenessDetector/service/utils/freshnessColorDisplay.mjs +0 -131
  77. package/dist/esm/components/FaceLivenessDetector/service/utils/streamProvider.mjs +0 -126
  78. package/dist/esm/components/FaceLivenessDetector/service/utils/videoRecorder.mjs +0 -108
  79. package/dist/types/components/FaceLivenessDetector/service/types/service.d.ts +0 -5
  80. package/dist/types/components/FaceLivenessDetector/service/utils/freshnessColorDisplay.d.ts +0 -21
  81. package/dist/types/components/FaceLivenessDetector/service/utils/streamProvider.d.ts +0 -42
  82. package/dist/types/components/FaceLivenessDetector/service/utils/videoRecorder.d.ts +0 -27
package/README.md CHANGED
@@ -1,23 +1,23 @@
1
- # Amplify UI
1
+ # Amplify UI React Liveness
2
2
 
3
- Amplify UI is an open-source UI library with cloud-connected components that are endlessly customizable, accessible, and can integrate into _any_ application. Amplify UI consists of:
3
+ The React Liveness package provides components for face liveness detection in Amplify connected applications.
4
4
 
5
- 1. Connected components that simplify complex cloud-connected workflows, like Authenticator.
6
- 2. Primitive components that create consistency across Amplify UI and allow you to build complete applications that fit your brand, like Buttons and Badges.
7
- 3. Data-bound components that make it easy to display dynamic data, like DataStoreCollections.
8
- 4. Theming capabilities that allow you to customize the appearance of Amplify UI to match your brand.
5
+ ## Contents
9
6
 
10
- ## React Documentation
7
+ ### Core Components
11
8
 
12
- - https://ui.docs.amplify.aws/react
9
+ - `FaceLivenessDetector` - Component for face liveness detection
10
+ - `FaceLivenessDetectorCore` - Core component for face liveness detection
13
11
 
14
- ## Features 🚀
12
+ ### Type Definitions
15
13
 
16
- - **Better developer experience** Connected-components like Authenticator are being written with framework-specific implementations so that they follow framework conventions and are easier to integrate into your application.
17
- - **Endlessly customizable** Every detail of Amplify UI is customizable to match your brand. Style all of Amplify UI with themes, override components with your own, or build your own UI and use Amplify for complex state management.
18
- - **Accessible** Amplify UI components follow [WCAG](https://www.w3.org/WAI/standards-guidelines/wcag/) and [WAI-ARIA](https://www.w3.org/TR/wai-aria-1.2/) best practices and guidelines such as color contrast, keyboard navigation, accessible labels, and focus management.
19
- - **Primitive components (React only right now)** Primitive components are used in the connected components, like Authenticator, you can also customize them and use them to build the rest of your UI.
14
+ - `FaceLivenessDetectorProps` - Props for FaceLivenessDetector component
15
+ - `FaceLivenessDetectorCoreProps` - Props for FaceLivenessDetectorCore component
16
+ - `AwsCredentialProvider` - Type for AWS credential provider
17
+ - `AwsCredentials` - Type for AWS credentials
18
+ - `AwsTemporaryCredentials` - Type for AWS temporary credentials
19
+ - `ErrorState` - Type for error state
20
20
 
21
- ## We love contributors!!
21
+ ## React Documentation
22
22
 
23
- See our contributing guide [CONTRIBUTING.md](/CONTRIBUTING.md) to help us scale Amplify UI!
23
+ - https://ui.docs.amplify.aws/react
@@ -7,9 +7,11 @@ import '@tensorflow-models/face-detection';
7
7
  import '@tensorflow/tfjs-backend-wasm';
8
8
  import '@tensorflow/tfjs-backend-cpu';
9
9
  import '@aws-amplify/core/internals/utils';
10
- import '@aws-sdk/client-rekognitionstreaming';
10
+ import './service/utils/constants.mjs';
11
+ import './service/utils/ColorSequenceDisplay/ColorSequenceDisplay.mjs';
12
+ import '@aws-amplify/ui';
11
13
  import './service/utils/createStreamingClient/createStreamingClient.mjs';
12
- import './service/utils/freshnessColorDisplay.mjs';
14
+ import './service/utils/StreamRecorder/StreamRecorder.mjs';
13
15
  import { View, Flex } from '@aws-amplify/ui-react';
14
16
  import { FaceLivenessDetectorProvider } from './providers/FaceLivenessDetectorProvider.mjs';
15
17
  import { LivenessCheck } from './LivenessCheck/LivenessCheck.mjs';
@@ -0,0 +1,13 @@
1
+ import { Flex, View, Label, SelectField } from '@aws-amplify/ui-react';
2
+ import React__default from 'react';
3
+ import { LivenessClassNames } from '../types/classNames.mjs';
4
+
5
+ const CameraSelector = (props) => {
6
+ const { onSelect: onCameraChange, devices: selectableDevices, deviceId: selectedDeviceId, } = props;
7
+ return (React__default.createElement(Flex, { className: LivenessClassNames.StartScreenCameraSelect },
8
+ React__default.createElement(View, { className: LivenessClassNames.StartScreenCameraSelectContainer },
9
+ React__default.createElement(Label, { htmlFor: "amplify-liveness-camera-select", className: `${LivenessClassNames.StartScreenCameraSelect}__label` }, "Camera:"),
10
+ React__default.createElement(SelectField, { id: "amplify-liveness-camera-select", testId: "amplify-liveness-camera-select", label: "Camera", labelHidden: true, value: selectedDeviceId, onChange: onCameraChange }, selectableDevices.map((device) => (React__default.createElement("option", { value: device.deviceId, key: device.deviceId }, device.label)))))));
11
+ };
12
+
13
+ export { CameraSelector };
@@ -1,6 +1,6 @@
1
1
  import React__default, { useRef, useState } from 'react';
2
2
  import { classNames } from '@aws-amplify/ui';
3
- import { Loader, View, Flex, Text, Label, SelectField, Button } from '@aws-amplify/ui-react';
3
+ import { View, Flex, Loader, Text, Button } from '@aws-amplify/ui-react';
4
4
  import { useColorMode } from '@aws-amplify/ui-react/internal';
5
5
  import '../service/machine/machine.mjs';
6
6
  import { FaceMatchState } from '../service/types/liveness.mjs';
@@ -10,9 +10,10 @@ import '@tensorflow/tfjs-backend-wasm';
10
10
  import '@tensorflow/tfjs-backend-cpu';
11
11
  import '@aws-amplify/core/internals/utils';
12
12
  import { drawStaticOval, clearOvalCanvas } from '../service/utils/liveness.mjs';
13
- import '@aws-sdk/client-rekognitionstreaming';
13
+ import { FACE_MOVEMENT_CHALLENGE } from '../service/utils/constants.mjs';
14
+ import '../service/utils/ColorSequenceDisplay/ColorSequenceDisplay.mjs';
14
15
  import '../service/utils/createStreamingClient/createStreamingClient.mjs';
15
- import '../service/utils/freshnessColorDisplay.mjs';
16
+ import '../service/utils/StreamRecorder/StreamRecorder.mjs';
16
17
  import { useLivenessActor } from '../hooks/useLivenessActor.mjs';
17
18
  import { useLivenessSelector, createLivenessSelector } from '../hooks/useLivenessSelector.mjs';
18
19
  import { useMediaStreamInVideo } from '../hooks/useMediaStreamInVideo.mjs';
@@ -20,16 +21,18 @@ import { LivenessClassNames } from '../types/classNames.mjs';
20
21
  import { selectErrorState, Hint } from '../shared/Hint.mjs';
21
22
  import { MatchIndicator } from '../shared/MatchIndicator.mjs';
22
23
  import { Overlay } from '../shared/Overlay.mjs';
24
+ import { isDeviceUserFacing } from '../utils/device.mjs';
23
25
  import { FaceLivenessErrorModal, renderErrorModal } from '../shared/FaceLivenessErrorModal.mjs';
24
26
  import { DefaultPhotosensitiveWarning, DefaultRecordingIcon, DefaultCancelButton } from '../shared/DefaultStartScreenComponents.mjs';
27
+ import { CameraSelector } from './CameraSelector.mjs';
25
28
 
29
+ const selectChallengeType = createLivenessSelector((state) => state.context.parsedSessionInformation?.Challenge?.Name);
26
30
  const selectVideoConstraints = createLivenessSelector((state) => state.context.videoAssociatedParams?.videoConstraints);
27
31
  const selectVideoStream = createLivenessSelector((state) => state.context.videoAssociatedParams?.videoMediaStream);
28
32
  const selectFaceMatchPercentage = createLivenessSelector((state) => state.context.faceMatchAssociatedParams?.faceMatchPercentage);
29
33
  const selectFaceMatchState = createLivenessSelector((state) => state.context.faceMatchAssociatedParams?.faceMatchState);
30
34
  const selectSelectedDeviceId = createLivenessSelector((state) => state.context.videoAssociatedParams?.selectedDeviceId);
31
35
  const selectSelectableDevices = createLivenessSelector((state) => state.context.videoAssociatedParams?.selectableDevices);
32
- const centeredLoader = (React__default.createElement(Loader, { size: "large", className: LivenessClassNames.Loader, "data-testid": "centered-loader" }));
33
36
  const showMatchIndicatorStates = [
34
37
  FaceMatchState.TOO_FAR,
35
38
  FaceMatchState.CANT_IDENTIFY,
@@ -47,6 +50,7 @@ const LivenessCameraModule = (props) => {
47
50
  const { cancelLivenessCheckText, recordingIndicatorText } = streamDisplayText;
48
51
  const { ErrorView = FaceLivenessErrorModal, PhotosensitiveWarning = DefaultPhotosensitiveWarning, } = customComponents ?? {};
49
52
  const [state, send] = useLivenessActor();
53
+ const isFaceMovementChallenge = useLivenessSelector(selectChallengeType) === FACE_MOVEMENT_CHALLENGE.type;
50
54
  const videoStream = useLivenessSelector(selectVideoStream);
51
55
  const videoConstraints = useLivenessSelector(selectVideoConstraints);
52
56
  const selectedDeviceId = useLivenessSelector(selectSelectedDeviceId);
@@ -59,8 +63,14 @@ const LivenessCameraModule = (props) => {
59
63
  const canvasRef = useRef(null);
60
64
  const freshnessColorRef = useRef(null);
61
65
  const [isCameraReady, setIsCameraReady] = useState(false);
62
- const isCheckingCamera = state.matches('cameraCheck');
63
- const isWaitingForCamera = state.matches('waitForDOMAndCameraDetails');
66
+ const [isMetadataLoaded, setIsMetadataLoaded] = useState(false);
67
+ const [isCameraUserFacing, setIsCameraUserFacing] = useState(true);
68
+ const isInitCamera = state.matches('initCamera');
69
+ const isInitWebsocket = state.matches('initWebsocket');
70
+ const isCheckingCamera = state.matches({ initCamera: 'cameraCheck' });
71
+ const isWaitingForCamera = state.matches({
72
+ initCamera: 'waitForDOMAndCameraDetails',
73
+ });
64
74
  const isStartView = state.matches('start') || state.matches('userCancel');
65
75
  const isDetectFaceBeforeStart = state.matches('detectFaceBeforeStart');
66
76
  const isRecording = state.matches('recording');
@@ -74,18 +84,29 @@ const LivenessCameraModule = (props) => {
74
84
  const [mediaWidth, setMediaWidth] = useState(videoWidth);
75
85
  const [mediaHeight, setMediaHeight] = useState(videoHeight);
76
86
  const [aspectRatio, setAspectRatio] = useState(() => videoWidth && videoHeight ? videoWidth / videoHeight : 0);
87
+ // Only mobile device camera selection for no light challenge
88
+ const hasMultipleDevices = !!selectableDevices?.length && selectableDevices.length > 1;
89
+ const allowDeviceSelection = isStartView &&
90
+ hasMultipleDevices &&
91
+ (!isMobileScreen || isFaceMovementChallenge);
77
92
  React__default.useEffect(() => {
78
- if (canvasRef?.current && videoRef?.current && videoStream && isStartView) {
79
- drawStaticOval(canvasRef.current, videoRef.current, videoStream);
93
+ async function checkCameraFacing() {
94
+ const isUserFacing = await isDeviceUserFacing(selectedDeviceId);
95
+ setIsCameraUserFacing(isUserFacing);
80
96
  }
81
- }, [canvasRef, videoRef, videoStream, colorMode, isStartView]);
97
+ checkCameraFacing();
98
+ }, [selectedDeviceId]);
82
99
  React__default.useEffect(() => {
100
+ const shouldDrawOval = canvasRef?.current &&
101
+ videoRef?.current &&
102
+ videoStream &&
103
+ isStartView &&
104
+ isMetadataLoaded;
105
+ if (shouldDrawOval) {
106
+ drawStaticOval(canvasRef.current, videoRef.current, videoStream);
107
+ }
83
108
  const updateColorModeHandler = (e) => {
84
- if (e.matches &&
85
- canvasRef?.current &&
86
- videoRef?.current &&
87
- videoStream &&
88
- isStartView) {
109
+ if (e.matches && shouldDrawOval) {
89
110
  drawStaticOval(canvasRef.current, videoRef.current, videoStream);
90
111
  }
91
112
  };
@@ -97,7 +118,7 @@ const LivenessCameraModule = (props) => {
97
118
  darkModePreference.removeEventListener('change', updateColorModeHandler);
98
119
  lightModePreference.addEventListener('change', updateColorModeHandler);
99
120
  };
100
- }, [canvasRef, videoRef, videoStream, isStartView]);
121
+ }, [videoRef, videoStream, colorMode, isStartView, isMetadataLoaded]);
101
122
  React__default.useLayoutEffect(() => {
102
123
  if (isCameraReady) {
103
124
  send({
@@ -128,6 +149,9 @@ const LivenessCameraModule = (props) => {
128
149
  const handleMediaPlay = () => {
129
150
  setIsCameraReady(true);
130
151
  };
152
+ const handleLoadedMetadata = () => {
153
+ setIsMetadataLoaded(true);
154
+ };
131
155
  const beginLivenessCheck = React__default.useCallback(() => {
132
156
  send({
133
157
  type: 'BEGIN',
@@ -136,6 +160,7 @@ const LivenessCameraModule = (props) => {
136
160
  const onCameraChange = React__default.useCallback((e) => {
137
161
  const newDeviceId = e.target.value;
138
162
  const changeCamera = async () => {
163
+ setIsMetadataLoaded(false);
139
164
  const newStream = await navigator.mediaDevices.getUserMedia({
140
165
  video: {
141
166
  ...videoConstraints,
@@ -152,16 +177,19 @@ const LivenessCameraModule = (props) => {
152
177
  }, [videoConstraints, send]);
153
178
  if (isCheckingCamera) {
154
179
  return (React__default.createElement(Flex, { justifyContent: 'center', className: LivenessClassNames.StartScreenCameraWaiting },
155
- React__default.createElement(Loader, { size: "large", className: LivenessClassNames.Loader, "data-testid": "centered-loader", position: "unset" }),
180
+ React__default.createElement(Loader, { size: "large", className: LivenessClassNames.CenteredLoader, "data-testid": "centered-loader", position: "unset" }),
156
181
  React__default.createElement(Text, { fontSize: "large", fontWeight: "bold", "data-testid": "waiting-camera-permission", className: `${LivenessClassNames.StartScreenCameraWaiting}__text` }, cameraDisplayText.waitingCameraPermissionText)));
157
182
  }
183
+ const shouldShowCenteredLoader = isInitCamera || isInitWebsocket;
158
184
  // We don't show full screen camera on the pre check screen (isStartView/isWaitingForCamera)
159
- const shouldShowFullScreenCamera = isMobileScreen && !isStartView && !isWaitingForCamera;
185
+ const shouldShowFullScreenCamera = isMobileScreen && !isStartView && !shouldShowCenteredLoader;
160
186
  return (React__default.createElement(React__default.Fragment, null,
161
- photoSensitivityWarning,
187
+ !isFaceMovementChallenge && photoSensitivityWarning,
188
+ shouldShowCenteredLoader && (React__default.createElement(Flex, { className: LivenessClassNames.ConnectingLoader },
189
+ React__default.createElement(Loader, { size: "large", className: LivenessClassNames.Loader, "data-testid": "centered-loader" }),
190
+ React__default.createElement(Text, { className: LivenessClassNames.LandscapeErrorModalHeader }, hintDisplayText.hintConnectingText))),
162
191
  React__default.createElement(Flex, { className: classNames(LivenessClassNames.CameraModule, shouldShowFullScreenCamera &&
163
192
  `${LivenessClassNames.CameraModule}--mobile`), "data-testid": testId, gap: "zero" },
164
- !isCameraReady && centeredLoader,
165
193
  React__default.createElement(Overlay, { horizontal: "center", vertical: isRecording && !isFlashingFreshness ? 'start' : 'space-between', className: LivenessClassNames.InstructionOverlay },
166
194
  isRecording && (React__default.createElement(DefaultRecordingIcon, { recordingIndicatorText: recordingIndicatorText })),
167
195
  !isStartView && !isWaitingForCamera && !isCheckSucceeded && (React__default.createElement(DefaultCancelButton, { cancelLivenessCheckText: cancelLivenessCheckText })),
@@ -180,19 +208,13 @@ const LivenessCameraModule = (props) => {
180
208
  React__default.createElement(View, { className: LivenessClassNames.VideoAnchor, style: {
181
209
  aspectRatio: `${aspectRatio}`,
182
210
  } },
183
- React__default.createElement("video", { ref: videoRef, muted: true, autoPlay: true, playsInline: true, width: mediaWidth, height: mediaHeight, onCanPlay: handleMediaPlay, "data-testid": "video", className: classNames(LivenessClassNames.Video, isRecordingStopped && LivenessClassNames.FadeOut), "aria-label": cameraDisplayText.a11yVideoLabelText }),
211
+ React__default.createElement("video", { ref: videoRef, muted: true, autoPlay: true, playsInline: true, width: mediaWidth, height: mediaHeight, onCanPlay: handleMediaPlay, onLoadedMetadata: handleLoadedMetadata, "data-testid": "video", className: classNames(LivenessClassNames.Video, isCameraUserFacing && LivenessClassNames.UserFacingVideo, isRecordingStopped && LivenessClassNames.FadeOut), "aria-label": cameraDisplayText.a11yVideoLabelText }),
184
212
  React__default.createElement(Flex, { className: classNames(LivenessClassNames.OvalCanvas, shouldShowFullScreenCamera &&
185
213
  `${LivenessClassNames.OvalCanvas}--mobile`, isRecordingStopped && LivenessClassNames.FadeOut) },
186
214
  React__default.createElement(View, { as: "canvas", ref: canvasRef })),
187
- isStartView &&
188
- !isMobileScreen &&
189
- selectableDevices &&
190
- selectableDevices.length > 1 && (React__default.createElement(Flex, { className: LivenessClassNames.StartScreenCameraSelect },
191
- React__default.createElement(View, { className: LivenessClassNames.StartScreenCameraSelectContainer },
192
- React__default.createElement(Label, { htmlFor: "amplify-liveness-camera-select", className: `${LivenessClassNames.StartScreenCameraSelect}__label` }, "Camera:"),
193
- React__default.createElement(SelectField, { id: "amplify-liveness-camera-select", label: "Camera", labelHidden: true, value: selectedDeviceId, onChange: onCameraChange }, selectableDevices?.map((device) => (React__default.createElement("option", { value: device.deviceId, key: device.deviceId }, device.label))))))))),
215
+ allowDeviceSelection ? (React__default.createElement(CameraSelector, { onSelect: onCameraChange, devices: selectableDevices, deviceId: selectedDeviceId })) : null)),
194
216
  isStartView && (React__default.createElement(Flex, { justifyContent: "center" },
195
217
  React__default.createElement(Button, { variation: "primary", type: "button", onClick: beginLivenessCheck }, instructionDisplayText.startScreenBeginCheckText)))));
196
218
  };
197
219
 
198
- export { LivenessCameraModule, selectFaceMatchPercentage, selectFaceMatchState, selectSelectableDevices, selectSelectedDeviceId, selectVideoConstraints, selectVideoStream };
220
+ export { LivenessCameraModule, selectChallengeType, selectFaceMatchPercentage, selectFaceMatchState, selectSelectableDevices, selectSelectedDeviceId, selectVideoConstraints, selectVideoStream };
@@ -8,14 +8,15 @@ import '@tensorflow-models/face-detection';
8
8
  import '@tensorflow/tfjs-backend-wasm';
9
9
  import '@tensorflow/tfjs-backend-cpu';
10
10
  import '@aws-amplify/core/internals/utils';
11
- import { getLandscapeMediaQuery, isMobileScreen } from '../utils/device.mjs';
12
- import '@aws-sdk/client-rekognitionstreaming';
11
+ import '../service/utils/constants.mjs';
12
+ import '../service/utils/ColorSequenceDisplay/ColorSequenceDisplay.mjs';
13
+ import '@aws-amplify/ui';
13
14
  import '../service/utils/createStreamingClient/createStreamingClient.mjs';
14
- import '../service/utils/freshnessColorDisplay.mjs';
15
+ import '../service/utils/StreamRecorder/StreamRecorder.mjs';
15
16
  import { LivenessCameraModule } from './LivenessCameraModule.mjs';
16
17
  import { useLivenessActor } from '../hooks/useLivenessActor.mjs';
17
18
  import { useLivenessSelector, createLivenessSelector } from '../hooks/useLivenessSelector.mjs';
18
- import '@aws-amplify/ui';
19
+ import { getLandscapeMediaQuery, isMobileScreen } from '../utils/device.mjs';
19
20
  import { CancelButton } from '../shared/CancelButton.mjs';
20
21
  import { defaultErrorDisplayText } from '../displayText.mjs';
21
22
  import { LandscapeErrorModal } from '../shared/LandscapeErrorModal.mjs';