@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
@@ -1,7 +1,6 @@
1
- import { LivenessOvalDetails, IlluminationState, Face, FaceMatchState, BoundingBox, ErrorState } from '../types';
2
- import { FaceDetection } from '../types/faceDetection';
3
- import { ClientFreshnessColorSequence } from '../types/service';
4
- import { SessionInformation } from '@aws-sdk/client-rekognitionstreaming';
1
+ import type { LivenessOvalDetails, Face, BoundingBox, ErrorState, ParsedSessionInformation, FaceDetection } from '../types';
2
+ import { IlluminationState, FaceMatchState } from '../types';
3
+ import type { ColorSequence } from './ColorSequenceDisplay';
5
4
  interface OvalBoundingBox {
6
5
  ovalBoundingBox: BoundingBox;
7
6
  minOvalX: number;
@@ -21,20 +20,21 @@ export declare function getIntersectionOverUnion(box1: BoundingBox, box2: Boundi
21
20
  * Returns the details of a randomly generated liveness oval
22
21
  * from SDK
23
22
  */
24
- export declare function getOvalDetailsFromSessionInformation({ sessionInformation, videoWidth, }: {
25
- sessionInformation: SessionInformation;
23
+ export declare function getOvalDetailsFromSessionInformation({ parsedSessionInformation, videoWidth, }: {
24
+ parsedSessionInformation: ParsedSessionInformation;
26
25
  videoWidth: number;
27
26
  }): LivenessOvalDetails;
28
27
  /**
29
28
  * Returns the details of a statically generated liveness oval based on the video dimensions
30
29
  */
31
- export declare function getStaticLivenessOvalDetails({ width, height, widthSeed, centerXSeed, centerYSeed, ratioMultiplier, }: {
30
+ export declare function getStaticLivenessOvalDetails({ width, height, widthSeed, centerXSeed, centerYSeed, ratioMultiplier, ovalHeightWidthRatio, }: {
32
31
  width: number;
33
32
  height: number;
34
33
  widthSeed?: number;
35
34
  centerXSeed?: number;
36
35
  centerYSeed?: number;
37
36
  ratioMultiplier?: number;
37
+ ovalHeightWidthRatio?: number;
38
38
  }): LivenessOvalDetails;
39
39
  /**
40
40
  * Draws the provided liveness oval on the canvas.
@@ -50,7 +50,12 @@ export declare function drawStaticOval(canvasEl: HTMLCanvasElement, videoEl: HTM
50
50
  export declare function clearOvalCanvas({ canvas, }: {
51
51
  canvas: HTMLCanvasElement;
52
52
  }): void;
53
- export declare function generateBboxFromLandmarks(face: Face, oval: LivenessOvalDetails, frameHeight: number): BoundingBox;
53
+ export declare function generateBboxFromLandmarks({ ovalHeightWidthRatio, face, oval, frameHeight, }: {
54
+ ovalHeightWidthRatio?: number;
55
+ face: Face;
56
+ oval: LivenessOvalDetails;
57
+ frameHeight: number;
58
+ }): BoundingBox;
54
59
  /**
55
60
  * Returns the illumination state in the provided video frame.
56
61
  */
@@ -82,31 +87,16 @@ interface FillOverlayCanvasFractionalInput {
82
87
  scaleFactor: number;
83
88
  }
84
89
  export declare function fillOverlayCanvasFractional({ overlayCanvas, prevColor, nextColor, videoEl, ovalDetails, heightFraction, scaleFactor, }: FillOverlayCanvasFractionalInput): void;
85
- export declare const isClientFreshnessColorSequence: (obj: ClientFreshnessColorSequence | undefined) => obj is ClientFreshnessColorSequence;
86
- export declare function getColorsSequencesFromSessionInformation(sessionInformation: SessionInformation): ClientFreshnessColorSequence[];
87
- export declare function getRGBArrayFromColorString(colorStr: string): number[];
90
+ export declare function getColorsSequencesFromSessionInformation(parsedSessionInformation: ParsedSessionInformation): ColorSequence[];
88
91
  export declare function getFaceMatchState(faceDetector: FaceDetection, videoEl: HTMLVideoElement): Promise<FaceMatchState>;
89
- export declare function isFaceDistanceBelowThreshold({ faceDetector, videoEl, ovalDetails, reduceThreshold, isMobile, }: {
92
+ export declare function isFaceDistanceBelowThreshold({ parsedSessionInformation, faceDetector, videoEl, ovalDetails, reduceThreshold, }: {
93
+ parsedSessionInformation: ParsedSessionInformation;
90
94
  faceDetector: FaceDetection;
91
95
  videoEl: HTMLVideoElement;
92
96
  ovalDetails: LivenessOvalDetails;
93
97
  reduceThreshold?: boolean;
94
- isMobile?: boolean;
95
98
  }): Promise<{
96
99
  isDistanceBelowThreshold: boolean;
97
100
  error?: ErrorState;
98
101
  }>;
99
- export declare function getBoundingBox({ deviceHeight, deviceWidth, height, width, top, left, }: {
100
- deviceHeight: number;
101
- deviceWidth: number;
102
- height: number;
103
- width: number;
104
- top: number;
105
- left: number;
106
- }): {
107
- Height: number;
108
- Width: number;
109
- Top: number;
110
- Left: number;
111
- };
112
102
  export {};
@@ -1,5 +1,5 @@
1
- import { LivenessResponseStream } from '@aws-sdk/client-rekognitionstreaming';
2
- export declare const isServerSesssionInformationEvent: (value: unknown) => value is LivenessResponseStream.ServerSessionInformationEventMember;
1
+ import type { LivenessResponseStream } from '@aws-sdk/client-rekognitionstreaming';
2
+ export declare const isServerSessionInformationEvent: (value: unknown) => value is LivenessResponseStream.ServerSessionInformationEventMember;
3
3
  export declare const isConnectionTimeoutError: (error: unknown) => error is Error;
4
4
  export declare const isDisconnectionEvent: (value: unknown) => value is LivenessResponseStream.DisconnectionEventMember;
5
5
  export declare const isValidationExceptionEvent: (value: unknown) => value is LivenessResponseStream.ValidationExceptionMember;
@@ -0,0 +1,7 @@
1
+ import type { FaceMovementServerChallenge, FaceMovementAndLightServerChallenge, SessionInformation as ServerSessionInformation } from '@aws-sdk/client-rekognitionstreaming';
2
+ import type { FaceMovementAndLightChallenge, FaceMovementChallenge, ParsedSessionInformation } from '../types';
3
+ export declare const isFaceMovementAndLightChallenge: (value: unknown) => value is FaceMovementAndLightChallenge;
4
+ export declare const isFaceMovementChallenge: (value: unknown) => value is FaceMovementChallenge;
5
+ export declare const isFaceMovementAndLightServerChallenge: (value: unknown) => value is FaceMovementAndLightServerChallenge;
6
+ export declare const isFaceMovementServerChallenge: (value: unknown) => value is FaceMovementServerChallenge;
7
+ export declare const createSessionInfoFromServerSessionInformation: (serverSessionInformation: ServerSessionInformation) => ParsedSessionInformation;
@@ -0,0 +1,21 @@
1
+ import type { ClientSessionInformationEvent, LivenessRequestStream } from '@aws-sdk/client-rekognitionstreaming';
2
+ export interface RequestStream extends AsyncGenerator<LivenessRequestStream> {
3
+ }
4
+ export interface VideoStream extends ReadableStream<StreamResult> {
5
+ }
6
+ export type StreamResultType = 'closeCode' | 'sessionInfo' | 'streamStop' | 'streamVideo';
7
+ export type StreamResult<T extends StreamResultType = StreamResultType> = T extends 'closeCode' ? {
8
+ type: T;
9
+ data: {
10
+ closeCode: number;
11
+ };
12
+ } : T extends 'streamVideo' ? {
13
+ type: T;
14
+ data: Blob;
15
+ } : T extends 'sessionInfo' ? {
16
+ type: T;
17
+ data: ClientSessionInformationEvent;
18
+ } : T extends 'streamStop' ? {
19
+ type: T;
20
+ data?: never;
21
+ } : never;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { CheckScreenComponents } from './FaceLivenessErrorModal';
2
+ import type { CheckScreenComponents } from './FaceLivenessErrorModal';
3
3
  export type FaceLivenessDetectorComponents = StartScreenComponents & CheckScreenComponents;
4
4
  export interface StartScreenComponents {
5
5
  PhotosensitiveWarning?: React.ComponentType;
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
- import { ErrorState } from '../service';
3
- import { ErrorDisplayText } from '../displayText';
2
+ import type { ErrorState } from '../service';
3
+ import type { ErrorDisplayText } from '../displayText';
4
4
  export interface CheckScreenComponents {
5
5
  ErrorView?: React.ComponentType<FaceLivenessErrorModalProps>;
6
6
  }
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { IlluminationState, FaceMatchState } from '../service';
3
- import { HintDisplayText } from '../displayText';
3
+ import type { HintDisplayText } from '../displayText';
4
4
  export declare const selectErrorState: import("../hooks").LivenessSelectorFn<"CONNECTION_TIMEOUT" | "TIMEOUT" | "RUNTIME_ERROR" | "FRESHNESS_TIMEOUT" | "SERVER_ERROR" | "CAMERA_FRAMERATE_ERROR" | "CAMERA_ACCESS_ERROR" | "FACE_DISTANCE_ERROR" | "MOBILE_LANDSCAPE_ERROR" | "MULTIPLE_FACES_ERROR" | undefined>;
5
5
  export declare const selectFaceMatchState: import("../hooks").LivenessSelectorFn<FaceMatchState | undefined>;
6
6
  export declare const selectIlluminationState: import("../hooks").LivenessSelectorFn<IlluminationState | undefined>;
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { FlexProps } from '@aws-amplify/ui-react';
2
+ import type { FlexProps } from '@aws-amplify/ui-react';
3
3
  interface OverlayProps extends FlexProps {
4
4
  horizontal?: 'start' | 'center' | 'end';
5
5
  vertical?: 'start' | 'center' | 'end' | 'space-between';
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { ViewProps } from '@aws-amplify/ui-react';
2
+ import type { ViewProps } from '@aws-amplify/ui-react';
3
3
  interface ToastProps extends ViewProps {
4
4
  variation?: 'default' | 'primary' | 'error';
5
5
  size?: 'medium' | 'large';
@@ -2,6 +2,8 @@ export declare enum LivenessClassNames {
2
2
  CameraModule = "amplify-liveness-camera-module",
3
3
  CancelContainer = "amplify-liveness-cancel-container",
4
4
  CancelButton = "amplify-liveness-cancel-button",
5
+ CenteredLoader = "amplify-liveness-centered-loader",
6
+ ConnectingLoader = "amplify-liveness-connecting-loader",
5
7
  CountdownContainer = "amplify-liveness-countdown-container",
6
8
  DescriptionBullet = "amplify-liveness-description-bullet",
7
9
  DescriptionBulletIndex = "amplify-liveness-description-bullet__index",
@@ -41,6 +43,7 @@ export declare enum LivenessClassNames {
41
43
  Toast = "amplify-liveness-toast",
42
44
  ToastContainer = "amplify-liveness-toast__container",
43
45
  ToastMessage = "amplify-liveness-toast__message",
46
+ UserFacingVideo = "amplify-liveness-video--user-facing",
44
47
  Video = "amplify-liveness-video",
45
48
  VideoAnchor = "amplify-liveness-video-anchor"
46
49
  }
@@ -1,4 +1,5 @@
1
1
  export declare function isMobileScreen(): boolean;
2
+ export declare function isDeviceUserFacing(deviceId: string | undefined): Promise<boolean>;
2
3
  export declare function isIOS(): boolean;
3
4
  export declare function isPortrait(): boolean;
4
5
  /**
@@ -1,4 +1,4 @@
1
- import { LivenessDisplayText, HintDisplayText, CameraDisplayText, InstructionDisplayText, StreamDisplayText, ErrorDisplayText } from '../displayText';
1
+ import type { LivenessDisplayText, HintDisplayText, CameraDisplayText, InstructionDisplayText, StreamDisplayText, ErrorDisplayText } from '../displayText';
2
2
  interface LivenessDisplayTextInterface {
3
3
  hintDisplayText: Required<HintDisplayText>;
4
4
  cameraDisplayText: Required<CameraDisplayText>;
@@ -1 +1,2 @@
1
- export { FaceLivenessDetector, FaceLivenessDetectorProps, FaceLivenessDetectorCore, FaceLivenessDetectorCoreProps, AwsCredentialProvider, AwsCredentials, AwsTemporaryCredentials, ErrorState, } from './components';
1
+ export type { FaceLivenessDetectorProps, FaceLivenessDetectorCoreProps, AwsCredentialProvider, AwsCredentials, AwsTemporaryCredentials, ErrorState, } from './components';
2
+ export { FaceLivenessDetector, FaceLivenessDetectorCore } from './components';
@@ -1 +1 @@
1
- export declare const VERSION = "3.3.8";
1
+ export declare const VERSION = "3.4.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aws-amplify/ui-react-liveness",
3
- "version": "3.3.8",
3
+ "version": "3.4.0",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/esm/index.mjs",
6
6
  "exports": {
@@ -48,15 +48,15 @@
48
48
  "react-dom": "^16.14 || ^17 || ^18 || ^19"
49
49
  },
50
50
  "dependencies": {
51
- "@aws-amplify/ui": "6.10.2",
52
- "@aws-amplify/ui-react": "6.11.1",
53
- "@aws-sdk/client-rekognitionstreaming": "3.621.0",
51
+ "@aws-amplify/ui": "6.10.3",
52
+ "@aws-amplify/ui-react": "6.11.2",
53
+ "@aws-sdk/client-rekognitionstreaming": "3.828.0",
54
54
  "@aws-sdk/util-format-url": "3.609.0",
55
- "@smithy/eventstream-serde-browser": "^2.0.4",
56
- "@smithy/fetch-http-handler": "^2.1.3",
55
+ "@smithy/eventstream-serde-browser": "^4.0.4",
56
+ "@smithy/fetch-http-handler": "^5.0.4",
57
57
  "@smithy/protocol-http": "^3.0.3",
58
- "@smithy/signature-v4": "2.1.4",
59
- "@smithy/types": "^3.3.0",
58
+ "@smithy/signature-v4": "5.1.2",
59
+ "@smithy/types": "^4.3.1",
60
60
  "@mediapipe/face_detection": "~0.4.0",
61
61
  "@tensorflow-models/face-detection": "1.0.2",
62
62
  "@tensorflow/tfjs-backend-cpu": "4.11.0",
@@ -64,8 +64,8 @@
64
64
  "@tensorflow/tfjs-converter": "4.11.0",
65
65
  "@tensorflow/tfjs-core": "4.11.0",
66
66
  "@xstate/react": "^3.2.2",
67
- "nanoid": "3.3.8",
68
67
  "tslib": "^2.5.2",
68
+ "uuid": "^11.1.0",
69
69
  "xstate": "^4.33.6"
70
70
  },
71
71
  "devDependencies": {
@@ -85,4 +85,4 @@
85
85
  "limit": "225 kB"
86
86
  }
87
87
  ]
88
- }
88
+ }
@@ -1,131 +0,0 @@
1
- import { fillOverlayCanvasFractional, getRGBArrayFromColorString } from './liveness.mjs';
2
-
3
- const TICK_RATE = 10; // ms -- the rate at which we will render/check colors
4
- var COLOR_STAGE;
5
- (function (COLOR_STAGE) {
6
- COLOR_STAGE["SCROLLING"] = "SCROLLING";
7
- COLOR_STAGE["FLAT"] = "FLAT";
8
- })(COLOR_STAGE || (COLOR_STAGE = {}));
9
- class FreshnessColorDisplay {
10
- constructor(context, freshnessColorsSequence) {
11
- this.context = context;
12
- this.freshnessColorsSequence = freshnessColorsSequence;
13
- this.isFirstTick = true;
14
- }
15
- async displayColorTick() {
16
- return new Promise((resolve, reject) => {
17
- setTimeout(() => {
18
- this.displayNextColorTick(resolve, reject);
19
- }, Math.min(TICK_RATE));
20
- });
21
- }
22
- init() {
23
- this.stageIndex = 0;
24
- this.currColorIndex = 0;
25
- this.currColorSequence = this.freshnessColorsSequence[0];
26
- this.prevColorSequence = this.freshnessColorsSequence[0];
27
- this.stage = COLOR_STAGE.FLAT;
28
- this.timeLastFlatOrScrollChange = Date.now();
29
- this.timeLastFaceMatchChecked = Date.now();
30
- }
31
- displayNextColorTick(resolve, _) {
32
- const { freshnessColorEl } = this.context.freshnessColorAssociatedParams;
33
- const { ovalDetails, scaleFactor } = this.context.ovalAssociatedParams;
34
- const { videoEl } = this.context.videoAssociatedParams;
35
- const tickStartTime = Date.now();
36
- // Send a colorStart time only for the first tick of the first color
37
- if (this.isFirstTick) {
38
- this.init();
39
- this.isFirstTick = false;
40
- this.sendColorStartTime({
41
- tickStartTime: tickStartTime,
42
- currColor: this.currColorSequence.color,
43
- prevColor: this.currColorSequence.color,
44
- currColorIndex: this.stageIndex,
45
- });
46
- }
47
- let timeSinceLastColorChange = tickStartTime - this.timeLastFlatOrScrollChange;
48
- freshnessColorEl.style.display = 'block';
49
- // Every 10 ms tick we will check if the threshold for flat or scrolling, if so we will try to go to the next stage
50
- if ((this.stage === COLOR_STAGE.FLAT &&
51
- timeSinceLastColorChange >=
52
- this.currColorSequence.flatDisplayDuration) ||
53
- (this.stage === COLOR_STAGE.SCROLLING &&
54
- timeSinceLastColorChange >= this.currColorSequence.downscrollDuration)) {
55
- this.incrementStageIndex(tickStartTime);
56
- timeSinceLastColorChange = 0;
57
- }
58
- // Every 10 ms tick we will update the colors displayed
59
- if (this.currColorIndex < this.freshnessColorsSequence.length) {
60
- const heightFraction = timeSinceLastColorChange /
61
- (this.stage === COLOR_STAGE.SCROLLING
62
- ? this.currColorSequence.downscrollDuration
63
- : this.currColorSequence.flatDisplayDuration);
64
- fillOverlayCanvasFractional({
65
- overlayCanvas: freshnessColorEl,
66
- prevColor: this.prevColorSequence.color,
67
- nextColor: this.currColorSequence.color,
68
- videoEl: videoEl,
69
- ovalDetails: ovalDetails,
70
- heightFraction,
71
- scaleFactor: scaleFactor,
72
- });
73
- resolve(false);
74
- }
75
- else {
76
- freshnessColorEl.style.display = 'none';
77
- resolve(true);
78
- }
79
- }
80
- // FLAT - prev = 0, curr = 0
81
- // SCROLL - prev = 0, curr = 1
82
- // FLAT - prev = 1, curr = 1
83
- // SCROLL - prev = 1, curr = 2
84
- // SCROLL - prev = 2, curr = 3
85
- incrementStageIndex(tickStartTime) {
86
- this.stageIndex += 1;
87
- this.prevColorSequence = this.freshnessColorsSequence[this.currColorIndex];
88
- if (this.stage === COLOR_STAGE.FLAT) {
89
- this.currColorIndex += 1;
90
- this.stage = COLOR_STAGE.SCROLLING;
91
- }
92
- else if (this.stage === COLOR_STAGE.SCROLLING) {
93
- const nextFlatColor = this.freshnessColorsSequence[this.currColorIndex];
94
- if (nextFlatColor.flatDisplayDuration > 0) {
95
- this.stage = COLOR_STAGE.FLAT;
96
- }
97
- else {
98
- this.stage = COLOR_STAGE.SCROLLING;
99
- this.currColorIndex += 1;
100
- }
101
- }
102
- this.currColorSequence = this.freshnessColorsSequence[this.currColorIndex];
103
- this.timeLastFlatOrScrollChange = Date.now();
104
- if (this.currColorSequence) {
105
- this.sendColorStartTime({
106
- tickStartTime: tickStartTime,
107
- currColor: this.currColorSequence.color,
108
- prevColor: this.prevColorSequence.color,
109
- currColorIndex: this.stageIndex,
110
- });
111
- }
112
- }
113
- sendColorStartTime({ tickStartTime, currColor, prevColor, currColorIndex, }) {
114
- const { livenessStreamProvider, challengeId } = this.context;
115
- livenessStreamProvider.sendClientInfo({
116
- Challenge: {
117
- FaceMovementAndLightChallenge: {
118
- ChallengeId: challengeId,
119
- ColorDisplayed: {
120
- CurrentColor: { RGB: getRGBArrayFromColorString(currColor) },
121
- PreviousColor: { RGB: getRGBArrayFromColorString(prevColor) },
122
- SequenceNumber: currColorIndex,
123
- CurrentColorStartTimestamp: tickStartTime,
124
- },
125
- },
126
- },
127
- });
128
- }
129
- }
130
-
131
- export { FreshnessColorDisplay };
@@ -1,126 +0,0 @@
1
- import { StartFaceLivenessSessionCommand } from '@aws-sdk/client-rekognitionstreaming';
2
- import { VideoRecorder } from './videoRecorder.mjs';
3
- import { createStreamingClient } from './createStreamingClient/createStreamingClient.mjs';
4
-
5
- const TIME_SLICE = 1000;
6
- function isBlob(obj) {
7
- return obj.arrayBuffer !== undefined;
8
- }
9
- function isClientSessionInformationEvent(obj) {
10
- return obj.Challenge !== undefined;
11
- }
12
- function isEndStreamWithCodeEvent(obj) {
13
- return obj.code !== undefined;
14
- }
15
- class LivenessStreamProvider {
16
- constructor({ sessionId, region, stream, videoEl, credentialProvider, endpointOverride, systemClockOffset, }) {
17
- this.sessionId = sessionId;
18
- this.region = region;
19
- this.stream = stream;
20
- this.videoEl = videoEl;
21
- this.videoRecorder = new VideoRecorder(stream);
22
- this.credentialProvider = credentialProvider;
23
- this.endpointOverride = endpointOverride;
24
- this.systemClockOffset = systemClockOffset;
25
- this.initPromise = this.init();
26
- }
27
- async getResponseStream() {
28
- await this.initPromise;
29
- return this.responseStream;
30
- }
31
- startRecordingLivenessVideo() {
32
- this.videoRecorder.start(TIME_SLICE);
33
- }
34
- sendClientInfo(clientInfo) {
35
- this.videoRecorder.dispatch(new MessageEvent('clientSesssionInfo', { data: { clientInfo } }));
36
- }
37
- async stopVideo() {
38
- await this.videoRecorder.stop();
39
- }
40
- dispatchStopVideoEvent() {
41
- this.videoRecorder.dispatch(new Event('stopVideo'));
42
- }
43
- async endStreamWithCode(code) {
44
- if (this.videoRecorder.getState() === 'recording') {
45
- await this.stopVideo();
46
- }
47
- this.videoRecorder.dispatch(new MessageEvent('endStreamWithCode', { data: { code } }));
48
- return;
49
- }
50
- async init() {
51
- this._client = await createStreamingClient({
52
- credentialsProvider: this.credentialProvider,
53
- endpointOverride: this.endpointOverride,
54
- region: this.region,
55
- systemClockOffset: this.systemClockOffset,
56
- });
57
- this.responseStream = await this.startLivenessVideoConnection();
58
- }
59
- // Creates a generator from a stream of video chunks and livenessActionDocuments and yields VideoEvent and ClientEvents
60
- getAsyncGeneratorFromReadableStream(stream) {
61
- // eslint-disable-next-line @typescript-eslint/no-this-alias
62
- const current = this;
63
- this._reader = stream.getReader();
64
- return async function* () {
65
- while (true) {
66
- const { done, value } = (await current._reader.read());
67
- if (done) {
68
- return;
69
- }
70
- // Video chunks blobs should be sent as video events
71
- if (value === 'stopVideo') {
72
- // sending an empty video chunk signals that we have ended sending video
73
- yield {
74
- VideoEvent: {
75
- VideoChunk: new Uint8Array([]),
76
- TimestampMillis: Date.now(),
77
- },
78
- };
79
- }
80
- else if (isBlob(value)) {
81
- const buffer = await value.arrayBuffer();
82
- const chunk = new Uint8Array(buffer);
83
- if (chunk.length > 0) {
84
- yield {
85
- VideoEvent: {
86
- VideoChunk: chunk,
87
- TimestampMillis: Date.now(),
88
- },
89
- };
90
- }
91
- }
92
- else if (isClientSessionInformationEvent(value)) {
93
- yield {
94
- ClientSessionInformationEvent: {
95
- Challenge: value.Challenge,
96
- },
97
- };
98
- }
99
- else if (isEndStreamWithCodeEvent(value)) {
100
- yield {
101
- VideoEvent: {
102
- VideoChunk: new Uint8Array([]),
103
- // this is a custom type that does not match LivenessRequestStream.
104
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
105
- TimestampMillis: { closeCode: value.code },
106
- },
107
- };
108
- }
109
- }
110
- };
111
- }
112
- async startLivenessVideoConnection() {
113
- const livenessRequestGenerator = this.getAsyncGeneratorFromReadableStream(this.videoRecorder.videoStream)();
114
- const mediaSettings = this.stream.getTracks()[0].getSettings();
115
- const response = await this._client.send(new StartFaceLivenessSessionCommand({
116
- ChallengeVersions: 'FaceMovementAndLightChallenge_1.0.0',
117
- SessionId: this.sessionId,
118
- LivenessRequestStream: livenessRequestGenerator,
119
- VideoWidth: (mediaSettings.width ?? this.videoEl.width).toString(),
120
- VideoHeight: (mediaSettings.height ?? this.videoEl.height).toString(),
121
- }));
122
- return response.LivenessResponseStream;
123
- }
124
- }
125
-
126
- export { LivenessStreamProvider };
@@ -1,108 +0,0 @@
1
- import { isAndroidChromeWithBrokenH264 } from '../../utils/device.mjs';
2
-
3
- // Equivalent to 2 Kbps - needed for maintaining video quality at 60 FPS
4
- const BITS_PER_SECOND = 2000000;
5
- // Only to be used with Chrome for the Android Chrome H264 Bug - https://issues.chromium.org/issues/343199623
6
- const ALTERNATE_CHROME_MIME_TYPE = 'video/x-matroska;codecs=vp8';
7
- /**
8
- * Helper wrapper class over the native MediaRecorder.
9
- */
10
- class VideoRecorder {
11
- constructor(stream) {
12
- if (typeof MediaRecorder === 'undefined') {
13
- throw Error('MediaRecorder is not supported by this browser');
14
- }
15
- this._stream = stream;
16
- this._chunks = [];
17
- this._recorder = new MediaRecorder(stream, {
18
- bitsPerSecond: BITS_PER_SECOND,
19
- mimeType: isAndroidChromeWithBrokenH264()
20
- ? ALTERNATE_CHROME_MIME_TYPE
21
- : undefined,
22
- });
23
- this._setupCallbacks();
24
- }
25
- getState() {
26
- return this._recorder.state;
27
- }
28
- start(timeSlice) {
29
- this.clearRecordedData();
30
- this.recordingStartApiTimestamp = Date.now();
31
- this._recorder.start(timeSlice);
32
- }
33
- async stop() {
34
- if (this.getState() === 'recording') {
35
- this._recorder.stop();
36
- }
37
- return this._recorderStopped;
38
- }
39
- pause() {
40
- this._recorder.pause();
41
- }
42
- clearRecordedData() {
43
- this._chunks = [];
44
- }
45
- dispatch(event) {
46
- this._recorder.dispatchEvent(event);
47
- }
48
- getVideoChunkSize() {
49
- return this._chunks.length;
50
- }
51
- _setupCallbacks() {
52
- // Creates a Readablestream of video chunks. Waits to receive a clientSessionInfo event before pushing
53
- // a livenessActionDocument to the ReadableStream and finally closing the ReadableStream
54
- this.videoStream = new ReadableStream({
55
- start: (controller) => {
56
- if (!this._recorder) {
57
- return;
58
- }
59
- this._recorder.ondataavailable = (e) => {
60
- if (e.data && e.data.size > 0) {
61
- if (this._chunks.length === 0) {
62
- this.firstChunkTimestamp = Date.now();
63
- }
64
- this._chunks.push(e.data);
65
- controller.enqueue(e.data);
66
- }
67
- };
68
- this._recorder.addEventListener('clientSesssionInfo', (e) => {
69
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
70
- controller.enqueue(e.data.clientInfo);
71
- });
72
- this._recorder.addEventListener('stopVideo', () => {
73
- controller.enqueue('stopVideo');
74
- });
75
- this._recorder.addEventListener('endStream', () => {
76
- controller.close();
77
- });
78
- this._recorder.addEventListener('endStreamWithCode', (e) => {
79
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
80
- controller.enqueue({
81
- type: 'endStreamWithCode',
82
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
83
- code: e.data.code,
84
- });
85
- });
86
- },
87
- });
88
- this.recorderStarted = new Promise((resolve) => {
89
- this._recorder.onstart = () => {
90
- this.recorderStartTimestamp = Date.now();
91
- resolve();
92
- };
93
- });
94
- this._recorderStopped = new Promise((resolve) => {
95
- this._recorder.onstop = () => {
96
- this.recorderEndTimestamp = Date.now();
97
- resolve();
98
- };
99
- });
100
- this._recorder.onerror = () => {
101
- if (this.getState() !== 'stopped') {
102
- this.stop();
103
- }
104
- };
105
- }
106
- }
107
-
108
- export { VideoRecorder };
@@ -1,5 +0,0 @@
1
- export interface ClientFreshnessColorSequence {
2
- color: string;
3
- downscrollDuration: number;
4
- flatDisplayDuration: number;
5
- }
@@ -1,21 +0,0 @@
1
- import { LivenessContext } from '../types/machine';
2
- import { ClientFreshnessColorSequence } from '../types/service';
3
- export declare class FreshnessColorDisplay {
4
- private freshnessColorsSequence;
5
- private context;
6
- private stageIndex;
7
- private stage;
8
- private currColorIndex;
9
- private currColorSequence;
10
- private prevColorSequence;
11
- private timeLastFlatOrScrollChange;
12
- private timeFaceMatched;
13
- private timeLastFaceMatchChecked;
14
- private isFirstTick;
15
- constructor(context: LivenessContext, freshnessColorsSequence: ClientFreshnessColorSequence[]);
16
- displayColorTick(): Promise<boolean>;
17
- private init;
18
- private displayNextColorTick;
19
- private incrementStageIndex;
20
- private sendColorStartTime;
21
- }