santoid-sdk 1.0.7 → 2.0.1
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 +113 -29
- package/browser/liveness/index.js +1 -0
- package/liveness/index.d.ts +9 -0
- package/liveness/index.js +29 -0
- package/liveness/methods/livenessDetection.d.ts +6 -0
- package/{dist/esm/liveness/index.js → liveness/methods/livenessDetection.js} +2 -22
- package/liveness/methods/uploadIdentificationDocument.d.ts +91 -0
- package/liveness/methods/uploadIdentificationDocument.js +238 -0
- package/liveness/utils/index.d.ts +2 -0
- package/{dist/esm/liveness → liveness}/utils/index.js +10 -1
- package/{dist/esm/liveness → liveness}/utils/types.d.ts +2 -2
- package/{dist/node/liveness → liveness}/utils/types.js +1 -1
- package/{dist/esm/liveness → liveness}/utils/websocket.js +1 -1
- package/{dist/node → node}/auth/index.js +3 -6
- package/node/liveness/index.d.ts +9 -0
- package/node/liveness/index.js +29 -0
- package/node/liveness/methods/livenessDetection.d.ts +6 -0
- package/{dist/node/liveness/index.js → node/liveness/methods/livenessDetection.js} +2 -3
- package/node/liveness/methods/uploadIdentificationDocument.d.ts +91 -0
- package/node/liveness/methods/uploadIdentificationDocument.js +239 -0
- package/node/liveness/utils/index.d.ts +2 -0
- package/{dist/node → node}/liveness/utils/index.js +10 -1
- package/package.json +12 -29
- package/tsconfig.json +6 -2
- package/tsconfig.prod.json +26 -0
- package/{dist/utils → utils}/constants.d.ts +1 -1
- package/{dist/utils → utils}/constants.js +1 -1
- package/{dist/utils → utils}/types.d.ts +11 -8
- package/webpack.config.cjs +12 -2
- package/dist/browser/liveness/index.js +0 -1
- package/dist/esm/liveness/index.d.ts +0 -9
- package/dist/esm/liveness/utils/index.d.ts +0 -1
- package/dist/node/liveness/index.d.ts +0 -4
- package/dist/node/liveness/utils/index.d.ts +0 -1
- package/src/esm/liveness/index.ts +0 -156
- package/src/esm/liveness/utils/getNextFrame.ts +0 -76
- package/src/esm/liveness/utils/index.ts +0 -16
- package/src/esm/liveness/utils/types.ts +0 -7
- package/src/esm/liveness/utils/websocket.ts +0 -33
- package/src/index.ts +0 -0
- package/src/node/auth/index.ts +0 -43
- package/src/node/liveness/index.ts +0 -135
- package/src/node/liveness/utils/index.ts +0 -3
- package/src/node/liveness/utils/types.ts +0 -8
- package/src/node/liveness/utils/websocket.ts +0 -35
- package/src/utils/constants.ts +0 -3
- package/src/utils/types.ts +0 -46
- /package/{dist/index.d.ts → index.d.ts} +0 -0
- /package/{dist/index.js → index.js} +0 -0
- /package/{dist/esm/liveness → liveness}/utils/getNextFrame.d.ts +0 -0
- /package/{dist/esm/liveness → liveness}/utils/getNextFrame.js +0 -0
- /package/{dist/esm/liveness → liveness}/utils/websocket.d.ts +0 -0
- /package/{dist/node → node}/auth/index.d.ts +0 -0
- /package/{dist/node → node}/liveness/utils/types.d.ts +0 -0
- /package/{dist/esm → node}/liveness/utils/types.js +0 -0
- /package/{dist/node → node}/liveness/utils/websocket.d.ts +0 -0
- /package/{dist/node → node}/liveness/utils/websocket.js +0 -0
- /package/{dist/utils → utils}/types.js +0 -0
|
@@ -0,0 +1,239 @@
|
|
|
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.uploadIdentificationDocument = void 0;
|
|
7
|
+
const form_data_1 = __importDefault(require("form-data"));
|
|
8
|
+
const axios_1 = __importDefault(require("axios"));
|
|
9
|
+
const constants_1 = require("../../../utils/constants");
|
|
10
|
+
const utils_1 = require("../utils");
|
|
11
|
+
const livenessDetection_1 = require("./livenessDetection");
|
|
12
|
+
async function typificationPredict(options, file) {
|
|
13
|
+
var _a, _b, _c;
|
|
14
|
+
const formData = new form_data_1.default();
|
|
15
|
+
formData.append('track', options.track);
|
|
16
|
+
formData.append('imageFile', file, 'imageFile.jpg');
|
|
17
|
+
const decodedToken = (0, utils_1.tryDecodeJwt)(options.token);
|
|
18
|
+
const domain = (_a = options.domain) !== null && _a !== void 0 ? _a : (_b = decodedToken === null || decodedToken === void 0 ? void 0 : decodedToken.claims) === null || _b === void 0 ? void 0 : _b.domain;
|
|
19
|
+
const axiosConfig = {
|
|
20
|
+
headers: {
|
|
21
|
+
'Content-Type': 'multipart/form-data',
|
|
22
|
+
Authorization: `Bearer ${options.token}`,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
if (axiosConfig.headers && domain) {
|
|
26
|
+
axiosConfig.headers.Domain = domain;
|
|
27
|
+
}
|
|
28
|
+
const response = await axios_1.default.post(`${(_c = options === null || options === void 0 ? void 0 : options.customApiUrl) !== null && _c !== void 0 ? _c : constants_1.API_GATEWAY_URL}/api/v3/typification/predict`, formData, axiosConfig);
|
|
29
|
+
return response.data;
|
|
30
|
+
}
|
|
31
|
+
async function faceMatch(options, firstImage, secondImage) {
|
|
32
|
+
var _a, _b, _c;
|
|
33
|
+
const formData = new form_data_1.default();
|
|
34
|
+
formData.append('track', options.track);
|
|
35
|
+
formData.append('firstImage', firstImage, 'firstImage.jpg');
|
|
36
|
+
formData.append('secondImage', secondImage, 'secondImage.jpg');
|
|
37
|
+
const decodedToken = (0, utils_1.tryDecodeJwt)(options.token);
|
|
38
|
+
const domain = (_a = options.domain) !== null && _a !== void 0 ? _a : (_b = decodedToken === null || decodedToken === void 0 ? void 0 : decodedToken.claims) === null || _b === void 0 ? void 0 : _b.domain;
|
|
39
|
+
const axiosConfig = {
|
|
40
|
+
params: {
|
|
41
|
+
sensitive_data_compliance: true,
|
|
42
|
+
},
|
|
43
|
+
headers: {
|
|
44
|
+
'Content-Type': 'multipart/form-data',
|
|
45
|
+
Authorization: `Bearer ${options.token}`,
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
if (axiosConfig.headers && domain) {
|
|
49
|
+
axiosConfig.headers.Domain = domain;
|
|
50
|
+
}
|
|
51
|
+
const response = await axios_1.default.post(`${(_c = options === null || options === void 0 ? void 0 : options.customApiUrl) !== null && _c !== void 0 ? _c : constants_1.API_GATEWAY_URL}/api/v1/facematch/pair`, formData, axiosConfig);
|
|
52
|
+
return response.data;
|
|
53
|
+
}
|
|
54
|
+
function uploadIdentificationDocument(options) {
|
|
55
|
+
let results = {
|
|
56
|
+
uploadedDocument: null,
|
|
57
|
+
typification: {
|
|
58
|
+
status: null,
|
|
59
|
+
results: null,
|
|
60
|
+
loading: false,
|
|
61
|
+
error: null,
|
|
62
|
+
},
|
|
63
|
+
liveness: {
|
|
64
|
+
status: null,
|
|
65
|
+
results: null,
|
|
66
|
+
loading: false,
|
|
67
|
+
error: null,
|
|
68
|
+
},
|
|
69
|
+
faceMatch: {
|
|
70
|
+
status: null,
|
|
71
|
+
results: null,
|
|
72
|
+
loading: false,
|
|
73
|
+
error: null,
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
async function startFaceMatch(firstImage, secondImage) {
|
|
77
|
+
var _a, _b, _c;
|
|
78
|
+
try {
|
|
79
|
+
updateResults({
|
|
80
|
+
faceMatch: {
|
|
81
|
+
status: null,
|
|
82
|
+
results: null,
|
|
83
|
+
loading: true,
|
|
84
|
+
error: null,
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
const faceMatchResults = await faceMatch(options, firstImage, secondImage);
|
|
88
|
+
updateResults({
|
|
89
|
+
faceMatch: {
|
|
90
|
+
results: faceMatchResults,
|
|
91
|
+
status: 'success',
|
|
92
|
+
loading: false,
|
|
93
|
+
error: null,
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
await ((_a = options.errorCallback) === null || _a === void 0 ? void 0 : _a.call(options, { code: 'face-match-error', details: (_b = err === null || err === void 0 ? void 0 : err.response) === null || _b === void 0 ? void 0 : _b.data }));
|
|
99
|
+
updateResults({
|
|
100
|
+
faceMatch: {
|
|
101
|
+
results: null,
|
|
102
|
+
status: 'error',
|
|
103
|
+
loading: false,
|
|
104
|
+
error: (_c = err === null || err === void 0 ? void 0 : err.response) === null || _c === void 0 ? void 0 : _c.data,
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function tryStartFaceMatch() {
|
|
110
|
+
var _a;
|
|
111
|
+
if (results.uploadedDocument &&
|
|
112
|
+
((_a = results.liveness.results) === null || _a === void 0 ? void 0 : _a.successFrames.front) &&
|
|
113
|
+
!results.faceMatch.results &&
|
|
114
|
+
!results.faceMatch.loading) {
|
|
115
|
+
void startFaceMatch(results.uploadedDocument, results.liveness.results.successFrames.front);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function updateUploadedDocument(file) {
|
|
119
|
+
results.uploadedDocument = file;
|
|
120
|
+
tryStartFaceMatch();
|
|
121
|
+
}
|
|
122
|
+
function updateResults(updatedResults) {
|
|
123
|
+
var _a, _b, _c;
|
|
124
|
+
results = Object.assign(Object.assign({}, results), updatedResults);
|
|
125
|
+
void ((_a = options.resultChangeCallback) === null || _a === void 0 ? void 0 : _a.call(options, results));
|
|
126
|
+
if (Object.entries(results).every(([key, value]) => key === 'uploadedDocument' || !!value.results)) {
|
|
127
|
+
void ((_b = options.successCallback) === null || _b === void 0 ? void 0 : _b.call(options, results));
|
|
128
|
+
void ((_c = options.endCallback) === null || _c === void 0 ? void 0 : _c.call(options));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (results.faceMatch.status !== 'error') {
|
|
132
|
+
tryStartFaceMatch();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async function startDocumentUpload(file) {
|
|
136
|
+
var _a, _b, _c;
|
|
137
|
+
try {
|
|
138
|
+
updateResults({
|
|
139
|
+
typification: {
|
|
140
|
+
status: null,
|
|
141
|
+
results: null,
|
|
142
|
+
loading: true,
|
|
143
|
+
error: null,
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
updateUploadedDocument(file);
|
|
147
|
+
const typificationResults = await typificationPredict(options, file);
|
|
148
|
+
updateResults({
|
|
149
|
+
typification: {
|
|
150
|
+
status: 'success',
|
|
151
|
+
results: typificationResults,
|
|
152
|
+
loading: false,
|
|
153
|
+
error: null,
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
catch (err) {
|
|
158
|
+
await ((_a = options.errorCallback) === null || _a === void 0 ? void 0 : _a.call(options, { code: 'typification-error', details: (_b = err === null || err === void 0 ? void 0 : err.response) === null || _b === void 0 ? void 0 : _b.data }));
|
|
159
|
+
updateResults({
|
|
160
|
+
typification: {
|
|
161
|
+
status: 'error',
|
|
162
|
+
results: null,
|
|
163
|
+
loading: false,
|
|
164
|
+
error: (_c = err === null || err === void 0 ? void 0 : err.response) === null || _c === void 0 ? void 0 : _c.data,
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
async function startLivenessDetection(startLivenessDetectionOptions) {
|
|
170
|
+
var _a, _b, _c, _d, _e;
|
|
171
|
+
const adaptedLivenessOptions = Object.assign({}, startLivenessDetectionOptions);
|
|
172
|
+
delete adaptedLivenessOptions.successCallback;
|
|
173
|
+
delete adaptedLivenessOptions.errorCallback;
|
|
174
|
+
updateResults({
|
|
175
|
+
liveness: {
|
|
176
|
+
results: null,
|
|
177
|
+
status: null,
|
|
178
|
+
loading: true,
|
|
179
|
+
error: null,
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
try {
|
|
183
|
+
return await (0, livenessDetection_1.livenessDetection)(Object.assign(Object.assign({ domain: options.domain, customId: options.customId, customWebSocketUrl: options.customWebSocketUrl, successCallback: (livenessResults) => {
|
|
184
|
+
var _a;
|
|
185
|
+
void ((_a = startLivenessDetectionOptions === null || startLivenessDetectionOptions === void 0 ? void 0 : startLivenessDetectionOptions.successCallback) === null || _a === void 0 ? void 0 : _a.call(startLivenessDetectionOptions, livenessResults));
|
|
186
|
+
updateResults({
|
|
187
|
+
liveness: {
|
|
188
|
+
status: 'success',
|
|
189
|
+
results: (livenessResults),
|
|
190
|
+
loading: false,
|
|
191
|
+
error: null,
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
}, errorCallback: async (livenessErrorDetails) => {
|
|
195
|
+
var _a, _b;
|
|
196
|
+
if ((livenessErrorDetails === null || livenessErrorDetails === void 0 ? void 0 : livenessErrorDetails.code) === 'wrong-position') {
|
|
197
|
+
void ((_a = startLivenessDetectionOptions === null || startLivenessDetectionOptions === void 0 ? void 0 : startLivenessDetectionOptions.errorCallback) === null || _a === void 0 ? void 0 : _a.call(startLivenessDetectionOptions, livenessErrorDetails));
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
void ((_b = options.errorCallback) === null || _b === void 0 ? void 0 : _b.call(options, livenessErrorDetails));
|
|
201
|
+
}
|
|
202
|
+
updateResults({
|
|
203
|
+
liveness: {
|
|
204
|
+
status: 'error',
|
|
205
|
+
results: null,
|
|
206
|
+
loading: (livenessErrorDetails === null || livenessErrorDetails === void 0 ? void 0 : livenessErrorDetails.code) === 'wrong-position',
|
|
207
|
+
error: livenessErrorDetails,
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
} }, adaptedLivenessOptions), { token: (_a = adaptedLivenessOptions.token) !== null && _a !== void 0 ? _a : options.token, track: (_b = adaptedLivenessOptions.track) !== null && _b !== void 0 ? _b : options.track }));
|
|
211
|
+
}
|
|
212
|
+
catch (err) {
|
|
213
|
+
await ((_c = options.errorCallback) === null || _c === void 0 ? void 0 : _c.call(options, { code: 'liveness-error', details: (_d = err === null || err === void 0 ? void 0 : err.response) === null || _d === void 0 ? void 0 : _d.data }));
|
|
214
|
+
updateResults({
|
|
215
|
+
liveness: {
|
|
216
|
+
status: 'error',
|
|
217
|
+
results: null,
|
|
218
|
+
loading: false,
|
|
219
|
+
error: (_e = err === null || err === void 0 ? void 0 : err.response) === null || _e === void 0 ? void 0 : _e.data,
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function startAll(file, startLivenessDetectionOptions) {
|
|
225
|
+
void startDocumentUpload(file);
|
|
226
|
+
void startLivenessDetection(startLivenessDetectionOptions);
|
|
227
|
+
}
|
|
228
|
+
function getResults() {
|
|
229
|
+
return results;
|
|
230
|
+
}
|
|
231
|
+
return {
|
|
232
|
+
getResults,
|
|
233
|
+
startDocumentUpload,
|
|
234
|
+
startLivenessDetection,
|
|
235
|
+
startFaceComparison: tryStartFaceMatch,
|
|
236
|
+
startAll,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
exports.uploadIdentificationDocument = uploadIdentificationDocument;
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.decodeJwt = void 0;
|
|
3
|
+
exports.tryDecodeJwt = exports.decodeJwt = void 0;
|
|
4
4
|
function decodeJwt(token) {
|
|
5
5
|
return JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString());
|
|
6
6
|
}
|
|
7
7
|
exports.decodeJwt = decodeJwt;
|
|
8
|
+
function tryDecodeJwt(token) {
|
|
9
|
+
try {
|
|
10
|
+
return decodeJwt(token);
|
|
11
|
+
}
|
|
12
|
+
catch (_a) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.tryDecodeJwt = tryDecodeJwt;
|
package/package.json
CHANGED
|
@@ -1,36 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "santoid-sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "",
|
|
5
|
-
"main": "
|
|
6
|
-
"types": "
|
|
5
|
+
"main": "liveness/index.js",
|
|
6
|
+
"types": "liveness/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"expose:cmd": "mv -v dist/* ./",
|
|
9
|
-
"
|
|
10
|
-
"build:
|
|
11
|
-
"build:typescript": "
|
|
12
|
-
"build": "npm run build:typescript && npm run build:
|
|
13
|
-
"test": "jest",
|
|
14
|
-
"test:coverage": "jest --coverage"
|
|
15
|
-
},
|
|
16
|
-
"exports": {
|
|
17
|
-
".": "./dist/index.js",
|
|
18
|
-
"./liveness": "./dist/esm/liveness/index.js",
|
|
19
|
-
"./node/liveness": "./dist/node/liveness/index.js",
|
|
20
|
-
"./node/auth": "./dist/node/auth/index.js"
|
|
21
|
-
},
|
|
22
|
-
"typesVersions": {
|
|
23
|
-
"*": {
|
|
24
|
-
"liveness": [
|
|
25
|
-
"dist/esm/liveness/index.d.ts"
|
|
26
|
-
],
|
|
27
|
-
"node/liveness": [
|
|
28
|
-
"dist/node/liveness/index.d.ts"
|
|
29
|
-
],
|
|
30
|
-
"node/auth": [
|
|
31
|
-
"dist/node/auth/index.d.ts"
|
|
32
|
-
]
|
|
33
|
-
}
|
|
8
|
+
"expose:cmd": "mv -v dist/* ./ && rm -rf ./dist",
|
|
9
|
+
"build:clear": "rm -rf ./browser ./liveness ./node ./utils ./index.js ./index.d.ts ./dist",
|
|
10
|
+
"build:webpack": "webpack --mode=production",
|
|
11
|
+
"build:typescript": "npm run build:clear && tsc -p tsconfig.prod.json",
|
|
12
|
+
"build": "npm run build:typescript && npm run build:webpack && npm run expose:cmd",
|
|
13
|
+
"test": "jest --coverage false",
|
|
14
|
+
"test:coverage": "jest --coverage --runInBand"
|
|
34
15
|
},
|
|
35
16
|
"keywords": [],
|
|
36
17
|
"author": "SantoDigital",
|
|
@@ -58,6 +39,8 @@
|
|
|
58
39
|
"webpack-node-externals": "^3.0.0"
|
|
59
40
|
},
|
|
60
41
|
"dependencies": {
|
|
42
|
+
"axios": "^1.5.1",
|
|
43
|
+
"form-data": "^4.0.0",
|
|
61
44
|
"ws": "^8.14.2"
|
|
62
45
|
}
|
|
63
46
|
}
|
package/tsconfig.json
CHANGED
|
@@ -5,12 +5,16 @@
|
|
|
5
5
|
"target": "es2017",
|
|
6
6
|
"moduleResolution": "node",
|
|
7
7
|
"outDir": "dist",
|
|
8
|
-
"rootDir": "src",
|
|
9
8
|
"baseUrl": "./",
|
|
10
9
|
"declaration": true,
|
|
11
10
|
"esModuleInterop": true,
|
|
12
11
|
"strictNullChecks": true,
|
|
13
12
|
},
|
|
14
13
|
|
|
15
|
-
"include": [
|
|
14
|
+
"include": [
|
|
15
|
+
"./.eslintrc.js",
|
|
16
|
+
"./webpack.config.cjs",
|
|
17
|
+
"./jest.config.cjs",
|
|
18
|
+
"**/*.ts",
|
|
19
|
+
],
|
|
16
20
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"typeRoots": ["@types", "./node_modules/@types"],
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"target": "es2017",
|
|
6
|
+
"moduleResolution": "node",
|
|
7
|
+
"outDir": "dist",
|
|
8
|
+
"baseUrl": "./",
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"strictNullChecks": true,
|
|
12
|
+
|
|
13
|
+
"rootDir": "src",
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
"include": [
|
|
17
|
+
"./.eslintrc.js",
|
|
18
|
+
"./webpack.config.cjs",
|
|
19
|
+
"./jest.config.cjs",
|
|
20
|
+
"src/**/*.ts",
|
|
21
|
+
],
|
|
22
|
+
|
|
23
|
+
"exclude": [
|
|
24
|
+
"__tests__/**/*.ts"
|
|
25
|
+
]
|
|
26
|
+
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
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
|
|
2
|
+
export declare const API_GATEWAY_URL = "https://api.santoid.com.br";
|
|
3
3
|
export declare const SEND_FRAMES_INTERVAL_MS = 100;
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SEND_FRAMES_INTERVAL_MS = exports.API_GATEWAY_URL = exports.WEBSOCKET_BASE_URL = void 0;
|
|
4
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
|
|
5
|
+
exports.API_GATEWAY_URL = 'https://api.santoid.com.br';
|
|
6
6
|
exports.SEND_FRAMES_INTERVAL_MS = 100;
|
|
@@ -1,32 +1,36 @@
|
|
|
1
1
|
export type TCallbackFunction = (...args: any[]) => void | Promise<void>;
|
|
2
2
|
export type TPositions = 'front' | 'right' | 'left' | 'up' | 'bottom';
|
|
3
|
-
export type TErrorCode = 'wrong-position' | 'internal-error';
|
|
3
|
+
export type TErrorCode = 'wrong-position' | 'internal-error' | 'typification-error' | 'face-match-error' | 'liveness-error';
|
|
4
4
|
export interface IDecodedToken {
|
|
5
5
|
claims: {
|
|
6
6
|
domain: string;
|
|
7
7
|
};
|
|
8
8
|
}
|
|
9
|
-
interface ILivenessResults<FrameType> {
|
|
9
|
+
export interface ILivenessResults<FrameType> {
|
|
10
10
|
livenessId: string;
|
|
11
11
|
successFrames: Record<TPositions, FrameType>;
|
|
12
12
|
}
|
|
13
|
-
export interface
|
|
13
|
+
export interface IBaseSDKOptions {
|
|
14
14
|
token: string;
|
|
15
15
|
track: string;
|
|
16
16
|
customId?: string;
|
|
17
17
|
domain?: string;
|
|
18
|
-
|
|
18
|
+
customWebSocketUrl?: string;
|
|
19
|
+
customApiUrl?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface ISDKOptions extends IBaseSDKOptions {
|
|
22
|
+
nextStepCallback?: <TStepType = TPositions>(step: TStepType) => void | Promise<void>;
|
|
19
23
|
frontCallback?: TCallbackFunction;
|
|
20
24
|
rightCallback?: TCallbackFunction;
|
|
21
25
|
leftCallback?: TCallbackFunction;
|
|
22
26
|
upCallback?: TCallbackFunction;
|
|
23
27
|
bottomCallback?: TCallbackFunction;
|
|
24
|
-
errorCallback?: (error
|
|
28
|
+
errorCallback?: (error?: {
|
|
25
29
|
code: TErrorCode;
|
|
30
|
+
details?: any;
|
|
26
31
|
}) => void | Promise<void>;
|
|
27
|
-
successCallback?: <FrameType
|
|
32
|
+
successCallback?: <FrameType, ResultsType = ILivenessResults<FrameType>>(results?: ResultsType) => void | Promise<void>;
|
|
28
33
|
endCallback?: TCallbackFunction;
|
|
29
|
-
customWebSocketUrl?: string;
|
|
30
34
|
}
|
|
31
35
|
export interface IWebSocketMessage {
|
|
32
36
|
can_send_next_bytes?: boolean;
|
|
@@ -36,4 +40,3 @@ export interface IWebSocketMessage {
|
|
|
36
40
|
success?: boolean;
|
|
37
41
|
livenessId: string;
|
|
38
42
|
}
|
|
39
|
-
export {};
|
package/webpack.config.cjs
CHANGED
|
@@ -7,6 +7,7 @@ const generalConfig = {
|
|
|
7
7
|
aggregateTimeout: 600,
|
|
8
8
|
ignored: /node_modules/,
|
|
9
9
|
},
|
|
10
|
+
|
|
10
11
|
plugins: [
|
|
11
12
|
new CleanWebpackPlugin({
|
|
12
13
|
cleanStaleWebpackAssets: false,
|
|
@@ -15,22 +16,31 @@ const generalConfig = {
|
|
|
15
16
|
],
|
|
16
17
|
}),
|
|
17
18
|
],
|
|
19
|
+
|
|
18
20
|
module: {
|
|
19
21
|
rules: [
|
|
20
22
|
{
|
|
21
23
|
test: /\.tsx?$/,
|
|
22
|
-
use:
|
|
24
|
+
use: [
|
|
25
|
+
{
|
|
26
|
+
loader: 'ts-loader',
|
|
27
|
+
options: {
|
|
28
|
+
configFile: 'tsconfig.prod.json',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
],
|
|
23
32
|
exclude: /node_modules/,
|
|
24
33
|
},
|
|
25
34
|
],
|
|
26
35
|
},
|
|
36
|
+
|
|
27
37
|
resolve: {
|
|
28
38
|
extensions: ['.tsx', '.ts', '.js'],
|
|
29
39
|
},
|
|
30
40
|
}
|
|
31
41
|
|
|
32
42
|
const browserConfig = {
|
|
33
|
-
entry: './src/
|
|
43
|
+
entry: './src/liveness/index.ts',
|
|
34
44
|
target: 'web',
|
|
35
45
|
output: {
|
|
36
46
|
path: path.resolve(__dirname, './dist/browser/liveness'),
|
|
@@ -1 +0,0 @@
|
|
|
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})()));
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { type TWebSDKOptions } from './utils/types';
|
|
2
|
-
export * from './utils/types';
|
|
3
|
-
export declare function livenessDetection(options: TWebSDKOptions): Promise<{
|
|
4
|
-
stopLivenessDetection: () => Promise<void>;
|
|
5
|
-
videoStream: MediaStream | undefined;
|
|
6
|
-
}>;
|
|
7
|
-
export default class SantoiDSDK {
|
|
8
|
-
static livenessDetection: typeof livenessDetection;
|
|
9
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function decodeJwt(token: string): any;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function decodeJwt(token: string): any;
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
import { type TPositions, type IWebSocketMessage, type TWebSDKOptions } from './utils/types'
|
|
2
|
-
import { SEND_FRAMES_INTERVAL_MS } from '../../utils/constants'
|
|
3
|
-
import { builtInGetNextFrame, type builtInGetNextFrameReturn } from './utils/getNextFrame'
|
|
4
|
-
|
|
5
|
-
import { connectToWebSocket, disconnectFromWebSocket } from './utils/websocket'
|
|
6
|
-
|
|
7
|
-
export * from './utils/types'
|
|
8
|
-
|
|
9
|
-
async function onWebSocketMessage (options: TWebSDKOptions, event: MessageEvent) {
|
|
10
|
-
const message = event.data
|
|
11
|
-
|
|
12
|
-
let messageObj: IWebSocketMessage | undefined
|
|
13
|
-
|
|
14
|
-
try {
|
|
15
|
-
messageObj = JSON.parse(message)
|
|
16
|
-
} catch (err) {
|
|
17
|
-
console.error('Cannot parse API message', err)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (messageObj?.next_step && !messageObj.error) {
|
|
21
|
-
await options.nextStepCallback?.(messageObj.next_step)
|
|
22
|
-
await options[`${messageObj.next_step}Callback`]?.()
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (messageObj?.error) {
|
|
26
|
-
await options.errorCallback?.({ code: 'wrong-position' })
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return messageObj
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export async function livenessDetection (options: TWebSDKOptions) {
|
|
33
|
-
type FrameType = Blob | null | undefined
|
|
34
|
-
|
|
35
|
-
let websocketClosedBySDK = false
|
|
36
|
-
let builtInGetNextFrameReturn: builtInGetNextFrameReturn | undefined
|
|
37
|
-
let validationSuccess = false
|
|
38
|
-
let endCalled = false
|
|
39
|
-
let canSendNextBytes = true
|
|
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
|
-
|
|
52
|
-
async function stopLivenessDetection (options: TWebSDKOptions, websocket?: WebSocket, intervalKey?: any) {
|
|
53
|
-
if (intervalKey) {
|
|
54
|
-
clearInterval(intervalKey)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (websocket) {
|
|
58
|
-
disconnectFromWebSocket(websocket)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (builtInGetNextFrameReturn) {
|
|
62
|
-
builtInGetNextFrameReturn.stopGetNextFrame()
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
!endCalled && await options.endCallback?.()
|
|
66
|
-
endCalled = true
|
|
67
|
-
|
|
68
|
-
websocketClosedBySDK = true
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
let sendFramesIntervalKey: any
|
|
72
|
-
let websocket: WebSocket | undefined
|
|
73
|
-
|
|
74
|
-
try {
|
|
75
|
-
websocket = await connectToWebSocket(options)
|
|
76
|
-
|
|
77
|
-
await options.nextStepCallback?.('front')
|
|
78
|
-
await options.frontCallback?.()
|
|
79
|
-
|
|
80
|
-
if (!options.getNextFrame && !builtInGetNextFrameReturn) {
|
|
81
|
-
builtInGetNextFrameReturn = await builtInGetNextFrame()
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
sendFramesIntervalKey = setInterval(async () => {
|
|
85
|
-
try {
|
|
86
|
-
if (canSendNextBytes) {
|
|
87
|
-
let bytes
|
|
88
|
-
|
|
89
|
-
if (options.getNextFrame) {
|
|
90
|
-
bytes = await options.getNextFrame()
|
|
91
|
-
} else {
|
|
92
|
-
bytes = await builtInGetNextFrameReturn?.getNextFrame()
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (bytes) {
|
|
96
|
-
websocket?.send(bytes)
|
|
97
|
-
lastSentBytes = bytes
|
|
98
|
-
canSendNextBytes = false
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
} catch (err) {
|
|
102
|
-
await stopLivenessDetection(options, websocket, sendFramesIntervalKey)
|
|
103
|
-
}
|
|
104
|
-
}, SEND_FRAMES_INTERVAL_MS)
|
|
105
|
-
|
|
106
|
-
websocket.addEventListener('message', async (event) => {
|
|
107
|
-
const parsedMessage = await onWebSocketMessage(options, event)
|
|
108
|
-
|
|
109
|
-
if (parsedMessage) {
|
|
110
|
-
canSendNextBytes = !!parsedMessage?.can_send_next_bytes
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (parsedMessage?.validation && currentStep) {
|
|
114
|
-
successFrames[currentStep] = lastSentBytes
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (parsedMessage?.next_step) {
|
|
118
|
-
currentStep = parsedMessage.next_step
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (parsedMessage?.success) {
|
|
122
|
-
successFrames.bottom = lastSentBytes
|
|
123
|
-
|
|
124
|
-
validationSuccess = true
|
|
125
|
-
await options.successCallback?.<FrameType>({ livenessId: parsedMessage.livenessId, successFrames })
|
|
126
|
-
await stopLivenessDetection(options, websocket, sendFramesIntervalKey)
|
|
127
|
-
}
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
websocket.addEventListener('error', async () => {
|
|
131
|
-
!validationSuccess && options.errorCallback?.({ code: 'internal-error' })
|
|
132
|
-
await stopLivenessDetection(options, websocket, sendFramesIntervalKey)
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
websocket.addEventListener('close', async () => {
|
|
136
|
-
if (!websocketClosedBySDK) {
|
|
137
|
-
!validationSuccess && options.errorCallback?.({ code: 'internal-error' })
|
|
138
|
-
await stopLivenessDetection(options, websocket, sendFramesIntervalKey)
|
|
139
|
-
}
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
return {
|
|
143
|
-
stopLivenessDetection: async () => { await stopLivenessDetection(options, websocket, sendFramesIntervalKey) },
|
|
144
|
-
videoStream: builtInGetNextFrameReturn?.videoStream,
|
|
145
|
-
}
|
|
146
|
-
} catch (err) {
|
|
147
|
-
!validationSuccess && options.errorCallback?.({ code: 'internal-error' })
|
|
148
|
-
await stopLivenessDetection(options, websocket, sendFramesIntervalKey)
|
|
149
|
-
throw err
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Class for use in browsers
|
|
154
|
-
export default class SantoiDSDK {
|
|
155
|
-
static livenessDetection = livenessDetection
|
|
156
|
-
}
|