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