@powercred/liveness-web 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/liveness.js CHANGED
@@ -1,4 +1,4 @@
1
- const ee = { gettingReady: "Getting ready…", center: "Center your face in the oval", moveCloser: "Move a little closer", moveBack: "Move a little back", lookStraight: "Look straight at the camera", noFace: "We can't see your face", multipleFaces: "Only one person, please", turnLeft: "Turn your head to your LEFT", turnRight: "Turn your head to your RIGHT", lookUp: "Look UP", lookDown: "Look DOWN", smile: "Smile", blink: "Blink once", openMouth: "Open your mouth", holdStill: "Hold still", great: "Great!", wrongDirection: "That was the other way — let's try again", faceLost: "We lost your face — let's try again", timeUp: "Time's up — let's try again", tooSlow: "That took a while — let's try again", flashIntro: "Hold still — the screen will flash colours", checking: "Checking…", passedTitle: "Done", passedDetail: "Thank you, your liveness check is complete.", submittedTitle: "Thank you", failedTitle: "We couldn't confirm that", failedDetail: "Please try again in good light, facing the camera.", noAttemptsDetail: "Please contact the company that asked you to do this check.", tryAgain: "Try again", cameraDenied: "Camera access is needed. Allow it in your browser settings and try again.", cameraUnavailable: "We couldn't start your camera.", unsupportedBrowser: "This browser can't run the check. Please use an up-to-date Chrome, Safari, Edge or Firefox.", insecureContext: "This page must be opened over https.", network: "Connection problem. Please check your internet and try again.", sessionExpired: "This check has expired. Please start again.", serviceUnavailable: "The check is temporarily unavailable. Please try again shortly.", genericError: "Something went wrong. Please try again." }, te = `
1
+ const oe = { gettingReady: "Getting ready…", center: "Center your face in the oval", moveCloser: "Move a little closer", moveBack: "Move a little back", lookStraight: "Look straight at the camera", noFace: "We can't see your face", multipleFaces: "Only one person, please", turnLeft: "Turn your head to your LEFT", turnRight: "Turn your head to your RIGHT", lookUp: "Look UP", lookDown: "Look DOWN", smile: "Smile", blink: "Blink once", openMouth: "Open your mouth", holdStill: "Hold still", great: "Great!", wrongDirection: "That was the other way — let's try again", faceLost: "We lost your face — let's try again", interrupted: "The check was interrupted — let's try again", timeUp: "Time's up — let's try again", tooSlow: "That took a while — let's try again", flashIntro: "Hold still — the screen will flash colours", checking: "Checking…", passedTitle: "Done", passedDetail: "Thank you, your liveness check is complete.", submittedTitle: "Thank you", failedTitle: "We couldn't confirm that", failedDetail: "Please try again in good light, facing the camera.", noAttemptsDetail: "Please contact the company that asked you to do this check.", tryAgain: "Try again", cameraDenied: "Camera access is needed. Allow it in your browser settings and try again.", cameraUnavailable: "We couldn't start your camera.", unsupportedBrowser: "This browser can't run the check. Please use an up-to-date Chrome, Safari, Edge or Firefox.", insecureContext: "This page must be opened over https.", network: "Connection problem. Please check your internet and try again.", sessionExpired: "This check has expired. Please start again.", serviceUnavailable: "The check is temporarily unavailable. Please try again shortly.", genericError: "Something went wrong. Please try again." }, le = `
2
2
  :host { all: initial; display: block; }
3
3
  .pcl { --primary: var(--pcl-primary, #4b45a1); --ok: #1f9d55; --warn: #e3a008; --bad: #d64545;
4
4
  font-family: var(--pcl-font, system-ui, -apple-system, "Segoe UI", sans-serif); color: #fff;
@@ -43,11 +43,11 @@ button { font: inherit; font-size: 16px; font-weight: 600; color: #fff; backgrou
43
43
  button:focus-visible { outline: 3px solid #fff; outline-offset: 2px; }
44
44
  .sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
45
45
  `;
46
- class se {
46
+ class ce {
47
47
  constructor(e = {}) {
48
48
  this.host = document.createElement("div");
49
49
  const s = this.host.attachShadow({ mode: "open" });
50
- s.innerHTML = `<style>${te}</style>
50
+ s.innerHTML = `<style>${le}</style>
51
51
  <div class="pcl">
52
52
  <div class="stage">
53
53
  <video playsinline muted autoplay></video>
@@ -95,35 +95,35 @@ class se {
95
95
  showPanel(e, s, i = "", n) {
96
96
  const a = e === "working" ? '<div class="spinner" aria-hidden="true"></div>' : `<div class="icon ${e}" aria-hidden="true">${e === "ok" ? "✓" : "!"}</div>`;
97
97
  if (this.panel.innerHTML = `${a}<p class="title"></p>${i ? '<p class="detail"></p>' : ""}${n ? '<button type="button"></button>' : ""}`, this.panel.querySelector(".title").textContent = s, i && (this.panel.querySelector(".detail").textContent = i), this.panel.hidden = !1, !n) return Promise.resolve();
98
- const o = this.panel.querySelector("button");
99
- return o.textContent = n, o.focus(), new Promise((r) => o.addEventListener("click", () => r(), { once: !0 }));
98
+ const r = this.panel.querySelector("button");
99
+ return r.textContent = n, r.focus(), new Promise((o) => r.addEventListener("click", () => o(), { once: !0 }));
100
100
  }
101
101
  hidePanel() {
102
102
  this.panel.hidden = !0, this.panel.innerHTML = "";
103
103
  }
104
104
  }
105
- const ie = { runtime: "liveness-runtime", runtimeCompat: "liveness-runtime-compat", model: "liveness-face.bin" }, ne = import.meta.url, ae = "assets/";
106
- function oe(t) {
107
- const e = new URL(t || ae, t ? document.baseURI : ne).href;
105
+ const de = { runtime: "liveness-runtime", runtimeCompat: "liveness-runtime-compat", model: "liveness-face.bin" }, he = import.meta.url, ue = "assets/";
106
+ function pe(t) {
107
+ const e = new URL(t || ue, t ? document.baseURI : he).href;
108
108
  return e.endsWith("/") ? e : e + "/";
109
109
  }
110
- class L extends Error {
110
+ class U extends Error {
111
111
  }
112
- class O {
112
+ class I {
113
113
  constructor(e) {
114
114
  this.engine = e, this.lastTs = 0, this.inferenceMs = [];
115
115
  }
116
116
  static async create(e, s = 2e4) {
117
- const i = oe(e), n = import("./liveness-device-C5ygqTPx.js").then((o) => o.createEngine(i, ie));
117
+ const i = pe(e), n = import("./liveness-device-C5ygqTPx.js").then((r) => r.createEngine(i, de));
118
118
  let a;
119
119
  try {
120
- const o = await Promise.race([n, new Promise((r, l) => {
121
- a = setTimeout(() => l(new L("face tracker load timed out")), s);
120
+ const r = await Promise.race([n, new Promise((o, l) => {
121
+ a = setTimeout(() => l(new U("face tracker load timed out")), s);
122
122
  })]);
123
- return new O(o);
124
- } catch (o) {
125
- throw n.then((r) => r.close(), () => {
126
- }), o instanceof L ? o : new L(String(o));
123
+ return new I(r);
124
+ } catch (r) {
125
+ throw n.then((o) => o.close(), () => {
126
+ }), r instanceof U ? r : new U(String(r));
127
127
  } finally {
128
128
  clearTimeout(a);
129
129
  }
@@ -143,24 +143,24 @@ class O {
143
143
  this.engine.close();
144
144
  }
145
145
  }
146
- function P(t) {
146
+ function x(t) {
147
147
  return t.faceCount >= 1 && t.yaw !== void 0;
148
148
  }
149
- class re {
149
+ class me {
150
150
  constructor(e = 0.5) {
151
151
  this.alpha = e;
152
152
  }
153
153
  apply(e) {
154
- return P(e) ? (this.yaw = this.yaw === void 0 ? e.yaw : this.alpha * e.yaw + (1 - this.alpha) * this.yaw, this.pitch = this.pitch === void 0 ? e.pitch : this.alpha * e.pitch + (1 - this.alpha) * this.pitch, { ...e, yaw: this.yaw, pitch: this.pitch }) : e;
154
+ return x(e) ? (this.yaw = this.yaw === void 0 ? e.yaw : this.alpha * e.yaw + (1 - this.alpha) * this.yaw, this.pitch = this.pitch === void 0 ? e.pitch : this.alpha * e.pitch + (1 - this.alpha) * this.pitch, { ...e, yaw: this.yaw, pitch: this.pitch }) : e;
155
155
  }
156
156
  }
157
- function le(t) {
157
+ function fe(t) {
158
158
  if (t.length === 0) return;
159
159
  const e = [...t].sort((i, n) => i - n), s = Math.floor(e.length / 2);
160
160
  return e.length % 2 ? e[s] : (e[s - 1] + e[s]) / 2;
161
161
  }
162
- const f = { turnHeadDeg: 20, nodDeg: 15, jawOpen: 0.4, smile: 0.5, blinkClosed: 0.6, blinkOpen: 0.25, blinkMaxMs: 600, poseHoldMs: 150, expressionHoldMs: 300, baselineMs: 300 };
163
- class A {
162
+ const w = { turnHeadDeg: 20, nodDeg: 15, jawOpen: 0.4, smile: 0.5, blinkClosed: 0.6, blinkOpen: 0.25, blinkMaxMs: 600, poseHoldMs: 150, expressionHoldMs: 300, baselineMs: 300 };
163
+ class R {
164
164
  constructor(e) {
165
165
  this.ms = e, this.since = null, this.misses = 0;
166
166
  }
@@ -168,17 +168,17 @@ class A {
168
168
  return s ? (this.since === null && (this.since = e), this.misses = 0, e - this.since >= this.ms) : this.since !== null && this.misses === 0 ? (this.misses = 1, !1) : (this.since = null, this.misses = 0, !1);
169
169
  }
170
170
  }
171
- class z {
171
+ class G {
172
172
  constructor(e, s, i) {
173
- this.axis = e, this.negative = s, this.threshold = i, this.passedAt = null, this.start = null, this.samples = [], this.extreme = 0, this.hold = new A(f.poseHoldMs), this.opposite = new A(f.poseHoldMs);
173
+ this.axis = e, this.negative = s, this.threshold = i, this.passedAt = null, this.start = null, this.samples = [], this.extreme = 0, this.hold = new R(w.poseHoldMs), this.opposite = new R(w.poseHoldMs);
174
174
  }
175
175
  feed(e) {
176
176
  if (this.passedAt !== null) return "passed";
177
- if (this.start === null && (this.start = e.t), !P(e)) return this.hold.update(e.t, !1), this.opposite.update(e.t, !1), "pending";
177
+ if (this.start === null && (this.start = e.t), !x(e)) return this.hold.update(e.t, !1), this.opposite.update(e.t, !1), "pending";
178
178
  const s = e[this.axis];
179
179
  if (this.baseline === void 0) {
180
- if (this.samples.push(s), e.t - this.start < f.baselineMs) return "pending";
181
- this.baseline = le(this.samples);
180
+ if (this.samples.push(s), e.t - this.start < w.baselineMs) return "pending";
181
+ this.baseline = fe(this.samples);
182
182
  }
183
183
  const i = s - this.baseline;
184
184
  (this.negative ? i < this.extreme : i > this.extreme) && (this.extreme = i);
@@ -186,80 +186,80 @@ class z {
186
186
  return this.opposite.update(e.t, a) ? "wrong_direction" : this.hold.update(e.t, n) ? (this.passedAt = e.t, "passed") : "pending";
187
187
  }
188
188
  get peak() {
189
- return this.axis === "yaw" ? { yaw: R(this.extreme) } : { pitch: R(this.extreme) };
189
+ return this.axis === "yaw" ? { yaw: D(this.extreme) } : { pitch: D(this.extreme) };
190
190
  }
191
191
  get confidence() {
192
- return U(Math.abs(this.extreme) / (this.threshold * 1.5));
192
+ return j(Math.abs(this.extreme) / (this.threshold * 1.5));
193
193
  }
194
194
  }
195
- class q {
195
+ class X {
196
196
  constructor(e, s) {
197
- this.attr = e, this.threshold = s, this.passedAt = null, this.highest = 0, this.hold = new A(f.expressionHoldMs);
197
+ this.attr = e, this.threshold = s, this.passedAt = null, this.highest = 0, this.hold = new R(w.expressionHoldMs);
198
198
  }
199
199
  feed(e) {
200
200
  if (this.passedAt !== null) return "passed";
201
- const s = P(e) ? e[this.attr] ?? 0 : 0;
202
- return this.highest = Math.max(this.highest, s), this.hold.update(e.t, P(e) && s >= this.threshold) ? (this.passedAt = e.t, "passed") : "pending";
201
+ const s = x(e) ? e[this.attr] ?? 0 : 0;
202
+ return this.highest = Math.max(this.highest, s), this.hold.update(e.t, x(e) && s >= this.threshold) ? (this.passedAt = e.t, "passed") : "pending";
203
203
  }
204
204
  get peak() {
205
- return { score: R(this.highest, 3) };
205
+ return { score: D(this.highest, 3) };
206
206
  }
207
207
  get confidence() {
208
- return U(this.highest);
208
+ return j(this.highest);
209
209
  }
210
210
  }
211
- class ce {
211
+ class we {
212
212
  constructor() {
213
213
  this.passedAt = null, this.closedAt = null, this.highest = 0;
214
214
  }
215
215
  feed(e) {
216
216
  if (this.passedAt !== null) return "passed";
217
- if (!P(e)) return "pending";
218
- if (this.highest = Math.max(this.highest, e.blink), e.blink >= f.blinkClosed) this.closedAt === null && (this.closedAt = e.t);
217
+ if (!x(e)) return "pending";
218
+ if (this.highest = Math.max(this.highest, e.blink), e.blink >= w.blinkClosed) this.closedAt === null && (this.closedAt = e.t);
219
219
  else if (this.closedAt !== null) {
220
- if (e.t - this.closedAt > f.blinkMaxMs) this.closedAt = null;
221
- else if (e.blink <= f.blinkOpen) return this.passedAt = this.closedAt, "passed";
220
+ if (e.t - this.closedAt > w.blinkMaxMs) this.closedAt = null;
221
+ else if (e.blink <= w.blinkOpen) return this.passedAt = this.closedAt, "passed";
222
222
  }
223
223
  return "pending";
224
224
  }
225
225
  get peak() {
226
- return { score: R(this.highest, 3) };
226
+ return { score: D(this.highest, 3) };
227
227
  }
228
228
  get confidence() {
229
- return U(this.highest);
229
+ return j(this.highest);
230
230
  }
231
231
  }
232
- function B(t, e) {
232
+ function J(t, e) {
233
233
  switch (t) {
234
234
  case "turn_head":
235
- return new z("yaw", e === "left", f.turnHeadDeg);
235
+ return new G("yaw", e === "left", w.turnHeadDeg);
236
236
  case "nod":
237
- return new z("pitch", e === "up", f.nodDeg);
237
+ return new G("pitch", e === "up", w.nodDeg);
238
238
  case "smile":
239
- return new q("smile", f.smile);
239
+ return new X("smile", w.smile);
240
240
  case "open_mouth":
241
- return new q("jawOpen", f.jawOpen);
241
+ return new X("jawOpen", w.jawOpen);
242
242
  case "blink":
243
- return new ce();
243
+ return new we();
244
244
  }
245
245
  }
246
- const x = { holdMs: 800, center: 0.1, minHeight: 0.35, maxHeight: 0.7, maxAngle: 12 };
247
- function de(t) {
248
- return t.faceCount > 1 ? "multiple_faces" : P(t) ? t.boxHeight < x.minHeight ? "move_closer" : t.boxHeight > x.maxHeight ? "move_back" : Math.abs(t.centerX - 0.5) > x.center || Math.abs(t.centerY - 0.5) > x.center ? "center" : Math.abs(t.yaw) > x.maxAngle || Math.abs(t.pitch) > x.maxAngle ? "look_straight" : "ok" : "no_face";
246
+ const k = { holdMs: 800, center: 0.1, minHeight: 0.35, maxHeight: 0.7, maxAngle: 12 };
247
+ function ge(t) {
248
+ return t.faceCount > 1 ? "multiple_faces" : x(t) ? t.boxHeight < k.minHeight ? "move_closer" : t.boxHeight > k.maxHeight ? "move_back" : Math.abs(t.centerX - 0.5) > k.center || Math.abs(t.centerY - 0.5) > k.center ? "center" : Math.abs(t.yaw) > k.maxAngle || Math.abs(t.pitch) > k.maxAngle ? "look_straight" : "ok" : "no_face";
249
249
  }
250
- class he {
250
+ class ve {
251
251
  constructor() {
252
- this.hold = new A(x.holdMs);
252
+ this.hold = new R(k.holdMs);
253
253
  }
254
254
  feed(e) {
255
- const s = de(e);
255
+ const s = ge(e);
256
256
  return { hint: s, ready: this.hold.update(e.t, s === "ok") };
257
257
  }
258
258
  }
259
- function N(t) {
260
- return P(t) && t.faceCount === 1 && Math.abs(t.yaw) < 10 && Math.abs(t.pitch) < 10 && t.blink < 0.3;
259
+ function Y(t) {
260
+ return x(t) && t.faceCount === 1 && Math.abs(t.yaw) < 10 && Math.abs(t.pitch) < 10 && t.blink < 0.3;
261
261
  }
262
- class ue {
262
+ class be {
263
263
  constructor() {
264
264
  this.multi = 0, this.lostSince = null;
265
265
  }
@@ -271,24 +271,24 @@ class ue {
271
271
  return null;
272
272
  }
273
273
  }
274
- function U(t) {
274
+ function j(t) {
275
275
  return Math.max(0, Math.min(1, t));
276
276
  }
277
- function R(t, e = 1) {
277
+ function D(t, e = 1) {
278
278
  const s = 10 ** e;
279
279
  return Math.round(t * s) / s;
280
280
  }
281
- const pe = "liveness-web", me = "0.1.0";
282
- function fe(t) {
281
+ const ye = "liveness-web", ke = "0.1.1";
282
+ function _e(t) {
283
283
  const e = navigator.userAgent, s = navigator.userAgentData;
284
- return { schema_version: 1, liveness_session_id: t.session.liveness_session_id, sdk: { name: pe, version: me }, platform: { os: (s?.platform || navigator.platform || "").slice(0, 64) || null, device: null, browser: e.slice(0, 64) }, camera: { width: t.camera.width ?? null, height: t.camera.height ?? null, fps_measured: t.camera.frameRate ?? null, facing: "user" }, video: { mime: t.video.mime, duration_ms: t.video.durationMs, started_at_epoch_ms: t.video.startedAtEpochMs }, mode: t.session.mode, challenges: t.challenges, flash: t.flash, stills: t.stills, device_result: { passed: !0, aborted_reason: null, mode: t.mode, fallback_reason: t.fallbackReason, frames_total: t.tally.framesTotal, frames_with_face: t.tally.framesWithFace, frames_with_two_faces: t.tally.framesWithTwoFaces } };
284
+ return { schema_version: 1, liveness_session_id: t.session.liveness_session_id, sdk: { name: ye, version: ke }, platform: { os: (s?.platform || navigator.platform || "").slice(0, 64) || null, device: null, browser: e.slice(0, 64) }, camera: { width: t.camera.width ?? null, height: t.camera.height ?? null, fps_measured: t.camera.frameRate ?? null, facing: "user" }, video: { mime: t.video.mime, duration_ms: t.video.durationMs, started_at_epoch_ms: t.video.startedAtEpochMs }, mode: t.session.mode, challenges: t.challenges, flash: t.flash, stills: t.stills, device_result: { passed: !0, aborted_reason: null, mode: t.mode, fallback_reason: t.fallbackReason, frames_total: t.tally.framesTotal, frames_with_face: t.tally.framesWithFace, frames_with_two_faces: t.tally.framesWithTwoFaces } };
285
285
  }
286
286
  class p extends Error {
287
287
  constructor(e, s) {
288
288
  super(s || e), this.code = e;
289
289
  }
290
290
  }
291
- async function we() {
291
+ async function K() {
292
292
  if (!window.isSecureContext) throw new p("insecure_context", "The camera needs an https page");
293
293
  if (!navigator.mediaDevices?.getUserMedia) throw new p("unsupported_browser");
294
294
  if (typeof MediaRecorder > "u") throw new p("unsupported_browser");
@@ -299,16 +299,16 @@ async function we() {
299
299
  throw e === "NotAllowedError" || e === "SecurityError" ? new p("camera_denied") : new p("camera_unavailable", e);
300
300
  }
301
301
  }
302
- function ge(t) {
302
+ function Q(t) {
303
303
  t?.getTracks().forEach((e) => e.stop());
304
304
  }
305
- function ve(t = (e) => MediaRecorder.isTypeSupported(e)) {
305
+ function xe(t = (e) => MediaRecorder.isTypeSupported(e)) {
306
306
  return ["video/mp4;codecs=avc1.42E01E", "video/mp4", "video/webm;codecs=vp9", "video/webm;codecs=vp8", "video/webm"].find((e) => t(e)) || "";
307
307
  }
308
- class be {
308
+ class Me {
309
309
  constructor(e, s = 12e5) {
310
310
  this.chunks = [], this.t0 = 0, this.epoch = 0;
311
- const i = ve();
311
+ const i = xe();
312
312
  this.recorder = new MediaRecorder(e, i ? { mimeType: i, videoBitsPerSecond: s } : { videoBitsPerSecond: s }), this.recorder.ondataavailable = (n) => {
313
313
  n.data && n.data.size && this.chunks.push(n.data);
314
314
  };
@@ -332,21 +332,23 @@ class be {
332
332
  }
333
333
  }
334
334
  }
335
- async function ye(t, e) {
335
+ async function Pe(t, e) {
336
336
  const s = t.videoWidth, i = t.videoHeight, n = Math.min(1, 1280 / Math.max(s, i)), a = document.createElement("canvas");
337
337
  a.width = Math.round(s * n), a.height = Math.round(i * n), a.getContext("2d").drawImage(t, 0, 0, a.width, a.height);
338
- let o = 0.9;
338
+ let r = 0.9;
339
339
  for (; ; ) {
340
- const r = await new Promise((l) => a.toBlob(l, "image/jpeg", o));
341
- if (!r) throw new p("capture_failed");
342
- if (r.size <= e || o <= 0.45) return r;
343
- o -= 0.1;
340
+ const o = await new Promise((l) => a.toBlob(l, "image/jpeg", r));
341
+ if (!o) throw new p("capture_failed");
342
+ if (o.size <= e || r <= 0.45) return o;
343
+ r -= 0.1;
344
344
  }
345
345
  }
346
- const M = (t) => new Promise((e) => setTimeout(e, t)), V = () => new Promise((t) => requestAnimationFrame(t)), ke = 120, _e = 700, xe = 400, Me = 1e3, Pe = 5e3, Ce = 2200;
347
- class C extends Error {
346
+ const _ = (t) => new Promise((e) => setTimeout(e, t)), Ce = () => new Promise((t) => requestAnimationFrame(t)), Te = 120, Se = 700, Ee = 400, Ae = 1e3, Re = 5e3, De = 2200;
347
+ class A extends Error {
348
+ }
349
+ class Z extends Error {
348
350
  }
349
- function H(t, e) {
351
+ function W(t, e) {
350
352
  switch (t.type) {
351
353
  case "turn_head":
352
354
  return t.direction === "left" ? e.turnLeft : e.turnRight;
@@ -360,7 +362,7 @@ function H(t, e) {
360
362
  return e.openMouth;
361
363
  }
362
364
  }
363
- function Te(t, e) {
365
+ function Fe(t, e) {
364
366
  switch (t) {
365
367
  case "ok":
366
368
  return e.lookStraight;
@@ -378,131 +380,141 @@ function Te(t, e) {
378
380
  return e.lookStraight;
379
381
  }
380
382
  }
381
- async function Se(t) {
382
- const { session: e, view: s, strings: i } = t, n = t.mode === "device" && t.tracker !== null, a = new re(), o = { framesTotal: 0, framesWithFace: 0, framesWithTwoFaces: 0 };
383
- let r = null;
384
- const l = () => {
385
- if (t.isCancelled()) throw new C();
386
- }, w = () => new Promise((h) => {
387
- const d = s.video;
388
- d.requestVideoFrameCallback ? d.requestVideoFrameCallback(() => h()) : requestAnimationFrame(() => h()), setTimeout(h, 250);
389
- }), b = async (h, d) => {
390
- await w(), l();
391
- const m = a.apply(t.tracker.detect(s.video, h));
392
- return d && (o.framesTotal++, m.faceCount >= 1 && o.framesWithFace++, m.faceCount >= 2 && o.framesWithTwoFaces++), m;
383
+ async function Le(t) {
384
+ const { session: e, view: s, strings: i } = t, n = t.mode === "device" && t.tracker !== null, a = new me(), r = { framesTotal: 0, framesWithFace: 0, framesWithTwoFaces: 0 };
385
+ let o = null, l = !1, m = () => {
386
+ };
387
+ const P = new Promise((d) => {
388
+ m = d;
389
+ }), M = () => {
390
+ document.visibilityState === "hidden" && (l = !0, m());
391
+ };
392
+ M(), document.addEventListener("visibilitychange", M);
393
+ const c = () => {
394
+ if (t.isCancelled()) throw new A();
395
+ if (l) throw new Z();
396
+ }, C = async () => {
397
+ const d = await Promise.race([Ce(), P.then(() => NaN)]);
398
+ return c(), d;
399
+ }, E = () => new Promise((d) => {
400
+ const f = s.video;
401
+ f.requestVideoFrameCallback ? f.requestVideoFrameCallback(() => d()) : requestAnimationFrame(() => d()), setTimeout(d, 250);
402
+ }), u = async (d, f) => {
403
+ await E(), c();
404
+ const b = a.apply(t.tracker.detect(s.video, d));
405
+ return f && (r.framesTotal++, b.faceCount >= 1 && r.framesWithFace++, b.faceCount >= 2 && r.framesWithTwoFaces++), b;
393
406
  };
394
407
  try {
395
- let h = null;
408
+ let d = null;
396
409
  if (n) {
397
- const v = new he(), y = performance.now();
398
- let c = 0;
410
+ const g = new ve(), v = performance.now();
411
+ let h = 0;
399
412
  for (; ; ) {
400
- h = await b(performance.now() - y, !1), c++;
401
- const S = t.tracker.medianInferenceMs();
402
- if (c >= 15 && S !== null && S > ke) return { kind: "fallback", reason: "slow_device" };
403
- const { hint: _, ready: E } = v.feed(h);
404
- if (s.setPrompt(Te(_, i)), s.setOval(_ === "ok" ? "ok" : "warn"), E) break;
413
+ d = await u(performance.now() - v, !1), h++;
414
+ const T = t.tracker.medianInferenceMs();
415
+ if (h >= 15 && T !== null && T > Te) return { kind: "fallback", reason: "slow_device" };
416
+ const { hint: y, ready: S } = g.feed(d);
417
+ if (s.setPrompt(Fe(y, i)), s.setOval(y === "ok" ? "ok" : "warn"), S) break;
405
418
  }
406
419
  }
407
- r = new be(t.stream), await r.start(), t.emit({ type: "recording_started" });
408
- const d = e.limits.max_video_seconds * 1e3, m = [], T = [], u = async (v) => {
409
- T.push({ index: m.length, captured_at_ms: r.now(), reason: v }), m.push(await ye(s.video, e.limits.max_still_bytes));
420
+ o = new Me(t.stream), await o.start(), t.emit({ type: "recording_started" });
421
+ const f = e.limits.max_video_seconds * 1e3, b = [], $ = [], F = async (g) => {
422
+ $.push({ index: b.length, captured_at_ms: o.now(), reason: g }), b.push(await Pe(s.video, e.limits.max_still_bytes));
410
423
  };
411
424
  if (n) {
412
- const v = performance.now() + 1e3;
413
- for (; h && !N(h) && performance.now() < v; ) h = await b(r.now(), !0);
414
- await u("positioning");
415
- } else s.setOval("idle"), s.setPrompt(i.lookStraight), await M(1500), l(), await u("positioning");
416
- const g = [], k = [], D = e.challenges.length;
425
+ const g = performance.now() + 1e3;
426
+ for (; d && !Y(d) && performance.now() < g; ) d = await u(o.now(), !0);
427
+ await F("positioning");
428
+ } else s.setOval("idle"), s.setPrompt(i.lookStraight), await _(1500), c(), await F("positioning");
429
+ const L = [], q = [], H = e.challenges.length;
417
430
  if (e.mode === "active") {
418
- const v = new ue();
419
- for (const [y, c] of e.challenges.entries()) {
420
- s.setProgress(D, y, y), s.setPrompt(H(c, i)), s.setOval("idle"), t.emit({ type: "challenge_started", challenge: c });
421
- const S = r.now();
431
+ const g = new be();
432
+ for (const [v, h] of e.challenges.entries()) {
433
+ s.setProgress(H, v, v), s.setPrompt(W(h, i)), s.setOval("idle"), t.emit({ type: "challenge_started", challenge: h });
434
+ const T = o.now();
422
435
  if (n) {
423
- let _ = B(c.type, c.direction), E = 1, W = performance.now();
436
+ let y = J(h.type, h.direction), S = 1, z = performance.now();
424
437
  for (; ; ) {
425
- const I = await b(r.now(), !0), j = v.feed(I);
426
- if (j) return { kind: "aborted", reason: j };
427
- if (r.now() > d - Pe) return { kind: "aborted", reason: "too_slow" };
428
- const $ = _.feed(I);
429
- if ($ === "wrong_direction") return { kind: "aborted", reason: "wrong_direction" };
430
- if ($ === "passed") {
431
- g.push({ order: c.order, type: c.type, direction: c.direction, start_ms: S, end_ms: r.now(), passed: !0, confidence: Ae(_.confidence), timed_out: E > 1, peak: _.peak }), k.push(c.type), s.setOval("ok"), s.setPrompt(i.great), s.setProgress(D, y + 1, null), t.emit({ type: "challenge_passed", challenge: c }), await M(xe);
438
+ const B = await u(o.now(), !0), N = g.feed(B);
439
+ if (N) return { kind: "aborted", reason: N };
440
+ if (o.now() > f - Re) return { kind: "aborted", reason: "too_slow" };
441
+ const V = y.feed(B);
442
+ if (V === "wrong_direction") return { kind: "aborted", reason: "wrong_direction" };
443
+ if (V === "passed") {
444
+ L.push({ order: h.order, type: h.type, direction: h.direction, start_ms: T, end_ms: o.now(), passed: !0, confidence: Oe(y.confidence), timed_out: S > 1, peak: y.peak }), q.push(h.type), s.setOval("ok"), s.setPrompt(i.great), s.setProgress(H, v + 1, null), t.emit({ type: "challenge_passed", challenge: h }), await _(Ee);
432
445
  break;
433
446
  }
434
- if (performance.now() - W > c.timeout_ms) {
435
- if (E > 1) return { kind: "aborted", reason: `challenge_timeout:${c.type}` };
436
- E = 2, _ = B(c.type, c.direction), W = performance.now(), s.setPrompt(H(c, i));
447
+ if (performance.now() - z > h.timeout_ms) {
448
+ if (S > 1) return { kind: "aborted", reason: `challenge_timeout:${h.type}` };
449
+ S = 2, y = J(h.type, h.direction), z = performance.now(), s.setPrompt(W(h, i));
437
450
  }
438
451
  }
439
- } else await G(s, t, t.timedWindowMs, H(c, i)), g.push({ order: c.order, type: c.type, direction: c.direction, start_ms: S, end_ms: r.now(), passed: null, confidence: null, timed_out: !1, peak: null }), s.setProgress(D, y + 1, null), s.setPrompt(i.lookStraight), await M(_e), l();
452
+ } else await ee(s, c, t.timedWindowMs, W(h, i)), L.push({ order: h.order, type: h.type, direction: h.direction, start_ms: T, end_ms: o.now(), passed: null, confidence: null, timed_out: !1, peak: null }), s.setProgress(H, v + 1, null), s.setPrompt(i.lookStraight), await _(Se), c();
440
453
  }
441
- } else await G(s, t, Ce, i.holdStill);
442
- const Y = await Ee(t, r);
443
- if (s.setFlash(null), s.setPrompt(i.lookStraight), n) {
444
- const v = performance.now() + 2e3;
454
+ } else await ee(s, c, De, i.holdStill);
455
+ const ie = await He(t, o, c, C);
456
+ if (c(), s.setFlash(null), s.setPrompt(i.lookStraight), n) {
457
+ const g = performance.now() + 2e3;
445
458
  for (; ; ) {
446
- const y = await b(r.now(), !0);
447
- if (N(y) || performance.now() > v) break;
459
+ const v = await u(o.now(), !0);
460
+ if (Y(v) || performance.now() > g) break;
448
461
  }
449
- } else await M(1500), l();
450
- await u("return_to_centre");
451
- const K = r.now(), Q = r.epoch, F = await r.stop();
452
- if (r = null, F.size > e.limits.max_video_bytes) throw new p("recording_too_large");
453
- const Z = fe({ session: e, mode: t.mode, fallbackReason: t.fallbackReason, camera: t.stream.getVideoTracks()[0]?.getSettings() ?? {}, video: { mime: F.type, durationMs: K, startedAtEpochMs: Q }, challenges: g, flash: Y, stills: T, tally: o });
454
- return { kind: "recorded", video: F, stills: m, metadata: Z, passedChallenges: k };
462
+ } else await _(1500), c();
463
+ await F("return_to_centre"), c();
464
+ const ne = o.now(), ae = o.epoch, O = await o.stop();
465
+ if (o = null, O.size > e.limits.max_video_bytes) throw new p("recording_too_large");
466
+ const re = _e({ session: e, mode: t.mode, fallbackReason: t.fallbackReason, camera: t.stream.getVideoTracks()[0]?.getSettings() ?? {}, video: { mime: O.type, durationMs: ne, startedAtEpochMs: ae }, challenges: L, flash: ie, stills: $, tally: r });
467
+ return { kind: "recorded", video: O, stills: b, metadata: re, passedChallenges: q };
468
+ } catch (d) {
469
+ if (d instanceof Z) return { kind: "aborted", reason: "interrupted" };
470
+ throw d;
455
471
  } finally {
456
- r?.abort(), s.setFlash(null), s.setCountdown(null), s.setDebug(null);
472
+ document.removeEventListener("visibilitychange", M), o?.abort(), s.setFlash(null), s.setCountdown(null), s.setDebug(null);
457
473
  }
458
474
  }
459
- async function G(t, e, s, i) {
475
+ async function ee(t, e, s, i) {
460
476
  t.setPrompt(i);
461
477
  const n = performance.now() + s;
462
- for (; performance.now() < n; ) {
463
- if (e.isCancelled()) throw new C();
464
- t.setCountdown(Math.ceil((n - performance.now()) / 1e3)), await M(100);
465
- }
478
+ for (; performance.now() < n; ) e(), t.setCountdown(Math.ceil((n - performance.now()) / 1e3)), await _(100);
466
479
  t.setCountdown(null);
467
480
  }
468
- async function Ee(t, e) {
469
- const s = t.session.flash, i = { enabled: !1, started_at_ms: null, segments: [], screen_brightness: null, exposure_locked: !1, skipped_reason: null };
470
- if (!s.enabled) return i;
471
- if (!t.allowFlash) return { ...i, skipped_reason: "disabled_by_host" };
472
- if (window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) return { ...i, skipped_reason: "reduced_motion" };
473
- if (t.emit({ type: "flash_started" }), t.view.setFlash("#000000"), t.view.setPrompt(t.strings.flashIntro), await M(Me), t.isCancelled()) throw new C();
474
- t.view.setPrompt(""), i.enabled = !0;
475
- for (const n of s.segments) {
476
- await V(), t.view.setFlash(n.color);
477
- const a = await V(), o = Math.round(a - e.t0);
478
- i.started_at_ms === null && (i.started_at_ms = o), await M(Math.max(0, n.duration_ms - (performance.now() - a))), i.segments.push({ color: n.color, start_ms: o, end_ms: e.now() });
479
- }
480
- return t.view.setFlash(null), t.emit({ type: "flash_ended" }), i;
481
- }
482
- function Ae(t) {
481
+ async function He(t, e, s, i) {
482
+ const n = t.session.flash, a = { enabled: !1, started_at_ms: null, segments: [], screen_brightness: null, exposure_locked: !1, skipped_reason: null };
483
+ if (!n.enabled) return a;
484
+ if (!t.allowFlash) return { ...a, skipped_reason: "disabled_by_host" };
485
+ if (window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) return { ...a, skipped_reason: "reduced_motion" };
486
+ t.emit({ type: "flash_started" }), t.view.setFlash("#000000"), t.view.setPrompt(t.strings.flashIntro), await _(Ae), s(), t.view.setPrompt(""), a.enabled = !0;
487
+ for (const r of n.segments) {
488
+ await i(), t.view.setFlash(r.color);
489
+ const o = await i(), l = Math.round(o - e.t0);
490
+ a.started_at_ms === null && (a.started_at_ms = l), await _(Math.max(0, r.duration_ms - (performance.now() - o))), a.segments.push({ color: r.color, start_ms: l, end_ms: e.now() });
491
+ }
492
+ return t.view.setFlash(null), t.emit({ type: "flash_ended" }), a;
493
+ }
494
+ function Oe(t) {
483
495
  return Math.round(t * 100) / 100;
484
496
  }
485
- const Re = 6e4;
486
- async function De(t, e, s) {
497
+ const Ue = 6e4;
498
+ async function We(t, e, s) {
487
499
  const i = new FormData();
488
- i.append("video", s.video, s.video.type === "video/mp4" ? "attempt.mp4" : "attempt.webm"), s.stills.forEach((a, o) => i.append("stills", a, `${o}.jpg`)), i.append("metadata", JSON.stringify(s.metadata)), i.append("token", e.token);
500
+ i.append("video", s.video, s.video.type === "video/mp4" ? "attempt.mp4" : "attempt.webm"), s.stills.forEach((a, r) => i.append("stills", a, `${r}.jpg`)), i.append("metadata", JSON.stringify(s.metadata)), i.append("token", e.token);
489
501
  const n = t.replace(/\/+$/, "") + e.upload_url;
490
502
  for (let a = 1; ; a++) {
491
- const o = new AbortController(), r = setTimeout(() => o.abort(), Re);
503
+ const r = new AbortController(), o = setTimeout(() => r.abort(), Ue);
492
504
  let l;
493
505
  try {
494
- l = await fetch(n, { method: "POST", body: i, signal: o.signal });
495
- } catch (b) {
496
- if (clearTimeout(r), a < 2) continue;
497
- throw new p("network", String(b));
506
+ l = await fetch(n, { method: "POST", body: i, signal: r.signal });
507
+ } catch (P) {
508
+ if (clearTimeout(o), a < 2) continue;
509
+ throw new p("network", String(P));
498
510
  }
499
- clearTimeout(r);
500
- const w = await l.json().catch(() => ({}));
501
- if (l.ok) return w;
502
- throw new p(Fe(l.status), Le(w) || `HTTP ${l.status}`);
511
+ clearTimeout(o);
512
+ const m = await l.json().catch(() => ({}));
513
+ if (l.ok) return m;
514
+ throw new p(Ie(l.status), je(m) || `HTTP ${l.status}`);
503
515
  }
504
516
  }
505
- function Fe(t) {
517
+ function Ie(t) {
506
518
  switch (t) {
507
519
  case 401:
508
520
  return "session_invalid";
@@ -522,73 +534,76 @@ function Fe(t) {
522
534
  return "server_error";
523
535
  }
524
536
  }
525
- function Le(t) {
537
+ function je(t) {
526
538
  const e = t?.detail;
527
539
  return e && typeof e == "object" && "error" in e ? String(e.error) : typeof e == "string" ? e : null;
528
540
  }
529
- const He = { wrong_direction: "wrongDirection", face_lost: "faceLost", multiple_faces: "multipleFaces", too_slow: "tooSlow" }, Oe = { camera_denied: "cameraDenied", camera_unavailable: "cameraUnavailable", unsupported_browser: "unsupportedBrowser", insecure_context: "insecureContext", network: "network", session_expired: "sessionExpired", session_invalid: "sessionExpired", service_unavailable: "serviceUnavailable", attempts_exhausted: "noAttemptsDetail" };
530
- class Ue {
541
+ const $e = { interrupted: "interrupted", wrong_direction: "wrongDirection", face_lost: "faceLost", multiple_faces: "multipleFaces", too_slow: "tooSlow" }, qe = { camera_denied: "cameraDenied", camera_unavailable: "cameraUnavailable", unsupported_browser: "unsupportedBrowser", insecure_context: "insecureContext", network: "network", session_expired: "sessionExpired", session_invalid: "sessionExpired", service_unavailable: "serviceUnavailable", attempts_exhausted: "noAttemptsDetail" };
542
+ class ze {
531
543
  constructor(e) {
532
544
  if (this.config = e, this.view = null, this.stream = null, this.tracker = null, this.cancelled = !1, this.running = !1, this.wakeOnCancel = null, !e.baseUrl) throw new Error("PowerCredLiveness: baseUrl is required");
533
545
  if (!e.session && !e.sessionProvider) throw new Error("PowerCredLiveness: pass session or sessionProvider");
534
- this.strings = { ...ee, ...e.strings || {} };
546
+ this.strings = { ...oe, ...e.strings || {} };
535
547
  }
536
548
  async start(e) {
537
549
  if (this.running) throw new Error("PowerCredLiveness: already running");
538
550
  this.running = !0, this.cancelled = !1;
539
- const s = this.strings, i = this.view = new se(this.config.theme);
551
+ const s = this.strings, i = this.view = new ce(this.config.theme);
540
552
  i.mount(e), i.setPrompt(s.gettingReady);
541
553
  let n = null, a = null;
542
554
  try {
543
555
  if (n = this.config.session ?? await this.config.sessionProvider(), Date.parse(n.expires_at) < Date.now()) throw new p("session_expired");
544
- const o = n.client_checks === "none" ? "none" : "device", r = o === "device" ? O.create(this.config.assetsUrl).catch(() => null) : Promise.resolve(null);
545
- this.stream = await we(), await i.attach(this.stream), this.emit({ type: "camera_ready" }), this.tracker = await r;
546
- let l = o === "device" && this.tracker ? "device" : "none", w = o === "device" && !this.tracker ? "model_unavailable" : null;
547
- this.emit({ type: "mode", mode: l, fallbackReason: w });
548
- const b = this.config.maxLocalRetries ?? 2;
549
- let h = 0;
556
+ const r = n.client_checks === "none" ? "none" : "device", o = r === "device" ? I.create(this.config.assetsUrl).catch(() => null) : Promise.resolve(null);
557
+ this.stream = await K(), await i.attach(this.stream), this.emit({ type: "camera_ready" }), this.tracker = await o;
558
+ let l = r === "device" && this.tracker ? "device" : "none", m = r === "device" && !this.tracker ? "model_unavailable" : null;
559
+ this.emit({ type: "mode", mode: l, fallbackReason: m });
560
+ const P = this.config.maxLocalRetries ?? 2;
561
+ let M = 0;
550
562
  for (; ; ) {
551
- const d = await Se({ session: n, view: i, strings: s, stream: this.stream, tracker: l === "device" ? this.tracker : null, mode: l, fallbackReason: w, allowFlash: this.config.flash !== !1, timedWindowMs: Math.round((this.config.timedWindowSeconds ?? 3.5) * 1e3), debug: !1, emit: (g) => this.emit(g), isCancelled: () => this.cancelled });
552
- if (d.kind === "fallback") {
553
- this.tracker?.close(), this.tracker = null, l = "none", w = d.reason, this.emit({ type: "mode", mode: l, fallbackReason: w });
563
+ const c = await Le({ session: n, view: i, strings: s, stream: this.stream, tracker: l === "device" ? this.tracker : null, mode: l, fallbackReason: m, allowFlash: this.config.flash !== !1, timedWindowMs: Math.round((this.config.timedWindowSeconds ?? 3.5) * 1e3), debug: !1, emit: (d) => this.emit(d), isCancelled: () => this.cancelled });
564
+ if (c.kind === "fallback") {
565
+ this.tracker?.close(), this.tracker = null, l = "none", m = c.reason, this.emit({ type: "mode", mode: l, fallbackReason: m });
554
566
  continue;
555
567
  }
556
- if (a = { mode: l, fallbackReason: w, passedChallenges: d.kind === "recorded" ? d.passedChallenges : [] }, d.kind === "aborted") {
557
- this.emit({ type: "attempt_aborted", reason: d.reason }), h++;
558
- const g = s[He[d.reason] ?? "timeUp"];
559
- if (h > b) return this.config.showResult !== !1 && await i.showPanel("bad", s.failedTitle, s.failedDetail), this.finish({ status: "failed", livenessSessionId: n.liveness_session_id, device: a, reason: d.reason });
560
- await this.untilCancelled(i.showPanel("bad", g, "", s.tryAgain)), i.hidePanel();
568
+ if (a = { mode: l, fallbackReason: m, passedChallenges: c.kind === "recorded" ? c.passedChallenges : [] }, c.kind === "aborted") {
569
+ this.emit({ type: "attempt_aborted", reason: c.reason }), c.reason !== "interrupted" && M++;
570
+ const d = s[$e[c.reason] ?? "timeUp"];
571
+ if (M > P) return this.config.showResult !== !1 && await i.showPanel("bad", s.failedTitle, s.failedDetail), this.finish({ status: "failed", livenessSessionId: n.liveness_session_id, device: a, reason: c.reason });
572
+ await this.untilCancelled(i.showPanel("bad", d, "", s.tryAgain)), i.hidePanel(), await this.ensureCamera(i);
561
573
  continue;
562
574
  }
563
- const m = d.stills[d.stills.length - 1], T = () => De(this.config.baseUrl, n, d);
564
- if (this.emit({ type: "uploading", bytes: d.video.size }), this.config.waitForServer === !1) {
565
- const g = n.liveness_session_id;
566
- return T().then((k) => this.serverResult(k), (k) => this.emit({ type: "error", code: X(k), message: J(k) })), this.config.showResult !== !1 && await i.showPanel("ok", s.submittedTitle), this.finish({ status: "submitted", livenessSessionId: g, device: a, selfie: m });
575
+ const C = c.stills[c.stills.length - 1], E = () => We(this.config.baseUrl, n, c);
576
+ if (this.emit({ type: "uploading", bytes: c.video.size }), this.config.waitForServer === !1) {
577
+ const d = n.liveness_session_id;
578
+ return E().then((f) => this.serverResult(f), (f) => this.emit({ type: "error", code: te(f), message: se(f) })), this.config.showResult !== !1 && await i.showPanel("ok", s.submittedTitle), this.finish({ status: "submitted", livenessSessionId: d, device: a, selfie: C });
567
579
  }
568
580
  await i.showPanel("working", s.checking);
569
- const u = await T();
570
- if (this.serverResult(u), u.status === "passed") return this.config.showResult !== !1 && await i.showPanel("ok", s.passedTitle, s.passedDetail), this.finish({ status: "passed", livenessSessionId: u.liveness_session_id, attempt: u.attempt, device: a, server: u, retryAllowed: !1, selfie: m });
581
+ const u = await E();
582
+ if (this.serverResult(u), u.status === "passed") return this.config.showResult !== !1 && await i.showPanel("ok", s.passedTitle, s.passedDetail), this.finish({ status: "passed", livenessSessionId: u.liveness_session_id, attempt: u.attempt, device: a, server: u, retryAllowed: !1, selfie: C });
571
583
  if (u.retry_allowed) {
572
- await this.untilCancelled(i.showPanel("bad", s.failedTitle, s.failedDetail, s.tryAgain)), i.hidePanel();
584
+ await this.untilCancelled(i.showPanel("bad", s.failedTitle, s.failedDetail, s.tryAgain)), i.hidePanel(), await this.ensureCamera(i);
573
585
  continue;
574
586
  }
575
- return this.config.showResult !== !1 && await i.showPanel("bad", s.failedTitle, s.noAttemptsDetail), this.finish({ status: u.status === "inconclusive" ? "inconclusive" : "failed", livenessSessionId: u.liveness_session_id, attempt: u.attempt, device: a, server: u, retryAllowed: !1, selfie: m });
587
+ return this.config.showResult !== !1 && await i.showPanel("bad", s.failedTitle, s.noAttemptsDetail), this.finish({ status: u.status === "inconclusive" ? "inconclusive" : "failed", livenessSessionId: u.liveness_session_id, attempt: u.attempt, device: a, server: u, retryAllowed: !1, selfie: C });
576
588
  }
577
- } catch (o) {
578
- if (o instanceof C) return this.finish({ status: "cancelled", livenessSessionId: n?.liveness_session_id ?? null, device: a, reason: "cancelled" });
579
- const r = X(o);
580
- this.emit({ type: "error", code: r, message: J(o) });
581
- const l = s[Oe[r] ?? "genericError"];
582
- return this.config.showResult !== !1 && await i.showPanel("bad", l), this.finish({ status: "error", livenessSessionId: n?.liveness_session_id ?? null, device: a, reason: r });
589
+ } catch (r) {
590
+ if (r instanceof A) return this.finish({ status: "cancelled", livenessSessionId: n?.liveness_session_id ?? null, device: a, reason: "cancelled" });
591
+ const o = te(r);
592
+ this.emit({ type: "error", code: o, message: se(r) });
593
+ const l = s[qe[o] ?? "genericError"];
594
+ return this.config.showResult !== !1 && await i.showPanel("bad", l), this.finish({ status: "error", livenessSessionId: n?.liveness_session_id ?? null, device: a, reason: o });
583
595
  }
584
596
  }
597
+ async ensureCamera(e) {
598
+ this.stream?.getVideoTracks().some((s) => s.readyState === "live") || (Q(this.stream), this.stream = await K(), await e.attach(this.stream));
599
+ }
585
600
  cancel() {
586
601
  this.cancelled = !0, this.wakeOnCancel?.();
587
602
  }
588
603
  untilCancelled(e) {
589
604
  return new Promise((s, i) => {
590
- if (this.cancelled) return i(new C());
591
- this.wakeOnCancel = () => i(new C()), e.then(() => {
605
+ if (this.cancelled) return i(new A());
606
+ this.wakeOnCancel = () => i(new A()), e.then(() => {
592
607
  this.wakeOnCancel = null, s();
593
608
  });
594
609
  });
@@ -600,7 +615,7 @@ class Ue {
600
615
  return this.release(), this.running = !1, e;
601
616
  }
602
617
  release() {
603
- ge(this.stream), this.stream = null, this.tracker?.close(), this.tracker = null;
618
+ Q(this.stream), this.stream = null, this.tracker?.close(), this.tracker = null;
604
619
  }
605
620
  serverResult(e) {
606
621
  this.emit({ type: "server_result", result: e });
@@ -616,15 +631,15 @@ class Ue {
616
631
  }
617
632
  }
618
633
  }
619
- function X(t) {
634
+ function te(t) {
620
635
  return t instanceof p ? t.code : "unexpected";
621
636
  }
622
- function J(t) {
637
+ function se(t) {
623
638
  return t instanceof p ? t.message : "Unexpected error";
624
639
  }
625
- const We = "0.1.0";
640
+ const Be = "0.1.1";
626
641
  export {
627
- Ue as PowerCredLiveness,
628
- We as VERSION,
629
- ee as defaultStrings
642
+ ze as PowerCredLiveness,
643
+ Be as VERSION,
644
+ oe as defaultStrings
630
645
  };