@incodetech/core 0.0.0-dev-20260911-aec162f0 → 0.0.0-dev-20260914-8aef7789
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{FaceDetectionProvider-Cn1wS-sA.d.ts → BaseWasmProvider-CO0GfaHM.d.ts} +7 -37
- package/dist/{BrowserDiagnosticsCryptoProvider-8sT0QLgq.esm.js → BrowserDiagnosticsCryptoProvider-BoYzmYY5.esm.js} +1 -1
- package/dist/{onDeviceFaceResults-hle2Ci9l.esm.js → FaceDetectionProvider-0bWjPgW5.esm.js} +219 -340
- package/dist/FaceDetectionProvider-CyLxkzRP.d.ts +36 -0
- package/dist/{IIdCaptureCapability-DDWlQzhi.d.ts → IIdCaptureCapability-nfpic2z2.d.ts} +7 -3
- package/dist/{IWasmUtilCapability-SNPhmIwB.d.ts → IWasmUtilCapability-DaP6pfHq.d.ts} +10 -4
- package/dist/{MotionSensorProvider-Vlyhbcty.esm.js → MotionSensorProvider-BnZ8_1Sk.esm.js} +1 -1
- package/dist/{StreamCanvasCapture-D2XcXCZ4.esm.js → StreamCanvasCapture-C9jtgBdT.esm.js} +2 -2
- package/dist/{deepsightService-MZOpj7Vp.d.ts → StreamCanvasCapture-D9Dz8kqB.d.ts} +54 -41
- package/dist/ae-signature.esm.js +1 -1
- package/dist/{apiError-XdhqSAmg.esm.js → apiError-CixFeCyt.esm.js} +1 -1
- package/dist/authentication.d.ts +3 -3
- package/dist/authentication.esm.js +2 -2
- package/dist/{authenticationManager-DqBOkMzk.esm.js → authenticationManager-CN26fkJa.esm.js} +4 -4
- package/dist/{authenticationManager-BCkV6CSG.d.ts → authenticationManager-D7UUqgnN.d.ts} +1 -1
- package/dist/{authenticationStateMachine-Cto_G5bN.esm.js → authenticationStateMachine-CUXpIxAD.esm.js} +6 -62
- package/dist/avatar.d.ts +1 -1
- package/dist/avatar.esm.js +1 -1
- package/dist/{backCameraStream-DE_5qY04.esm.js → backCameraStream-BOtyQowf.esm.js} +75 -18
- package/dist/{camera-_2sXMXiF.esm.js → camera-sIa9ceW2.esm.js} +19 -1
- package/dist/camera.esm.js +1 -1
- package/dist/{canvas-E1zGkel4.esm.js → canvas-BxFzWTt-.esm.js} +19 -0
- package/dist/createCameraCycleOwnership-DQ5-F2oW.esm.js +826 -0
- package/dist/{createFaceAvatar-DQKaRise.esm.js → createFaceAvatar-BNHdeFj8.esm.js} +2 -2
- package/dist/{createFaceAvatar-pUEkdk4X.d.ts → createFaceAvatar-CTM9aj9Q.d.ts} +12 -6
- package/dist/curp-validation.d.ts +1 -1
- package/dist/{curpValidationManager-cSd2MrOQ.d.ts → curpValidationManager-CTJB2RsD.d.ts} +1 -1
- package/dist/{deepsightLoader-Dwr1zKFa.esm.js → deepsightLoader-Dhz9T_KJ.esm.js} +19 -53
- package/dist/document-capture.esm.js +2 -2
- package/dist/{documentCaptureManager-BTpHZMgW.esm.js → documentCaptureManager-BwcbMwo5.esm.js} +1 -1
- package/dist/{documentCaptureStateMachine-CPizkpcg.esm.js → documentCaptureStateMachine-F8SCOtL_.esm.js} +4 -4
- package/dist/dynamic-forms.esm.js +2 -2
- package/dist/{dynamicFormsManager-Cmh84Nz4.esm.js → dynamicFormsManager-CNBrBOR3.esm.js} +1 -1
- package/dist/{dynamicFormsStateMachine-DZr7Ugvy.esm.js → dynamicFormsStateMachine-Bo2qrjHB.esm.js} +1 -1
- package/dist/ekyb.d.ts +1 -1
- package/dist/ekyb.esm.js +3 -3
- package/dist/{ekybManager-Dc2tT9fu.esm.js → ekybManager-D8DdfRAD.esm.js} +1 -1
- package/dist/{ekybStateMachine-GSEMOiHn.esm.js → ekybStateMachine-oPCbEFob.esm.js} +1 -1
- package/dist/electronic-signature.esm.js +1 -1
- package/dist/{electronicSignatureManager-CpLuqw7T.esm.js → electronicSignatureManager-DkKQ07vx.esm.js} +1 -1
- package/dist/extensibility.d.ts +11 -58
- package/dist/extensibility.esm.js +13 -13
- package/dist/{faceCaptureManagerFactory-kDmbL0I7.esm.js → faceCaptureManagerFactory-D_EjQnnE.esm.js} +19 -4
- package/dist/{faceCaptureManagerFactory-CzUr_ZPq.d.ts → faceCaptureManagerFactory-DqrYpjA5.d.ts} +24 -12
- package/dist/{faceCaptureSetup-CAGBnLVx.esm.js → faceCaptureSetup-WeO8-TfR.esm.js} +999 -382
- package/dist/{feature-management-B6CtmH1O.esm.js → feature-management-BEqf3Sr3.esm.js} +1 -1
- package/dist/feature-management.esm.js +1 -1
- package/dist/fiscal-qr.esm.js +1 -1
- package/dist/{fiscalQrManager-DI6uOffY.esm.js → fiscalQrManager-Bp_-3LJr.esm.js} +3 -3
- package/dist/flow-events.d.ts +1 -1
- package/dist/flow.d.ts +6 -6
- package/dist/flow.esm.js +3 -3
- package/dist/{flowCompletionService-BpoZDpAn.esm.js → flowCompletionService-DELbVeL5.esm.js} +1 -1
- package/dist/{flowServices-BVnSStkh.esm.js → flowServices-Brr2fh_c.esm.js} +5 -5
- package/dist/geolocation.esm.js +2 -2
- package/dist/{geolocationManager-CLm86P8G.esm.js → geolocationManager-CtVZDjng.esm.js} +1 -1
- package/dist/{geolocationStateMachine-Bi3vy7Wl.esm.js → geolocationStateMachine-tjsYcMhr.esm.js} +1 -1
- package/dist/home.d.ts +1 -1
- package/dist/id-selfie-flow.d.ts +3 -3
- package/dist/id-selfie-flow.esm.js +10 -10
- package/dist/id.d.ts +4 -4
- package/dist/id.esm.js +35 -44
- package/dist/{idCaptureDefaults-BLsd7shz.esm.js → idCaptureDefaults-C66YvkgN.esm.js} +19 -14
- package/dist/{idCaptureManager-DW1GeEUk.d.ts → idCaptureManager-DE_jyr5X.d.ts} +98 -37
- package/dist/{idCaptureManager-BUTdcmaD.esm.js → idCaptureManager-zjul9YdZ.esm.js} +27 -17
- package/dist/{idCaptureServices-fzIhBqAK.esm.js → idCaptureServices-UXYCBZPK.esm.js} +80 -20
- package/dist/{idCaptureStateMachine-Cp2_revF.esm.js → idCaptureStateMachine-D3pqfK2Z.esm.js} +1954 -1082
- package/dist/{index-1PoJuUJ-.d.ts → index-BGxFwnld.d.ts} +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/mandatory-consent.d.ts +2 -2
- package/dist/{mandatoryConsentManager-BJnylLZO.d.ts → mandatoryConsentManager-CZwhsUlO.d.ts} +1 -1
- package/dist/{permissionGuards-DxbvOoZJ.esm.js → permissionGuards-o1JLtewE.esm.js} +1 -1
- package/dist/{permissionServices-f7nBnW5P.esm.js → permissionServices-7lzEiOsO.esm.js} +3 -3
- package/dist/personhood.d.ts +5 -5
- package/dist/personhood.esm.js +8 -8
- package/dist/qe-signature.esm.js +1 -1
- package/dist/{runChildModule-BPlX2IDO.esm.js → runChildModule-BDlvNMrA.esm.js} +1 -1
- package/dist/{safeStorage-Dp9m6aOh.esm.js → safeStorage-1O9k0ulP.esm.js} +8 -8
- package/dist/{sdkVersion-Dr9_E3d9.esm.js → sdkVersion-CS_0s_Lc.esm.js} +1 -1
- package/dist/selfie.d.ts +4 -4
- package/dist/selfie.esm.js +12 -74
- package/dist/{selfieManager-BdP-RgH4.esm.js → selfieManager-BouB9yUQ.esm.js} +4 -4
- package/dist/{selfieManager-Bg_Xwe4p.d.ts → selfieManager-DZ3u_WN9.d.ts} +1 -1
- package/dist/{selfieStateMachine-B8vFeT39.esm.js → selfieStateMachine-TGfI9hNp.esm.js} +22 -31
- package/dist/{session-C2THUsQZ.esm.js → session-m9j27bHm.esm.js} +3 -3
- package/dist/session.d.ts +1 -1
- package/dist/session.esm.js +4 -4
- package/dist/{sessionInitializer-CEycxhm4.esm.js → sessionInitializer-CUpgbHzs.esm.js} +4 -4
- package/dist/{setup-D6yz9se2.d.ts → setup-CEX95gJ1.d.ts} +11 -6
- package/dist/{setup-BHJ3-fhX.esm.js → setup-CfNAVG-d.esm.js} +12 -11
- package/dist/{trueSightService-DLzYznkh.esm.js → trueSightService-TqmmYye3.esm.js} +4 -4
- package/dist/types-BhHF-CuL.d.ts +6 -0
- package/dist/{types-DJ2OM9rw.d.ts → types-BzuUebkB.d.ts} +1 -1
- package/dist/{types-DzmqFoCH.d.ts → types-CBctcPeF.d.ts} +1 -1
- package/dist/{types-BBI4-s9u2.d.ts → types-CoOlCUp82.d.ts} +5 -5
- package/dist/{types-hSqUyXyw.d.ts → types-DL0CXuWv.d.ts} +3 -3
- package/dist/types-Ds928RiU.d.ts +1 -0
- package/dist/{types-_pWNFY1F.d.ts → types-eLtVBhon.d.ts} +1 -1
- package/dist/video-selfie.d.ts +3 -3
- package/dist/video-selfie.esm.js +5 -5
- package/dist/{videoSelfieCameraWarmer-D5E12WjL.esm.js → videoSelfieCameraWarmer-C-cESczy.esm.js} +9 -9
- package/dist/{videoSelfieStepDetector-B8TvFDNK.d.ts → videoSelfieStepDetector-CdXIFh9s.d.ts} +4 -4
- package/dist/virtualCameraCheck-WOloJ-do.esm.js +48 -0
- package/dist/{warmup-BOM-sD-6.esm.js → warmup-CUUnwYxe.esm.js} +282 -90
- package/dist/{warmup-CXHBgvFC.d.ts → warmup-Cis2p6O0.d.ts} +13 -2
- package/dist/wasm.d.ts +9 -3
- package/dist/wasm.esm.js +10 -4
- package/dist/{wasmDsFlagSync-C3k_VK9o.esm.js → wasmDsFlagSync-BJtLh2XK.esm.js} +1 -1
- package/dist/{wasmWebClient-BJCaFeBL.esm.js → wasmWebClient-B7baE-Wf.esm.js} +223 -2
- package/dist/workflow.d.ts +1 -1
- package/dist/workflow.esm.js +15 -15
- package/package.json +1 -1
- package/dist/imageFile-CLaua6xO.esm.js +0 -69
- package/dist/types-m4t_cT5J.d.ts +0 -6
- package/dist/{Face2DProvider-UUQt_vRC.esm.js → Face2DProvider-BF48sz5c.esm.js} +1 -1
- package/dist/{PrivacyLensProvider-D8PS7AJa.esm.js → PrivacyLensProvider-EwnC_C5n.esm.js} +1 -1
- package/dist/{selfieErrorUtils-C6gC06J7.esm.js → selfieErrorUtils-C77GXJH6.esm.js} +1 -1
|
@@ -0,0 +1,826 @@
|
|
|
1
|
+
import { c as CAMERA_CYCLE_OWNERSHIP_DOMAIN, l as getCameraCycleOwnershipDomain, s as wasmRuntime } from "./warmup-CUUnwYxe.esm.js";
|
|
2
|
+
import { t as getTimestamp } from "./IBrowserEnvironmentCapability-DEaRRk-R.esm.js";
|
|
3
|
+
import { t as api } from "./api-Bx3gKW_y.esm.js";
|
|
4
|
+
import { t as endpoints } from "./endpoints-D3B9mUHh.esm.js";
|
|
5
|
+
import { t as fromCallback } from "./xstate-actors.esm-BXeQ-Ucz.esm.js";
|
|
6
|
+
//#region ../infra/src/capabilities/ICameraCycleCapability.ts
|
|
7
|
+
/**
|
|
8
|
+
* Fixed protected-endpoint identifiers owned by ml-wasm-kit.
|
|
9
|
+
*
|
|
10
|
+
* Keep these values aligned with `ProtectedEndpointCatalog`; callers must not
|
|
11
|
+
* invent endpoint ids or pass raw URLs into the protected upload path.
|
|
12
|
+
*/
|
|
13
|
+
const PROTECTED_CAPTURE_TARGET = {
|
|
14
|
+
selfie: 1,
|
|
15
|
+
authentication: 2,
|
|
16
|
+
frontId: 3,
|
|
17
|
+
backId: 4,
|
|
18
|
+
frontSecondId: 5,
|
|
19
|
+
backSecondId: 6
|
|
20
|
+
};
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region src/internal/manualReview/manualReviewService.ts
|
|
23
|
+
async function flagFaceManualReview() {
|
|
24
|
+
try {
|
|
25
|
+
await api.put(endpoints.updateSession, { manualSelfieCheckNeeded: true });
|
|
26
|
+
} catch {}
|
|
27
|
+
}
|
|
28
|
+
async function flagIdManualReview() {
|
|
29
|
+
try {
|
|
30
|
+
await api.put(endpoints.updateSession, { manualIdCheckNeeded: true });
|
|
31
|
+
} catch {}
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region ../infra/src/media/imageFile.ts
|
|
35
|
+
const DEFAULT_IMAGE_MIME_TYPE = "image/jpeg";
|
|
36
|
+
const DEFAULT_IMAGE_QUALITY = .92;
|
|
37
|
+
const canNormalizeImageFile = (file) => file.type.startsWith("image/") && typeof document !== "undefined" && typeof Image !== "undefined" && typeof URL !== "undefined" && typeof URL.createObjectURL === "function";
|
|
38
|
+
const readFileAsDataUrl = (file) => new Promise((resolve, reject) => {
|
|
39
|
+
const reader = new FileReader();
|
|
40
|
+
reader.onload = () => {
|
|
41
|
+
const result = reader.result;
|
|
42
|
+
if (typeof result === "string") {
|
|
43
|
+
resolve(result);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
reject(/* @__PURE__ */ new Error("FileReader produced non-string result"));
|
|
47
|
+
};
|
|
48
|
+
reader.onerror = () => {
|
|
49
|
+
reject(reader.error ?? /* @__PURE__ */ new Error("FileReader failed"));
|
|
50
|
+
};
|
|
51
|
+
reader.readAsDataURL(file);
|
|
52
|
+
});
|
|
53
|
+
const loadImage = (url) => new Promise((resolve, reject) => {
|
|
54
|
+
const image = new Image();
|
|
55
|
+
image.onload = () => resolve(image);
|
|
56
|
+
image.onerror = () => reject(/* @__PURE__ */ new Error("Image decoding failed"));
|
|
57
|
+
image.src = url;
|
|
58
|
+
});
|
|
59
|
+
const fileToCanvasDataUrl = async (file, options) => {
|
|
60
|
+
const objectUrl = URL.createObjectURL(file);
|
|
61
|
+
try {
|
|
62
|
+
const image = await loadImage(objectUrl);
|
|
63
|
+
const width = image.naturalWidth || image.width;
|
|
64
|
+
const height = image.naturalHeight || image.height;
|
|
65
|
+
if (width <= 0 || height <= 0) return readFileAsDataUrl(file);
|
|
66
|
+
const canvas = document.createElement("canvas");
|
|
67
|
+
canvas.width = width;
|
|
68
|
+
canvas.height = height;
|
|
69
|
+
const context = canvas.getContext("2d");
|
|
70
|
+
if (!context) return readFileAsDataUrl(file);
|
|
71
|
+
context.fillStyle = "#fff";
|
|
72
|
+
context.fillRect(0, 0, width, height);
|
|
73
|
+
context.drawImage(image, 0, 0, width, height);
|
|
74
|
+
return canvas.toDataURL(options.mimeType ?? DEFAULT_IMAGE_MIME_TYPE, options.quality ?? DEFAULT_IMAGE_QUALITY);
|
|
75
|
+
} finally {
|
|
76
|
+
URL.revokeObjectURL(objectUrl);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
const imageFileToDataUrl = async (file, options = {}) => {
|
|
80
|
+
if (!canNormalizeImageFile(file)) return readFileAsDataUrl(file);
|
|
81
|
+
try {
|
|
82
|
+
return await fileToCanvasDataUrl(file, options);
|
|
83
|
+
} catch {
|
|
84
|
+
return readFileAsDataUrl(file);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region ../infra/src/providers/wasm/CameraCycleProvider.ts
|
|
89
|
+
function asRecord(value) {
|
|
90
|
+
return typeof value === "object" && value !== null ? value : null;
|
|
91
|
+
}
|
|
92
|
+
function responseData(value) {
|
|
93
|
+
const response = asRecord(value);
|
|
94
|
+
return asRecord(response?.data) ?? response ?? {};
|
|
95
|
+
}
|
|
96
|
+
function optionalString(value, key) {
|
|
97
|
+
return typeof value[key] === "string" ? value[key] : void 0;
|
|
98
|
+
}
|
|
99
|
+
function optionalNumber(value, key) {
|
|
100
|
+
return typeof value[key] === "number" && Number.isFinite(value[key]) ? value[key] : void 0;
|
|
101
|
+
}
|
|
102
|
+
function optionalBoolean(value, key) {
|
|
103
|
+
return typeof value[key] === "boolean" ? value[key] : void 0;
|
|
104
|
+
}
|
|
105
|
+
function optionalStringArray(value, key) {
|
|
106
|
+
const candidate = value[key];
|
|
107
|
+
return Array.isArray(candidate) && candidate.every((item) => typeof item === "string") ? [...candidate] : void 0;
|
|
108
|
+
}
|
|
109
|
+
function assertResponseTarget(raw, target) {
|
|
110
|
+
const response = asRecord(raw);
|
|
111
|
+
const data = asRecord(response?.data);
|
|
112
|
+
for (const reported of [response?.target, data?.target]) if (reported !== void 0 && reported !== target) throw new Error("[Incode SDK] Protected response target mismatch.");
|
|
113
|
+
}
|
|
114
|
+
function sanitizeSelfie(raw) {
|
|
115
|
+
const data = responseData(raw);
|
|
116
|
+
return {
|
|
117
|
+
kind: "selfie",
|
|
118
|
+
target: PROTECTED_CAPTURE_TARGET.selfie,
|
|
119
|
+
confidence: optionalNumber(data, "confidence"),
|
|
120
|
+
isBright: optionalBoolean(data, "isBright"),
|
|
121
|
+
hasLenses: optionalBoolean(data, "hasLenses"),
|
|
122
|
+
hasFaceMask: optionalBoolean(data, "hasFaceMask"),
|
|
123
|
+
hasClosedEyes: optionalBoolean(data, "hasClosedEyes"),
|
|
124
|
+
hasHeadCover: optionalBoolean(data, "hasHeadCover"),
|
|
125
|
+
sessionStatus: optionalString(data, "sessionStatus")
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function sanitizeAuthentication(raw) {
|
|
129
|
+
const data = responseData(raw);
|
|
130
|
+
const status = optionalString(data, "overallStatus");
|
|
131
|
+
const captureAttemptsLimit = asRecord(data.captureAttemptsLimit);
|
|
132
|
+
const error = asRecord(data.error);
|
|
133
|
+
return {
|
|
134
|
+
kind: "authentication",
|
|
135
|
+
target: PROTECTED_CAPTURE_TARGET.authentication,
|
|
136
|
+
overallStatus: status === "PASS" || status === "FAIL" ? status : void 0,
|
|
137
|
+
attemptsRemaining: optionalNumber(data, "attemptsRemaining") ?? (captureAttemptsLimit ? optionalNumber(captureAttemptsLimit, "remaining") : void 0),
|
|
138
|
+
errorName: optionalString(data, "errorName") ?? (error ? optionalString(error, "name") : void 0)
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function sanitizeId(raw, target) {
|
|
142
|
+
const data = responseData(raw);
|
|
143
|
+
const side = optionalString(data, "side");
|
|
144
|
+
return {
|
|
145
|
+
kind: "id",
|
|
146
|
+
target,
|
|
147
|
+
failReason: optionalString(data, "failReason"),
|
|
148
|
+
side: side === "front" || side === "back" ? side : void 0,
|
|
149
|
+
isDocumentExpired: optionalBoolean(data, "isDocumentExpired"),
|
|
150
|
+
classification: optionalBoolean(data, "classification"),
|
|
151
|
+
readability: optionalBoolean(data, "readability"),
|
|
152
|
+
idQualityAttemptApproved: optionalBoolean(data, "idQualityAttemptApproved"),
|
|
153
|
+
sharpness: optionalNumber(data, "sharpness"),
|
|
154
|
+
glare: optionalNumber(data, "glare"),
|
|
155
|
+
skipGlareFront: optionalBoolean(data, "skipGlareFront"),
|
|
156
|
+
skipGlareBack: optionalBoolean(data, "skipGlareBack"),
|
|
157
|
+
showMandatoryConsent: optionalBoolean(data, "showMandatoryConsent"),
|
|
158
|
+
typeOfId: optionalString(data, "typeOfId"),
|
|
159
|
+
skipBackIdCapture: optionalBoolean(data, "skipBackIdCapture"),
|
|
160
|
+
regulationType: optionalString(data, "regulationType"),
|
|
161
|
+
countryCode: optionalString(data, "countryCode"),
|
|
162
|
+
acceptedDocuments: optionalStringArray(data, "acceptedDocuments"),
|
|
163
|
+
forceFrontIdCapture: optionalBoolean(data, "forceFrontIdCapture"),
|
|
164
|
+
idValidationCompleted: optionalBoolean(data, "idValidationCompleted"),
|
|
165
|
+
sessionStatus: optionalString(data, "sessionStatus"),
|
|
166
|
+
success: optionalBoolean(data, "success")
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
function sanitizeProtectedResponse(request, raw) {
|
|
170
|
+
assertResponseTarget(raw, request.target);
|
|
171
|
+
switch (request.target) {
|
|
172
|
+
case PROTECTED_CAPTURE_TARGET.selfie: return sanitizeSelfie(raw);
|
|
173
|
+
case PROTECTED_CAPTURE_TARGET.authentication: return sanitizeAuthentication(raw);
|
|
174
|
+
case PROTECTED_CAPTURE_TARGET.frontId:
|
|
175
|
+
case PROTECTED_CAPTURE_TARGET.backId:
|
|
176
|
+
case PROTECTED_CAPTURE_TARGET.frontSecondId:
|
|
177
|
+
case PROTECTED_CAPTURE_TARGET.backSecondId: return sanitizeId(raw, request.target);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
var CameraCycleProvider = class {
|
|
181
|
+
constructor(runtime = wasmRuntime) {
|
|
182
|
+
this.runtime = runtime;
|
|
183
|
+
this[CAMERA_CYCLE_OWNERSHIP_DOMAIN] = getCameraCycleOwnershipDomain(runtime);
|
|
184
|
+
}
|
|
185
|
+
adoptStream(stream, constraints, options) {
|
|
186
|
+
return this.runtime.adoptCameraStream(stream, constraints, options);
|
|
187
|
+
}
|
|
188
|
+
setWorkflowConsuming(workflow, consuming) {
|
|
189
|
+
if (consuming && (workflow === 2 || workflow === 3)) throw new Error("[Incode SDK] Protected still capture is unavailable for video-selfie workflows.");
|
|
190
|
+
return this.runtime.setWorkflowConsuming(workflow, consuming);
|
|
191
|
+
}
|
|
192
|
+
captureProtectedFrame(target) {
|
|
193
|
+
return this.runtime.captureProtectedFrame(target);
|
|
194
|
+
}
|
|
195
|
+
paintFrameToCanvas(canvas, options) {
|
|
196
|
+
return this.runtime.paintFrameToCanvas(canvas, options);
|
|
197
|
+
}
|
|
198
|
+
getCaptureSize() {
|
|
199
|
+
return this.runtime.getCaptureSize();
|
|
200
|
+
}
|
|
201
|
+
getUnprotectedStream() {
|
|
202
|
+
return this.runtime.getUnprotectedStream();
|
|
203
|
+
}
|
|
204
|
+
async postProtectedRequest(request) {
|
|
205
|
+
return sanitizeProtectedResponse(request, await this.runtime.postProtectedRequest(request));
|
|
206
|
+
}
|
|
207
|
+
release() {
|
|
208
|
+
this.runtime.releaseCameraCycle();
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
const cameraCycleProvider = new CameraCycleProvider();
|
|
212
|
+
//#endregion
|
|
213
|
+
//#region src/internal/cameraCycle/protectedAttemptActor.ts
|
|
214
|
+
/**
|
|
215
|
+
* Runs the protected lifecycle inside an owning callback actor. Keeping the
|
|
216
|
+
* implementation callable lets domain controllers compose the exact same
|
|
217
|
+
* lifecycle without placing its capability-bearing input in machine context.
|
|
218
|
+
*/
|
|
219
|
+
const runProtectedAttempt = ({ input, sendBack, receive }) => {
|
|
220
|
+
const abortController = new AbortController();
|
|
221
|
+
let active = true;
|
|
222
|
+
let backgrounded = input.initiallyBackgrounded === true;
|
|
223
|
+
let ready = false;
|
|
224
|
+
let committed = false;
|
|
225
|
+
let finalized = false;
|
|
226
|
+
let deliveryInFlight = false;
|
|
227
|
+
let delivered = false;
|
|
228
|
+
let consuming = false;
|
|
229
|
+
let recorderStarted = false;
|
|
230
|
+
let recorderOperationInFlight = false;
|
|
231
|
+
let recorderPrepared = false;
|
|
232
|
+
let preparedRecording = {};
|
|
233
|
+
let pocCompleted = false;
|
|
234
|
+
let recorderResumedAfterPoc = false;
|
|
235
|
+
let postPocDisplayStream = null;
|
|
236
|
+
let finalizeDeferred = false;
|
|
237
|
+
let pendingReadyStream = null;
|
|
238
|
+
let pendingDeliveryEvent = null;
|
|
239
|
+
let visibilityGeneration = 0;
|
|
240
|
+
let unadoptedStream = input.streamSource.kind === "preAcquired" ? input.streamSource.stream : null;
|
|
241
|
+
let resourcesReleased = false;
|
|
242
|
+
let cycleTransferred = false;
|
|
243
|
+
let commandQueue = Promise.resolve();
|
|
244
|
+
const now = input.getTimestamp ?? getTimestamp;
|
|
245
|
+
let startupStartedAt;
|
|
246
|
+
const startupTiming = {};
|
|
247
|
+
const measure = (operation) => {
|
|
248
|
+
const startedAt = now();
|
|
249
|
+
return {
|
|
250
|
+
value: operation(),
|
|
251
|
+
durationMs: Math.max(0, now() - startedAt)
|
|
252
|
+
};
|
|
253
|
+
};
|
|
254
|
+
const reportStartupTiming = (consumeMs, totalMs) => {
|
|
255
|
+
if (startupStartedAt === void 0 || !input.onStartupTiming) return;
|
|
256
|
+
try {
|
|
257
|
+
input.onStartupTiming({
|
|
258
|
+
acquireMs: startupTiming.acquireMs ?? 0,
|
|
259
|
+
adoptMs: startupTiming.adoptMs ?? 0,
|
|
260
|
+
prcMs: startupTiming.prcMs ?? 0,
|
|
261
|
+
displayStreamMs: startupTiming.displayStreamMs ?? 0,
|
|
262
|
+
configureMs: startupTiming.configureMs ?? 0,
|
|
263
|
+
recorderMs: startupTiming.recorderMs ?? 0,
|
|
264
|
+
consumeMs,
|
|
265
|
+
totalMs
|
|
266
|
+
});
|
|
267
|
+
} catch {}
|
|
268
|
+
};
|
|
269
|
+
const sendParent = (event) => {
|
|
270
|
+
sendBack(event);
|
|
271
|
+
};
|
|
272
|
+
const releaseRawStream = (stream) => {
|
|
273
|
+
try {
|
|
274
|
+
input.releaseUnadoptedStream(stream);
|
|
275
|
+
} catch {}
|
|
276
|
+
};
|
|
277
|
+
const reportFailure = (stage, code) => {
|
|
278
|
+
if (!active) return;
|
|
279
|
+
sendParent({
|
|
280
|
+
type: "PROTECTED_ATTEMPT_FAILED",
|
|
281
|
+
attemptId: input.attemptId,
|
|
282
|
+
failure: {
|
|
283
|
+
stage,
|
|
284
|
+
code
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
};
|
|
288
|
+
const releaseResources = () => {
|
|
289
|
+
if (resourcesReleased) return;
|
|
290
|
+
resourcesReleased = true;
|
|
291
|
+
abortController.abort();
|
|
292
|
+
if (consuming) {
|
|
293
|
+
try {
|
|
294
|
+
input.cycle.setWorkflowConsuming(input.workflow, false);
|
|
295
|
+
} catch {}
|
|
296
|
+
consuming = false;
|
|
297
|
+
}
|
|
298
|
+
try {
|
|
299
|
+
input.recorder.dispose();
|
|
300
|
+
} catch {}
|
|
301
|
+
recorderStarted = false;
|
|
302
|
+
pendingReadyStream = null;
|
|
303
|
+
postPocDisplayStream = null;
|
|
304
|
+
pendingDeliveryEvent = null;
|
|
305
|
+
finalizeDeferred = false;
|
|
306
|
+
if (unadoptedStream) releaseRawStream(unadoptedStream);
|
|
307
|
+
unadoptedStream = null;
|
|
308
|
+
if (cycleTransferred) input.cycleOwnership.releaseByAttempt();
|
|
309
|
+
else input.cycleOwnership.releaseByController();
|
|
310
|
+
};
|
|
311
|
+
const deactivate = () => {
|
|
312
|
+
if (!active && resourcesReleased) return;
|
|
313
|
+
active = false;
|
|
314
|
+
ready = false;
|
|
315
|
+
releaseResources();
|
|
316
|
+
};
|
|
317
|
+
const failClosed = (stage, code) => {
|
|
318
|
+
reportFailure(stage, code);
|
|
319
|
+
deactivate();
|
|
320
|
+
};
|
|
321
|
+
const stopConsuming = () => {
|
|
322
|
+
if (!consuming) return true;
|
|
323
|
+
try {
|
|
324
|
+
if (!input.cycle.setWorkflowConsuming(input.workflow, false)) return false;
|
|
325
|
+
} catch {
|
|
326
|
+
return false;
|
|
327
|
+
}
|
|
328
|
+
consuming = false;
|
|
329
|
+
return true;
|
|
330
|
+
};
|
|
331
|
+
const pauseRecorderForBackground = () => {
|
|
332
|
+
if (recorderOperationInFlight) return;
|
|
333
|
+
if (!recorderStarted) return;
|
|
334
|
+
if (recorderPrepared && !recorderResumedAfterPoc) return;
|
|
335
|
+
try {
|
|
336
|
+
input.recorder.pauseForBackground();
|
|
337
|
+
} catch {
|
|
338
|
+
reportFailure("recorder", "protected-attempt-background-pause-failed");
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
const startConsumingAndAnnounceReady = (displayStream) => {
|
|
342
|
+
const consume = measure(() => input.cycle.setWorkflowConsuming(input.workflow, true));
|
|
343
|
+
if (!consume.value) {
|
|
344
|
+
failClosed("consume", "protected-attempt-consume-failed");
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
347
|
+
const startupTotalMs = startupStartedAt === void 0 ? 0 : Math.max(0, now() - startupStartedAt);
|
|
348
|
+
consuming = true;
|
|
349
|
+
ready = true;
|
|
350
|
+
pendingReadyStream = null;
|
|
351
|
+
if (input.resourceSink) {
|
|
352
|
+
input.resourceSink.ready(displayStream);
|
|
353
|
+
sendParent({
|
|
354
|
+
type: "PROTECTED_ATTEMPT_READY_SIGNAL",
|
|
355
|
+
attemptId: input.attemptId
|
|
356
|
+
});
|
|
357
|
+
} else sendParent({
|
|
358
|
+
type: "PROTECTED_ATTEMPT_READY",
|
|
359
|
+
attemptId: input.attemptId,
|
|
360
|
+
displayStream
|
|
361
|
+
});
|
|
362
|
+
reportStartupTiming(consume.durationMs, startupTotalMs);
|
|
363
|
+
return true;
|
|
364
|
+
};
|
|
365
|
+
const start = async () => {
|
|
366
|
+
let stage = "acquire";
|
|
367
|
+
try {
|
|
368
|
+
startupStartedAt = now();
|
|
369
|
+
const acquisitionStartedAt = now();
|
|
370
|
+
const acquired = input.streamSource.kind === "preAcquired" ? {
|
|
371
|
+
stream: input.streamSource.stream,
|
|
372
|
+
constraints: input.streamSource.constraints
|
|
373
|
+
} : await input.streamSource.acquire(abortController.signal);
|
|
374
|
+
startupTiming.acquireMs = Math.max(0, now() - acquisitionStartedAt);
|
|
375
|
+
if (!active || abortController.signal.aborted) {
|
|
376
|
+
releaseRawStream(acquired.stream);
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
unadoptedStream = acquired.stream;
|
|
380
|
+
stage = "adopt";
|
|
381
|
+
if (input.beforeAdopt) {
|
|
382
|
+
await input.beforeAdopt(acquired.stream);
|
|
383
|
+
if (!active || abortController.signal.aborted) return;
|
|
384
|
+
}
|
|
385
|
+
const adoption = measure(() => input.cycle.adoptStream(acquired.stream, acquired.constraints, input.captureOptions));
|
|
386
|
+
startupTiming.adoptMs = adoption.durationMs;
|
|
387
|
+
if (!adoption.value) throw new Error("protected camera stream adoption was rejected");
|
|
388
|
+
unadoptedStream = null;
|
|
389
|
+
input.cycleOwnership.transferToAttempt();
|
|
390
|
+
cycleTransferred = true;
|
|
391
|
+
stage = "prc";
|
|
392
|
+
const prcStartedAt = now();
|
|
393
|
+
await input.runPrc();
|
|
394
|
+
startupTiming.prcMs = Math.max(0, now() - prcStartedAt);
|
|
395
|
+
if (!active) return;
|
|
396
|
+
const displayStreamResult = measure(() => input.cycle.getUnprotectedStream());
|
|
397
|
+
startupTiming.displayStreamMs = displayStreamResult.durationMs;
|
|
398
|
+
const displayStream = displayStreamResult.value;
|
|
399
|
+
if (!displayStream) throw new Error("protected camera cycle did not provide a stream");
|
|
400
|
+
stage = "configure";
|
|
401
|
+
const configureStartedAt = now();
|
|
402
|
+
await input.configureWorkflow();
|
|
403
|
+
startupTiming.configureMs = Math.max(0, now() - configureStartedAt);
|
|
404
|
+
if (!active) return;
|
|
405
|
+
recorderOperationInFlight = true;
|
|
406
|
+
const recorderStartedAt = now();
|
|
407
|
+
try {
|
|
408
|
+
await input.recorder.start(displayStream);
|
|
409
|
+
recorderStarted = input.recorder.mode !== "none";
|
|
410
|
+
} catch {
|
|
411
|
+
try {
|
|
412
|
+
input.recorder.dispose();
|
|
413
|
+
} catch {}
|
|
414
|
+
recorderStarted = false;
|
|
415
|
+
} finally {
|
|
416
|
+
startupTiming.recorderMs = Math.max(0, now() - recorderStartedAt);
|
|
417
|
+
recorderOperationInFlight = false;
|
|
418
|
+
}
|
|
419
|
+
if (!active) return;
|
|
420
|
+
if (backgrounded) {
|
|
421
|
+
pauseRecorderForBackground();
|
|
422
|
+
pendingReadyStream = displayStream;
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
stage = "consume";
|
|
426
|
+
startConsumingAndAnnounceReady(displayStream);
|
|
427
|
+
} catch {
|
|
428
|
+
if (!active) return;
|
|
429
|
+
failClosed(stage, `protected-attempt-${stage}-failed`);
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
const commitAutoCapture = (preview) => {
|
|
433
|
+
if (!active || !ready || backgrounded || committed) return;
|
|
434
|
+
if (!stopConsuming()) {
|
|
435
|
+
failClosed("consume", "protected-attempt-stop-consuming-failed");
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
committed = true;
|
|
439
|
+
if (input.resourceSink) {
|
|
440
|
+
input.resourceSink.autoCommitted(preview);
|
|
441
|
+
sendParent({
|
|
442
|
+
type: "PROTECTED_AUTO_COMMITTED_SIGNAL",
|
|
443
|
+
attemptId: input.attemptId
|
|
444
|
+
});
|
|
445
|
+
} else sendParent({
|
|
446
|
+
type: "PROTECTED_AUTO_COMMITTED",
|
|
447
|
+
attemptId: input.attemptId,
|
|
448
|
+
preview
|
|
449
|
+
});
|
|
450
|
+
};
|
|
451
|
+
const commitManualCapture = () => {
|
|
452
|
+
if (!active || !ready || backgrounded || committed) return;
|
|
453
|
+
let preview;
|
|
454
|
+
try {
|
|
455
|
+
preview = input.cycle.captureProtectedFrame(input.target);
|
|
456
|
+
} catch {
|
|
457
|
+
reportFailure("manualCommit", "protected-attempt-manual-commit-refused");
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
if (!stopConsuming()) {
|
|
461
|
+
failClosed("consume", "protected-attempt-stop-consuming-failed");
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
committed = true;
|
|
465
|
+
if (input.resourceSink) {
|
|
466
|
+
input.resourceSink.manualCommitted(preview);
|
|
467
|
+
sendParent({
|
|
468
|
+
type: "PROTECTED_MANUAL_COMMITTED_SIGNAL",
|
|
469
|
+
attemptId: input.attemptId
|
|
470
|
+
});
|
|
471
|
+
} else sendParent({
|
|
472
|
+
type: "PROTECTED_MANUAL_COMMITTED",
|
|
473
|
+
attemptId: input.attemptId,
|
|
474
|
+
preview
|
|
475
|
+
});
|
|
476
|
+
};
|
|
477
|
+
const finalize = async () => {
|
|
478
|
+
if (!active || !ready || finalized) return;
|
|
479
|
+
if (backgrounded) {
|
|
480
|
+
finalizeDeferred = true;
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
if (!committed) {
|
|
484
|
+
reportFailure("poc", "protected-attempt-not-committed");
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
finalizeDeferred = false;
|
|
488
|
+
if (recorderStarted && !recorderPrepared) {
|
|
489
|
+
recorderOperationInFlight = true;
|
|
490
|
+
try {
|
|
491
|
+
preparedRecording = await input.recorder.prepareForPoc();
|
|
492
|
+
recorderPrepared = true;
|
|
493
|
+
} catch {
|
|
494
|
+
if (!active) return;
|
|
495
|
+
failClosed("recorder", "protected-attempt-recorder-finalize-failed");
|
|
496
|
+
return;
|
|
497
|
+
} finally {
|
|
498
|
+
recorderOperationInFlight = false;
|
|
499
|
+
}
|
|
500
|
+
if (!active) return;
|
|
501
|
+
if (backgrounded) {
|
|
502
|
+
pauseRecorderForBackground();
|
|
503
|
+
finalizeDeferred = true;
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
if (!pocCompleted) {
|
|
508
|
+
try {
|
|
509
|
+
await input.runPoc();
|
|
510
|
+
pocCompleted = true;
|
|
511
|
+
} catch {
|
|
512
|
+
if (!active) return;
|
|
513
|
+
failClosed("poc", "protected-attempt-poc-failed");
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
if (!active) return;
|
|
517
|
+
if (backgrounded) {
|
|
518
|
+
finalizeDeferred = true;
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
let displayStream = postPocDisplayStream;
|
|
523
|
+
if (input.recorder.mode === "suspendResume" && recorderStarted && !recorderResumedAfterPoc) {
|
|
524
|
+
displayStream = input.cycle.getUnprotectedStream();
|
|
525
|
+
if (!displayStream) {
|
|
526
|
+
failClosed("recorder", "protected-attempt-resume-stream-missing");
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
try {
|
|
530
|
+
recorderOperationInFlight = true;
|
|
531
|
+
await input.recorder.resumeAfterPoc(displayStream);
|
|
532
|
+
recorderResumedAfterPoc = true;
|
|
533
|
+
postPocDisplayStream = displayStream;
|
|
534
|
+
} catch {
|
|
535
|
+
if (!active) return;
|
|
536
|
+
failClosed("recorder", "protected-attempt-recorder-resume-failed");
|
|
537
|
+
return;
|
|
538
|
+
} finally {
|
|
539
|
+
recorderOperationInFlight = false;
|
|
540
|
+
}
|
|
541
|
+
if (!active) return;
|
|
542
|
+
if (backgrounded) {
|
|
543
|
+
pauseRecorderForBackground();
|
|
544
|
+
finalizeDeferred = true;
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
finalized = true;
|
|
549
|
+
if (input.resourceSink) {
|
|
550
|
+
input.resourceSink.finalized(preparedRecording, displayStream);
|
|
551
|
+
sendParent({
|
|
552
|
+
type: "PROTECTED_ATTEMPT_FINALIZED_SIGNAL",
|
|
553
|
+
attemptId: input.attemptId
|
|
554
|
+
});
|
|
555
|
+
} else sendParent({
|
|
556
|
+
type: "PROTECTED_ATTEMPT_FINALIZED",
|
|
557
|
+
attemptId: input.attemptId,
|
|
558
|
+
recording: preparedRecording,
|
|
559
|
+
displayStream
|
|
560
|
+
});
|
|
561
|
+
};
|
|
562
|
+
const uploadProtected = async (command) => {
|
|
563
|
+
if (!active || !finalized || deliveryInFlight || delivered) return;
|
|
564
|
+
if (backgrounded) {
|
|
565
|
+
pendingDeliveryEvent = {
|
|
566
|
+
type: "PROTECTED_ATTEMPT_FAILED",
|
|
567
|
+
attemptId: input.attemptId,
|
|
568
|
+
failure: {
|
|
569
|
+
stage: "upload",
|
|
570
|
+
code: "protected-attempt-backgrounded"
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
if (command.request.target !== input.target) {
|
|
576
|
+
reportFailure("upload", "protected-attempt-target-mismatch");
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
deliveryInFlight = true;
|
|
580
|
+
try {
|
|
581
|
+
const result = await input.cycle.postProtectedRequest(command.request);
|
|
582
|
+
if (active) {
|
|
583
|
+
if (result.target !== input.target) {
|
|
584
|
+
reportFailure("upload", "protected-attempt-result-target-mismatch");
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
delivered = true;
|
|
588
|
+
const event = input.resourceSink ? (() => {
|
|
589
|
+
input.resourceSink.uploadDone(result);
|
|
590
|
+
return {
|
|
591
|
+
type: "PROTECTED_UPLOAD_DONE_SIGNAL",
|
|
592
|
+
attemptId: input.attemptId
|
|
593
|
+
};
|
|
594
|
+
})() : {
|
|
595
|
+
type: "PROTECTED_UPLOAD_DONE",
|
|
596
|
+
attemptId: input.attemptId,
|
|
597
|
+
result
|
|
598
|
+
};
|
|
599
|
+
if (backgrounded) pendingDeliveryEvent = event;
|
|
600
|
+
else sendParent(event);
|
|
601
|
+
}
|
|
602
|
+
} catch {
|
|
603
|
+
if (backgrounded) pendingDeliveryEvent = {
|
|
604
|
+
type: "PROTECTED_ATTEMPT_FAILED",
|
|
605
|
+
attemptId: input.attemptId,
|
|
606
|
+
failure: {
|
|
607
|
+
stage: "upload",
|
|
608
|
+
code: "protected-attempt-upload-failed"
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
else reportFailure("upload", "protected-attempt-upload-failed");
|
|
612
|
+
} finally {
|
|
613
|
+
deliveryInFlight = false;
|
|
614
|
+
}
|
|
615
|
+
};
|
|
616
|
+
const uploadFaceResults = async (command) => {
|
|
617
|
+
if (!active || !finalized || deliveryInFlight || delivered) return;
|
|
618
|
+
if (backgrounded) {
|
|
619
|
+
pendingDeliveryEvent = {
|
|
620
|
+
type: "PROTECTED_ATTEMPT_FAILED",
|
|
621
|
+
attemptId: input.attemptId,
|
|
622
|
+
failure: {
|
|
623
|
+
stage: "upload",
|
|
624
|
+
code: "protected-attempt-backgrounded"
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
if (input.target !== PROTECTED_CAPTURE_TARGET.selfie && input.target !== PROTECTED_CAPTURE_TARGET.authentication) {
|
|
630
|
+
reportFailure("upload", "protected-attempt-target-mismatch");
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
if (!input.faceResults) {
|
|
634
|
+
reportFailure("upload", "protected-attempt-face-results-unavailable");
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
deliveryInFlight = true;
|
|
638
|
+
try {
|
|
639
|
+
await input.faceResults.postFaceResults(command.config);
|
|
640
|
+
if (active) {
|
|
641
|
+
delivered = true;
|
|
642
|
+
const result = {
|
|
643
|
+
kind: "onDeviceFace",
|
|
644
|
+
target: input.target
|
|
645
|
+
};
|
|
646
|
+
const event = input.resourceSink ? (() => {
|
|
647
|
+
input.resourceSink.uploadDone(result);
|
|
648
|
+
return {
|
|
649
|
+
type: "PROTECTED_UPLOAD_DONE_SIGNAL",
|
|
650
|
+
attemptId: input.attemptId
|
|
651
|
+
};
|
|
652
|
+
})() : {
|
|
653
|
+
type: "PROTECTED_UPLOAD_DONE",
|
|
654
|
+
attemptId: input.attemptId,
|
|
655
|
+
result
|
|
656
|
+
};
|
|
657
|
+
if (backgrounded) pendingDeliveryEvent = event;
|
|
658
|
+
else sendParent(event);
|
|
659
|
+
}
|
|
660
|
+
} catch {
|
|
661
|
+
if (backgrounded) pendingDeliveryEvent = {
|
|
662
|
+
type: "PROTECTED_ATTEMPT_FAILED",
|
|
663
|
+
attemptId: input.attemptId,
|
|
664
|
+
failure: {
|
|
665
|
+
stage: "upload",
|
|
666
|
+
code: "protected-attempt-upload-failed"
|
|
667
|
+
}
|
|
668
|
+
};
|
|
669
|
+
else reportFailure("upload", "protected-attempt-upload-failed");
|
|
670
|
+
} finally {
|
|
671
|
+
deliveryInFlight = false;
|
|
672
|
+
}
|
|
673
|
+
};
|
|
674
|
+
const handleCommand = async (command, receivedVisibilityGeneration) => {
|
|
675
|
+
if (!active) return;
|
|
676
|
+
switch (command.type) {
|
|
677
|
+
case "AUTO_CAPTURE": {
|
|
678
|
+
const preview = input.capturePresentationFrame?.();
|
|
679
|
+
if (preview) commitAutoCapture(preview);
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
case "AUTO_CAPTURED":
|
|
683
|
+
commitAutoCapture(command.preview);
|
|
684
|
+
return;
|
|
685
|
+
case "MANUAL_CAPTURE":
|
|
686
|
+
commitManualCapture();
|
|
687
|
+
return;
|
|
688
|
+
case "FINALIZE":
|
|
689
|
+
await finalize();
|
|
690
|
+
return;
|
|
691
|
+
case "UPLOAD_PROTECTED":
|
|
692
|
+
await uploadProtected(command);
|
|
693
|
+
return;
|
|
694
|
+
case "UPLOAD_FACE_RESULTS":
|
|
695
|
+
await uploadFaceResults(command);
|
|
696
|
+
return;
|
|
697
|
+
case "BACKGROUND": return;
|
|
698
|
+
case "FOREGROUND": {
|
|
699
|
+
if (!backgrounded) return;
|
|
700
|
+
if (receivedVisibilityGeneration !== visibilityGeneration) return;
|
|
701
|
+
let resumedStream = null;
|
|
702
|
+
if (recorderStarted && (!recorderPrepared || recorderResumedAfterPoc)) {
|
|
703
|
+
resumedStream = input.cycle.getUnprotectedStream();
|
|
704
|
+
if (!resumedStream) {
|
|
705
|
+
reportFailure("recorder", "protected-attempt-foreground-stream-missing");
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
recorderOperationInFlight = true;
|
|
709
|
+
try {
|
|
710
|
+
await input.recorder.resumeFromBackground(resumedStream);
|
|
711
|
+
if (!active) return;
|
|
712
|
+
if (receivedVisibilityGeneration !== visibilityGeneration) {
|
|
713
|
+
recorderOperationInFlight = false;
|
|
714
|
+
pauseRecorderForBackground();
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
if (pocCompleted && recorderResumedAfterPoc) postPocDisplayStream = resumedStream;
|
|
718
|
+
} catch {
|
|
719
|
+
if (!active) return;
|
|
720
|
+
reportFailure("recorder", "protected-attempt-background-resume-failed");
|
|
721
|
+
return;
|
|
722
|
+
} finally {
|
|
723
|
+
recorderOperationInFlight = false;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
backgrounded = false;
|
|
727
|
+
if (pendingReadyStream) {
|
|
728
|
+
const readyStream = resumedStream ?? pendingReadyStream;
|
|
729
|
+
try {
|
|
730
|
+
if (!startConsumingAndAnnounceReady(readyStream)) return;
|
|
731
|
+
} catch {
|
|
732
|
+
failClosed("consume", "protected-attempt-consume-failed");
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
if (finalizeDeferred) {
|
|
737
|
+
await finalize();
|
|
738
|
+
if (!active || backgrounded) return;
|
|
739
|
+
}
|
|
740
|
+
if (pendingDeliveryEvent) {
|
|
741
|
+
const event = pendingDeliveryEvent;
|
|
742
|
+
pendingDeliveryEvent = null;
|
|
743
|
+
sendParent(event);
|
|
744
|
+
}
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
case "RELEASE": return;
|
|
748
|
+
}
|
|
749
|
+
};
|
|
750
|
+
let startup = backgrounded ? null : start();
|
|
751
|
+
const ensureStartup = () => {
|
|
752
|
+
startup ??= start();
|
|
753
|
+
return startup;
|
|
754
|
+
};
|
|
755
|
+
receive((command) => {
|
|
756
|
+
if (command.type === "RELEASE") {
|
|
757
|
+
if (!active) return;
|
|
758
|
+
deactivate();
|
|
759
|
+
sendParent({
|
|
760
|
+
type: "PROTECTED_ATTEMPT_RELEASED",
|
|
761
|
+
attemptId: input.attemptId
|
|
762
|
+
});
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
if (command.type === "BACKGROUND") {
|
|
766
|
+
if (!active) return;
|
|
767
|
+
backgrounded = true;
|
|
768
|
+
visibilityGeneration += 1;
|
|
769
|
+
pauseRecorderForBackground();
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
if (!active) return;
|
|
773
|
+
const receivedVisibilityGeneration = command.type === "FOREGROUND" ? visibilityGeneration : void 0;
|
|
774
|
+
if (command.type === "FOREGROUND" && startup === null) {
|
|
775
|
+
if (receivedVisibilityGeneration !== visibilityGeneration) return;
|
|
776
|
+
backgrounded = false;
|
|
777
|
+
commandQueue = commandQueue.then(async () => {
|
|
778
|
+
await ensureStartup();
|
|
779
|
+
}).catch(() => {
|
|
780
|
+
failClosed("acquire", "protected-attempt-command-failed");
|
|
781
|
+
});
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
commandQueue = commandQueue.then(async () => {
|
|
785
|
+
await ensureStartup();
|
|
786
|
+
await handleCommand(command, receivedVisibilityGeneration);
|
|
787
|
+
}).catch(() => {
|
|
788
|
+
failClosed("internal", "protected-attempt-command-failed");
|
|
789
|
+
});
|
|
790
|
+
});
|
|
791
|
+
return deactivate;
|
|
792
|
+
};
|
|
793
|
+
fromCallback(runProtectedAttempt);
|
|
794
|
+
//#endregion
|
|
795
|
+
//#region ../infra/src/providers/wasm/createCameraCycleOwnership.ts
|
|
796
|
+
/** Creates an attempt lease in the underlying runtime's ownership domain. */
|
|
797
|
+
function createCameraCycleOwnership(cycle) {
|
|
798
|
+
const domain = getCameraCycleOwnershipDomain(cycle);
|
|
799
|
+
const creationSnapshot = domain.snapshot();
|
|
800
|
+
const owner = Symbol("protectedCameraCycleOwner");
|
|
801
|
+
let state = "controller";
|
|
802
|
+
const releaseNative = () => {
|
|
803
|
+
try {
|
|
804
|
+
cycle.release();
|
|
805
|
+
} catch {}
|
|
806
|
+
};
|
|
807
|
+
return {
|
|
808
|
+
transferToAttempt() {
|
|
809
|
+
if (state !== "controller") return;
|
|
810
|
+
state = "attempt";
|
|
811
|
+
domain.transfer(owner);
|
|
812
|
+
},
|
|
813
|
+
releaseByController() {
|
|
814
|
+
if (state !== "controller") return;
|
|
815
|
+
state = "released";
|
|
816
|
+
if (domain.releaseController(creationSnapshot.generation, creationSnapshot.activeOwner === void 0)) releaseNative();
|
|
817
|
+
},
|
|
818
|
+
releaseByAttempt() {
|
|
819
|
+
if (state !== "attempt") return;
|
|
820
|
+
state = "released";
|
|
821
|
+
if (domain.releaseAttempt(owner)) releaseNative();
|
|
822
|
+
}
|
|
823
|
+
};
|
|
824
|
+
}
|
|
825
|
+
//#endregion
|
|
826
|
+
export { flagFaceManualReview as a, imageFileToDataUrl as i, runProtectedAttempt as n, flagIdManualReview as o, cameraCycleProvider as r, PROTECTED_CAPTURE_TARGET as s, createCameraCycleOwnership as t };
|