biometry-sdk 1.0.1 → 1.0.3
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/dist/index.d.ts +2 -2
- package/dist/index.js +18 -0
- package/dist/sdk.js +272 -0
- package/dist/sdk.test.d.ts +1 -0
- package/dist/sdk.test.js +451 -0
- package/dist/types.js +2 -0
- package/package.json +8 -34
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
1
|
+
export * from './sdk';
|
|
2
|
+
export * from './types';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
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("./sdk"), exports);
|
|
18
|
+
__exportStar(require("./types"), exports);
|
package/dist/sdk.js
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
14
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
15
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
16
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
17
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
18
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
19
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
23
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
24
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
25
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
26
|
+
function step(op) {
|
|
27
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
28
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
29
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
30
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
31
|
+
switch (op[0]) {
|
|
32
|
+
case 0: case 1: t = op; break;
|
|
33
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
34
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
35
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
36
|
+
default:
|
|
37
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
38
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
39
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
40
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
41
|
+
if (t[2]) _.ops.pop();
|
|
42
|
+
_.trys.pop(); continue;
|
|
43
|
+
}
|
|
44
|
+
op = body.call(thisArg, _);
|
|
45
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
46
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.BiometrySDK = void 0;
|
|
51
|
+
var BiometrySDK = /** @class */ (function () {
|
|
52
|
+
function BiometrySDK(apiKey) {
|
|
53
|
+
if (!apiKey) {
|
|
54
|
+
throw new Error('API Key is required to initialize the SDK.');
|
|
55
|
+
}
|
|
56
|
+
this.apiKey = apiKey;
|
|
57
|
+
}
|
|
58
|
+
BiometrySDK.prototype.request = function (path, method, body, headers) {
|
|
59
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
60
|
+
var defaultHeaders, requestHeaders, response, error;
|
|
61
|
+
return __generator(this, function (_a) {
|
|
62
|
+
switch (_a.label) {
|
|
63
|
+
case 0:
|
|
64
|
+
defaultHeaders = {
|
|
65
|
+
Authorization: "Bearer ".concat(this.apiKey),
|
|
66
|
+
};
|
|
67
|
+
requestHeaders = __assign(__assign({}, defaultHeaders), headers);
|
|
68
|
+
if (body && !(body instanceof FormData)) {
|
|
69
|
+
requestHeaders['Content-Type'] = 'application/json';
|
|
70
|
+
body = JSON.stringify(body);
|
|
71
|
+
}
|
|
72
|
+
return [4 /*yield*/, fetch("".concat(BiometrySDK.BASE_URL).concat(path), {
|
|
73
|
+
method: method,
|
|
74
|
+
headers: requestHeaders,
|
|
75
|
+
body: body,
|
|
76
|
+
})];
|
|
77
|
+
case 1:
|
|
78
|
+
response = _a.sent();
|
|
79
|
+
if (!!response.ok) return [3 /*break*/, 3];
|
|
80
|
+
return [4 /*yield*/, response.json()];
|
|
81
|
+
case 2:
|
|
82
|
+
error = _a.sent();
|
|
83
|
+
throw new Error("Error ".concat(response.status, ": ").concat(error.message));
|
|
84
|
+
case 3: return [4 /*yield*/, response.json()];
|
|
85
|
+
case 4: return [2 /*return*/, _a.sent()];
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Submits consent for a user.
|
|
92
|
+
*
|
|
93
|
+
* @param {boolean} isConsentGiven - Indicates whether the user has given consent.
|
|
94
|
+
* @param {string} userFullName - The full name of the user giving consent.
|
|
95
|
+
* @returns {Promise<ConsentResponse>} A promise resolving to the consent response.
|
|
96
|
+
* @throws {Error} - If the user's full name is not provided or if the request fails.
|
|
97
|
+
*/
|
|
98
|
+
BiometrySDK.prototype.giveConsent = function (isConsentGiven, userFullName) {
|
|
99
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
100
|
+
var body, response;
|
|
101
|
+
return __generator(this, function (_a) {
|
|
102
|
+
switch (_a.label) {
|
|
103
|
+
case 0:
|
|
104
|
+
if (!userFullName) {
|
|
105
|
+
throw new Error('User Full Name is required to give consent.');
|
|
106
|
+
}
|
|
107
|
+
body = {
|
|
108
|
+
is_consent_given: isConsentGiven,
|
|
109
|
+
user_fullname: userFullName,
|
|
110
|
+
};
|
|
111
|
+
return [4 /*yield*/, this.request('/consent', 'POST', body)];
|
|
112
|
+
case 1:
|
|
113
|
+
response = _a.sent();
|
|
114
|
+
return [2 /*return*/, {
|
|
115
|
+
is_consent_given: response.is_consent_given,
|
|
116
|
+
user_fullname: response.user_fullname,
|
|
117
|
+
}];
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* Onboards a user's voice for biometric authentication.
|
|
124
|
+
*
|
|
125
|
+
* @param {File} audio - The audio file containing the user's voice.
|
|
126
|
+
* @param {string} userFullName - The full name of the user being onboarded.
|
|
127
|
+
* @param {string} uniqueId - A unique identifier for the onboarding process.
|
|
128
|
+
* @param {string} phrase - The phrase spoken in the audio file.
|
|
129
|
+
* @param {string} [requestUserProvidedId] - An optional user-provided ID to link transactions within a unified group.
|
|
130
|
+
* @returns {Promise<VoiceOnboardingResponse>} - A promise resolving to the voice onboarding response.
|
|
131
|
+
* @throws {Error} - If required parameters are missing or the request fails.
|
|
132
|
+
*/
|
|
133
|
+
BiometrySDK.prototype.onboardVoice = function (audio, userFullName, uniqueId, phrase, requestUserProvidedId) {
|
|
134
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
135
|
+
var formData, headers;
|
|
136
|
+
return __generator(this, function (_a) {
|
|
137
|
+
if (!userFullName)
|
|
138
|
+
throw new Error('User fullname is required.');
|
|
139
|
+
if (!uniqueId)
|
|
140
|
+
throw new Error('Unique ID is required.');
|
|
141
|
+
if (!phrase)
|
|
142
|
+
throw new Error('Phrase is required.');
|
|
143
|
+
if (!audio)
|
|
144
|
+
throw new Error('Audio file is required.');
|
|
145
|
+
formData = new FormData();
|
|
146
|
+
formData.append('unique_id', uniqueId);
|
|
147
|
+
formData.append('phrase', phrase);
|
|
148
|
+
formData.append('voice', audio);
|
|
149
|
+
headers = {
|
|
150
|
+
'X-User-Fullname': userFullName,
|
|
151
|
+
};
|
|
152
|
+
if (requestUserProvidedId) {
|
|
153
|
+
headers['X-Request-User-Provided-ID'] = requestUserProvidedId;
|
|
154
|
+
}
|
|
155
|
+
return [2 /*return*/, this.request('/api-gateway/onboard/voice', 'POST', formData, headers)];
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* Onboards a user's face for biometric authentication.
|
|
161
|
+
*
|
|
162
|
+
* @param {File} face - Image file that contains user's face.
|
|
163
|
+
* @param {string} userFullName - The full name of the user being onboarded.
|
|
164
|
+
* @param {string} isDocument - Indicates whether the image is a document.
|
|
165
|
+
* @param {string} [requestUserProvidedId] - An optional user-provided ID to link transactions within a unified group.
|
|
166
|
+
* @returns {Promise<FaceOnboardingResponse>} - A promise resolving to the voice onboarding response.
|
|
167
|
+
* @throws {Error} - If required parameters are missing or the request fails.
|
|
168
|
+
*/
|
|
169
|
+
BiometrySDK.prototype.onboardFace = function (face, userFullName, isDocument, requestUserProvidedId) {
|
|
170
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
171
|
+
var formData, headers;
|
|
172
|
+
return __generator(this, function (_a) {
|
|
173
|
+
if (!userFullName)
|
|
174
|
+
throw new Error('User fullname is required.');
|
|
175
|
+
if (!face)
|
|
176
|
+
throw new Error('Face image is required.');
|
|
177
|
+
formData = new FormData();
|
|
178
|
+
formData.append('face', face);
|
|
179
|
+
if (isDocument) {
|
|
180
|
+
formData.append('is_document', 'true');
|
|
181
|
+
}
|
|
182
|
+
headers = {
|
|
183
|
+
'X-User-Fullname': userFullName,
|
|
184
|
+
};
|
|
185
|
+
if (requestUserProvidedId) {
|
|
186
|
+
headers['X-Request-User-Provided-ID'] = requestUserProvidedId;
|
|
187
|
+
}
|
|
188
|
+
return [2 /*return*/, this.request('/api-gateway/onboard/face', 'POST', formData, headers)];
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
};
|
|
192
|
+
/**
|
|
193
|
+
* Matches a user's face from video against a reference image.
|
|
194
|
+
*
|
|
195
|
+
* @param {File} image - Reference image file that contains user's face.
|
|
196
|
+
* @param {string} video - Video file that contains user's face.
|
|
197
|
+
* @param {string} userFullName - Pass the full name of end-user to process Voice and Face recognition services.
|
|
198
|
+
* @param {string} processVideoRequestId - ID from the response header of /process-video endpoint.
|
|
199
|
+
* @param {boolean} usePrefilledVideo - Pass true to use the video from the process-video endpoint.
|
|
200
|
+
* @param {string} [requestUserProvidedId] - An optional user-provided ID to link transactions within a unified group.
|
|
201
|
+
* @returns {Promise<FaceMatchResponse>} - A promise resolving to the voice onboarding response.
|
|
202
|
+
* @throws {Error} - If required parameters are missing or the request fails.
|
|
203
|
+
*/
|
|
204
|
+
BiometrySDK.prototype.matchFaces = function (image, video, userFullName, processVideoRequestId, usePrefilledVideo, requestUserProvidedId) {
|
|
205
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
206
|
+
var formData, headers;
|
|
207
|
+
return __generator(this, function (_a) {
|
|
208
|
+
if (!image)
|
|
209
|
+
throw new Error('Face image is required.');
|
|
210
|
+
if ((!processVideoRequestId && !usePrefilledVideo) && !video)
|
|
211
|
+
throw new Error('Video is required.');
|
|
212
|
+
formData = new FormData();
|
|
213
|
+
if (video) {
|
|
214
|
+
formData.append('video', video);
|
|
215
|
+
}
|
|
216
|
+
formData.append('image', image);
|
|
217
|
+
headers = {};
|
|
218
|
+
if (userFullName) {
|
|
219
|
+
headers['X-User-Fullname'] = userFullName;
|
|
220
|
+
}
|
|
221
|
+
if (processVideoRequestId) {
|
|
222
|
+
headers['X-Request-Id'] = processVideoRequestId;
|
|
223
|
+
}
|
|
224
|
+
if (processVideoRequestId && usePrefilledVideo) {
|
|
225
|
+
headers['X-Use-Prefilled-Video'] = 'true';
|
|
226
|
+
}
|
|
227
|
+
if (requestUserProvidedId) {
|
|
228
|
+
headers['X-Request-User-Provided-ID'] = requestUserProvidedId;
|
|
229
|
+
}
|
|
230
|
+
return [2 /*return*/, this.request('/api-gateway/match-faces', 'POST', formData, headers)];
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
};
|
|
234
|
+
/**
|
|
235
|
+
* Process the video through Biometry services to check liveness and authorize user
|
|
236
|
+
*
|
|
237
|
+
* @param {File} video - Video file that you want to process.
|
|
238
|
+
* @param {string} phrase - Set of numbers that user needs to say out loud in the video.
|
|
239
|
+
* @param {string} userFullName - Pass the full name of end-user to process Voice and Face recognition services.
|
|
240
|
+
* @param {string} requestUserProvidedId - An optional user-provided ID to link transactions within a unified group.
|
|
241
|
+
* @param {object} deviceInfo - Pass the device information in JSON format to include in transaction.
|
|
242
|
+
* @returns
|
|
243
|
+
*/
|
|
244
|
+
BiometrySDK.prototype.processVideo = function (video, phrase, userFullName, requestUserProvidedId, deviceInfo) {
|
|
245
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
246
|
+
var formData, headers;
|
|
247
|
+
return __generator(this, function (_a) {
|
|
248
|
+
if (!video)
|
|
249
|
+
throw new Error('Video is required.');
|
|
250
|
+
if (!phrase)
|
|
251
|
+
throw new Error('Phrase is required.');
|
|
252
|
+
formData = new FormData();
|
|
253
|
+
formData.append('phrase', phrase);
|
|
254
|
+
formData.append('video', video);
|
|
255
|
+
headers = {};
|
|
256
|
+
if (userFullName) {
|
|
257
|
+
headers['X-User-Fullname'] = userFullName;
|
|
258
|
+
}
|
|
259
|
+
if (requestUserProvidedId) {
|
|
260
|
+
headers['X-Request-User-Provided-ID'] = requestUserProvidedId;
|
|
261
|
+
}
|
|
262
|
+
if (deviceInfo) {
|
|
263
|
+
headers['X-Device-Info'] = JSON.stringify(deviceInfo);
|
|
264
|
+
}
|
|
265
|
+
return [2 /*return*/, this.request('/api-gateway/process-video', 'POST', formData, headers)];
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
};
|
|
269
|
+
BiometrySDK.BASE_URL = 'https://api.biometrysolutions.com';
|
|
270
|
+
return BiometrySDK;
|
|
271
|
+
}());
|
|
272
|
+
exports.BiometrySDK = BiometrySDK;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/sdk.test.js
ADDED
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
var sdk_1 = require("./sdk");
|
|
40
|
+
// Mock the fetch API globally
|
|
41
|
+
global.fetch = jest.fn();
|
|
42
|
+
describe('BiometrySDK', function () {
|
|
43
|
+
var apiKey = 'test-api-key';
|
|
44
|
+
var sdk = new sdk_1.BiometrySDK(apiKey);
|
|
45
|
+
afterEach(function () {
|
|
46
|
+
jest.clearAllMocks();
|
|
47
|
+
});
|
|
48
|
+
it('should throw an error if no API key is provided', function () {
|
|
49
|
+
expect(function () { return new sdk_1.BiometrySDK(''); }).toThrow('API Key is required to initialize the SDK.');
|
|
50
|
+
});
|
|
51
|
+
// CONSENT
|
|
52
|
+
it('should call fetch with correct headers and body when giving consent', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
53
|
+
var result;
|
|
54
|
+
return __generator(this, function (_a) {
|
|
55
|
+
switch (_a.label) {
|
|
56
|
+
case 0:
|
|
57
|
+
fetch.mockResolvedValueOnce({
|
|
58
|
+
ok: true,
|
|
59
|
+
json: function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
60
|
+
return [2 /*return*/, ({ is_consent_given: true, user_fullname: 'John Doe' })];
|
|
61
|
+
}); }); },
|
|
62
|
+
});
|
|
63
|
+
return [4 /*yield*/, sdk.giveConsent(true, 'John Doe')];
|
|
64
|
+
case 1:
|
|
65
|
+
result = _a.sent();
|
|
66
|
+
expect(fetch).toHaveBeenCalledWith('https://api.biometrysolutions.com/consent', expect.objectContaining({
|
|
67
|
+
method: 'POST',
|
|
68
|
+
headers: {
|
|
69
|
+
Authorization: "Bearer ".concat(apiKey),
|
|
70
|
+
'Content-Type': 'application/json',
|
|
71
|
+
},
|
|
72
|
+
body: JSON.stringify({
|
|
73
|
+
is_consent_given: true,
|
|
74
|
+
user_fullname: 'John Doe',
|
|
75
|
+
}),
|
|
76
|
+
}));
|
|
77
|
+
expect(result).toEqual({ is_consent_given: true, user_fullname: 'John Doe', });
|
|
78
|
+
return [2 /*return*/];
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}); });
|
|
82
|
+
it('should throw an error if response is not ok', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
83
|
+
return __generator(this, function (_a) {
|
|
84
|
+
switch (_a.label) {
|
|
85
|
+
case 0:
|
|
86
|
+
fetch.mockResolvedValueOnce({
|
|
87
|
+
ok: false,
|
|
88
|
+
status: 400,
|
|
89
|
+
json: function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
90
|
+
return [2 /*return*/, ({ error: 'is_consent_given must be true' })];
|
|
91
|
+
}); }); },
|
|
92
|
+
});
|
|
93
|
+
return [4 /*yield*/, expect(sdk.giveConsent(true, 'John Doe')).rejects.toThrow('Error 400: undefined')];
|
|
94
|
+
case 1:
|
|
95
|
+
_a.sent();
|
|
96
|
+
return [2 /*return*/];
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}); });
|
|
100
|
+
// VOICE ONBOARDING
|
|
101
|
+
it('should throw an error if user fullname is missing', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
102
|
+
var audioFile;
|
|
103
|
+
return __generator(this, function (_a) {
|
|
104
|
+
switch (_a.label) {
|
|
105
|
+
case 0:
|
|
106
|
+
audioFile = new File(['audio data'], 'audio.wav', { type: 'audio/wav' });
|
|
107
|
+
return [4 /*yield*/, expect(sdk.onboardVoice(audioFile, '', 'uniqueId', 'phrase')).rejects.toThrowError('User fullname is required.')];
|
|
108
|
+
case 1:
|
|
109
|
+
_a.sent();
|
|
110
|
+
return [2 /*return*/];
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}); });
|
|
114
|
+
it('should throw an error if unique ID is missing', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
115
|
+
var audioFile;
|
|
116
|
+
return __generator(this, function (_a) {
|
|
117
|
+
switch (_a.label) {
|
|
118
|
+
case 0:
|
|
119
|
+
audioFile = new File(['audio data'], 'audio.wav', { type: 'audio/wav' });
|
|
120
|
+
return [4 /*yield*/, expect(sdk.onboardVoice(audioFile, 'User Name', '', 'phrase')).rejects.toThrowError('Unique ID is required.')];
|
|
121
|
+
case 1:
|
|
122
|
+
_a.sent();
|
|
123
|
+
return [2 /*return*/];
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}); });
|
|
127
|
+
it('should throw an error if phrase is missing', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
128
|
+
var audioFile;
|
|
129
|
+
return __generator(this, function (_a) {
|
|
130
|
+
switch (_a.label) {
|
|
131
|
+
case 0:
|
|
132
|
+
audioFile = new File(['audio data'], 'audio.wav', { type: 'audio/wav' });
|
|
133
|
+
return [4 /*yield*/, expect(sdk.onboardVoice(audioFile, 'User Name', 'uniqueId', '')).rejects.toThrowError('Phrase is required.')];
|
|
134
|
+
case 1:
|
|
135
|
+
_a.sent();
|
|
136
|
+
return [2 /*return*/];
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}); });
|
|
140
|
+
it('should throw an error if audio file is missing', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
141
|
+
return __generator(this, function (_a) {
|
|
142
|
+
switch (_a.label) {
|
|
143
|
+
case 0: return [4 /*yield*/, expect(sdk.onboardVoice(null, 'User Name', 'uniqueId', 'phrase')).rejects.toThrowError('Audio file is required.')];
|
|
144
|
+
case 1:
|
|
145
|
+
_a.sent();
|
|
146
|
+
return [2 /*return*/];
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}); });
|
|
150
|
+
it('should successfully onboard voice and return the response', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
151
|
+
var mockResponse, audioFile, userFullName, uniqueId, phrase, formDataSpy, result;
|
|
152
|
+
return __generator(this, function (_a) {
|
|
153
|
+
switch (_a.label) {
|
|
154
|
+
case 0:
|
|
155
|
+
mockResponse = {
|
|
156
|
+
status: 'good',
|
|
157
|
+
};
|
|
158
|
+
fetch.mockResolvedValueOnce({
|
|
159
|
+
ok: true,
|
|
160
|
+
json: function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
161
|
+
return [2 /*return*/, mockResponse];
|
|
162
|
+
}); }); },
|
|
163
|
+
});
|
|
164
|
+
audioFile = new File(['audio data'], 'audio.wav', { type: 'audio/wav' });
|
|
165
|
+
userFullName = 'User Name';
|
|
166
|
+
uniqueId = 'uniqueId';
|
|
167
|
+
phrase = 'phrase';
|
|
168
|
+
formDataSpy = jest.spyOn(FormData.prototype, 'append');
|
|
169
|
+
return [4 /*yield*/, sdk.onboardVoice(audioFile, userFullName, uniqueId, phrase)];
|
|
170
|
+
case 1:
|
|
171
|
+
result = _a.sent();
|
|
172
|
+
expect(formDataSpy).toHaveBeenCalledWith('unique_id', uniqueId);
|
|
173
|
+
expect(formDataSpy).toHaveBeenCalledWith('phrase', phrase);
|
|
174
|
+
expect(formDataSpy).toHaveBeenCalledWith('voice', audioFile);
|
|
175
|
+
expect(fetch).toHaveBeenCalledWith('https://api.biometrysolutions.com/api-gateway/onboard/voice', expect.objectContaining({
|
|
176
|
+
method: 'POST',
|
|
177
|
+
headers: {
|
|
178
|
+
'Authorization': "Bearer ".concat(apiKey),
|
|
179
|
+
'X-User-Fullname': userFullName,
|
|
180
|
+
},
|
|
181
|
+
body: expect.any(FormData)
|
|
182
|
+
}));
|
|
183
|
+
expect(result).toEqual(mockResponse);
|
|
184
|
+
return [2 /*return*/];
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}); });
|
|
188
|
+
// FACE ONBOARDING
|
|
189
|
+
it('should throw an error if user fullname is missing', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
190
|
+
var imageFile;
|
|
191
|
+
return __generator(this, function (_a) {
|
|
192
|
+
switch (_a.label) {
|
|
193
|
+
case 0:
|
|
194
|
+
imageFile = new File(['image data'], 'image.jpg', { type: 'image/jpeg' });
|
|
195
|
+
return [4 /*yield*/, expect(sdk.onboardFace(imageFile, '')).rejects.toThrowError('User fullname is required.')];
|
|
196
|
+
case 1:
|
|
197
|
+
_a.sent();
|
|
198
|
+
return [2 /*return*/];
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
}); });
|
|
202
|
+
it('should throw an error if image file is missing', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
203
|
+
return __generator(this, function (_a) {
|
|
204
|
+
switch (_a.label) {
|
|
205
|
+
case 0: return [4 /*yield*/, expect(sdk.onboardFace(null, 'User Name')).rejects.toThrowError('Face image is required.')];
|
|
206
|
+
case 1:
|
|
207
|
+
_a.sent();
|
|
208
|
+
return [2 /*return*/];
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}); });
|
|
212
|
+
it('should successfully onboard face and return the response', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
213
|
+
var mockResponse, imageFile, userFullName, formDataSpy, result;
|
|
214
|
+
return __generator(this, function (_a) {
|
|
215
|
+
switch (_a.label) {
|
|
216
|
+
case 0:
|
|
217
|
+
mockResponse = {
|
|
218
|
+
code: 200,
|
|
219
|
+
description: 'Face onboarded successfully',
|
|
220
|
+
};
|
|
221
|
+
fetch.mockResolvedValueOnce({
|
|
222
|
+
ok: true,
|
|
223
|
+
json: function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
224
|
+
return [2 /*return*/, mockResponse];
|
|
225
|
+
}); }); },
|
|
226
|
+
});
|
|
227
|
+
imageFile = new File(['image data'], 'image.jpg', { type: 'image/jpeg' });
|
|
228
|
+
userFullName = 'User Name';
|
|
229
|
+
formDataSpy = jest.spyOn(FormData.prototype, 'append');
|
|
230
|
+
return [4 /*yield*/, sdk.onboardFace(imageFile, userFullName)];
|
|
231
|
+
case 1:
|
|
232
|
+
result = _a.sent();
|
|
233
|
+
expect(formDataSpy).toHaveBeenCalledWith('face', imageFile);
|
|
234
|
+
expect(fetch).toHaveBeenCalledWith('https://api.biometrysolutions.com/api-gateway/onboard/face', expect.objectContaining({
|
|
235
|
+
method: 'POST',
|
|
236
|
+
headers: {
|
|
237
|
+
'Authorization': "Bearer ".concat(apiKey),
|
|
238
|
+
'X-User-Fullname': userFullName,
|
|
239
|
+
},
|
|
240
|
+
body: expect.any(FormData)
|
|
241
|
+
}));
|
|
242
|
+
expect(result).toEqual(mockResponse);
|
|
243
|
+
return [2 /*return*/];
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
}); });
|
|
247
|
+
// FACE MATCH
|
|
248
|
+
it('should throw an error if face image is missing', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
249
|
+
return __generator(this, function (_a) {
|
|
250
|
+
switch (_a.label) {
|
|
251
|
+
case 0: return [4 /*yield*/, expect(sdk.matchFaces(null, null)).rejects.toThrowError('Face image is required.')];
|
|
252
|
+
case 1:
|
|
253
|
+
_a.sent();
|
|
254
|
+
return [2 /*return*/];
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
}); });
|
|
258
|
+
it('should throw an error if video file is missing', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
259
|
+
var imageFile;
|
|
260
|
+
return __generator(this, function (_a) {
|
|
261
|
+
switch (_a.label) {
|
|
262
|
+
case 0:
|
|
263
|
+
imageFile = new File(['image data'], 'image.jpg', { type: 'image/jpeg' });
|
|
264
|
+
return [4 /*yield*/, expect(sdk.matchFaces(imageFile, null)).rejects.toThrowError('Video is required.')];
|
|
265
|
+
case 1:
|
|
266
|
+
_a.sent();
|
|
267
|
+
return [2 /*return*/];
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
}); });
|
|
271
|
+
it('should successfully match faces and return the response', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
272
|
+
var mockResponse, imageFile, videoFile, formDataSpy, result;
|
|
273
|
+
return __generator(this, function (_a) {
|
|
274
|
+
switch (_a.label) {
|
|
275
|
+
case 0:
|
|
276
|
+
mockResponse = {
|
|
277
|
+
code: 200,
|
|
278
|
+
result: 1,
|
|
279
|
+
description: 'Matched',
|
|
280
|
+
anchor: {
|
|
281
|
+
code: 200,
|
|
282
|
+
description: 'Anchor face',
|
|
283
|
+
},
|
|
284
|
+
target: {
|
|
285
|
+
code: 200,
|
|
286
|
+
description: 'Target face',
|
|
287
|
+
},
|
|
288
|
+
};
|
|
289
|
+
fetch.mockResolvedValueOnce({
|
|
290
|
+
ok: true,
|
|
291
|
+
json: function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
292
|
+
return [2 /*return*/, mockResponse];
|
|
293
|
+
}); }); },
|
|
294
|
+
});
|
|
295
|
+
imageFile = new File(['image data'], 'image.jpg', { type: 'image/jpeg' });
|
|
296
|
+
videoFile = new File(['video data'], 'video.mp4', { type: 'video/mp4' });
|
|
297
|
+
formDataSpy = jest.spyOn(FormData.prototype, 'append');
|
|
298
|
+
return [4 /*yield*/, sdk.matchFaces(imageFile, videoFile)];
|
|
299
|
+
case 1:
|
|
300
|
+
result = _a.sent();
|
|
301
|
+
expect(formDataSpy).toHaveBeenCalledWith('video', videoFile);
|
|
302
|
+
expect(formDataSpy).toHaveBeenCalledWith('image', imageFile);
|
|
303
|
+
expect(fetch).toHaveBeenCalledWith('https://api.biometrysolutions.com/api-gateway/match-faces', expect.objectContaining({
|
|
304
|
+
method: 'POST',
|
|
305
|
+
headers: {
|
|
306
|
+
'Authorization': "Bearer ".concat(apiKey),
|
|
307
|
+
},
|
|
308
|
+
body: expect.any(FormData)
|
|
309
|
+
}));
|
|
310
|
+
expect(result).toEqual(mockResponse);
|
|
311
|
+
return [2 /*return*/];
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
}); });
|
|
315
|
+
it('should successfully match faces if processVideoRequestId is provided', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
316
|
+
var mockResponse, imageFile, formDataSpy, result;
|
|
317
|
+
return __generator(this, function (_a) {
|
|
318
|
+
switch (_a.label) {
|
|
319
|
+
case 0:
|
|
320
|
+
mockResponse = {
|
|
321
|
+
code: 200,
|
|
322
|
+
result: 1,
|
|
323
|
+
description: 'Matched',
|
|
324
|
+
anchor: {
|
|
325
|
+
code: 200,
|
|
326
|
+
description: 'Anchor face',
|
|
327
|
+
},
|
|
328
|
+
target: {
|
|
329
|
+
code: 200,
|
|
330
|
+
description: 'Target face',
|
|
331
|
+
},
|
|
332
|
+
};
|
|
333
|
+
fetch.mockResolvedValueOnce({
|
|
334
|
+
ok: true,
|
|
335
|
+
json: function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
336
|
+
return [2 /*return*/, mockResponse];
|
|
337
|
+
}); }); },
|
|
338
|
+
});
|
|
339
|
+
imageFile = new File(['image data'], 'image.jpg', { type: 'image/jpeg' });
|
|
340
|
+
formDataSpy = jest.spyOn(FormData.prototype, 'append');
|
|
341
|
+
return [4 /*yield*/, sdk.matchFaces(imageFile, undefined, 'User Name', 'processVideoRequestId', true)];
|
|
342
|
+
case 1:
|
|
343
|
+
result = _a.sent();
|
|
344
|
+
expect(formDataSpy).toHaveBeenCalledWith('image', imageFile);
|
|
345
|
+
expect(fetch).toHaveBeenCalledWith('https://api.biometrysolutions.com/api-gateway/match-faces', expect.objectContaining({
|
|
346
|
+
method: 'POST',
|
|
347
|
+
headers: {
|
|
348
|
+
'Authorization': "Bearer ".concat(apiKey),
|
|
349
|
+
'X-User-Fullname': 'User Name',
|
|
350
|
+
'X-Request-Id': 'processVideoRequestId',
|
|
351
|
+
'X-Use-Prefilled-Video': 'true',
|
|
352
|
+
},
|
|
353
|
+
body: expect.any(FormData)
|
|
354
|
+
}));
|
|
355
|
+
expect(result).toEqual(mockResponse);
|
|
356
|
+
return [2 /*return*/];
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
}); });
|
|
360
|
+
// PROCESS VIDEO
|
|
361
|
+
it('should throw an error if video file is missing', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
362
|
+
return __generator(this, function (_a) {
|
|
363
|
+
switch (_a.label) {
|
|
364
|
+
case 0: return [4 /*yield*/, expect(sdk.processVideo(null, 'phrase')).rejects.toThrowError('Video is required.')];
|
|
365
|
+
case 1:
|
|
366
|
+
_a.sent();
|
|
367
|
+
return [2 /*return*/];
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
}); });
|
|
371
|
+
it('should throw an error if phrase is missing', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
372
|
+
var videoFile;
|
|
373
|
+
return __generator(this, function (_a) {
|
|
374
|
+
switch (_a.label) {
|
|
375
|
+
case 0:
|
|
376
|
+
videoFile = new File(['video data'], 'video.mp4', { type: 'video/mp4' });
|
|
377
|
+
return [4 /*yield*/, expect(sdk.processVideo(videoFile, '')).rejects.toThrowError('Phrase is required.')];
|
|
378
|
+
case 1:
|
|
379
|
+
_a.sent();
|
|
380
|
+
return [2 /*return*/];
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
}); });
|
|
384
|
+
it('should successfully process video and return the response', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
385
|
+
var mockResponse, videoFile, phrase, formDataSpy, result;
|
|
386
|
+
return __generator(this, function (_a) {
|
|
387
|
+
switch (_a.label) {
|
|
388
|
+
case 0:
|
|
389
|
+
mockResponse = {
|
|
390
|
+
data: {
|
|
391
|
+
'Active Speaker Detection': {
|
|
392
|
+
code: 0,
|
|
393
|
+
description: 'Successful check',
|
|
394
|
+
result: 90.00,
|
|
395
|
+
},
|
|
396
|
+
'Face Liveness Detection': {
|
|
397
|
+
code: 0,
|
|
398
|
+
description: 'Successful check',
|
|
399
|
+
result: true,
|
|
400
|
+
},
|
|
401
|
+
'Face Recognition': {
|
|
402
|
+
code: 0,
|
|
403
|
+
description: 'Successful check',
|
|
404
|
+
},
|
|
405
|
+
'Visual Speech Recognition': {
|
|
406
|
+
code: 0,
|
|
407
|
+
description: 'Successful check',
|
|
408
|
+
result: 'ONE TWO THREE FOUR FIVE SIX SEVEN EIGHT',
|
|
409
|
+
},
|
|
410
|
+
'Voice Recognition': {
|
|
411
|
+
status: 'good',
|
|
412
|
+
id: '123',
|
|
413
|
+
score: 0.99,
|
|
414
|
+
imposter_prob: 0.01,
|
|
415
|
+
log_odds: '1.0',
|
|
416
|
+
},
|
|
417
|
+
},
|
|
418
|
+
result_conditions: {
|
|
419
|
+
failed_conditions: [],
|
|
420
|
+
failed_refer_conditions: [],
|
|
421
|
+
status: 'pass',
|
|
422
|
+
},
|
|
423
|
+
message: 'video processed successfully',
|
|
424
|
+
};
|
|
425
|
+
fetch.mockResolvedValueOnce({
|
|
426
|
+
ok: true,
|
|
427
|
+
json: function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
428
|
+
return [2 /*return*/, mockResponse];
|
|
429
|
+
}); }); },
|
|
430
|
+
});
|
|
431
|
+
videoFile = new File(['video data'], 'video.mp4', { type: 'video/mp4' });
|
|
432
|
+
phrase = 'ONE TWO THREE FOUR FIVE SIX SEVEN EIGHT';
|
|
433
|
+
formDataSpy = jest.spyOn(FormData.prototype, 'append');
|
|
434
|
+
return [4 /*yield*/, sdk.processVideo(videoFile, phrase)];
|
|
435
|
+
case 1:
|
|
436
|
+
result = _a.sent();
|
|
437
|
+
expect(formDataSpy).toHaveBeenCalledWith('video', videoFile);
|
|
438
|
+
expect(formDataSpy).toHaveBeenCalledWith('phrase', phrase);
|
|
439
|
+
expect(fetch).toHaveBeenCalledWith('https://api.biometrysolutions.com/api-gateway/process-video', expect.objectContaining({
|
|
440
|
+
method: 'POST',
|
|
441
|
+
headers: {
|
|
442
|
+
'Authorization': "Bearer ".concat(apiKey),
|
|
443
|
+
},
|
|
444
|
+
body: expect.any(FormData)
|
|
445
|
+
}));
|
|
446
|
+
expect(result).toEqual(mockResponse);
|
|
447
|
+
return [2 /*return*/];
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
}); });
|
|
451
|
+
});
|
package/dist/types.js
ADDED
package/package.json
CHANGED
|
@@ -1,42 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "biometry-sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
|
-
"module": "dist/index.m.js",
|
|
6
|
-
"unpkg": "dist/index.umd.js",
|
|
7
5
|
"types": "dist/index.d.ts",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist/**/*",
|
|
8
|
+
"README.md"
|
|
9
|
+
],
|
|
8
10
|
"scripts": {
|
|
9
|
-
"build": "tsc"
|
|
10
|
-
"test": "jest"
|
|
11
|
+
"build": "tsc"
|
|
11
12
|
},
|
|
12
|
-
"keywords": [],
|
|
13
|
-
"author": "",
|
|
14
|
-
"license": "ISC",
|
|
15
|
-
"description": "",
|
|
16
13
|
"devDependencies": {
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
"ts-jest": "^29.2.5",
|
|
20
|
-
"typescript": "^5.7.2"
|
|
21
|
-
},
|
|
22
|
-
"compilerOptions": {
|
|
23
|
-
"target": "ES2017",
|
|
24
|
-
"module": "CommonJS",
|
|
25
|
-
"outDir": "./dist",
|
|
26
|
-
"strict": true,
|
|
27
|
-
"declaration": true
|
|
28
|
-
},
|
|
29
|
-
"include": [
|
|
30
|
-
"src/**/*"
|
|
31
|
-
],
|
|
32
|
-
"exports": {
|
|
33
|
-
".": {
|
|
34
|
-
"import": "./dist/index.js",
|
|
35
|
-
"require": "./dist/index.js"
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
"files": [
|
|
39
|
-
"dist",
|
|
40
|
-
"README.md"
|
|
41
|
-
]
|
|
14
|
+
"typescript": "^5.0.0"
|
|
15
|
+
}
|
|
42
16
|
}
|