santoid-sdk 1.0.4 → 1.0.6
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.
- package/README.md +3 -2
- package/dist/browser/liveness/index.js +1 -1
- package/dist/esm/liveness/index.js +18 -1
- package/dist/node/liveness/index.js +18 -1
- package/dist/utils/types.d.ts +10 -3
- package/jest.config.cjs +17 -0
- package/package.json +11 -4
- package/src/esm/liveness/index.ts +26 -2
- package/src/node/liveness/index.ts +27 -2
- package/src/utils/types.ts +12 -3
- package/tsconfig.json +2 -1
package/README.md
CHANGED
|
@@ -91,7 +91,8 @@ async function startLivenessDetection () {
|
|
|
91
91
|
errorCallback: ({ errorCode }) => {},
|
|
92
92
|
|
|
93
93
|
// (Opcional) Função executada em caso de sucesso
|
|
94
|
-
|
|
94
|
+
// O ID da solicitação pode ser recebido pelos parâmetros, como no exemplo abaixo
|
|
95
|
+
successCallback: ({ livenessId }) => {},
|
|
95
96
|
|
|
96
97
|
// (Opcional) Função executada quando a validação é finalizada
|
|
97
98
|
endCallback: () => {},
|
|
@@ -147,7 +148,7 @@ Ao importar a biblioteca via tag script, a função **livenessDetection** ficar
|
|
|
147
148
|
<body>
|
|
148
149
|
<button onclick="startLiveness()">Iniciar</button>
|
|
149
150
|
|
|
150
|
-
<script src="https://cdn.jsdelivr.net/npm/santoid-sdk@1.0.
|
|
151
|
+
<script src="https://cdn.jsdelivr.net/npm/santoid-sdk@1.0.6/dist/browser/liveness/index.js"></script>
|
|
151
152
|
|
|
152
153
|
<script>
|
|
153
154
|
async function startLiveness () {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("SantoiDSDK",[],t):"object"==typeof exports?exports.SantoiDSDK=t():e.SantoiDSDK=t()}(this,(()=>(()=>{"use strict";var e={401:function(e,t,o){var n=this&&this.__createBinding||(Object.create?function(e,t,o,n){void 0===n&&(n=o);var a=Object.getOwnPropertyDescriptor(t,o);a&&!("get"in a?!t.__esModule:a.writable||a.configurable)||(a={enumerable:!0,get:function(){return t[o]}}),Object.defineProperty(e,n,a)}:function(e,t,o,n){void 0===n&&(n=o),e[n]=t[o]}),a=this&&this.__exportStar||function(e,t){for(var o in e)"default"===o||Object.prototype.hasOwnProperty.call(t,o)||n(t,e,o)};Object.defineProperty(t,"__esModule",{value:!0}),t.livenessDetection=void 0;const r=o(553),i=o(793),
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("SantoiDSDK",[],t):"object"==typeof exports?exports.SantoiDSDK=t():e.SantoiDSDK=t()}(this,(()=>(()=>{"use strict";var e={401:function(e,t,o){var n=this&&this.__createBinding||(Object.create?function(e,t,o,n){void 0===n&&(n=o);var a=Object.getOwnPropertyDescriptor(t,o);a&&!("get"in a?!t.__esModule:a.writable||a.configurable)||(a={enumerable:!0,get:function(){return t[o]}}),Object.defineProperty(e,n,a)}:function(e,t,o,n){void 0===n&&(n=o),e[n]=t[o]}),a=this&&this.__exportStar||function(e,t){for(var o in e)"default"===o||Object.prototype.hasOwnProperty.call(t,o)||n(t,e,o)};Object.defineProperty(t,"__esModule",{value:!0}),t.livenessDetection=void 0;const r=o(553),i=o(793),l=o(692);async function c(e){var t,o,n;let a,c=!1,s=!1,d=!1,u=!0;const v={front:void 0,right:void 0,left:void 0,up:void 0,bottom:void 0};let p,f,_,b="front";async function m(e,t,o){var n;o&&clearInterval(o),t&&(0,l.disconnectFromWebSocket)(t),a&&a.stopGetNextFrame(),!d&&await(null===(n=e.endCallback)||void 0===n?void 0:n.call(e)),d=!0,c=!0}try{return _=await(0,l.connectToWebSocket)(e),await(null===(t=e.nextStepCallback)||void 0===t?void 0:t.call(e,"front")),await(null===(o=e.frontCallback)||void 0===o?void 0:o.call(e)),e.getNextFrame||a||(a=await(0,i.builtInGetNextFrame)()),f=setInterval((async()=>{try{if(u){let t;t=e.getNextFrame?await e.getNextFrame():await(null==a?void 0:a.getNextFrame()),t&&(null==_||_.send(t),p=t,u=!1)}}catch(t){await m(e,_,f)}}),r.SEND_FRAMES_INTERVAL_MS),_.addEventListener("message",(async t=>{var o;const n=await async function(e,t){var o,n,a;const r=t.data;let i;try{i=JSON.parse(r)}catch(e){console.error("Cannot parse API message",e)}return(null==i?void 0:i.next_step)&&!i.error&&(await(null===(o=e.nextStepCallback)||void 0===o?void 0:o.call(e,i.next_step)),await(null===(n=e[`${i.next_step}Callback`])||void 0===n?void 0:n.call(e))),(null==i?void 0:i.error)&&await(null===(a=e.errorCallback)||void 0===a?void 0:a.call(e,{code:"wrong-position"})),i}(e,t);n&&(u=!!(null==n?void 0:n.can_send_next_bytes)),(null==n?void 0:n.validation)&&b&&(v[b]=p),(null==n?void 0:n.next_step)&&(b=n.next_step),(null==n?void 0:n.success)&&(v.bottom=p,s=!0,await(null===(o=e.successCallback)||void 0===o?void 0:o.call(e,{livenessId:n.livenessId,successFrames:v})),await m(e,_,f))})),_.addEventListener("error",(async()=>{var t;!s&&(null===(t=e.errorCallback)||void 0===t||t.call(e,{code:"internal-error"})),await m(e,_,f)})),_.addEventListener("close",(async()=>{var t;c||(!s&&(null===(t=e.errorCallback)||void 0===t||t.call(e,{code:"internal-error"})),await m(e,_,f))})),{stopLivenessDetection:async()=>{await m(e,_,f)},videoStream:null==a?void 0:a.videoStream}}catch(t){throw!s&&(null===(n=e.errorCallback)||void 0===n||n.call(e,{code:"internal-error"})),await m(e,_,f),t}}a(o(722),t),t.livenessDetection=c;class s{}s.livenessDetection=c,t.default=s},793:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.builtInGetNextFrame=void 0,t.builtInGetNextFrame=async function(){let e,t,o,n;return e&&t&&o||(e=await navigator.mediaDevices.getUserMedia({video:!0}),t=document.createElement("video"),t.setAttribute("autoplay","true"),t.style.transform="scale(-1, 1)",t.style.position="absolute",t.style.left="99999px",document.body.appendChild(t),t.srcObject=e,o=document.createElement("canvas"),n=o.getContext("2d")),{getNextFrame:async function(){if(o&&t)return o.width=t.videoWidth,o.height=t.videoHeight,null==n||n.drawImage(t,0,0,o.width,o.height),await new Promise(((e,t)=>{o?o.toBlob((t=>{e(t)})):e(null)}));throw new Error("Cannot found video element")},stopGetNextFrame:function(){t&&(document.body.removeChild(t),t=void 0),o&&(o=void 0),n&&(n=void 0),null==e||e.getTracks().forEach((e=>{e.stop()})),e=void 0},videoStream:e}}},268:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.decodeJwt=void 0,t.decodeJwt=function(e){const t=e.split(".")[1].replace(/-/g,"+").replace(/_/g,"/"),o=decodeURIComponent(window.atob(t).split("").map((e=>"%"+("00"+e.charCodeAt(0).toString(16)).slice(-2))).join(""));return JSON.parse(o)}},722:function(e,t,o){var n=this&&this.__createBinding||(Object.create?function(e,t,o,n){void 0===n&&(n=o);var a=Object.getOwnPropertyDescriptor(t,o);a&&!("get"in a?!t.__esModule:a.writable||a.configurable)||(a={enumerable:!0,get:function(){return t[o]}}),Object.defineProperty(e,n,a)}:function(e,t,o,n){void 0===n&&(n=o),e[n]=t[o]}),a=this&&this.__exportStar||function(e,t){for(var o in e)"default"===o||Object.prototype.hasOwnProperty.call(t,o)||n(t,e,o)};Object.defineProperty(t,"__esModule",{value:!0}),a(o(307),t)},692:(e,t,o)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.disconnectFromWebSocket=t.connectToWebSocket=void 0;const n=o(268),a=o(553);t.connectToWebSocket=async function(e){var t,o;const r=(0,n.decodeJwt)(e.token),i=`?x_endpoint_api_userinfo=${e.token}&domain=${null!==(t=e.domain)&&void 0!==t?t:r.claims.domain}&track=${e.track}&customerRequestId=${e.customId}`,l=new WebSocket(`${null!==(o=e.customWebSocketUrl)&&void 0!==o?o:a.WEBSOCKET_BASE_URL}${i}`);return await async function(e){if(await new Promise((t=>{const o=setInterval((()=>{[3,1].includes(e.readyState)&&(clearInterval(o),t())}),5)})),3===e.readyState)throw new Error("Cannot connect to server")}(l),l},t.disconnectFromWebSocket=function(e){var t;[2,3].includes(e.readyState)||null===(t=e.close)||void 0===t||t.call(e)}},553:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.SEND_FRAMES_INTERVAL_MS=t.API_GATEWAY_URL=t.WEBSOCKET_BASE_URL=void 0,t.WEBSOCKET_BASE_URL="wss://santoid-liveness-w4ynos5dlq-ue.a.run.app/api/v1/liveness/ws",t.API_GATEWAY_URL="https://api.santoid.com.br/api/v1/service-account/refresh-token",t.SEND_FRAMES_INTERVAL_MS=100},307:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0})}},t={},o=function o(n){var a=t[n];if(void 0!==a)return a.exports;var r=t[n]={exports:{}};return e[n].call(r.exports,r,r.exports,o),r.exports}(401);return o.default})()));
|
|
@@ -45,6 +45,15 @@ async function livenessDetection(options) {
|
|
|
45
45
|
let validationSuccess = false;
|
|
46
46
|
let endCalled = false;
|
|
47
47
|
let canSendNextBytes = true;
|
|
48
|
+
const successFrames = {
|
|
49
|
+
front: undefined,
|
|
50
|
+
right: undefined,
|
|
51
|
+
left: undefined,
|
|
52
|
+
up: undefined,
|
|
53
|
+
bottom: undefined,
|
|
54
|
+
};
|
|
55
|
+
let lastSentBytes;
|
|
56
|
+
let currentStep = 'front';
|
|
48
57
|
async function stopLivenessDetection(options, websocket, intervalKey) {
|
|
49
58
|
var _a;
|
|
50
59
|
if (intervalKey) {
|
|
@@ -81,6 +90,7 @@ async function livenessDetection(options) {
|
|
|
81
90
|
}
|
|
82
91
|
if (bytes) {
|
|
83
92
|
websocket === null || websocket === void 0 ? void 0 : websocket.send(bytes);
|
|
93
|
+
lastSentBytes = bytes;
|
|
84
94
|
canSendNextBytes = false;
|
|
85
95
|
}
|
|
86
96
|
}
|
|
@@ -95,9 +105,16 @@ async function livenessDetection(options) {
|
|
|
95
105
|
if (parsedMessage) {
|
|
96
106
|
canSendNextBytes = !!(parsedMessage === null || parsedMessage === void 0 ? void 0 : parsedMessage.can_send_next_bytes);
|
|
97
107
|
}
|
|
108
|
+
if ((parsedMessage === null || parsedMessage === void 0 ? void 0 : parsedMessage.validation) && currentStep) {
|
|
109
|
+
successFrames[currentStep] = lastSentBytes;
|
|
110
|
+
}
|
|
111
|
+
if (parsedMessage === null || parsedMessage === void 0 ? void 0 : parsedMessage.next_step) {
|
|
112
|
+
currentStep = parsedMessage.next_step;
|
|
113
|
+
}
|
|
98
114
|
if (parsedMessage === null || parsedMessage === void 0 ? void 0 : parsedMessage.success) {
|
|
115
|
+
successFrames.bottom = lastSentBytes;
|
|
99
116
|
validationSuccess = true;
|
|
100
|
-
await ((_a = options.successCallback) === null || _a === void 0 ? void 0 : _a.call(options));
|
|
117
|
+
await ((_a = options.successCallback) === null || _a === void 0 ? void 0 : _a.call(options, { livenessId: parsedMessage.livenessId, successFrames }));
|
|
101
118
|
await stopLivenessDetection(options, websocket, sendFramesIntervalKey);
|
|
102
119
|
}
|
|
103
120
|
});
|
|
@@ -28,6 +28,15 @@ async function livenessDetection(options) {
|
|
|
28
28
|
let validationSuccess = false;
|
|
29
29
|
let endCalled = false;
|
|
30
30
|
let canSendNextBytes = true;
|
|
31
|
+
const successFrames = {
|
|
32
|
+
front: undefined,
|
|
33
|
+
right: undefined,
|
|
34
|
+
left: undefined,
|
|
35
|
+
up: undefined,
|
|
36
|
+
bottom: undefined,
|
|
37
|
+
};
|
|
38
|
+
let lastSentBytes;
|
|
39
|
+
let currentStep = 'front';
|
|
31
40
|
async function stopLivenessDetection(options, websocket, intervalKey) {
|
|
32
41
|
var _a;
|
|
33
42
|
if (intervalKey) {
|
|
@@ -52,6 +61,7 @@ async function livenessDetection(options) {
|
|
|
52
61
|
const bytes = await options.getNextFrame();
|
|
53
62
|
if (bytes) {
|
|
54
63
|
websocket === null || websocket === void 0 ? void 0 : websocket.send(bytes);
|
|
64
|
+
lastSentBytes = bytes;
|
|
55
65
|
canSendNextBytes = false;
|
|
56
66
|
}
|
|
57
67
|
}
|
|
@@ -66,9 +76,16 @@ async function livenessDetection(options) {
|
|
|
66
76
|
if (parsedMessage) {
|
|
67
77
|
canSendNextBytes = !!(parsedMessage === null || parsedMessage === void 0 ? void 0 : parsedMessage.can_send_next_bytes);
|
|
68
78
|
}
|
|
79
|
+
if ((parsedMessage === null || parsedMessage === void 0 ? void 0 : parsedMessage.validation) && currentStep) {
|
|
80
|
+
successFrames[currentStep] = lastSentBytes;
|
|
81
|
+
}
|
|
82
|
+
if (parsedMessage === null || parsedMessage === void 0 ? void 0 : parsedMessage.next_step) {
|
|
83
|
+
currentStep = parsedMessage.next_step;
|
|
84
|
+
}
|
|
69
85
|
if (parsedMessage === null || parsedMessage === void 0 ? void 0 : parsedMessage.success) {
|
|
86
|
+
successFrames.bottom = lastSentBytes;
|
|
70
87
|
validationSuccess = true;
|
|
71
|
-
await ((_a = options.successCallback) === null || _a === void 0 ? void 0 : _a.call(options));
|
|
88
|
+
await ((_a = options.successCallback) === null || _a === void 0 ? void 0 : _a.call(options, { livenessId: parsedMessage.livenessId, successFrames }));
|
|
72
89
|
await stopLivenessDetection(options, websocket, sendFramesIntervalKey);
|
|
73
90
|
}
|
|
74
91
|
});
|
package/dist/utils/types.d.ts
CHANGED
|
@@ -6,6 +6,10 @@ export interface IDecodedToken {
|
|
|
6
6
|
domain: string;
|
|
7
7
|
};
|
|
8
8
|
}
|
|
9
|
+
interface ILivenessResults<FrameType> {
|
|
10
|
+
livenessId: string;
|
|
11
|
+
successFrames: Record<TPositions, FrameType>;
|
|
12
|
+
}
|
|
9
13
|
export interface ISDKOptions {
|
|
10
14
|
token: string;
|
|
11
15
|
track: string;
|
|
@@ -20,13 +24,16 @@ export interface ISDKOptions {
|
|
|
20
24
|
errorCallback?: (error: {
|
|
21
25
|
code: TErrorCode;
|
|
22
26
|
}) => void | Promise<void>;
|
|
23
|
-
successCallback?:
|
|
27
|
+
successCallback?: <FrameType>(results: ILivenessResults<FrameType>) => void | Promise<void>;
|
|
24
28
|
endCallback?: TCallbackFunction;
|
|
25
29
|
customWebSocketUrl?: string;
|
|
26
30
|
}
|
|
27
31
|
export interface IWebSocketMessage {
|
|
28
|
-
success?: boolean;
|
|
29
|
-
error?: boolean;
|
|
30
32
|
can_send_next_bytes?: boolean;
|
|
31
33
|
next_step?: TPositions;
|
|
34
|
+
validation?: boolean;
|
|
35
|
+
error?: boolean;
|
|
36
|
+
success?: boolean;
|
|
37
|
+
livenessId: string;
|
|
32
38
|
}
|
|
39
|
+
export {};
|
package/jest.config.cjs
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const config = {
|
|
2
|
+
testEnvironment: 'jsdom',
|
|
3
|
+
transform: {
|
|
4
|
+
'^.+\\.ts?$': 'ts-jest',
|
|
5
|
+
},
|
|
6
|
+
collectCoverageFrom: [
|
|
7
|
+
'<rootDir>/src/**/*.ts',
|
|
8
|
+
],
|
|
9
|
+
coveragePathIgnorePatterns: [
|
|
10
|
+
'types.ts',
|
|
11
|
+
],
|
|
12
|
+
setupFiles: [
|
|
13
|
+
'jest-canvas-mock',
|
|
14
|
+
],
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
module.exports = config
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "santoid-sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/esm/liveness/index.js",
|
|
6
6
|
"types": "dist/esm/liveness/index.d.ts",
|
|
@@ -8,11 +8,13 @@
|
|
|
8
8
|
"expose:cmd": "mv -v dist/* ./",
|
|
9
9
|
"dev:webpack": "webpack --mode=development --watch --progress",
|
|
10
10
|
"build:browser-node": "webpack --mode=production",
|
|
11
|
-
"build:typescript": "rm -rf ./dist
|
|
12
|
-
"build": "npm run build:typescript && npm run build:browser-node"
|
|
11
|
+
"build:typescript": "rm -rf ./dist && tsc",
|
|
12
|
+
"build": "npm run build:typescript && npm run build:browser-node",
|
|
13
|
+
"test": "jest",
|
|
14
|
+
"test:coverage": "jest --coverage"
|
|
13
15
|
},
|
|
14
16
|
"exports": {
|
|
15
|
-
".": "./dist",
|
|
17
|
+
".": "./dist/index.js",
|
|
16
18
|
"./liveness": "./dist/esm/liveness/index.js",
|
|
17
19
|
"./node/liveness": "./dist/node/liveness/index.js",
|
|
18
20
|
"./node/auth": "./dist/node/auth/index.js"
|
|
@@ -34,6 +36,7 @@
|
|
|
34
36
|
"author": "SantoDigital",
|
|
35
37
|
"license": "Apache-2.0",
|
|
36
38
|
"devDependencies": {
|
|
39
|
+
"@types/jest": "^29.5.5",
|
|
37
40
|
"@types/node": "^20.6.2",
|
|
38
41
|
"@types/ws": "^8.5.6",
|
|
39
42
|
"@typescript-eslint/eslint-plugin": "^6.4.0",
|
|
@@ -43,6 +46,10 @@
|
|
|
43
46
|
"eslint-plugin-import": "^2.25.2",
|
|
44
47
|
"eslint-plugin-n": "^15.0.0 || ^16.0.0 ",
|
|
45
48
|
"eslint-plugin-promise": "^6.0.0",
|
|
49
|
+
"jest": "^29.7.0",
|
|
50
|
+
"jest-canvas-mock": "^2.5.2",
|
|
51
|
+
"jest-environment-jsdom": "^29.7.0",
|
|
52
|
+
"ts-jest": "^29.1.1",
|
|
46
53
|
"ts-loader": "^9.4.4",
|
|
47
54
|
"ts-node": "^10.9.1",
|
|
48
55
|
"typescript": "*",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type IWebSocketMessage, type TWebSDKOptions } from './utils/types'
|
|
1
|
+
import { type TPositions, type IWebSocketMessage, type TWebSDKOptions } from './utils/types'
|
|
2
2
|
import { SEND_FRAMES_INTERVAL_MS } from '../../utils/constants'
|
|
3
3
|
import { builtInGetNextFrame, type builtInGetNextFrameReturn } from './utils/getNextFrame'
|
|
4
4
|
|
|
@@ -30,12 +30,25 @@ async function onWebSocketMessage (options: TWebSDKOptions, event: MessageEvent)
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
export async function livenessDetection (options: TWebSDKOptions) {
|
|
33
|
+
type FrameType = Blob | null | undefined
|
|
34
|
+
|
|
33
35
|
let websocketClosedBySDK = false
|
|
34
36
|
let builtInGetNextFrameReturn: builtInGetNextFrameReturn | undefined
|
|
35
37
|
let validationSuccess = false
|
|
36
38
|
let endCalled = false
|
|
37
39
|
let canSendNextBytes = true
|
|
38
40
|
|
|
41
|
+
const successFrames: Record<TPositions, FrameType> = {
|
|
42
|
+
front: undefined,
|
|
43
|
+
right: undefined,
|
|
44
|
+
left: undefined,
|
|
45
|
+
up: undefined,
|
|
46
|
+
bottom: undefined,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let lastSentBytes: FrameType
|
|
50
|
+
let currentStep: TPositions = 'front'
|
|
51
|
+
|
|
39
52
|
async function stopLivenessDetection (options: TWebSDKOptions, websocket?: WebSocket, intervalKey?: any) {
|
|
40
53
|
if (intervalKey) {
|
|
41
54
|
clearInterval(intervalKey)
|
|
@@ -81,6 +94,7 @@ export async function livenessDetection (options: TWebSDKOptions) {
|
|
|
81
94
|
|
|
82
95
|
if (bytes) {
|
|
83
96
|
websocket?.send(bytes)
|
|
97
|
+
lastSentBytes = bytes
|
|
84
98
|
canSendNextBytes = false
|
|
85
99
|
}
|
|
86
100
|
}
|
|
@@ -96,9 +110,19 @@ export async function livenessDetection (options: TWebSDKOptions) {
|
|
|
96
110
|
canSendNextBytes = !!parsedMessage?.can_send_next_bytes
|
|
97
111
|
}
|
|
98
112
|
|
|
113
|
+
if (parsedMessage?.validation && currentStep) {
|
|
114
|
+
successFrames[currentStep] = lastSentBytes
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (parsedMessage?.next_step) {
|
|
118
|
+
currentStep = parsedMessage.next_step
|
|
119
|
+
}
|
|
120
|
+
|
|
99
121
|
if (parsedMessage?.success) {
|
|
122
|
+
successFrames.bottom = lastSentBytes
|
|
123
|
+
|
|
100
124
|
validationSuccess = true
|
|
101
|
-
await options.successCallback
|
|
125
|
+
await options.successCallback?.<FrameType>({ livenessId: parsedMessage.livenessId, successFrames })
|
|
102
126
|
await stopLivenessDetection(options, websocket, sendFramesIntervalKey)
|
|
103
127
|
}
|
|
104
128
|
})
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type WebSocket from 'ws'
|
|
2
|
+
import { type Data } from 'ws'
|
|
2
3
|
|
|
3
|
-
import { type IWebSocketMessage, type TNodeSDKOptions } from './utils/types'
|
|
4
|
+
import { type TPositions, type IWebSocketMessage, type TNodeSDKOptions } from './utils/types'
|
|
4
5
|
import { SEND_FRAMES_INTERVAL_MS } from '../../utils/constants'
|
|
5
6
|
import { connectToWebSocket, disconnectFromWebSocket } from './utils/websocket'
|
|
6
7
|
|
|
@@ -28,11 +29,24 @@ async function onWebSocketMessage (options: TNodeSDKOptions, event: { data: stri
|
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
export async function livenessDetection (options: TNodeSDKOptions) {
|
|
32
|
+
type FrameType = Data | null | undefined
|
|
33
|
+
|
|
31
34
|
let websocketClosedBySDK = false
|
|
32
35
|
let validationSuccess = false
|
|
33
36
|
let endCalled = false
|
|
34
37
|
let canSendNextBytes = true
|
|
35
38
|
|
|
39
|
+
const successFrames: Record<TPositions, FrameType> = {
|
|
40
|
+
front: undefined,
|
|
41
|
+
right: undefined,
|
|
42
|
+
left: undefined,
|
|
43
|
+
up: undefined,
|
|
44
|
+
bottom: undefined,
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let lastSentBytes: FrameType
|
|
48
|
+
let currentStep: TPositions = 'front'
|
|
49
|
+
|
|
36
50
|
async function stopLivenessDetection (options: TNodeSDKOptions, websocket?: WebSocket, intervalKey?: any) {
|
|
37
51
|
if (intervalKey) {
|
|
38
52
|
clearInterval(intervalKey)
|
|
@@ -64,6 +78,7 @@ export async function livenessDetection (options: TNodeSDKOptions) {
|
|
|
64
78
|
|
|
65
79
|
if (bytes) {
|
|
66
80
|
websocket?.send(bytes)
|
|
81
|
+
lastSentBytes = bytes
|
|
67
82
|
canSendNextBytes = false
|
|
68
83
|
}
|
|
69
84
|
}
|
|
@@ -79,9 +94,19 @@ export async function livenessDetection (options: TNodeSDKOptions) {
|
|
|
79
94
|
canSendNextBytes = !!parsedMessage?.can_send_next_bytes
|
|
80
95
|
}
|
|
81
96
|
|
|
97
|
+
if (parsedMessage?.validation && currentStep) {
|
|
98
|
+
successFrames[currentStep] = lastSentBytes
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (parsedMessage?.next_step) {
|
|
102
|
+
currentStep = parsedMessage.next_step
|
|
103
|
+
}
|
|
104
|
+
|
|
82
105
|
if (parsedMessage?.success) {
|
|
106
|
+
successFrames.bottom = lastSentBytes
|
|
107
|
+
|
|
83
108
|
validationSuccess = true
|
|
84
|
-
await options.successCallback
|
|
109
|
+
await options.successCallback?.<FrameType>({ livenessId: parsedMessage.livenessId, successFrames })
|
|
85
110
|
await stopLivenessDetection(options, websocket, sendFramesIntervalKey)
|
|
86
111
|
}
|
|
87
112
|
})
|
package/src/utils/types.ts
CHANGED
|
@@ -10,6 +10,11 @@ export interface IDecodedToken {
|
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
interface ILivenessResults<FrameType> {
|
|
14
|
+
livenessId: string
|
|
15
|
+
successFrames: Record<TPositions, FrameType>
|
|
16
|
+
}
|
|
17
|
+
|
|
13
18
|
export interface ISDKOptions {
|
|
14
19
|
token: string
|
|
15
20
|
track: string
|
|
@@ -23,15 +28,19 @@ export interface ISDKOptions {
|
|
|
23
28
|
upCallback?: TCallbackFunction
|
|
24
29
|
bottomCallback?: TCallbackFunction
|
|
25
30
|
errorCallback?: (error: { code: TErrorCode }) => void | Promise<void>
|
|
26
|
-
successCallback?:
|
|
31
|
+
successCallback?: <FrameType>(results: ILivenessResults<FrameType>) => void | Promise<void>
|
|
27
32
|
endCallback?: TCallbackFunction
|
|
28
33
|
|
|
29
34
|
customWebSocketUrl?: string
|
|
30
35
|
}
|
|
31
36
|
|
|
32
37
|
export interface IWebSocketMessage {
|
|
33
|
-
success?: boolean
|
|
34
|
-
error?: boolean
|
|
35
38
|
can_send_next_bytes?: boolean
|
|
36
39
|
next_step?: TPositions
|
|
40
|
+
validation?: boolean
|
|
41
|
+
|
|
42
|
+
error?: boolean
|
|
43
|
+
|
|
44
|
+
success?: boolean
|
|
45
|
+
livenessId: string
|
|
37
46
|
}
|
package/tsconfig.json
CHANGED
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
"target": "es2017",
|
|
6
6
|
"moduleResolution": "node",
|
|
7
7
|
"outDir": "dist",
|
|
8
|
+
"rootDir": "src",
|
|
8
9
|
"baseUrl": "./",
|
|
9
10
|
"declaration": true,
|
|
10
11
|
"esModuleInterop": true,
|
|
11
12
|
"strictNullChecks": true,
|
|
12
13
|
},
|
|
13
14
|
|
|
14
|
-
"include": ["
|
|
15
|
+
"include": ["src/**/*.ts", "./.eslintrc.js", "./webpack.config.cjs", "./jest.config.cjs"],
|
|
15
16
|
}
|