@incodetech/core 0.0.0-dev-20260407-4677d7f → 0.0.0-dev-20260407-ebd92aa

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 (58) hide show
  1. package/dist/OpenViduRecordingProvider-PvkEhhDq.esm.js +87 -0
  2. package/dist/antifraud.d.ts +1 -1
  3. package/dist/authentication.d.ts +11 -11
  4. package/dist/authentication.esm.js +3 -3
  5. package/dist/{authenticationManager-CiXsOTdM.d.ts → authenticationManager-CXTPgE_2.d.ts} +2 -2
  6. package/dist/{authenticationManager-CW4qxgcq.esm.js → authenticationManager-D4esVx-z.esm.js} +2 -2
  7. package/dist/camera.d.ts +1 -1
  8. package/dist/consent.d.ts +49 -49
  9. package/dist/curp-validation.d.ts +5 -5
  10. package/dist/{deepsightService-CMAtxAC9.d.ts → deepsightService-CyEcAH-I.d.ts} +2 -2
  11. package/dist/document-capture.d.ts +70 -70
  12. package/dist/document-upload.d.ts +4 -4
  13. package/dist/ekyb.d.ts +3 -3
  14. package/dist/ekyc.d.ts +3 -3
  15. package/dist/email.d.ts +3 -3
  16. package/dist/{emailManager-DEIxY7l6.d.ts → emailManager-CtA6Tvry.d.ts} +2 -2
  17. package/dist/extensibility.d.ts +15 -15
  18. package/dist/extensibility.esm.js +5 -5
  19. package/dist/face-match.d.ts +1 -1
  20. package/dist/{faceCaptureManagerFactory-CWj-nXdx.d.ts → faceCaptureManagerFactory-Bp_mC9b2.d.ts} +8 -8
  21. package/dist/faceCaptureSetup-DzlTPjT9.esm.js +828 -0
  22. package/dist/flow.d.ts +17 -10
  23. package/dist/flow.esm.js +60 -13
  24. package/dist/geolocation.d.ts +2 -2
  25. package/dist/government-validation.d.ts +2 -2
  26. package/dist/id.d.ts +11 -11
  27. package/dist/id.esm.js +3 -3
  28. package/dist/{idCaptureManager-H-rkXnbK.d.ts → idCaptureManager-Bx298yFC.d.ts} +9 -8
  29. package/dist/{idCaptureManager-SHBRQ-X_.esm.js → idCaptureManager-bowLKHEs.esm.js} +61 -48
  30. package/dist/index.d.ts +2 -2
  31. package/dist/mandatory-consent.d.ts +52 -52
  32. package/dist/openviduLazy-BdsxPGgp.esm.js +12 -0
  33. package/dist/openviduLazy-NTgGtkeK.esm.js +3 -0
  34. package/dist/phone.d.ts +3 -3
  35. package/dist/{phoneManager-Clfbrs6b.d.ts → phoneManager-DlaiZtwZ.d.ts} +2 -2
  36. package/dist/recordingService-BDx_6XR9.esm.js +1024 -0
  37. package/dist/redirect-to-mobile.d.ts +2 -2
  38. package/dist/selfie.d.ts +11 -11
  39. package/dist/selfie.esm.js +3 -3
  40. package/dist/{selfieManager-DeGqD5aN.esm.js → selfieManager-DVvvlMMf.esm.js} +2 -2
  41. package/dist/{selfieManager-h_hhEefT.d.ts → selfieManager-UBgYgVnw.d.ts} +2 -2
  42. package/dist/session.d.ts +1 -1
  43. package/dist/{setup-DJ3dFl5k.d.ts → setup-DfinQjIF.d.ts} +1 -1
  44. package/dist/signature.d.ts +2 -2
  45. package/dist/{types-T0VjZW3T.d.ts → types-DcqFYowa.d.ts} +1 -1
  46. package/dist/{types-zH5PDmSe.d.ts → types-DufUK-_f.d.ts} +1 -1
  47. package/dist/wasm.d.ts +2 -2
  48. package/package.json +1 -1
  49. package/dist/faceCaptureSetup-DIE5cftl.esm.js +0 -1564
  50. package/dist/recordingsRepository-blYn-iKZ.esm.js +0 -352
  51. /package/dist/{Actor-C-jivmFF.d.ts → Actor-Cz_KnN47.d.ts} +0 -0
  52. /package/dist/{Manager-BqFybBV-.d.ts → Manager-N01KfnVA.d.ts} +0 -0
  53. /package/dist/{StateMachine-8d441d6x.d.ts → StateMachine-DU1S4Cik.d.ts} +0 -0
  54. /package/dist/{camera-CKsQVNlH.d.ts → camera-BcVDCZxW.d.ts} +0 -0
  55. /package/dist/{displayErrors-CjMXlBnu.d.ts → displayErrors-C0mf2glb.d.ts} +0 -0
  56. /package/dist/{flowCompletionService-BV6ThEJ1.d.ts → flowCompletionService-Dloh6J8n.d.ts} +0 -0
  57. /package/dist/{types-qhLxpptI.d.ts → types-UPqCMQKa.d.ts} +0 -0
  58. /package/dist/{warmup-CEOVQKby.d.ts → warmup-yzJJKXFi.d.ts} +0 -0
@@ -1,1564 +0,0 @@
1
- import { i as WasmPipelineType, r as mlWasmJSApi_default, t as BaseWasmProvider } from "./BaseWasmProvider-CQgeReKV.esm.js";
2
- import { r as getToken, t as api } from "./api-CyI8qTie.esm.js";
3
- import { _ as endpoints, o as createManagerInstrumentation } from "./events-BlVGS-8F.esm.js";
4
- import { i as fromPromise, n as assign, o as createManager, r as fromCallback, t as setup } from "./xstate.esm-BXrcOcSC.esm.js";
5
- import { a as StreamCanvasProcessingSession, i as uploadDeepsightVideo, l as StreamCanvasCapture, n as startRecording, o as OpenViduRecordingProvider, r as stopRecording$1, s as flagFaceManualReview, t as createRecordingSession } from "./recordingsRepository-blYn-iKZ.esm.js";
6
- import { n as IncodeCanvas } from "./deepsightService-C3gQ_9Ml.esm.js";
7
- import { i as stopCameraStream, r as requestCameraAccess } from "./camera-CsT06Zqy.esm.js";
8
- import { t as addDeviceStats } from "./stats-BZ1kFW4p.esm.js";
9
- import { n as requestPermission, t as checkPermission } from "./permissionServices-CDqkkway.esm.js";
10
- import { a as isIPhone14OrHigher, n as isDesktop, r as isIOS, t as isAndroid } from "./platform-Dcuv6w60.esm.js";
11
- import { n as getDesktopCameraStream, t as getBackCameraStream } from "./backCameraStream-CUo1USCT.esm.js";
12
- import { t as getDeviceClass } from "./getDeviceClass-BKd2FOAf.esm.js";
13
-
14
- //#region src/internal/faceCapture/faceCaptureManagerFactory.ts
15
- function getPermissionStatus(snapshot) {
16
- if (!snapshot.matches("permissions")) return;
17
- if (snapshot.matches({ permissions: "idle" })) return "idle";
18
- if (snapshot.matches({ permissions: "learnMore" })) return "learnMore";
19
- if (snapshot.matches({ permissions: "requesting" })) return "requesting";
20
- if (snapshot.matches({ permissions: "denied" })) return "denied";
21
- }
22
- function getCaptureStatus(snapshot) {
23
- if (snapshot.matches({ capture: "initializing" })) return "initializing";
24
- if (snapshot.matches({ capture: "detecting" })) return "detecting";
25
- if (snapshot.matches({ capture: "capturing" })) return "capturing";
26
- if (snapshot.matches({ capture: "capturingManual" })) return "capturing";
27
- if (snapshot.matches({ capture: "uploading" })) return "uploading";
28
- if (snapshot.matches({ capture: "uploadError" })) return "uploadError";
29
- if (snapshot.matches({ capture: "success" })) return "success";
30
- }
31
- function mapState(snapshot) {
32
- const { context } = snapshot;
33
- if (snapshot.matches("idle")) return { status: "idle" };
34
- if (snapshot.matches("loading")) return { status: "loading" };
35
- if (snapshot.matches("tutorial")) return { status: "tutorial" };
36
- if (snapshot.matches("closed")) return { status: "closed" };
37
- if (snapshot.matches("permissions")) {
38
- const permissionStatus = getPermissionStatus(snapshot);
39
- if (permissionStatus === void 0) return {
40
- status: "permissions",
41
- permissionStatus: "idle"
42
- };
43
- return {
44
- status: "permissions",
45
- permissionStatus
46
- };
47
- }
48
- if (snapshot.matches("capture")) return {
49
- status: "capture",
50
- captureStatus: getCaptureStatus(snapshot) ?? "initializing",
51
- stream: context.stream,
52
- detectionStatus: context.detectionStatus ?? "idle",
53
- debugFrame: context.debugFrame,
54
- attemptsRemaining: context.attemptsRemaining ?? 0,
55
- uploadError: context.uploadError,
56
- assistedOnboarding: context.config?.assistedOnboarding ?? false
57
- };
58
- if (snapshot.matches("processing")) return { status: "processing" };
59
- if (snapshot.matches("finished")) return {
60
- status: "finished",
61
- processResponse: context.processResponse
62
- };
63
- if (snapshot.matches("error")) {
64
- const errorValue = context.error;
65
- return {
66
- status: "error",
67
- error: typeof errorValue === "string" ? errorValue : errorValue ? errorValue.message : "Unknown error"
68
- };
69
- }
70
- return { status: "idle" };
71
- }
72
- function createApi({ actor, trackElementClicked, trackCaptureAttemptFinished }) {
73
- const snapshot = actor.getSnapshot();
74
- snapshot.context.dependencies.trackCaptureAttemptFinished = trackCaptureAttemptFinished;
75
- return {
76
- load() {
77
- actor.send({ type: "LOAD" });
78
- },
79
- nextStep() {
80
- trackElementClicked?.("nextStep");
81
- actor.send({ type: "NEXT_STEP" });
82
- },
83
- requestPermission() {
84
- trackElementClicked?.("requestPermission");
85
- actor.send({ type: "REQUEST_PERMISSION" });
86
- },
87
- goToLearnMore() {
88
- trackElementClicked?.("goToLearnMore");
89
- actor.send({ type: "GO_TO_LEARN_MORE" });
90
- },
91
- back() {
92
- trackElementClicked?.("back");
93
- actor.send({ type: "BACK" });
94
- },
95
- close() {
96
- trackElementClicked?.("close");
97
- actor.send({ type: "QUIT" });
98
- },
99
- reset() {
100
- actor.send({ type: "RESET" });
101
- },
102
- retryCapture() {
103
- trackElementClicked?.("retryCapture");
104
- actor.send({ type: "RETRY_CAPTURE" });
105
- },
106
- capture() {
107
- trackElementClicked?.("capture");
108
- actor.send({ type: "MANUAL_CAPTURE" });
109
- }
110
- };
111
- }
112
- function getFaceCaptureErrorPayload(snapshot) {
113
- const errorCode = snapshot.context.uploadError;
114
- if (typeof errorCode !== "string" || errorCode.length === 0) return;
115
- return { errorCode };
116
- }
117
- function createFaceCaptureManagerFromActor(actor, moduleName) {
118
- return createManager({
119
- actor,
120
- mapState,
121
- createApi,
122
- instrumentation: createManagerInstrumentation(moduleName, { getErrorPayload: getFaceCaptureErrorPayload })
123
- });
124
- }
125
-
126
- //#endregion
127
- //#region src/internal/faceCapture/types.ts
128
- const FACE_ERROR_CODES = {
129
- FACE_OCCLUDED: "FACE_OCCLUDED",
130
- LIVENESS: "LIVENESS_ERROR",
131
- BRIGHTNESS: "BRIGHTNESS_ERROR",
132
- LENSES: "LENSES_ERROR",
133
- MASK: "MASK_ERROR",
134
- CLOSED_EYES: "CLOSED_EYES_ERROR",
135
- HEAD_COVER: "HEAD_COVER_ERROR",
136
- SERVER: "SERVER_ERROR",
137
- FACE_NOT_FOUND: "FACE_NOT_FOUND",
138
- MULTIPLE_FACES: "MULTIPLE_FACES",
139
- TOO_BLURRY: "TOO_BLURRY_ERROR",
140
- TOO_DARK: "TOO_DARK_ERROR",
141
- USER_IS_NOT_RECOGNIZED: "USER_IS_NOT_RECOGNIZED",
142
- SPOOF_ATTEMPT_DETECTED: "SPOOF_ATTEMPT_DETECTED",
143
- FACE_TOO_DARK: "FACE_TOO_DARK",
144
- LENSES_DETECTED: "LENSES_DETECTED",
145
- FACE_MASK_DETECTED: "FACE_MASK_DETECTED",
146
- CLOSED_EYES_DETECTED: "CLOSED_EYES_DETECTED",
147
- HEAD_COVER_DETECTED: "HEAD_COVER_DETECTED",
148
- FACE_CROPPING_FAILED: "FACE_CROPPING_FAILED",
149
- FACE_TOO_SMALL: "FACE_TOO_SMALL",
150
- FACE_TOO_BLURRY: "FACE_TOO_BLURRY",
151
- BAD_PHOTO_QUALITY: "BAD_PHOTO_QUALITY",
152
- PROCESSING_ERROR: "PROCESSING_ERROR",
153
- BAD_REQUEST: "BAD_REQUEST",
154
- NONEXISTENT_CUSTOMER: "NONEXISTENT_CUSTOMER",
155
- HINT_NOT_PROVIDED: "HINT_NOT_PROVIDED",
156
- SELFIE_IMAGE_LOW_QUALITY: "SELFIE_IMAGE_LOW_QUALITY"
157
- };
158
-
159
- //#endregion
160
- //#region ../infra/src/providers/wasm/FaceDetectionProvider.ts
161
- var FaceDetectionProvider = class extends BaseWasmProvider {
162
- constructor() {
163
- super(WasmPipelineType.SelfieWithQualityMetrics);
164
- this.defaultThresholds = {
165
- frameMinX: 0,
166
- frameMinY: 0,
167
- frameMaxX: 1,
168
- frameMaxY: 1,
169
- brightnessThreshold: 50,
170
- blurrinessThreshold: 50,
171
- tiltRotationAngleThreshold: 15,
172
- minMagicCropSize: 200,
173
- headwearThreshold: .86,
174
- lensesThreshold: .95,
175
- closedEyesThreshold: .9,
176
- maskThreshold: .85,
177
- minFaceQualityScore: .63,
178
- faceOcclusionThreshold: .3
179
- };
180
- this.currentFrame = null;
181
- this.bestCanvas = null;
182
- this.bestFace = null;
183
- }
184
- async processFrame(image) {
185
- this.currentFrame = image;
186
- await this.processFrameWasm(image);
187
- }
188
- async initialize(config) {
189
- await this.initializeBase(config, "selfie");
190
- this.applyDefaults(config.autocaptureInterval ?? 0);
191
- }
192
- setCallbacks(callbacks) {
193
- this.ensureInitialized();
194
- const onBestShotWrapper = (face) => {
195
- this.bestFace = face;
196
- if (this.currentFrame) {
197
- const frameCanvas = IncodeCanvas.fromImageData(this.currentFrame);
198
- this.bestCanvas = frameCanvas.clone() ?? frameCanvas;
199
- }
200
- callbacks.onBestShot?.(face);
201
- };
202
- const onCaptureWrapper = () => {
203
- let frameCanvas = this.bestCanvas;
204
- if (!frameCanvas && this.currentFrame) frameCanvas = IncodeCanvas.fromImageData(this.currentFrame);
205
- if (!frameCanvas) return;
206
- const faceCoordinates = this.bestFace ? this.formatFaceCoordinates(this.bestFace) : this.createDefaultFaceCoordinates(frameCanvas);
207
- try {
208
- frameCanvas.updateBase64Image();
209
- frameCanvas.updateBlob();
210
- } catch {}
211
- callbacks.onCapture?.(frameCanvas, faceCoordinates);
212
- this.bestCanvas = null;
213
- this.bestFace = null;
214
- };
215
- mlWasmJSApi_default.setFaceDetectionCallbacks(this.getPipelineType(), callbacks.onFarAway ?? (() => {}), callbacks.onTooClose ?? (() => {}), callbacks.onTooManyFaces ?? (() => {}), callbacks.onNoFace ?? (() => {}), onCaptureWrapper, callbacks.onGetReady ?? (() => {}), callbacks.onGetReadyFinished ?? (() => {}), callbacks.onCenterFace ?? (() => {}), callbacks.onDark ?? (() => {}), callbacks.onBlur ?? (() => {}), callbacks.onFaceAngle ?? (() => {}), onBestShotWrapper, callbacks.onLenses ?? (() => {}), callbacks.onMask ?? (() => {}), callbacks.onEyesClosed ?? (() => {}), callbacks.onHeadWear ?? (() => {}), callbacks.onSwitchToManualCapture ?? (() => {}), callbacks.onFaceOccluded ?? (() => {}));
216
- }
217
- setPositionConstraints(constraints) {
218
- this.ensureInitialized();
219
- mlWasmJSApi_default.setFacePositionConstraints(this.getPipelineType(), constraints.minX, constraints.minY, constraints.maxX, constraints.maxY);
220
- }
221
- applyDefaults(autocaptureInterval = 0) {
222
- this.ensureInitialized();
223
- this.setThresholds({
224
- brightnessThreshold: this.defaultThresholds.brightnessThreshold,
225
- blurrinessThreshold: this.defaultThresholds.blurrinessThreshold,
226
- tiltRotationAngleThreshold: this.defaultThresholds.tiltRotationAngleThreshold,
227
- minMagicCropSize: this.defaultThresholds.minMagicCropSize,
228
- autocaptureInterval,
229
- minFaceQualityScore: this.defaultThresholds.minFaceQualityScore,
230
- faceOcclusionThreshold: this.defaultThresholds.faceOcclusionThreshold
231
- });
232
- this.setPositionConstraints({
233
- minX: this.defaultThresholds.frameMinX,
234
- minY: this.defaultThresholds.frameMinY,
235
- maxX: this.defaultThresholds.frameMaxX,
236
- maxY: this.defaultThresholds.frameMaxY
237
- });
238
- this.setAttributesThresholds({
239
- headwearThreshold: this.defaultThresholds.headwearThreshold,
240
- lensesThreshold: this.defaultThresholds.lensesThreshold,
241
- closedEyesThreshold: this.defaultThresholds.closedEyesThreshold,
242
- maskThreshold: this.defaultThresholds.maskThreshold
243
- });
244
- }
245
- setAutocaptureInterval(interval) {
246
- this.ensureInitialized();
247
- if (!this.currentThresholds) {
248
- this.applyDefaults(interval);
249
- return;
250
- }
251
- this.setThresholds({
252
- ...this.currentThresholds,
253
- autocaptureInterval: interval
254
- });
255
- }
256
- setThresholds(thresholds) {
257
- this.ensureInitialized();
258
- this.currentThresholds = { ...thresholds };
259
- mlWasmJSApi_default.setFaceDetectionThresholds(this.getPipelineType(), thresholds.brightnessThreshold, thresholds.blurrinessThreshold, thresholds.tiltRotationAngleThreshold, thresholds.minMagicCropSize, thresholds.autocaptureInterval, thresholds.minFaceQualityScore, thresholds.faceOcclusionThreshold);
260
- }
261
- setAttributesThresholds(thresholds) {
262
- this.ensureInitialized();
263
- mlWasmJSApi_default.setFaceAttributesThresholds(this.getPipelineType(), thresholds.headwearThreshold, thresholds.lensesThreshold, thresholds.closedEyesThreshold, thresholds.maskThreshold);
264
- }
265
- setChecksEnabled(config) {
266
- this.ensureInitialized();
267
- mlWasmJSApi_default.setFaceChecksEnabled(this.getPipelineType(), config.lenses, config.mask, config.closedEyes, config.headWear, config.occlusion);
268
- }
269
- setVideoSelfieMode(enabled) {
270
- this.ensureInitialized();
271
- mlWasmJSApi_default.setFaceDetectionMode(this.getPipelineType(), enabled);
272
- }
273
- reset() {
274
- super.reset();
275
- this.currentFrame = null;
276
- this.bestCanvas = null;
277
- this.bestFace = null;
278
- }
279
- createDefaultFaceCoordinates(canvas) {
280
- return {
281
- rightEyeX: 0,
282
- rightEyeY: 0,
283
- leftEyeX: 0,
284
- leftEyeY: 0,
285
- noseTipX: 0,
286
- noseTipY: 0,
287
- rightMouthX: 0,
288
- rightMouthY: 0,
289
- mouthX: 0,
290
- mouthY: 0,
291
- x: 0,
292
- y: 0,
293
- width: canvas.width() ?? 0,
294
- height: canvas.height() ?? 0
295
- };
296
- }
297
- formatFaceCoordinates(face) {
298
- return {
299
- rightEyeX: face.rightEye.x,
300
- rightEyeY: face.rightEye.y,
301
- leftEyeX: face.leftEye.x,
302
- leftEyeY: face.leftEye.y,
303
- noseTipX: face.noseTip.x,
304
- noseTipY: face.noseTip.y,
305
- rightMouthX: face.rightMouthCorner.x,
306
- rightMouthY: face.rightMouthCorner.y,
307
- mouthX: face.leftMouthCorner.x,
308
- mouthY: face.leftMouthCorner.y,
309
- x: face.rect.x,
310
- y: face.rect.y,
311
- width: face.rect.width,
312
- height: face.rect.height
313
- };
314
- }
315
- };
316
-
317
- //#endregion
318
- //#region src/modules/selfie/selfieUploadService.ts
319
- /**
320
- * Uploads a selfie image to the backend.
321
- */
322
- async function uploadSelfie({ encryptedBase64Image, faceCoordinates, signal, metadata, recordingId }) {
323
- try {
324
- const payload = {
325
- base64Image: encryptedBase64Image,
326
- faceCoordinates: faceCoordinates ?? void 0,
327
- encrypted: true,
328
- clientInfo: { deviceClass: getDeviceClass() },
329
- metadata: metadata ?? void 0
330
- };
331
- const query = { imageType: "selfie" };
332
- if (recordingId) query.recordingId = recordingId;
333
- const res = await api.post(endpoints.selfie, payload, {
334
- signal,
335
- query
336
- });
337
- if (!res.ok) throw new Error(`POST ${endpoints.selfie} failed: ${res.status} ${res.statusText}`);
338
- return res.data;
339
- } catch (error) {
340
- const errorCode = getFaceErrorCodeFromHttpError(error);
341
- if (errorCode) throw new Error(errorCode);
342
- throw new Error(FACE_ERROR_CODES.SERVER);
343
- }
344
- }
345
- const getFaceErrorCodeFromHttpError = (error) => {
346
- const err = error;
347
- if (err.ok !== false || typeof err.status !== "number") return;
348
- if (err.status !== 400) return FACE_ERROR_CODES.SERVER;
349
- if (typeof err.data?.status !== "number") return FACE_ERROR_CODES.BAD_REQUEST;
350
- return {
351
- 3004: FACE_ERROR_CODES.FACE_NOT_FOUND,
352
- 3005: FACE_ERROR_CODES.FACE_NOT_FOUND,
353
- 3006: FACE_ERROR_CODES.TOO_BLURRY,
354
- 3007: FACE_ERROR_CODES.TOO_DARK,
355
- 4010: FACE_ERROR_CODES.MULTIPLE_FACES,
356
- 4019: FACE_ERROR_CODES.FACE_NOT_FOUND,
357
- 4077: FACE_ERROR_CODES.BAD_PHOTO_QUALITY,
358
- 4078: FACE_ERROR_CODES.FACE_OCCLUDED
359
- }[err.data.status] ?? FACE_ERROR_CODES.BAD_REQUEST;
360
- };
361
- async function processFace(imageType = "selfie", signal) {
362
- return (await api.post(endpoints.processFace, {}, {
363
- query: { imageType },
364
- signal
365
- })).data;
366
- }
367
-
368
- //#endregion
369
- //#region src/internal/faceCapture/faceCaptureServices.ts
370
- function sendLabelInspectionEvent() {
371
- return addDeviceStats({ cameraLabelInspectionStatus: "FAIL" });
372
- }
373
- const MOBILE_SELFIE_CONSTRAINTS = {
374
- video: {
375
- facingMode: "user",
376
- height: { ideal: 480 },
377
- width: { ideal: 640 }
378
- },
379
- audio: false
380
- };
381
- const IPHONE14_SELFIE_CONSTRAINTS = {
382
- video: { height: { ideal: 1080 } },
383
- audio: false
384
- };
385
- function buildCameraConstraints(resolution) {
386
- if (resolution) return {
387
- video: {
388
- facingMode: "user",
389
- height: resolution.height ? { ideal: resolution.height } : void 0,
390
- width: resolution.width ? { ideal: resolution.width } : void 0
391
- },
392
- audio: false
393
- };
394
- if (isIPhone14OrHigher()) return IPHONE14_SELFIE_CONSTRAINTS;
395
- return MOBILE_SELFIE_CONSTRAINTS;
396
- }
397
- function stopStream(stream) {
398
- stopCameraStream(stream);
399
- }
400
- async function getFrontCameraStream(resolution) {
401
- if (resolution) return requestCameraAccess(buildCameraConstraints(resolution));
402
- if (isDesktop()) return getDesktopCameraStream({});
403
- return requestCameraAccess(buildCameraConstraints());
404
- }
405
- async function initializeCamera(params) {
406
- const { config } = params;
407
- const prcConstraints = buildCameraConstraints(config.cameraResolution);
408
- const provider = new FaceDetectionProvider();
409
- await provider.initialize({ autocaptureInterval: config.autoCaptureTimeout * 1e3 });
410
- provider.setChecksEnabled({
411
- lenses: config.validateLenses ?? false,
412
- mask: config.validateFaceMask ?? false,
413
- closedEyes: config.validateClosedEyes ?? false,
414
- headWear: config.validateHeadCover ?? false,
415
- occlusion: false
416
- });
417
- await params.deepsightService.performPrcCheck({ constraints: { video: prcConstraints.video } });
418
- return {
419
- stream: config.assistedOnboarding ? (await getBackCameraStream()).stream : await getFrontCameraStream(config.cameraResolution),
420
- provider
421
- };
422
- }
423
- /**
424
- * Encrypts the provided selfie image using WASM.
425
- */
426
- async function encryptSelfieImage({ canvas, dependencies }) {
427
- const base64Image = canvas.getBase64Image();
428
- if (!base64Image) throw new Error("Canvas image is empty or null");
429
- return (await dependencies.getWasmUtil()).encryptImage(base64Image);
430
- }
431
- function startDetection(params) {
432
- let lastStatus;
433
- let session;
434
- const { provider } = params;
435
- const setStatus = (status) => {
436
- if (session?.isDisposed() === true) return;
437
- if (lastStatus === status) return;
438
- lastStatus = status;
439
- params.onUpdate(status);
440
- };
441
- const stopDetectionLoop = () => {
442
- session?.dispose();
443
- };
444
- const reset = () => {
445
- provider.reset();
446
- };
447
- const cleanup = () => {
448
- stopDetectionLoop();
449
- };
450
- (async () => {
451
- try {
452
- provider.setCallbacks({
453
- onFarAway: () => setStatus("tooFar"),
454
- onTooClose: () => setStatus("tooClose"),
455
- onTooManyFaces: () => setStatus("tooManyFaces"),
456
- onNoFace: () => setStatus("idle"),
457
- onCenterFace: () => setStatus("centerFace"),
458
- onGetReady: () => setStatus("getReady"),
459
- onGetReadyFinished: () => setStatus("getReadyFinished"),
460
- onDark: () => {
461
- if (params.config.validateBrightness) setStatus("dark");
462
- },
463
- onBlur: () => setStatus("blur"),
464
- onFaceAngle: () => setStatus("faceAngle"),
465
- onLenses: () => {
466
- if (params.config.validateLenses) setStatus("lenses");
467
- },
468
- onMask: () => {
469
- if (params.config.validateFaceMask) setStatus("faceMask");
470
- },
471
- onEyesClosed: () => {
472
- if (params.config.validateClosedEyes) setStatus("eyesClosed");
473
- },
474
- onHeadWear: () => {
475
- if (params.config.validateHeadCover) setStatus("headWear");
476
- },
477
- onFaceOccluded: () => {},
478
- onSwitchToManualCapture: () => {
479
- setStatus("manualCapture");
480
- stopDetectionLoop();
481
- },
482
- onCapture: (canvas, faceCoordinates) => {
483
- setStatus("success");
484
- params.onSuccess(canvas, faceCoordinates);
485
- cleanup();
486
- }
487
- });
488
- setStatus("detecting");
489
- session = new StreamCanvasProcessingSession({
490
- capturer: params.capturer,
491
- provider,
492
- onFrame: params.onFrame
493
- });
494
- } catch {
495
- setStatus("error");
496
- cleanup();
497
- }
498
- })();
499
- return {
500
- cleanup,
501
- reset
502
- };
503
- }
504
- function buildResolutionFromStream(stream) {
505
- const track = stream.getVideoTracks()[0];
506
- if (!track) return;
507
- const settings = track.getSettings();
508
- const width = settings.width;
509
- const height = settings.height;
510
- if (typeof width === "number" && typeof height === "number") return `${width}x${height}`;
511
- }
512
- async function startRecordingSession(params) {
513
- if (params.config.deepsightLiveness === "VIDEOLIVENESS") return;
514
- if (params.config.enableFaceRecording !== true) return;
515
- if (params.existing) return params.existing;
516
- const provider = params.config.recording?.capability ?? new OpenViduRecordingProvider();
517
- const clonedStream = params.clonedStream;
518
- const hasAudio = clonedStream.getAudioTracks().length > 0;
519
- const resolution = buildResolutionFromStream(clonedStream);
520
- const session = await createRecordingSession("selfie");
521
- const connection = await provider.connect({
522
- sessionToken: session.token,
523
- stream: clonedStream,
524
- events: {}
525
- });
526
- await startRecording({
527
- videoRecordingId: session.videoRecordingId,
528
- type: "selfie",
529
- resolution,
530
- hasAudio
531
- });
532
- return {
533
- token: session.token,
534
- sessionId: session.sessionId,
535
- videoRecordingId: session.videoRecordingId,
536
- connection,
537
- resolution,
538
- hasAudio
539
- };
540
- }
541
- async function stopRecording(session) {
542
- try {
543
- await stopRecording$1(session.videoRecordingId);
544
- } finally {
545
- await session.connection.disconnect();
546
- }
547
- }
548
- async function initializeDeepsightSession(options) {
549
- const { loadDeepsightSession } = await import("./deepsightLoader-Bs5jHgca.esm.js");
550
- return loadDeepsightSession({
551
- ds: options.ds,
552
- storage: options.storage
553
- });
554
- }
555
-
556
- //#endregion
557
- //#region ../infra/src/media/VideoTrimmer.ts
558
- async function getDurationBySeek(videoBlob) {
559
- const video = document.createElement("video");
560
- video.preload = "metadata";
561
- video.src = URL.createObjectURL(videoBlob);
562
- try {
563
- if (!Number.isFinite(video.duration)) {
564
- video.currentTime = Number.MAX_SAFE_INTEGER;
565
- await new Promise((resolve) => {
566
- const onDurationChange = () => {
567
- if (Number.isFinite(video.duration)) {
568
- video.removeEventListener("durationchange", onDurationChange);
569
- video.removeEventListener("timeupdate", onTimeUpdate);
570
- resolve(video.duration);
571
- }
572
- };
573
- const onTimeUpdate = () => {
574
- if (Number.isFinite(video.duration)) {
575
- video.removeEventListener("timeupdate", onTimeUpdate);
576
- video.removeEventListener("durationchange", onDurationChange);
577
- resolve(video.duration);
578
- }
579
- };
580
- video.addEventListener("durationchange", onDurationChange);
581
- video.addEventListener("timeupdate", onTimeUpdate);
582
- });
583
- }
584
- const duration = video.duration;
585
- return Number.isFinite(duration) ? duration : null;
586
- } finally {
587
- URL.revokeObjectURL(video.src);
588
- video.src = "";
589
- }
590
- }
591
- async function trimLastNSecondsUsingPlayback(videoBlob, seconds) {
592
- const video = document.createElement("video");
593
- video.preload = "metadata";
594
- video.playsInline = true;
595
- video.muted = true;
596
- const videoURL = URL.createObjectURL(videoBlob);
597
- video.src = videoURL;
598
- const duration = await getDurationBySeek(videoBlob);
599
- if (!duration || duration < seconds) {
600
- URL.revokeObjectURL(videoURL);
601
- return videoBlob;
602
- }
603
- const startTime = Math.max(0, Math.floor(duration) - seconds);
604
- await new Promise((resolve) => {
605
- if (video.readyState >= 2) resolve();
606
- else video.addEventListener("loadedmetadata", () => resolve(), { once: true });
607
- });
608
- const canvas = document.createElement("canvas");
609
- canvas.width = 230;
610
- canvas.height = 320;
611
- const captureFps = isAndroid() ? 15 : 24;
612
- const stream = canvas.captureStream(captureFps);
613
- const ctx = canvas.getContext("2d");
614
- video.currentTime = startTime;
615
- await new Promise((resolve) => {
616
- video.addEventListener("seeked", () => resolve(), { once: true });
617
- });
618
- ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
619
- const mimeType = videoBlob.type || (MediaRecorder.isTypeSupported("video/webm") ? "video/webm" : "video/mp4");
620
- const mediaRecorder = new MediaRecorder(stream.clone(), {
621
- mimeType,
622
- videoBitsPerSecond: 5e5,
623
- bitsPerSecond: 5e5
624
- });
625
- const chunks = [];
626
- mediaRecorder.ondataavailable = (event) => {
627
- if (event.data.size > 0) chunks.push(event.data);
628
- };
629
- const recordingPromise = new Promise((resolve) => {
630
- mediaRecorder.onstop = () => {
631
- const trimmedBlob$1 = new Blob(chunks, { type: mimeType });
632
- URL.revokeObjectURL(videoURL);
633
- mediaRecorder.stream?.getTracks().forEach((track) => track.stop());
634
- stream.getTracks().forEach((track) => track.stop());
635
- video.src = "";
636
- resolve(trimmedBlob$1);
637
- };
638
- });
639
- video.addEventListener("play", () => {
640
- function drawVideo() {
641
- if (video.currentTime >= duration) {
642
- mediaRecorder.stop();
643
- video.pause();
644
- return;
645
- }
646
- ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
647
- requestAnimationFrame(drawVideo);
648
- }
649
- drawVideo();
650
- setTimeout(() => {
651
- mediaRecorder.start(100);
652
- }, 500);
653
- });
654
- video.play().catch(() => {
655
- URL.revokeObjectURL(videoURL);
656
- });
657
- const trimmedBlob = await recordingPromise;
658
- console.timeEnd("trimLastNSecondsUsingPlayback");
659
- return trimmedBlob;
660
- }
661
- async function trimLastNSeconds(videoBlob, seconds) {
662
- return await trimLastNSecondsUsingPlayback(videoBlob, seconds);
663
- }
664
-
665
- //#endregion
666
- //#region ../infra/src/providers/browser/LocalRecordingProvider.ts
667
- function toBase64(videoBlob) {
668
- return new Promise((resolve, reject) => {
669
- const reader = new FileReader();
670
- reader.onloadend = () => {
671
- const base64 = reader.result.split(",")[1];
672
- resolve(base64);
673
- };
674
- reader.onerror = () => reject(reader.error ?? /* @__PURE__ */ new Error("FileReader error"));
675
- reader.readAsDataURL(videoBlob);
676
- });
677
- }
678
- function getSupportedMediaRecorderMimeType() {
679
- const possibleTypes = isIOS() ? [
680
- "video/mp4",
681
- "video/webm",
682
- "video/webm;codecs=vp9",
683
- "video/webm;codecs=vp8"
684
- ] : [
685
- "video/webm",
686
- "video/webm;codecs=vp9",
687
- "video/webm;codecs=vp8",
688
- "video/mp4"
689
- ];
690
- for (const type of possibleTypes) if (MediaRecorder.isTypeSupported(type)) return type;
691
- return "";
692
- }
693
- function getAdaptiveMediaRecorderOptions() {
694
- const mimeType = getSupportedMediaRecorderMimeType();
695
- if (isIOS()) return {
696
- mimeType,
697
- videoBitsPerSecond: 1e6,
698
- bitsPerSecond: 1e6
699
- };
700
- return {
701
- mimeType,
702
- videoBitsPerSecond: 5e5,
703
- bitsPerSecond: 5e5
704
- };
705
- }
706
- var LocalRecordingProvider = class {
707
- constructor() {
708
- this.mediaRecorder = null;
709
- this._isRecording = false;
710
- this._hasError = false;
711
- this._error = null;
712
- this.mimeType = "";
713
- this.stream = null;
714
- this.pauseRecordingBound = this.pauseRecording.bind(this);
715
- }
716
- get isRecording() {
717
- return this._isRecording;
718
- }
719
- get hasError() {
720
- return this._hasError;
721
- }
722
- get error() {
723
- return this._error;
724
- }
725
- startRecording(stream) {
726
- this.reset();
727
- this.registerEventListeners();
728
- this.stream = stream;
729
- try {
730
- const options = getAdaptiveMediaRecorderOptions();
731
- this.mimeType = options.mimeType;
732
- const recorder = new MediaRecorder(stream.clone(), options);
733
- recorder.onerror = (event) => {
734
- this._error = `Recording error: ${event}`;
735
- this._isRecording = false;
736
- this._hasError = true;
737
- };
738
- recorder.start();
739
- this.mediaRecorder = recorder;
740
- this._isRecording = true;
741
- this._error = null;
742
- this._hasError = false;
743
- } catch (err) {
744
- this._error = `Failed to start recording: ${err}`;
745
- this._hasError = true;
746
- }
747
- }
748
- async stopRecording(trimSeconds, encrypt, generateChecksum) {
749
- const recorder = this.mediaRecorder;
750
- return new Promise((resolve, reject) => {
751
- this.removeEventListeners();
752
- if (recorder && this._isRecording) {
753
- const chunks = [];
754
- recorder.ondataavailable = (event) => {
755
- if (event.data.size > 0) chunks.push(event.data);
756
- };
757
- recorder.onstop = async () => {
758
- try {
759
- const trimmedVideo = await trimLastNSeconds(new Blob(chunks, { type: this.mimeType }), trimSeconds);
760
- const encryptedVideoBase64 = encrypt(await toBase64(trimmedVideo));
761
- generateChecksum(await trimmedVideo.arrayBuffer());
762
- this._isRecording = false;
763
- resolve({
764
- trimmedBlob: trimmedVideo,
765
- encryptedVideo: encryptedVideoBase64
766
- });
767
- } catch (error) {
768
- this._isRecording = false;
769
- this._error = `Recording stop failed: ${error}`;
770
- this._hasError = true;
771
- reject(error);
772
- }
773
- };
774
- recorder.stop();
775
- this._isRecording = false;
776
- } else resolve({
777
- trimmedBlob: new Blob([], { type: this.mimeType }),
778
- encryptedVideo: ""
779
- });
780
- recorder?.stream?.getTracks().forEach((track) => track.stop());
781
- });
782
- }
783
- reset() {
784
- this._isRecording = false;
785
- this._error = null;
786
- this._hasError = false;
787
- }
788
- pauseRecording() {
789
- if (!this._isRecording) return;
790
- if (this.mediaRecorder?.state === "recording") try {
791
- this.mediaRecorder.pause();
792
- } catch {}
793
- }
794
- registerEventListeners() {
795
- document.addEventListener("visibilitychange", this.pauseRecordingBound);
796
- }
797
- removeEventListeners() {
798
- document.removeEventListener("visibilitychange", this.pauseRecordingBound);
799
- }
800
- };
801
-
802
- //#endregion
803
- //#region src/internal/faceCapture/recordingService.ts
804
- /**
805
- * Records on-device and uploads encrypted video for liveness.
806
- */
807
- var LocalRecordingService = class {
808
- constructor(wasmUtil, sessionToken) {
809
- this.recorder = new LocalRecordingProvider();
810
- this.sessionToken = sessionToken;
811
- this.wasmUtil = wasmUtil;
812
- }
813
- async start(stream) {
814
- this.recorder.startRecording(stream);
815
- }
816
- async stop() {
817
- if (!this.recorder.isRecording) return { recordingId: null };
818
- const result = await this.recorder.stopRecording(10, (base64) => this.wasmUtil.encryptImage(base64), (buffer) => this.wasmUtil.ckvcks(buffer));
819
- if (!this.sessionToken) return { recordingId: null };
820
- return { recordingId: await uploadDeepsightVideo(result.encryptedVideo, this.sessionToken) };
821
- }
822
- cleanup() {
823
- this.recorder.reset();
824
- }
825
- };
826
- /**
827
- * Records through OpenVidu and manages the session lifecycle.
828
- */
829
- var OpenViduRecordingService = class {
830
- constructor(config) {
831
- this.provider = new OpenViduRecordingProvider();
832
- this.config = config;
833
- }
834
- async start(stream) {
835
- this.session = await startRecordingSession({
836
- config: {
837
- ...this.config,
838
- recording: { capability: this.provider }
839
- },
840
- clonedStream: stream.clone(),
841
- existing: this.session
842
- });
843
- }
844
- async stop() {
845
- if (this.session) {
846
- stopRecording(this.session);
847
- this.session = void 0;
848
- }
849
- return { recordingId: null };
850
- }
851
- cleanup() {
852
- if (this.session) stopRecording(this.session);
853
- }
854
- };
855
- /**
856
- * Creates the recording service for the current configuration.
857
- */
858
- function createRecordingService(params) {
859
- if (params.config.deepsightLiveness === "VIDEOLIVENESS") return new LocalRecordingService(params.wasmUtil, params.sessionToken);
860
- if (params.config.enableFaceRecording === true) return new OpenViduRecordingService(params.config);
861
- }
862
-
863
- //#endregion
864
- //#region src/internal/faceCapture/faceCaptureSetup.ts
865
- const getAttemptsFromConfig = (config) => {
866
- return config.captureAttempts ?? config.numberOfAttempts ?? 3;
867
- };
868
- const _faceCaptureMachine = setup({
869
- types: {
870
- context: {},
871
- events: {},
872
- input: {}
873
- },
874
- actors: {
875
- checkPermission: fromPromise(async () => {
876
- return checkPermission();
877
- }),
878
- requestPermission: fromPromise(async () => {
879
- return requestPermission();
880
- }),
881
- initializeCamera: fromPromise(async ({ input }) => {
882
- return initializeCamera({
883
- config: input.config,
884
- deepsightService: input.deepsightService
885
- });
886
- }),
887
- runDetection: fromCallback(({ input, sendBack }) => {
888
- if (!input.frameCapturer || !input.provider) {
889
- sendBack({
890
- type: "DETECTION_UPDATE",
891
- status: "error"
892
- });
893
- return () => {};
894
- }
895
- if (input.manualCaptureTriggered) {
896
- sendBack({
897
- type: "DETECTION_UPDATE",
898
- status: "manualCapture"
899
- });
900
- return () => {};
901
- }
902
- const { cleanup, reset } = startDetection({
903
- config: input.config,
904
- capturer: input.frameCapturer,
905
- onUpdate: (status) => sendBack({
906
- type: "DETECTION_UPDATE",
907
- status
908
- }),
909
- onFrame: (frame) => sendBack({
910
- type: "DETECTION_FRAME",
911
- frame
912
- }),
913
- onSuccess: (canvas, faceCoordinates) => sendBack({
914
- type: "DETECTION_SUCCESS",
915
- canvas,
916
- faceCoordinates
917
- }),
918
- provider: input.provider
919
- });
920
- sendBack({
921
- type: "DETECTION_RESET_READY",
922
- reset
923
- });
924
- return cleanup;
925
- }),
926
- initializeDeepsightSession: fromPromise(async ({ input }) => {
927
- return await initializeDeepsightSession({
928
- ds: input.ds,
929
- storage: input.storage
930
- });
931
- }),
932
- startRecording: fromPromise(async ({ input }) => {
933
- if (!input.stream) return input.recordingService;
934
- const wasmUtil = await input.dependencies.getWasmUtil();
935
- const sessionToken = getToken();
936
- const service = input.recordingService ?? createRecordingService({
937
- config: input.config,
938
- wasmUtil,
939
- sessionToken
940
- });
941
- if (service) await service.start(input.stream);
942
- return service;
943
- }),
944
- checkVirtualCamera: fromPromise(async ({ input }) => {
945
- if (!input.deepsightService || !input.stream) return false;
946
- const videoTrack = input.stream.getVideoTracks()[0];
947
- if (!videoTrack) return false;
948
- return input.deepsightService.checkVirtualCamera(videoTrack);
949
- }),
950
- prepareFaceUpload: fromPromise(async ({ input }) => {
951
- const ctx = input;
952
- const sessionToken = getToken();
953
- const recordingId = (await ctx.recordingService?.stop())?.recordingId ?? null;
954
- try {
955
- if (ctx.deepsightService) await Promise.all([ctx.deepsightService.performVirtualCameraCheck(sessionToken, "SELFIE"), ctx.deepsightService.analyzeFrame(ctx.capturedImage.getImageData())]);
956
- } catch (error) {}
957
- const logs = ctx.deepsightService?.getPipelineState() ?? "";
958
- ctx.dependencies.trackCaptureAttemptFinished?.({ logs });
959
- return {
960
- encryptedBase64Image: await encryptSelfieImage({
961
- canvas: ctx.capturedImage,
962
- dependencies: ctx.dependencies
963
- }),
964
- recordingId
965
- };
966
- }),
967
- uploadFace: fromPromise(async () => {
968
- throw new Error("uploadFace must be provided by variant");
969
- }),
970
- processFace: fromPromise(async () => {
971
- throw new Error("processFace must be provided by variant");
972
- })
973
- },
974
- actions: {
975
- stopMediaStream: assign(({ context }) => {
976
- context.frameCapturer?.dispose();
977
- if (context.stream) stopStream(context.stream);
978
- context.provider?.dispose();
979
- return {
980
- stream: void 0,
981
- provider: void 0,
982
- frameCapturer: void 0
983
- };
984
- }),
985
- setStreamAndCapturer: assign({
986
- stream: ({ event }) => {
987
- if ("output" in event) return event.output.stream;
988
- },
989
- provider: ({ event }) => {
990
- if ("output" in event) return event.output.provider;
991
- },
992
- frameCapturer: ({ event }) => {
993
- if ("output" in event) return new StreamCanvasCapture(event.output.stream);
994
- }
995
- }),
996
- trackTutorial: () => void 0,
997
- trackContinue: () => {},
998
- resetContext: assign(({ context }) => ({
999
- stream: void 0,
1000
- provider: void 0,
1001
- frameCapturer: void 0,
1002
- error: void 0,
1003
- detectionStatus: "idle",
1004
- debugFrame: void 0,
1005
- capturedImage: void 0,
1006
- faceCoordinates: void 0,
1007
- uploadResponse: void 0,
1008
- processResponse: void 0,
1009
- recordingService: void 0,
1010
- attemptsRemaining: getAttemptsFromConfig(context.config),
1011
- uploadError: void 0,
1012
- permissionResult: void 0,
1013
- resetDetection: void 0,
1014
- deepsightService: void 0,
1015
- manualCaptureTriggered: false
1016
- })),
1017
- resetDetection: ({ context }) => {
1018
- context.resetDetection?.();
1019
- },
1020
- captureImage: assign({ capturedImage: ({ context }) => {
1021
- if (context.capturedImage) return context.capturedImage;
1022
- return context.frameCapturer?.getLatestCanvas() ?? void 0;
1023
- } }),
1024
- captureLatestFrame: assign({ capturedImage: ({ context }) => {
1025
- return context.frameCapturer?.getLatestCanvas() ?? void 0;
1026
- } }),
1027
- clearUploadFailure: assign({
1028
- uploadError: () => void 0,
1029
- detectionStatus: () => "idle",
1030
- capturedImage: () => void 0
1031
- }),
1032
- clearStreamForRetry: assign(({ context }) => {
1033
- context.frameCapturer?.dispose();
1034
- if (context.stream) stopStream(context.stream);
1035
- context.provider?.dispose();
1036
- return {
1037
- stream: void 0,
1038
- provider: void 0,
1039
- frameCapturer: void 0
1040
- };
1041
- }),
1042
- decrementAttemptsRemaining: assign(({ context }) => ({ attemptsRemaining: context.attemptsRemaining - 1 })),
1043
- setUploadErrorFromUploadValidation: assign({ uploadError: () => FACE_ERROR_CODES.SERVER }),
1044
- setTerminalError: assign({ error: () => "Authentication failed" }),
1045
- clearRecordingService: assign({ recordingService: () => void 0 }),
1046
- cleanup: ({ context }) => {
1047
- context.deepsightService?.cleanup();
1048
- context.recordingService?.cleanup();
1049
- },
1050
- setPermissionResultFromEvent: assign({ permissionResult: ({ event }) => event.output }),
1051
- setPermissionDenied: assign({ permissionResult: () => "denied" }),
1052
- setPermissionRefresh: assign({ permissionResult: () => "refresh" }),
1053
- setDeepsightServiceFromEvent: assign({ deepsightService: ({ event }) => event.output }),
1054
- setErrorFromEvent: assign({ error: ({ event }) => String(event.error) }),
1055
- setDetectionStatusDetecting: assign({ detectionStatus: ({ context }) => context.manualCaptureTriggered ? "manualCapture" : "detecting" }),
1056
- setRecordingServiceFromEvent: assign({ recordingService: ({ context, event }) => {
1057
- return event.output ?? context.recordingService;
1058
- } }),
1059
- setDetectionStatusFromEvent: assign({ detectionStatus: ({ event }) => event.status }),
1060
- setManualCaptureTriggered: assign({ manualCaptureTriggered: ({ context, event }) => {
1061
- const status = event.status;
1062
- return context.manualCaptureTriggered || status === "manualCapture";
1063
- } }),
1064
- setDebugFrameFromEvent: assign({ debugFrame: ({ event }) => event.frame }),
1065
- setResetDetectionFromEvent: assign({ resetDetection: ({ event }) => event.reset }),
1066
- setCapturedImageFromEvent: assign({
1067
- capturedImage: ({ event }) => event.canvas,
1068
- faceCoordinates: ({ event }) => event.faceCoordinates
1069
- }),
1070
- setUploadPreparationFromEvent: assign({
1071
- encryptedBase64Image: ({ event }) => event.output.encryptedBase64Image,
1072
- uploadRecordingId: ({ event }) => event.output.recordingId
1073
- }),
1074
- setUploadResponseFromEvent: assign({ uploadResponse: ({ event }) => event.output }),
1075
- setProcessResponseFromEvent: assign({ processResponse: ({ event }) => event.output }),
1076
- setServerErrorAndDecrement: assign(({ context }) => ({
1077
- uploadError: FACE_ERROR_CODES.SERVER,
1078
- attemptsRemaining: context.attemptsRemaining - 1
1079
- })),
1080
- sendLabelInspection: () => {
1081
- sendLabelInspectionEvent();
1082
- },
1083
- flagFaceManualReview: () => {
1084
- flagFaceManualReview();
1085
- },
1086
- noOp: () => void 0
1087
- },
1088
- guards: {
1089
- hasShowTutorial: ({ context }) => context.config.showTutorial,
1090
- isPermissionGranted: ({ event }) => {
1091
- if ("output" in event) return event.output === "granted";
1092
- return false;
1093
- },
1094
- isPermissionDeniedError: ({ event }) => {
1095
- if ("error" in event) {
1096
- const error = event.error;
1097
- return error?.name === "NotAllowedError" || error?.name === "PermissionDeniedError";
1098
- }
1099
- return false;
1100
- },
1101
- hasStream: ({ context }) => context.stream !== void 0,
1102
- isCameraAndDeepsightReady: ({ context }) => context.stream !== void 0 && context.deepsightService !== void 0,
1103
- hasAttemptsRemaining: ({ context }) => context.attemptsRemaining > 0,
1104
- hasCapturedImage: ({ context }) => context.capturedImage !== void 0,
1105
- hasUploadValidationError: () => false,
1106
- isTerminalUploadError: () => false,
1107
- isNoAttemptsTerminal: () => false
1108
- }
1109
- }).createMachine({
1110
- id: "faceCapture",
1111
- initial: "idle",
1112
- context: ({ input }) => ({
1113
- config: input.config,
1114
- dependencies: input.dependencies,
1115
- authHint: input.authHint,
1116
- stream: void 0,
1117
- provider: void 0,
1118
- frameCapturer: void 0,
1119
- error: void 0,
1120
- detectionStatus: "idle",
1121
- debugFrame: void 0,
1122
- capturedImage: void 0,
1123
- faceCoordinates: void 0,
1124
- uploadResponse: void 0,
1125
- processResponse: void 0,
1126
- recordingService: void 0,
1127
- attemptsRemaining: getAttemptsFromConfig(input.config),
1128
- uploadError: void 0,
1129
- permissionResult: void 0,
1130
- resetDetection: void 0,
1131
- deepsightService: void 0,
1132
- encryptedBase64Image: void 0,
1133
- uploadRecordingId: void 0,
1134
- manualCaptureTriggered: false
1135
- }),
1136
- on: { QUIT: { target: "#faceCapture.closed" } },
1137
- states: {
1138
- idle: { on: { LOAD: [{
1139
- target: "tutorial",
1140
- guard: "hasShowTutorial"
1141
- }, { target: "loading" }] } },
1142
- loading: { invoke: [{
1143
- id: "checkPermissionLoading",
1144
- src: "checkPermission",
1145
- onDone: [{
1146
- target: "capture",
1147
- guard: "isPermissionGranted",
1148
- actions: "setPermissionResultFromEvent"
1149
- }, {
1150
- target: "permissions",
1151
- actions: "setPermissionResultFromEvent"
1152
- }]
1153
- }, {
1154
- id: "loadingInitDeepsight",
1155
- src: "initializeDeepsightSession",
1156
- input: ({ context }) => ({
1157
- ds: context.config.ds,
1158
- storage: context.dependencies.storage
1159
- }),
1160
- onDone: { actions: "setDeepsightServiceFromEvent" },
1161
- onError: { actions: "noOp" }
1162
- }] },
1163
- tutorial: {
1164
- initial: "checkingPermission",
1165
- entry: "trackTutorial",
1166
- states: {
1167
- checkingPermission: { invoke: {
1168
- id: "checkPermissionTutorial",
1169
- src: "checkPermission",
1170
- onDone: [{
1171
- target: "initializingCamera",
1172
- guard: "isPermissionGranted",
1173
- actions: "setPermissionResultFromEvent"
1174
- }, {
1175
- target: "ready",
1176
- actions: "setPermissionResultFromEvent"
1177
- }]
1178
- } },
1179
- initializingCamera: {
1180
- type: "parallel",
1181
- states: {
1182
- cameraInit: {
1183
- initial: "initializingDeepsight",
1184
- states: {
1185
- initializingDeepsight: { invoke: {
1186
- id: "tutorialInitDeepsight",
1187
- src: "initializeDeepsightSession",
1188
- input: ({ context }) => ({
1189
- ds: context.config.ds,
1190
- storage: context.dependencies.storage
1191
- }),
1192
- onDone: {
1193
- target: "initializingStream",
1194
- actions: "setDeepsightServiceFromEvent"
1195
- },
1196
- onError: { target: "#faceCapture.tutorial.ready" }
1197
- } },
1198
- initializingStream: { invoke: {
1199
- id: "tutorialInitCamera",
1200
- src: "initializeCamera",
1201
- input: ({ context }) => ({
1202
- config: context.config,
1203
- dependencies: context.dependencies,
1204
- deepsightService: context.deepsightService
1205
- }),
1206
- onDone: {
1207
- target: "ready",
1208
- actions: "setStreamAndCapturer"
1209
- },
1210
- onError: [{
1211
- target: "#faceCapture.tutorial.ready",
1212
- guard: "isPermissionDeniedError",
1213
- actions: "setPermissionDenied"
1214
- }, {
1215
- target: "#faceCapture.tutorial.ready",
1216
- actions: "setErrorFromEvent"
1217
- }]
1218
- } },
1219
- ready: { type: "final" }
1220
- }
1221
- },
1222
- userIntent: {
1223
- initial: "waiting",
1224
- states: {
1225
- waiting: { on: { NEXT_STEP: {
1226
- target: "clicked",
1227
- actions: "trackContinue"
1228
- } } },
1229
- clicked: { type: "final" }
1230
- }
1231
- }
1232
- },
1233
- onDone: { target: "#faceCapture.capture" }
1234
- },
1235
- ready: {
1236
- initial: "idle",
1237
- states: {
1238
- idle: { always: [{
1239
- target: "initializingDeepsight",
1240
- guard: ({ context }) => context.deepsightService === void 0
1241
- }, { target: "readyForNext" }] },
1242
- initializingDeepsight: { invoke: {
1243
- id: "initializeDeepsightTutorial",
1244
- src: "initializeDeepsightSession",
1245
- input: ({ context }) => ({
1246
- ds: context.config.ds,
1247
- storage: context.dependencies.storage
1248
- }),
1249
- onDone: {
1250
- target: "readyForNext",
1251
- actions: "setDeepsightServiceFromEvent"
1252
- },
1253
- onError: { target: "readyForNext" }
1254
- } },
1255
- readyForNext: { on: { NEXT_STEP: {
1256
- target: "#faceCapture.tutorial.waitingForPermission",
1257
- actions: "trackContinue"
1258
- } } }
1259
- }
1260
- },
1261
- waitingForPermission: { invoke: {
1262
- id: "checkPermissionWaiting",
1263
- src: "checkPermission",
1264
- onDone: [{
1265
- target: "#faceCapture.capture",
1266
- guard: "isPermissionGranted",
1267
- actions: "setPermissionResultFromEvent"
1268
- }, {
1269
- target: "#faceCapture.permissions",
1270
- actions: "setPermissionResultFromEvent"
1271
- }]
1272
- } }
1273
- }
1274
- },
1275
- permissions: {
1276
- initial: "checkingDeepsight",
1277
- states: {
1278
- checkingDeepsight: { always: [{
1279
- target: "initializingDeepsight",
1280
- guard: ({ context }) => context.deepsightService === void 0
1281
- }, { target: "idle" }] },
1282
- initializingDeepsight: { invoke: {
1283
- id: "initializeDeepsightPerms",
1284
- src: "initializeDeepsightSession",
1285
- input: ({ context }) => ({
1286
- ds: context.config.ds,
1287
- storage: context.dependencies.storage
1288
- }),
1289
- onDone: {
1290
- target: "idle",
1291
- actions: "setDeepsightServiceFromEvent"
1292
- },
1293
- onError: { target: "idle" }
1294
- } },
1295
- idle: {
1296
- invoke: {
1297
- id: "checkPermissionIdle",
1298
- src: "checkPermission",
1299
- onDone: [{
1300
- target: "#faceCapture.capture",
1301
- guard: "isPermissionGranted",
1302
- actions: "setPermissionResultFromEvent"
1303
- }, {
1304
- target: "denied",
1305
- guard: ({ event }) => event.output === "denied",
1306
- actions: "setPermissionResultFromEvent"
1307
- }]
1308
- },
1309
- on: {
1310
- REQUEST_PERMISSION: "requesting",
1311
- GO_TO_LEARN_MORE: "learnMore"
1312
- }
1313
- },
1314
- learnMore: { on: {
1315
- BACK: "idle",
1316
- REQUEST_PERMISSION: "requesting"
1317
- } },
1318
- requesting: { invoke: {
1319
- id: "requestPermission",
1320
- src: "requestPermission",
1321
- onDone: [
1322
- {
1323
- target: "#faceCapture.capture",
1324
- guard: "isPermissionGranted",
1325
- actions: "setPermissionResultFromEvent"
1326
- },
1327
- {
1328
- target: "denied",
1329
- guard: ({ event }) => event.output === "denied",
1330
- actions: "setPermissionResultFromEvent"
1331
- },
1332
- {
1333
- target: "idle",
1334
- actions: "setPermissionResultFromEvent"
1335
- }
1336
- ],
1337
- onError: { target: "denied" }
1338
- } },
1339
- denied: { entry: "setPermissionRefresh" }
1340
- }
1341
- },
1342
- capture: {
1343
- initial: "checkingDeepsight",
1344
- exit: [
1345
- "stopMediaStream",
1346
- "cleanup",
1347
- "clearRecordingService"
1348
- ],
1349
- states: {
1350
- checkingDeepsight: { always: [{
1351
- target: "initializingDeepsight",
1352
- guard: ({ context }) => context.deepsightService === void 0
1353
- }, { target: "checkingStream" }] },
1354
- initializingDeepsight: { invoke: {
1355
- id: "initializeDeepsightCapture",
1356
- src: "initializeDeepsightSession",
1357
- input: ({ context }) => ({
1358
- ds: context.config.ds,
1359
- storage: context.dependencies.storage
1360
- }),
1361
- onDone: {
1362
- target: "checkingStream",
1363
- actions: ["setDeepsightServiceFromEvent"]
1364
- },
1365
- onError: { target: "#faceCapture.permissions" }
1366
- } },
1367
- checkingStream: { always: [
1368
- {
1369
- target: "initializingDeepsight",
1370
- guard: ({ context }) => context.deepsightService === void 0
1371
- },
1372
- {
1373
- target: "detecting",
1374
- guard: "hasStream"
1375
- },
1376
- { target: "initializing" }
1377
- ] },
1378
- initializing: { invoke: {
1379
- id: "initializeCamera",
1380
- src: "initializeCamera",
1381
- input: ({ context }) => ({
1382
- config: context.config,
1383
- dependencies: context.dependencies,
1384
- deepsightService: context.deepsightService
1385
- }),
1386
- onDone: {
1387
- target: "detecting",
1388
- actions: ["setStreamAndCapturer"]
1389
- },
1390
- onError: [{
1391
- target: "#faceCapture.permissions",
1392
- guard: "isPermissionDeniedError",
1393
- actions: "setPermissionDenied"
1394
- }, {
1395
- target: "#faceCapture.error",
1396
- actions: "setErrorFromEvent"
1397
- }]
1398
- } },
1399
- detecting: {
1400
- entry: ["setDetectionStatusDetecting"],
1401
- invoke: [
1402
- {
1403
- id: "checkVirtualCamera",
1404
- src: "checkVirtualCamera",
1405
- input: ({ context }) => ({
1406
- stream: context.stream,
1407
- deepsightService: context.deepsightService
1408
- }),
1409
- onDone: [{
1410
- target: "#faceCapture.processing",
1411
- guard: ({ event }) => event.output === true,
1412
- actions: "sendLabelInspection"
1413
- }],
1414
- onError: { actions: "noOp" }
1415
- },
1416
- {
1417
- id: "startRecording",
1418
- src: "startRecording",
1419
- input: ({ context }) => ({
1420
- config: context.config,
1421
- dependencies: context.dependencies,
1422
- recordingService: context.recordingService,
1423
- stream: context.stream
1424
- }),
1425
- onDone: { actions: "setRecordingServiceFromEvent" },
1426
- onError: { actions: "noOp" }
1427
- },
1428
- {
1429
- id: "runDetection",
1430
- src: "runDetection",
1431
- input: ({ context }) => ({
1432
- frameCapturer: context.frameCapturer,
1433
- provider: context.provider,
1434
- config: context.config,
1435
- manualCaptureTriggered: context.manualCaptureTriggered
1436
- })
1437
- }
1438
- ],
1439
- on: {
1440
- DETECTION_UPDATE: { actions: ["setDetectionStatusFromEvent", "setManualCaptureTriggered"] },
1441
- DETECTION_FRAME: { actions: "setDebugFrameFromEvent" },
1442
- DETECTION_RESET_READY: { actions: "setResetDetectionFromEvent" },
1443
- DETECTION_SUCCESS: {
1444
- target: "capturing",
1445
- actions: "setCapturedImageFromEvent"
1446
- },
1447
- MANUAL_CAPTURE: { target: "capturingManual" }
1448
- }
1449
- },
1450
- capturing: {
1451
- entry: ["captureImage"],
1452
- always: [{
1453
- target: "preparingUpload",
1454
- guard: "hasCapturedImage"
1455
- }, {
1456
- target: "uploadError",
1457
- actions: "setServerErrorAndDecrement"
1458
- }]
1459
- },
1460
- capturingManual: {
1461
- entry: ["captureLatestFrame"],
1462
- always: [{
1463
- target: "preparingUpload",
1464
- guard: "hasCapturedImage"
1465
- }, {
1466
- target: "uploadError",
1467
- actions: "setServerErrorAndDecrement"
1468
- }]
1469
- },
1470
- preparingUpload: { invoke: {
1471
- id: "prepareFaceUpload",
1472
- src: "prepareFaceUpload",
1473
- input: ({ context }) => context,
1474
- onDone: {
1475
- target: "uploading",
1476
- actions: "setUploadPreparationFromEvent"
1477
- },
1478
- onError: {
1479
- target: "uploadError",
1480
- actions: "setServerErrorAndDecrement"
1481
- }
1482
- } },
1483
- uploading: { invoke: {
1484
- id: "uploadFace",
1485
- src: "uploadFace",
1486
- input: ({ context }) => context,
1487
- onDone: {
1488
- target: "validatingUpload",
1489
- actions: "setUploadResponseFromEvent"
1490
- },
1491
- onError: {
1492
- target: "uploadError",
1493
- actions: "setServerErrorAndDecrement"
1494
- }
1495
- } },
1496
- validatingUpload: { always: [
1497
- {
1498
- target: "#faceCapture.error",
1499
- guard: "isTerminalUploadError",
1500
- actions: "setTerminalError"
1501
- },
1502
- {
1503
- target: "uploadError",
1504
- guard: "hasUploadValidationError",
1505
- actions: ["setUploadErrorFromUploadValidation", "decrementAttemptsRemaining"]
1506
- },
1507
- { target: "success" }
1508
- ] },
1509
- uploadError: { on: { RETRY_CAPTURE: [
1510
- {
1511
- target: "checkingStream",
1512
- guard: "hasAttemptsRemaining",
1513
- actions: [
1514
- "resetDetection",
1515
- "clearUploadFailure",
1516
- "clearStreamForRetry"
1517
- ]
1518
- },
1519
- {
1520
- target: "#faceCapture.error",
1521
- guard: "isNoAttemptsTerminal",
1522
- actions: ["setTerminalError"]
1523
- },
1524
- {
1525
- target: "#faceCapture.finished",
1526
- actions: ["flagFaceManualReview"]
1527
- }
1528
- ] } },
1529
- success: {
1530
- entry: "cleanup",
1531
- after: { 3e3: { target: "#faceCapture.processing" } }
1532
- }
1533
- }
1534
- },
1535
- processing: { invoke: {
1536
- id: "processFace",
1537
- src: "processFace",
1538
- onDone: {
1539
- target: "finished",
1540
- actions: "setProcessResponseFromEvent"
1541
- },
1542
- onError: { target: "finished" }
1543
- } },
1544
- finished: {
1545
- entry: "stopMediaStream",
1546
- type: "final"
1547
- },
1548
- closed: {
1549
- entry: "stopMediaStream",
1550
- type: "final"
1551
- },
1552
- error: {
1553
- entry: "stopMediaStream",
1554
- on: { RESET: {
1555
- target: "idle",
1556
- actions: "resetContext"
1557
- } }
1558
- }
1559
- }
1560
- });
1561
- const faceCaptureMachine = _faceCaptureMachine;
1562
-
1563
- //#endregion
1564
- export { createFaceCaptureManagerFromActor as a, FACE_ERROR_CODES as i, processFace as n, uploadSelfie as r, faceCaptureMachine as t };