santoid-sdk 1.0.4 → 1.0.5

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 (34) hide show
  1. package/README.md +3 -2
  2. package/dist/browser/liveness/index.js +1 -1
  3. package/dist/jest.config.d.ts +3 -0
  4. package/dist/jest.config.js +18 -0
  5. package/dist/{esm → src/esm}/liveness/index.js +1 -1
  6. package/dist/src/index.d.ts +0 -0
  7. package/dist/src/index.js +0 -0
  8. package/dist/src/node/auth/index.d.ts +5 -0
  9. package/dist/src/node/auth/index.js +44 -0
  10. package/dist/src/node/liveness/index.d.ts +4 -0
  11. package/dist/src/node/liveness/index.js +98 -0
  12. package/dist/src/node/liveness/utils/index.d.ts +1 -0
  13. package/dist/src/node/liveness/utils/index.js +7 -0
  14. package/dist/src/node/liveness/utils/types.d.ts +6 -0
  15. package/dist/src/node/liveness/utils/types.js +17 -0
  16. package/dist/src/node/liveness/utils/websocket.d.ts +5 -0
  17. package/dist/src/node/liveness/utils/websocket.js +39 -0
  18. package/dist/src/utils/constants.d.ts +3 -0
  19. package/dist/src/utils/constants.js +6 -0
  20. package/dist/src/utils/types.d.ts +36 -0
  21. package/dist/src/utils/types.js +2 -0
  22. package/package.json +12 -5
  23. package/src/esm/liveness/index.ts +1 -1
  24. package/src/node/liveness/index.ts +1 -1
  25. package/src/utils/types.ts +10 -3
  26. /package/dist/{esm → src/esm}/liveness/index.d.ts +0 -0
  27. /package/dist/{esm → src/esm}/liveness/utils/getNextFrame.d.ts +0 -0
  28. /package/dist/{esm → src/esm}/liveness/utils/getNextFrame.js +0 -0
  29. /package/dist/{esm → src/esm}/liveness/utils/index.d.ts +0 -0
  30. /package/dist/{esm → src/esm}/liveness/utils/index.js +0 -0
  31. /package/dist/{esm → src/esm}/liveness/utils/types.d.ts +0 -0
  32. /package/dist/{esm → src/esm}/liveness/utils/types.js +0 -0
  33. /package/dist/{esm → src/esm}/liveness/utils/websocket.d.ts +0 -0
  34. /package/dist/{esm → src/esm}/liveness/utils/websocket.js +0 -0
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
- successCallback: () => {},
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.4/dist/browser/liveness/index.js"></script>
151
+ <script src="https://cdn.jsdelivr.net/npm/santoid-sdk@1.0.5/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),c=o(692);async function l(e){var t,o,n;let a,l,s,d=!1,u=!1,v=!1,p=!0;async function f(e,t,o){var n;o&&clearInterval(o),t&&(0,c.disconnectFromWebSocket)(t),a&&a.stopGetNextFrame(),!v&&await(null===(n=e.endCallback)||void 0===n?void 0:n.call(e)),v=!0,d=!0}try{return s=await(0,c.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)()),l=setInterval((async()=>{try{if(p){let t;t=e.getNextFrame?await e.getNextFrame():await(null==a?void 0:a.getNextFrame()),t&&(null==s||s.send(t),p=!1)}}catch(t){await f(e,s,l)}}),r.SEND_FRAMES_INTERVAL_MS),s.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&&(p=!!(null==n?void 0:n.can_send_next_bytes)),(null==n?void 0:n.success)&&(u=!0,await(null===(o=e.successCallback)||void 0===o?void 0:o.call(e)),await f(e,s,l))})),s.addEventListener("error",(async()=>{var t;!u&&(null===(t=e.errorCallback)||void 0===t||t.call(e,{code:"internal-error"})),await f(e,s,l)})),s.addEventListener("close",(async()=>{var t;d||(!u&&(null===(t=e.errorCallback)||void 0===t||t.call(e,{code:"internal-error"})),await f(e,s,l))})),{stopLivenessDetection:async()=>{await f(e,s,l)},videoStream:null==a?void 0:a.videoStream}}catch(t){throw!u&&(null===(n=e.errorCallback)||void 0===n||n.call(e,{code:"internal-error"})),await f(e,s,l),t}}a(o(722),t),t.livenessDetection=l;class s{}s.livenessDetection=l,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}`,c=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")}(c),c},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})()));
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),c=o(692);async function l(e){var t,o,n;let a,l,s,d=!1,u=!1,v=!1,p=!0;async function f(e,t,o){var n;o&&clearInterval(o),t&&(0,c.disconnectFromWebSocket)(t),a&&a.stopGetNextFrame(),!v&&await(null===(n=e.endCallback)||void 0===n?void 0:n.call(e)),v=!0,d=!0}try{return s=await(0,c.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)()),l=setInterval((async()=>{try{if(p){let t;t=e.getNextFrame?await e.getNextFrame():await(null==a?void 0:a.getNextFrame()),t&&(null==s||s.send(t),p=!1)}}catch(t){await f(e,s,l)}}),r.SEND_FRAMES_INTERVAL_MS),s.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&&(p=!!(null==n?void 0:n.can_send_next_bytes)),(null==n?void 0:n.success)&&(u=!0,await(null===(o=e.successCallback)||void 0===o?void 0:o.call(e,{livenessId:n.livenessId})),await f(e,s,l))})),s.addEventListener("error",(async()=>{var t;!u&&(null===(t=e.errorCallback)||void 0===t||t.call(e,{code:"internal-error"})),await f(e,s,l)})),s.addEventListener("close",(async()=>{var t;d||(!u&&(null===(t=e.errorCallback)||void 0===t||t.call(e,{code:"internal-error"})),await f(e,s,l))})),{stopLivenessDetection:async()=>{await f(e,s,l)},videoStream:null==a?void 0:a.videoStream}}catch(t){throw!u&&(null===(n=e.errorCallback)||void 0===n||n.call(e,{code:"internal-error"})),await f(e,s,l),t}}a(o(722),t),t.livenessDetection=l;class s{}s.livenessDetection=l,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}`,c=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")}(c),c},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})()));
@@ -0,0 +1,3 @@
1
+ import type { Config } from 'jest';
2
+ declare const config: Config;
3
+ export default config;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const config = {
4
+ testEnvironment: 'jsdom',
5
+ transform: {
6
+ '^.+\\.ts?$': 'ts-jest',
7
+ },
8
+ collectCoverageFrom: [
9
+ '<rootDir>/src/**/*.ts',
10
+ ],
11
+ coveragePathIgnorePatterns: [
12
+ 'types.ts',
13
+ ],
14
+ setupFiles: [
15
+ 'jest-canvas-mock',
16
+ ],
17
+ };
18
+ exports.default = config;
@@ -97,7 +97,7 @@ async function livenessDetection(options) {
97
97
  }
98
98
  if (parsedMessage === null || parsedMessage === void 0 ? void 0 : parsedMessage.success) {
99
99
  validationSuccess = true;
100
- await ((_a = options.successCallback) === null || _a === void 0 ? void 0 : _a.call(options));
100
+ await ((_a = options.successCallback) === null || _a === void 0 ? void 0 : _a.call(options, { livenessId: parsedMessage.livenessId }));
101
101
  await stopLivenessDetection(options, websocket, sendFramesIntervalKey);
102
102
  }
103
103
  });
File without changes
File without changes
@@ -0,0 +1,5 @@
1
+ export interface IInitalizeOptions {
2
+ customApiUrl?: string;
3
+ credentials?: string | Record<string, string>;
4
+ }
5
+ export declare function initialize(options?: IInitalizeOptions): Promise<string | undefined>;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.initialize = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const constants_1 = require("../../utils/constants");
9
+ async function initialize(options) {
10
+ var _a;
11
+ let credentialsBase64;
12
+ if (options === null || options === void 0 ? void 0 : options.credentials) {
13
+ if (typeof (options === null || options === void 0 ? void 0 : options.credentials) === 'string') {
14
+ credentialsBase64 = options === null || options === void 0 ? void 0 : options.credentials;
15
+ }
16
+ else if (typeof (options === null || options === void 0 ? void 0 : options.credentials) === 'object') {
17
+ credentialsBase64 = Buffer.from(JSON.stringify(options === null || options === void 0 ? void 0 : options.credentials)).toString('base64');
18
+ }
19
+ else {
20
+ throw new Error('Invalid credentials');
21
+ }
22
+ }
23
+ else {
24
+ if (process.env.SANTOID_SDK_CREDENTIALS) {
25
+ credentialsBase64 = fs_1.default.readFileSync(process.env.SANTOID_SDK_CREDENTIALS, { encoding: 'base64' });
26
+ }
27
+ else {
28
+ throw new Error('Credentials not found');
29
+ }
30
+ }
31
+ if (credentialsBase64) {
32
+ const response = await fetch((_a = options === null || options === void 0 ? void 0 : options.customApiUrl) !== null && _a !== void 0 ? _a : constants_1.API_GATEWAY_URL, {
33
+ method: 'POST',
34
+ body: JSON.stringify({ service_account_base64: credentialsBase64 }),
35
+ headers: { 'Content-Type': 'application/json' },
36
+ });
37
+ const token = await response.json();
38
+ if (typeof token !== 'string') {
39
+ throw new Error('Cannot generate token');
40
+ }
41
+ return token;
42
+ }
43
+ }
44
+ exports.initialize = initialize;
@@ -0,0 +1,4 @@
1
+ import { type TNodeSDKOptions } from './utils/types';
2
+ export declare function livenessDetection(options: TNodeSDKOptions): Promise<{
3
+ stopLivenessDetection: () => Promise<void>;
4
+ }>;
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.livenessDetection = void 0;
4
+ const constants_1 = require("../../utils/constants");
5
+ const websocket_1 = require("./utils/websocket");
6
+ async function onWebSocketMessage(options, event) {
7
+ var _a, _b, _c;
8
+ const message = event.data;
9
+ let messageObj;
10
+ try {
11
+ messageObj = JSON.parse(message);
12
+ }
13
+ catch (err) {
14
+ console.error('Cannot parse API message', err);
15
+ }
16
+ if ((messageObj === null || messageObj === void 0 ? void 0 : messageObj.next_step) && !messageObj.error) {
17
+ await ((_a = options.nextStepCallback) === null || _a === void 0 ? void 0 : _a.call(options, messageObj.next_step));
18
+ await ((_b = options[`${messageObj.next_step}Callback`]) === null || _b === void 0 ? void 0 : _b.call(options));
19
+ }
20
+ if (messageObj === null || messageObj === void 0 ? void 0 : messageObj.error) {
21
+ await ((_c = options.errorCallback) === null || _c === void 0 ? void 0 : _c.call(options, { code: 'wrong-position' }));
22
+ }
23
+ return messageObj;
24
+ }
25
+ async function livenessDetection(options) {
26
+ var _a, _b, _c;
27
+ let websocketClosedBySDK = false;
28
+ let validationSuccess = false;
29
+ let endCalled = false;
30
+ let canSendNextBytes = true;
31
+ async function stopLivenessDetection(options, websocket, intervalKey) {
32
+ var _a;
33
+ if (intervalKey) {
34
+ clearInterval(intervalKey);
35
+ }
36
+ if (websocket) {
37
+ (0, websocket_1.disconnectFromWebSocket)(websocket);
38
+ }
39
+ !endCalled && await ((_a = options.endCallback) === null || _a === void 0 ? void 0 : _a.call(options));
40
+ endCalled = true;
41
+ websocketClosedBySDK = true;
42
+ }
43
+ let sendFramesIntervalKey;
44
+ let websocket;
45
+ try {
46
+ websocket = await (0, websocket_1.connectToWebSocket)(options);
47
+ await ((_a = options.nextStepCallback) === null || _a === void 0 ? void 0 : _a.call(options, 'front'));
48
+ await ((_b = options.frontCallback) === null || _b === void 0 ? void 0 : _b.call(options));
49
+ sendFramesIntervalKey = setInterval(async () => {
50
+ try {
51
+ if (canSendNextBytes) {
52
+ const bytes = await options.getNextFrame();
53
+ if (bytes) {
54
+ websocket === null || websocket === void 0 ? void 0 : websocket.send(bytes);
55
+ canSendNextBytes = false;
56
+ }
57
+ }
58
+ }
59
+ catch (err) {
60
+ await stopLivenessDetection(options, websocket, sendFramesIntervalKey);
61
+ }
62
+ }, constants_1.SEND_FRAMES_INTERVAL_MS);
63
+ websocket.on('message', async (data) => {
64
+ var _a;
65
+ const parsedMessage = await onWebSocketMessage(options, { data: Buffer.from(data).toString() });
66
+ if (parsedMessage) {
67
+ canSendNextBytes = !!(parsedMessage === null || parsedMessage === void 0 ? void 0 : parsedMessage.can_send_next_bytes);
68
+ }
69
+ if (parsedMessage === null || parsedMessage === void 0 ? void 0 : parsedMessage.success) {
70
+ validationSuccess = true;
71
+ await ((_a = options.successCallback) === null || _a === void 0 ? void 0 : _a.call(options, { livenessId: parsedMessage.livenessId }));
72
+ await stopLivenessDetection(options, websocket, sendFramesIntervalKey);
73
+ }
74
+ });
75
+ websocket.on('error', async (event) => {
76
+ var _a;
77
+ !validationSuccess && ((_a = options.errorCallback) === null || _a === void 0 ? void 0 : _a.call(options, { code: 'internal-error' }));
78
+ await stopLivenessDetection(options, websocket, sendFramesIntervalKey);
79
+ });
80
+ websocket.on('close', async () => {
81
+ var _a;
82
+ if (!websocketClosedBySDK) {
83
+ !validationSuccess && ((_a = options.errorCallback) === null || _a === void 0 ? void 0 : _a.call(options, { code: 'internal-error' }));
84
+ await stopLivenessDetection(options, websocket, sendFramesIntervalKey);
85
+ }
86
+ });
87
+ return {
88
+ stopLivenessDetection: async () => { await stopLivenessDetection(options, websocket, sendFramesIntervalKey); },
89
+ };
90
+ }
91
+ catch (err) {
92
+ console.error('catch error', err);
93
+ !validationSuccess && ((_c = options.errorCallback) === null || _c === void 0 ? void 0 : _c.call(options, { code: 'internal-error' }));
94
+ await stopLivenessDetection(options, websocket, sendFramesIntervalKey);
95
+ throw err;
96
+ }
97
+ }
98
+ exports.livenessDetection = livenessDetection;
@@ -0,0 +1 @@
1
+ export declare function decodeJwt(token: string): any;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.decodeJwt = void 0;
4
+ function decodeJwt(token) {
5
+ return JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString());
6
+ }
7
+ exports.decodeJwt = decodeJwt;
@@ -0,0 +1,6 @@
1
+ import { type Data } from 'ws';
2
+ import { type ISDKOptions } from '../../../utils/types';
3
+ export type TNodeSDKOptions = ISDKOptions & {
4
+ getNextFrame: () => Promise<Data | null>;
5
+ };
6
+ export * from '../../../utils/types';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("../../../utils/types"), exports);
@@ -0,0 +1,5 @@
1
+ import WebSocket from 'ws';
2
+ import { type TNodeSDKOptions } from './types';
3
+ export declare function waitForWebSocketConnection(websocket: WebSocket): Promise<void>;
4
+ export declare function connectToWebSocket(options: TNodeSDKOptions): Promise<WebSocket>;
5
+ export declare function disconnectFromWebSocket(websocket: WebSocket): void;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.disconnectFromWebSocket = exports.connectToWebSocket = exports.waitForWebSocketConnection = void 0;
7
+ const ws_1 = __importDefault(require("ws"));
8
+ const _1 = require(".");
9
+ const constants_1 = require("../../../utils/constants");
10
+ async function waitForWebSocketConnection(websocket) {
11
+ await new Promise((resolve) => {
12
+ const intervalKey = setInterval(() => {
13
+ if ([3, 1].includes(websocket.readyState)) {
14
+ clearInterval(intervalKey);
15
+ resolve();
16
+ }
17
+ }, 5);
18
+ });
19
+ if (websocket.readyState === 3) {
20
+ throw new Error('Cannot connect to server');
21
+ }
22
+ }
23
+ exports.waitForWebSocketConnection = waitForWebSocketConnection;
24
+ async function connectToWebSocket(options) {
25
+ var _a, _b;
26
+ const decodedToken = (0, _1.decodeJwt)(options.token);
27
+ const query = `?x_endpoint_api_userinfo=${options.token}&domain=${(_a = options.domain) !== null && _a !== void 0 ? _a : decodedToken.claims.domain}&track=${options.track}&customerRequestId=${options.customId}`;
28
+ const websocket = new ws_1.default(`${(_b = options.customWebSocketUrl) !== null && _b !== void 0 ? _b : constants_1.WEBSOCKET_BASE_URL}${query}`);
29
+ await waitForWebSocketConnection(websocket);
30
+ return websocket;
31
+ }
32
+ exports.connectToWebSocket = connectToWebSocket;
33
+ function disconnectFromWebSocket(websocket) {
34
+ var _a;
35
+ if (![2, 3].includes(websocket.readyState)) {
36
+ (_a = websocket.close) === null || _a === void 0 ? void 0 : _a.call(websocket);
37
+ }
38
+ }
39
+ exports.disconnectFromWebSocket = disconnectFromWebSocket;
@@ -0,0 +1,3 @@
1
+ export declare const WEBSOCKET_BASE_URL = "wss://santoid-liveness-w4ynos5dlq-ue.a.run.app/api/v1/liveness/ws";
2
+ export declare const API_GATEWAY_URL = "https://api.santoid.com.br/api/v1/service-account/refresh-token";
3
+ export declare const SEND_FRAMES_INTERVAL_MS = 100;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SEND_FRAMES_INTERVAL_MS = exports.API_GATEWAY_URL = exports.WEBSOCKET_BASE_URL = void 0;
4
+ exports.WEBSOCKET_BASE_URL = 'wss://santoid-liveness-w4ynos5dlq-ue.a.run.app/api/v1/liveness/ws';
5
+ exports.API_GATEWAY_URL = 'https://api.santoid.com.br/api/v1/service-account/refresh-token';
6
+ exports.SEND_FRAMES_INTERVAL_MS = 100;
@@ -0,0 +1,36 @@
1
+ export type TCallbackFunction = (...args: any[]) => void | Promise<void>;
2
+ export type TPositions = 'front' | 'right' | 'left' | 'up' | 'bottom';
3
+ export type TErrorCode = 'wrong-position' | 'internal-error';
4
+ export interface IDecodedToken {
5
+ claims: {
6
+ domain: string;
7
+ };
8
+ }
9
+ export interface ILivenessResults {
10
+ livenessId?: string;
11
+ }
12
+ export interface ISDKOptions {
13
+ token: string;
14
+ track: string;
15
+ customId?: string;
16
+ domain?: string;
17
+ nextStepCallback?: (step: TPositions) => void | Promise<void>;
18
+ frontCallback?: TCallbackFunction;
19
+ rightCallback?: TCallbackFunction;
20
+ leftCallback?: TCallbackFunction;
21
+ upCallback?: TCallbackFunction;
22
+ bottomCallback?: TCallbackFunction;
23
+ errorCallback?: (error: {
24
+ code: TErrorCode;
25
+ }) => void | Promise<void>;
26
+ successCallback?: (results: ILivenessResults) => void | Promise<void>;
27
+ endCallback?: TCallbackFunction;
28
+ customWebSocketUrl?: string;
29
+ }
30
+ export interface IWebSocketMessage {
31
+ can_send_next_bytes?: boolean;
32
+ next_step?: TPositions;
33
+ error?: boolean;
34
+ success?: boolean;
35
+ livenessId?: string;
36
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,18 +1,20 @@
1
1
  {
2
2
  "name": "santoid-sdk",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "",
5
- "main": "dist/esm/liveness/index.js",
6
- "types": "dist/esm/liveness/index.d.ts",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
7
  "scripts": {
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
11
  "build:typescript": "rm -rf ./dist/esm && tsc",
12
- "build": "npm run build:typescript && npm run build:browser-node"
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": "*",
@@ -98,7 +98,7 @@ export async function livenessDetection (options: TWebSDKOptions) {
98
98
 
99
99
  if (parsedMessage?.success) {
100
100
  validationSuccess = true
101
- await options.successCallback?.()
101
+ await options.successCallback?.({ livenessId: parsedMessage.livenessId })
102
102
  await stopLivenessDetection(options, websocket, sendFramesIntervalKey)
103
103
  }
104
104
  })
@@ -81,7 +81,7 @@ export async function livenessDetection (options: TNodeSDKOptions) {
81
81
 
82
82
  if (parsedMessage?.success) {
83
83
  validationSuccess = true
84
- await options.successCallback?.()
84
+ await options.successCallback?.({ livenessId: parsedMessage.livenessId })
85
85
  await stopLivenessDetection(options, websocket, sendFramesIntervalKey)
86
86
  }
87
87
  })
@@ -10,6 +10,10 @@ export interface IDecodedToken {
10
10
  }
11
11
  }
12
12
 
13
+ export interface ILivenessResults {
14
+ livenessId?: string
15
+ }
16
+
13
17
  export interface ISDKOptions {
14
18
  token: string
15
19
  track: string
@@ -23,15 +27,18 @@ export interface ISDKOptions {
23
27
  upCallback?: TCallbackFunction
24
28
  bottomCallback?: TCallbackFunction
25
29
  errorCallback?: (error: { code: TErrorCode }) => void | Promise<void>
26
- successCallback?: TCallbackFunction
30
+ successCallback?: (results: ILivenessResults) => void | Promise<void>
27
31
  endCallback?: TCallbackFunction
28
32
 
29
33
  customWebSocketUrl?: string
30
34
  }
31
35
 
32
36
  export interface IWebSocketMessage {
33
- success?: boolean
34
- error?: boolean
35
37
  can_send_next_bytes?: boolean
36
38
  next_step?: TPositions
39
+
40
+ error?: boolean
41
+
42
+ success?: boolean
43
+ livenessId?: string
37
44
  }
File without changes
File without changes
File without changes
File without changes
File without changes