@aws-amplify/ui-react-liveness 3.3.9 → 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 (61) hide show
  1. package/dist/esm/components/FaceLivenessDetector/FaceLivenessDetectorCore.mjs +4 -2
  2. package/dist/esm/components/FaceLivenessDetector/LivenessCheck/CameraSelector.mjs +13 -0
  3. package/dist/esm/components/FaceLivenessDetector/LivenessCheck/LivenessCameraModule.mjs +50 -28
  4. package/dist/esm/components/FaceLivenessDetector/LivenessCheck/LivenessCheck.mjs +5 -4
  5. package/dist/esm/components/FaceLivenessDetector/service/machine/machine.mjs +247 -314
  6. package/dist/esm/components/FaceLivenessDetector/service/utils/ColorSequenceDisplay/ColorSequenceDisplay.mjs +140 -0
  7. package/dist/esm/components/FaceLivenessDetector/service/utils/StreamRecorder/StreamRecorder.mjs +171 -0
  8. package/dist/esm/components/FaceLivenessDetector/service/utils/TelemetryReporter/TelemetryReporter.mjs +27 -0
  9. package/dist/esm/components/FaceLivenessDetector/service/utils/constants.mjs +30 -7
  10. package/dist/esm/components/FaceLivenessDetector/service/utils/createRequestStreamGenerator/createRequestStreamGenerator.mjs +32 -0
  11. package/dist/esm/components/FaceLivenessDetector/service/utils/createRequestStreamGenerator/utils.mjs +148 -0
  12. package/dist/esm/components/FaceLivenessDetector/service/utils/createStreamingClient/Signer.mjs +2 -3
  13. package/dist/esm/components/FaceLivenessDetector/service/utils/createStreamingClient/createStreamingClient.mjs +36 -6
  14. package/dist/esm/components/FaceLivenessDetector/service/utils/createStreamingClient/resolveCredentials.mjs +7 -6
  15. package/dist/esm/components/FaceLivenessDetector/service/utils/getFaceMatchStateInLivenessOval.mjs +9 -5
  16. package/dist/esm/components/FaceLivenessDetector/service/utils/liveness.mjs +19 -34
  17. package/dist/esm/components/FaceLivenessDetector/service/utils/{eventUtils.mjs → responseStreamEvent.mjs} +2 -2
  18. package/dist/esm/components/FaceLivenessDetector/service/utils/sessionInformation.mjs +45 -0
  19. package/dist/esm/components/FaceLivenessDetector/shared/DefaultStartScreenComponents.mjs +3 -2
  20. package/dist/esm/components/FaceLivenessDetector/shared/FaceLivenessErrorModal.mjs +4 -2
  21. package/dist/esm/components/FaceLivenessDetector/shared/Hint.mjs +4 -7
  22. package/dist/esm/components/FaceLivenessDetector/types/classNames.mjs +3 -0
  23. package/dist/esm/components/FaceLivenessDetector/utils/device.mjs +12 -12
  24. package/dist/esm/index.mjs +12 -0
  25. package/dist/esm/version.mjs +1 -1
  26. package/dist/index.js +956 -775
  27. package/dist/styles.css +17 -2
  28. package/dist/types/components/FaceLivenessDetector/LivenessCheck/CameraSelector.d.ts +8 -0
  29. package/dist/types/components/FaceLivenessDetector/LivenessCheck/LivenessCameraModule.d.ts +1 -0
  30. package/dist/types/components/FaceLivenessDetector/index.d.ts +1 -0
  31. package/dist/types/components/FaceLivenessDetector/service/types/machine.d.ts +37 -24
  32. package/dist/types/components/FaceLivenessDetector/service/utils/ColorSequenceDisplay/ColorSequenceDisplay.d.ts +55 -0
  33. package/dist/types/components/FaceLivenessDetector/service/utils/ColorSequenceDisplay/index.d.ts +2 -0
  34. package/dist/types/components/FaceLivenessDetector/service/utils/StreamRecorder/StreamRecorder.d.ts +15 -0
  35. package/dist/types/components/FaceLivenessDetector/service/utils/StreamRecorder/index.d.ts +1 -0
  36. package/dist/types/components/FaceLivenessDetector/service/utils/TelemetryReporter/TelemetryReporter.d.ts +8 -0
  37. package/dist/types/components/FaceLivenessDetector/service/utils/TelemetryReporter/index.d.ts +2 -0
  38. package/dist/types/components/FaceLivenessDetector/service/utils/constants.d.ts +27 -3
  39. package/dist/types/components/FaceLivenessDetector/service/utils/createRequestStreamGenerator/createRequestStreamGenerator.d.ts +15 -0
  40. package/dist/types/components/FaceLivenessDetector/service/utils/createRequestStreamGenerator/index.d.ts +2 -0
  41. package/dist/types/components/FaceLivenessDetector/service/utils/createRequestStreamGenerator/utils.d.ts +30 -0
  42. package/dist/types/components/FaceLivenessDetector/service/utils/createStreamingClient/Signer.d.ts +0 -1
  43. package/dist/types/components/FaceLivenessDetector/service/utils/createStreamingClient/createStreamingClient.d.ts +27 -5
  44. package/dist/types/components/FaceLivenessDetector/service/utils/createStreamingClient/index.d.ts +1 -0
  45. package/dist/types/components/FaceLivenessDetector/service/utils/getFaceMatchStateInLivenessOval.d.ts +3 -4
  46. package/dist/types/components/FaceLivenessDetector/service/utils/index.d.ts +7 -4
  47. package/dist/types/components/FaceLivenessDetector/service/utils/liveness.d.ts +15 -26
  48. package/dist/types/components/FaceLivenessDetector/service/utils/{eventUtils.d.ts → responseStreamEvent.d.ts} +1 -1
  49. package/dist/types/components/FaceLivenessDetector/service/utils/sessionInformation.d.ts +7 -0
  50. package/dist/types/components/FaceLivenessDetector/service/utils/types.d.ts +21 -0
  51. package/dist/types/components/FaceLivenessDetector/types/classNames.d.ts +3 -0
  52. package/dist/types/components/FaceLivenessDetector/utils/device.d.ts +1 -0
  53. package/dist/types/version.d.ts +1 -1
  54. package/package.json +8 -8
  55. package/dist/esm/components/FaceLivenessDetector/service/utils/freshnessColorDisplay.mjs +0 -131
  56. package/dist/esm/components/FaceLivenessDetector/service/utils/streamProvider.mjs +0 -126
  57. package/dist/esm/components/FaceLivenessDetector/service/utils/videoRecorder.mjs +0 -108
  58. package/dist/types/components/FaceLivenessDetector/service/types/service.d.ts +0 -5
  59. package/dist/types/components/FaceLivenessDetector/service/utils/freshnessColorDisplay.d.ts +0 -21
  60. package/dist/types/components/FaceLivenessDetector/service/utils/streamProvider.d.ts +0 -42
  61. package/dist/types/components/FaceLivenessDetector/service/utils/videoRecorder.d.ts +0 -27
@@ -1,6 +1,6 @@
1
1
  import { fetchAuthSession } from 'aws-amplify/auth';
2
2
 
3
- const isCredentialsProvider = (credentialsProvider) => typeof credentialsProvider === 'function';
3
+ const isValidCredentialsProvider = (credentialsProvider) => typeof credentialsProvider === 'function';
4
4
  // the return interface of `fetchAuthSession` includes `credentials` as
5
5
  // optional, but `credentials` is always returned. If `fetchAuthSession`
6
6
  // is called for an unauthenticated end user, values of `accessKeyId`
@@ -15,13 +15,14 @@ const isCredentials = (credentials) => !!(credentials?.accessKeyId && credential
15
15
  * @returns {Promise<AwsCredentials | AwsCredentialProvider>} `credentials` object or valid `credentialsProvider` callback
16
16
  */
17
17
  async function resolveCredentials(credentialsProvider) {
18
- const hasCredentialsProvider = isCredentialsProvider(credentialsProvider);
19
- if (hasCredentialsProvider) {
20
- return credentialsProvider;
21
- }
22
- if (credentialsProvider && !hasCredentialsProvider) {
18
+ const hasValidCredentialsProvider = isValidCredentialsProvider(credentialsProvider);
19
+ // provided `credentialsProvider` is not valid
20
+ if (credentialsProvider && !hasValidCredentialsProvider) {
23
21
  throw new Error('Invalid credentialsProvider');
24
22
  }
23
+ if (hasValidCredentialsProvider) {
24
+ return credentialsProvider;
25
+ }
25
26
  try {
26
27
  const result = (await fetchAuthSession()).credentials;
27
28
  if (isCredentials(result)) {
@@ -5,10 +5,9 @@ import { FACE_MATCH_RANGE_MAX, FACE_MATCH_WEIGHT_MAX, FACE_MATCH_WEIGHT_MIN, FAC
5
5
  /**
6
6
  * Returns the state of the provided face with respect to the provided liveness oval.
7
7
  */
8
- function getFaceMatchStateInLivenessOval({ face, ovalDetails, initialFaceIntersection, sessionInformation, frameHeight, }) {
8
+ function getFaceMatchStateInLivenessOval({ face, ovalDetails, initialFaceIntersection, parsedSessionInformation, frameHeight, }) {
9
9
  let faceMatchState;
10
- const challengeConfig = sessionInformation?.Challenge?.FaceMovementAndLightChallenge
11
- ?.ChallengeConfig;
10
+ const challengeConfig = parsedSessionInformation.Challenge.ChallengeConfig;
12
11
  if (!challengeConfig ||
13
12
  !challengeConfig.OvalIouThreshold ||
14
13
  !challengeConfig.OvalIouHeightThreshold ||
@@ -17,8 +16,13 @@ function getFaceMatchStateInLivenessOval({ face, ovalDetails, initialFaceInterse
17
16
  !challengeConfig.FaceIouWidthThreshold) {
18
17
  throw new Error('Challenge information not returned from session information.');
19
18
  }
20
- const { OvalIouThreshold, FaceIouHeightThreshold, FaceIouWidthThreshold } = challengeConfig;
21
- const faceBoundingBox = generateBboxFromLandmarks(face, ovalDetails, frameHeight);
19
+ const { OvalIouThreshold, FaceIouHeightThreshold, FaceIouWidthThreshold, OvalHeightWidthRatio, } = challengeConfig;
20
+ const faceBoundingBox = generateBboxFromLandmarks({
21
+ ovalHeightWidthRatio: OvalHeightWidthRatio,
22
+ face,
23
+ oval: ovalDetails,
24
+ frameHeight,
25
+ });
22
26
  const minFaceX = faceBoundingBox.left;
23
27
  const maxFaceX = faceBoundingBox.right;
24
28
  const minFaceY = faceBoundingBox.top;
@@ -1,6 +1,6 @@
1
1
  import { IlluminationState, FaceMatchState } from '../types/liveness.mjs';
2
2
  import { LivenessErrorState } from '../types/error.mjs';
3
- import { PUPIL_DISTANCE_WEIGHT, FACE_HEIGHT_WEIGHT, FACE_DISTANCE_THRESHOLD, REDUCED_THRESHOLD_MOBILE, REDUCED_THRESHOLD } from './constants.mjs';
3
+ import { OVAL_HEIGHT_WIDTH_RATIO, PUPIL_DISTANCE_WEIGHT, FACE_HEIGHT_WEIGHT } from './constants.mjs';
4
4
 
5
5
  /**
6
6
  * Returns the random number between min and max
@@ -45,9 +45,8 @@ function getIntersectionOverUnion(box1, box2) {
45
45
  * Returns the details of a randomly generated liveness oval
46
46
  * from SDK
47
47
  */
48
- function getOvalDetailsFromSessionInformation({ sessionInformation, videoWidth, }) {
49
- const ovalParameters = sessionInformation?.Challenge?.FaceMovementAndLightChallenge
50
- ?.OvalParameters;
48
+ function getOvalDetailsFromSessionInformation({ parsedSessionInformation, videoWidth, }) {
49
+ const ovalParameters = parsedSessionInformation.Challenge.OvalParameters;
51
50
  if (!ovalParameters ||
52
51
  !ovalParameters.CenterX ||
53
52
  !ovalParameters.CenterY ||
@@ -69,7 +68,7 @@ function getOvalDetailsFromSessionInformation({ sessionInformation, videoWidth,
69
68
  /**
70
69
  * Returns the details of a statically generated liveness oval based on the video dimensions
71
70
  */
72
- function getStaticLivenessOvalDetails({ width, height, widthSeed = 1.0, centerXSeed = 0.5, centerYSeed = 0.5, ratioMultiplier = 0.8, }) {
71
+ function getStaticLivenessOvalDetails({ width, height, widthSeed = 1.0, centerXSeed = 0.5, centerYSeed = 0.5, ratioMultiplier = 0.8, ovalHeightWidthRatio = OVAL_HEIGHT_WIDTH_RATIO, }) {
73
72
  const videoHeight = height;
74
73
  let videoWidth = width;
75
74
  const ovalRatio = widthSeed * ratioMultiplier;
@@ -83,7 +82,7 @@ function getStaticLivenessOvalDetails({ width, height, widthSeed = 1.0, centerXS
83
82
  videoWidth = (3 / 4) * videoHeight;
84
83
  }
85
84
  const ovalWidth = ovalRatio * videoWidth;
86
- const ovalHeight = 1.618 * ovalWidth;
85
+ const ovalHeight = ovalHeightWidthRatio * ovalWidth;
87
86
  return {
88
87
  flippedCenterX: Math.floor(videoWidth - centerX),
89
88
  centerX: Math.floor(centerX),
@@ -146,7 +145,7 @@ function drawStaticOval(canvasEl, videoEl, videoMediaStream) {
146
145
  const ovalDetails = getStaticLivenessOvalDetails({
147
146
  width: width,
148
147
  height: height,
149
- ratioMultiplier: 0.5,
148
+ ratioMultiplier: 0.3,
150
149
  });
151
150
  ovalDetails.flippedCenterX = width - ovalDetails.centerX;
152
151
  // Compute scaleFactor which is how much our video element is scaled
@@ -180,7 +179,7 @@ function getPupilDistanceAndFaceHeight(face) {
180
179
  const faceHeight = Math.sqrt((eyeCenter[0] - mouth[0]) ** 2 + (eyeCenter[1] - mouth[1]) ** 2);
181
180
  return { pupilDistance, faceHeight };
182
181
  }
183
- function generateBboxFromLandmarks(face, oval, frameHeight) {
182
+ function generateBboxFromLandmarks({ ovalHeightWidthRatio = OVAL_HEIGHT_WIDTH_RATIO, face, oval, frameHeight, }) {
184
183
  const { leftEye, rightEye, nose, leftEar, rightEar } = face;
185
184
  const { height: ovalHeight, centerY } = oval;
186
185
  const ovalTop = centerY - ovalHeight / 2;
@@ -200,7 +199,7 @@ function generateBboxFromLandmarks(face, oval, frameHeight) {
200
199
  centerFaceY = eyeCenter[1];
201
200
  }
202
201
  const faceWidth = ocularWidth;
203
- const faceHeight = 1.68 * faceWidth;
202
+ const faceHeight = ovalHeightWidthRatio * faceWidth;
204
203
  const top = Math.max(centerFaceY - faceHeight / 2, 0);
205
204
  const bottom = Math.min(centerFaceY + faceHeight / 2, frameHeight);
206
205
  const left = Math.min(centerFaceX - ocularWidth / 2, rightEar[0]);
@@ -319,11 +318,11 @@ function fillOverlayCanvasFractional({ overlayCanvas, prevColor, nextColor, vide
319
318
  throw new Error('Cannot find Overlay Canvas.');
320
319
  }
321
320
  }
322
- const isClientFreshnessColorSequence = (obj) => !!obj;
323
- function getColorsSequencesFromSessionInformation(sessionInformation) {
324
- const colorSequenceFromSessionInfo = sessionInformation.Challenge.FaceMovementAndLightChallenge
321
+ const isColorSequence = (obj) => !!obj;
322
+ function getColorsSequencesFromSessionInformation(parsedSessionInformation) {
323
+ const colorSequenceFromServerChallenge = parsedSessionInformation.Challenge
325
324
  .ColorSequences ?? [];
326
- const colorSequences = colorSequenceFromSessionInfo.map(({ FreshnessColor, DownscrollDuration: downscrollDuration, FlatDisplayDuration: flatDisplayDuration, }) => {
325
+ const colorSequences = colorSequenceFromServerChallenge.map(({ FreshnessColor, DownscrollDuration: downscrollDuration, FlatDisplayDuration: flatDisplayDuration, }) => {
327
326
  const colorArray = FreshnessColor.RGB;
328
327
  const color = `rgb(${colorArray[0]},${colorArray[1]},${colorArray[2]})`;
329
328
  return typeof color !== 'undefined' &&
@@ -336,13 +335,7 @@ function getColorsSequencesFromSessionInformation(sessionInformation) {
336
335
  }
337
336
  : undefined;
338
337
  });
339
- return colorSequences.filter(isClientFreshnessColorSequence);
340
- }
341
- function getRGBArrayFromColorString(colorStr) {
342
- return colorStr
343
- .slice(colorStr.indexOf('(') + 1, colorStr.indexOf(')'))
344
- .split(',')
345
- .map((str) => parseInt(str));
338
+ return colorSequences.filter(isColorSequence);
346
339
  }
347
340
  async function getFaceMatchState(faceDetector, videoEl) {
348
341
  const detectedFaces = await faceDetector.detectFaces(videoEl);
@@ -366,7 +359,9 @@ async function getFaceMatchState(faceDetector, videoEl) {
366
359
  }
367
360
  return faceMatchState;
368
361
  }
369
- async function isFaceDistanceBelowThreshold({ faceDetector, videoEl, ovalDetails, reduceThreshold = false, isMobile = false, }) {
362
+ async function isFaceDistanceBelowThreshold({ parsedSessionInformation, faceDetector, videoEl, ovalDetails, reduceThreshold = false, }) {
363
+ const challengeConfig = parsedSessionInformation.Challenge.ChallengeConfig;
364
+ const { FaceDistanceThresholdMin, FaceDistanceThreshold } = challengeConfig;
370
365
  const detectedFaces = await faceDetector.detectFaces(videoEl);
371
366
  let detectedFace;
372
367
  let isDistanceBelowThreshold = false;
@@ -390,10 +385,8 @@ async function isFaceDistanceBelowThreshold({ faceDetector, videoEl, ovalDetails
390
385
  isDistanceBelowThreshold =
391
386
  calibratedPupilDistance / width <
392
387
  (!reduceThreshold
393
- ? FACE_DISTANCE_THRESHOLD
394
- : isMobile
395
- ? REDUCED_THRESHOLD_MOBILE
396
- : REDUCED_THRESHOLD);
388
+ ? FaceDistanceThresholdMin
389
+ : FaceDistanceThreshold);
397
390
  if (!isDistanceBelowThreshold) {
398
391
  error = LivenessErrorState.FACE_DISTANCE_ERROR;
399
392
  }
@@ -408,13 +401,5 @@ async function isFaceDistanceBelowThreshold({ faceDetector, videoEl, ovalDetails
408
401
  }
409
402
  return { isDistanceBelowThreshold, error };
410
403
  }
411
- function getBoundingBox({ deviceHeight, deviceWidth, height, width, top, left, }) {
412
- return {
413
- Height: height / deviceHeight,
414
- Width: width / deviceWidth,
415
- Top: top / deviceHeight,
416
- Left: left / deviceWidth,
417
- };
418
- }
419
404
 
420
- export { clearOvalCanvas, drawLivenessOvalInCanvas, drawStaticOval, estimateIllumination, fillOverlayCanvasFractional, generateBboxFromLandmarks, getBoundingBox, getColorsSequencesFromSessionInformation, getFaceMatchState, getIntersectionOverUnion, getOvalBoundingBox, getOvalDetailsFromSessionInformation, getRGBArrayFromColorString, getStaticLivenessOvalDetails, isCameraDeviceVirtual, isClientFreshnessColorSequence, isFaceDistanceBelowThreshold };
405
+ export { clearOvalCanvas, drawLivenessOvalInCanvas, drawStaticOval, estimateIllumination, fillOverlayCanvasFractional, generateBboxFromLandmarks, getColorsSequencesFromSessionInformation, getFaceMatchState, getIntersectionOverUnion, getOvalBoundingBox, getOvalDetailsFromSessionInformation, getStaticLivenessOvalDetails, isCameraDeviceVirtual, isFaceDistanceBelowThreshold };
@@ -1,6 +1,6 @@
1
1
  import { WEBSOCKET_CONNECTION_TIMEOUT_MESSAGE } from './createStreamingClient/CustomWebSocketFetchHandler.mjs';
2
2
 
3
- const isServerSesssionInformationEvent = (value) => {
3
+ const isServerSessionInformationEvent = (value) => {
4
4
  return !!value
5
5
  ?.ServerSessionInformationEvent;
6
6
  };
@@ -33,4 +33,4 @@ const isInvalidSignatureRegionException = (error) => {
33
33
  return (name === 'InvalidSignatureException' && message.includes('valid region'));
34
34
  };
35
35
 
36
- export { isConnectionTimeoutError, isDisconnectionEvent, isInternalServerExceptionEvent, isInvalidSignatureRegionException, isServerSesssionInformationEvent, isServiceQuotaExceededExceptionEvent, isThrottlingExceptionEvent, isValidationExceptionEvent };
36
+ export { isConnectionTimeoutError, isDisconnectionEvent, isInternalServerExceptionEvent, isInvalidSignatureRegionException, isServerSessionInformationEvent, isServiceQuotaExceededExceptionEvent, isThrottlingExceptionEvent, isValidationExceptionEvent };
@@ -0,0 +1,45 @@
1
+ import { FACE_MOVEMENT_AND_LIGHT_CHALLENGE, FACE_MOVEMENT_CHALLENGE } from './constants.mjs';
2
+
3
+ const isFaceMovementAndLightChallenge = (value) => {
4
+ return (value?.Challenge?.Name ===
5
+ 'FaceMovementAndLightChallenge');
6
+ };
7
+ const isFaceMovementChallenge = (value) => {
8
+ return (value?.Challenge?.Name ===
9
+ 'FaceMovementChallenge');
10
+ };
11
+ const isFaceMovementAndLightServerChallenge = (value) => {
12
+ return !!value
13
+ ?.FaceMovementAndLightChallenge;
14
+ };
15
+ const isFaceMovementServerChallenge = (value) => {
16
+ return !!value
17
+ ?.FaceMovementChallenge;
18
+ };
19
+ const createSessionInfoFromServerSessionInformation = (serverSessionInformation) => {
20
+ let challenge;
21
+ if (isFaceMovementAndLightServerChallenge(serverSessionInformation.Challenge)) {
22
+ challenge = {
23
+ ...serverSessionInformation.Challenge.FaceMovementAndLightChallenge,
24
+ Name: FACE_MOVEMENT_AND_LIGHT_CHALLENGE.type,
25
+ };
26
+ }
27
+ else if (isFaceMovementServerChallenge(serverSessionInformation.Challenge)) {
28
+ challenge = {
29
+ ...serverSessionInformation.Challenge.FaceMovementChallenge,
30
+ Name: FACE_MOVEMENT_CHALLENGE.type,
31
+ };
32
+ }
33
+ else {
34
+ throw new Error('Unsupported challenge type returned from session information.');
35
+ }
36
+ if (!challenge.ChallengeConfig ||
37
+ !challenge.ChallengeConfig.FaceDistanceThreshold ||
38
+ !challenge.ChallengeConfig.FaceDistanceThresholdMin ||
39
+ !challenge.ChallengeConfig.OvalHeightWidthRatio) {
40
+ throw new Error('Challenge config not returned from session information.');
41
+ }
42
+ return { ...serverSessionInformation, Challenge: challenge };
43
+ };
44
+
45
+ export { createSessionInfoFromServerSessionInformation, isFaceMovementAndLightChallenge, isFaceMovementAndLightServerChallenge, isFaceMovementChallenge, isFaceMovementServerChallenge };
@@ -9,9 +9,10 @@ import '@tensorflow-models/face-detection';
9
9
  import '@tensorflow/tfjs-backend-wasm';
10
10
  import '@tensorflow/tfjs-backend-cpu';
11
11
  import '@aws-amplify/core/internals/utils';
12
- import '@aws-sdk/client-rekognitionstreaming';
12
+ import '../service/utils/constants.mjs';
13
+ import '../service/utils/ColorSequenceDisplay/ColorSequenceDisplay.mjs';
13
14
  import '../service/utils/createStreamingClient/createStreamingClient.mjs';
14
- import '../service/utils/freshnessColorDisplay.mjs';
15
+ import '../service/utils/StreamRecorder/StreamRecorder.mjs';
15
16
  import '@xstate/react';
16
17
  import '../providers/FaceLivenessDetectorProvider.mjs';
17
18
  import { LivenessClassNames } from '../types/classNames.mjs';
@@ -9,9 +9,11 @@ import '@tensorflow-models/face-detection';
9
9
  import '@tensorflow/tfjs-backend-wasm';
10
10
  import '@tensorflow/tfjs-backend-cpu';
11
11
  import '@aws-amplify/core/internals/utils';
12
- import '@aws-sdk/client-rekognitionstreaming';
12
+ import '../service/utils/constants.mjs';
13
+ import '../service/utils/ColorSequenceDisplay/ColorSequenceDisplay.mjs';
14
+ import '@aws-amplify/ui';
13
15
  import '../service/utils/createStreamingClient/createStreamingClient.mjs';
14
- import '../service/utils/freshnessColorDisplay.mjs';
16
+ import '../service/utils/StreamRecorder/StreamRecorder.mjs';
15
17
  import { Toast } from './Toast.mjs';
16
18
  import { Overlay } from './Overlay.mjs';
17
19
  import { defaultErrorDisplayText } from '../displayText.mjs';
@@ -7,12 +7,13 @@ 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 { useLivenessActor } from '../hooks/useLivenessActor.mjs';
14
16
  import { createLivenessSelector, useLivenessSelector } from '../hooks/useLivenessSelector.mjs';
15
- import '@aws-amplify/ui';
16
17
  import { Toast } from './Toast.mjs';
17
18
  import { ToastWithLoader } from './ToastWithLoader.mjs';
18
19
 
@@ -41,7 +42,6 @@ const Hint = ({ hintDisplayText }) => {
41
42
  state.matches('detectFaceDistanceBeforeRecording');
42
43
  const isStartView = state.matches('start') || state.matches('userCancel');
43
44
  const isRecording = state.matches('recording');
44
- const isNotRecording = state.matches('notRecording');
45
45
  const isUploading = state.matches('uploading');
46
46
  const isCheckSuccessful = state.matches('checkSucceeded');
47
47
  const isCheckFailed = state.matches('checkFailed');
@@ -81,9 +81,6 @@ const Hint = ({ hintDisplayText }) => {
81
81
  isFaceFarEnoughBeforeRecordingState === false) {
82
82
  return React.createElement(DefaultToast, { text: hintDisplayText.hintTooCloseText });
83
83
  }
84
- if (isNotRecording) {
85
- return (React.createElement(ToastWithLoader, { displayText: hintDisplayText.hintConnectingText }));
86
- }
87
84
  if (isUploading) {
88
85
  return (React.createElement(React.Fragment, null,
89
86
  React.createElement(VisuallyHidden, { "aria-live": "assertive" }, hintDisplayText.hintCheckCompleteText),
@@ -3,6 +3,8 @@ var LivenessClassNames;
3
3
  LivenessClassNames["CameraModule"] = "amplify-liveness-camera-module";
4
4
  LivenessClassNames["CancelContainer"] = "amplify-liveness-cancel-container";
5
5
  LivenessClassNames["CancelButton"] = "amplify-liveness-cancel-button";
6
+ LivenessClassNames["CenteredLoader"] = "amplify-liveness-centered-loader";
7
+ LivenessClassNames["ConnectingLoader"] = "amplify-liveness-connecting-loader";
6
8
  LivenessClassNames["CountdownContainer"] = "amplify-liveness-countdown-container";
7
9
  LivenessClassNames["DescriptionBullet"] = "amplify-liveness-description-bullet";
8
10
  LivenessClassNames["DescriptionBulletIndex"] = "amplify-liveness-description-bullet__index";
@@ -42,6 +44,7 @@ var LivenessClassNames;
42
44
  LivenessClassNames["Toast"] = "amplify-liveness-toast";
43
45
  LivenessClassNames["ToastContainer"] = "amplify-liveness-toast__container";
44
46
  LivenessClassNames["ToastMessage"] = "amplify-liveness-toast__message";
47
+ LivenessClassNames["UserFacingVideo"] = "amplify-liveness-video--user-facing";
45
48
  LivenessClassNames["Video"] = "amplify-liveness-video";
46
49
  LivenessClassNames["VideoAnchor"] = "amplify-liveness-video-anchor";
47
50
  })(LivenessClassNames || (LivenessClassNames = {}));
@@ -11,6 +11,17 @@ function isMobileScreen() {
11
11
  /Android|iPhone|iPad/i.test(navigator.userAgent) || isNewerIpad();
12
12
  return isMobileDevice;
13
13
  }
14
+ async function isDeviceUserFacing(deviceId) {
15
+ const devices = await navigator.mediaDevices?.enumerateDevices();
16
+ // Find the video input device with the matching deviceId
17
+ const videoDevice = devices?.find((device) => device.deviceId === deviceId && device.kind === 'videoinput');
18
+ if (videoDevice) {
19
+ // Check if the device label contains the word "back"
20
+ return !videoDevice.label.toLowerCase().includes('back');
21
+ }
22
+ // If the device is not found or not a video input device, return false
23
+ return true;
24
+ }
14
25
  /**
15
26
  * Use window.matchMedia to direct landscape orientation
16
27
  * screen.orientation is not supported in Safari so we will use
@@ -20,16 +31,5 @@ function isMobileScreen() {
20
31
  function getLandscapeMediaQuery() {
21
32
  return window.matchMedia('(orientation: landscape)');
22
33
  }
23
- // minor version 146+ is confirmed to have the fix https://issues.chromium.org/issues/343199623#comment34
24
- function isAndroidChromeWithBrokenH264() {
25
- const groups = /Chrome\/125\.[0-9]+\.[0-9]+\.([0-9]+)/i.exec(navigator.userAgent);
26
- if (!groups) {
27
- return false;
28
- }
29
- const minorVersion = groups[1];
30
- return (/Android/i.test(navigator.userAgent) &&
31
- /Chrome\/125/i.test(navigator.userAgent) &&
32
- parseInt(minorVersion) < 146);
33
- }
34
34
 
35
- export { getLandscapeMediaQuery, isAndroidChromeWithBrokenH264, isMobileScreen };
35
+ export { getLandscapeMediaQuery, isDeviceUserFacing, isMobileScreen };
@@ -1,2 +1,14 @@
1
1
  export { default as FaceLivenessDetector } from './components/FaceLivenessDetector/FaceLivenessDetector.mjs';
2
2
  export { default as FaceLivenessDetectorCore } from './components/FaceLivenessDetector/FaceLivenessDetectorCore.mjs';
3
+ import './components/FaceLivenessDetector/service/machine/machine.mjs';
4
+ import './components/FaceLivenessDetector/service/types/liveness.mjs';
5
+ import '@tensorflow/tfjs-core';
6
+ import '@tensorflow-models/face-detection';
7
+ import '@tensorflow/tfjs-backend-wasm';
8
+ import '@tensorflow/tfjs-backend-cpu';
9
+ import '@aws-amplify/core/internals/utils';
10
+ import './components/FaceLivenessDetector/service/utils/constants.mjs';
11
+ import './components/FaceLivenessDetector/service/utils/ColorSequenceDisplay/ColorSequenceDisplay.mjs';
12
+ import '@aws-amplify/ui';
13
+ import './components/FaceLivenessDetector/service/utils/createStreamingClient/createStreamingClient.mjs';
14
+ import './components/FaceLivenessDetector/service/utils/StreamRecorder/StreamRecorder.mjs';
@@ -1,3 +1,3 @@
1
- const VERSION = '3.3.9';
1
+ const VERSION = '3.4.0';
2
2
 
3
3
  export { VERSION };