@monitordog/detector 1.0.8 → 1.0.10

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.
@@ -64,24 +64,24 @@ function h(e) {
64
64
  }
65
65
  //#endregion
66
66
  //#region src/events.ts
67
- function g(e) {
68
- if (e.faceCount === 0) return y("noFaceDetected", e);
69
- if (e.faceCount >= 2) return y("twoFacesDetected", e);
70
- if (e.phoneCount >= 1) return y("mobileDevice", e);
67
+ function ee(e) {
68
+ if (e.faceCount === 0) return _("noFaceDetected", e);
69
+ if (e.faceCount >= 2) return _("twoFacesDetected", e);
70
+ if (e.phoneCount >= 1) return _("mobileDevice", e);
71
71
  }
72
- function _(e) {
72
+ function te(e) {
73
73
  return {
74
- ...b(e, (/* @__PURE__ */ new Date()).toISOString()),
74
+ ...v(e, (/* @__PURE__ */ new Date()).toISOString()),
75
75
  properties: {},
76
76
  webcam_imgs: [],
77
77
  monitor_imgs: []
78
78
  };
79
79
  }
80
- function v(e) {
80
+ function g(e) {
81
81
  return e.phoneCount === 0 && e.faceCount === 1;
82
82
  }
83
- function y(e, t) {
84
- let n = b(e, (/* @__PURE__ */ new Date()).toISOString());
83
+ function _(e, t) {
84
+ let n = v(e, (/* @__PURE__ */ new Date()).toISOString());
85
85
  switch (e) {
86
86
  case "noFaceDetected": return {
87
87
  type: e,
@@ -98,7 +98,7 @@ function y(e, t) {
98
98
  payload: {
99
99
  ...n,
100
100
  properties: {
101
- confidence: x(t.faceDetections),
101
+ confidence: y(t.faceDetections),
102
102
  spots: t.faceDetections
103
103
  }
104
104
  }
@@ -108,16 +108,16 @@ function y(e, t) {
108
108
  payload: {
109
109
  ...n,
110
110
  properties: {
111
- confidence: x(t.phoneDetections),
111
+ confidence: y(t.phoneDetections),
112
112
  spots: t.phoneDetections
113
113
  }
114
114
  }
115
115
  };
116
116
  }
117
117
  }
118
- function b(e, t) {
118
+ function v(e, t) {
119
119
  return {
120
- basic_event_uuid: S(e),
120
+ basic_event_uuid: b(e),
121
121
  occured_at: t,
122
122
  sended_at: (/* @__PURE__ */ new Date()).toISOString(),
123
123
  device_type: l(),
@@ -125,10 +125,10 @@ function b(e, t) {
125
125
  device_id: "browser"
126
126
  };
127
127
  }
128
- function x(e) {
128
+ function y(e) {
129
129
  return e.reduce((e, t) => Math.max(e, t.score), 0);
130
130
  }
131
- function S(e) {
131
+ function b(e) {
132
132
  switch (e) {
133
133
  case "logout": return "12ca646a-d832-4581-b03c-48f95627507f";
134
134
  case "login": return "4c6f98ea-88d8-4215-9b6a-9b3ccb753465";
@@ -140,9 +140,9 @@ function S(e) {
140
140
  }
141
141
  //#endregion
142
142
  //#region src/service/auth-service.ts
143
- var C = "MonitorDog token refresh was superseded.", w = 300 * 1e3, T = class {
143
+ var x = "MonitorDog token refresh was superseded.", S = 300 * 1e3, C = class {
144
144
  services;
145
- refreshBeforeMs = w;
145
+ refreshBeforeMs = S;
146
146
  periodicRefreshIntervalMs = r;
147
147
  token;
148
148
  tokenExpiresAt;
@@ -236,7 +236,7 @@ var C = "MonitorDog token refresh was superseded.", w = 300 * 1e3, T = class {
236
236
  if (!t) throw Error("MonitorDog login email is required to refresh SDK token.");
237
237
  let n = await this.fetchSessionToken(t), r = i(n);
238
238
  if (!r || typeof r != "string") throw Error("MonitorDog SDK token response did not include a token.");
239
- if (e !== this.authSessionId) throw Error(C);
239
+ if (e !== this.authSessionId) throw Error(x);
240
240
  return this.setSessionTokenPayload(n), r;
241
241
  }
242
242
  startPeriodicRefresh() {
@@ -259,7 +259,7 @@ var C = "MonitorDog token refresh was superseded.", w = 300 * 1e3, T = class {
259
259
  return !!(this.tokenExpiresAt && Date.now() >= this.tokenExpiresAt);
260
260
  }
261
261
  isRefreshSupersededError(e) {
262
- return e instanceof Error && e.message === C;
262
+ return e instanceof Error && e.message === x;
263
263
  }
264
264
  async fetchSessionToken(e) {
265
265
  let t = this.services.options.sessionTokenProvider;
@@ -287,11 +287,11 @@ var C = "MonitorDog token refresh was superseded.", w = 300 * 1e3, T = class {
287
287
  let t = await this.authorizedFetch("/event", {
288
288
  method: "POST",
289
289
  headers: { "content-type": "application/json" },
290
- body: JSON.stringify(_(e))
290
+ body: JSON.stringify(te(e))
291
291
  });
292
292
  if (!t.ok) throw Error(`MonitorDog ${e} event failed: ${t.status}`);
293
293
  } catch (t) {
294
- let n = this.createSdkError(E(e), `MonitorDog ${e} event failed.`, t);
294
+ let n = this.createSdkError(w(e), `MonitorDog ${e} event failed.`, t);
295
295
  if (this.services.options.onAuthError?.(n), e === "logout") throw n;
296
296
  }
297
297
  }
@@ -299,12 +299,12 @@ var C = "MonitorDog token refresh was superseded.", w = 300 * 1e3, T = class {
299
299
  return n instanceof m ? n : new m(e, t, n);
300
300
  }
301
301
  };
302
- function E(e) {
302
+ function w(e) {
303
303
  return e === "logout" ? "LOGOUT_FAILED" : "SESSION_TOKEN_FAILED";
304
304
  }
305
305
  //#endregion
306
306
  //#region src/service/camera-service.ts
307
- var D = /(obs|virtual|xsplit|manycam|splitcam|webcammax|fake|loopback|camtwist|e2esoft|vcam|droidcam|iriun|epoccam|camo|mmhmm|nvidia broadcast|streamlabs|bandicam|wirecast|chromacam|youcam|cyberlink|altserver|logi capture|elgato|streamfx|screen capture|desktop capture)/i, O = class {
307
+ var T = /(obs|virtual|xsplit|manycam|splitcam|webcammax|fake|loopback|camtwist|e2esoft|vcam|droidcam|iriun|epoccam|camo|mmhmm|nvidia broadcast|streamlabs|bandicam|wirecast|chromacam|youcam|cyberlink|altserver|logi capture|elgato|streamfx|screen capture|desktop capture)/i, E = class {
308
308
  async createWebcamStream(e) {
309
309
  if (!navigator.mediaDevices?.getUserMedia) throw Error("getUserMedia is not available in this browser.");
310
310
  let t = this.getBaseWebcamConstraints(e), n = await this.createFirstCameraConstraints(t);
@@ -423,7 +423,7 @@ var D = /(obs|virtual|xsplit|manycam|splitcam|webcammax|fake|loopback|camtwist|e
423
423
  }
424
424
  isVirtualCamera(e) {
425
425
  let t = e.label.toLowerCase();
426
- return t ? D.test(t) : !1;
426
+ return t ? T.test(t) : !1;
427
427
  }
428
428
  isPermissionError(e) {
429
429
  return e instanceof DOMException && (e.name === "NotAllowedError" || e.name === "SecurityError");
@@ -447,7 +447,7 @@ var D = /(obs|virtual|xsplit|manycam|splitcam|webcammax|fake|loopback|camtwist|e
447
447
  };
448
448
  //#endregion
449
449
  //#region src/capture.ts
450
- function k(e) {
450
+ function D(e) {
451
451
  if (e.videoWidth === 0 || e.videoHeight === 0) throw Error("Video frame is not ready for capture.");
452
452
  let t = document.createElement("canvas"), n = t.getContext("2d");
453
453
  if (!n) throw Error("2D canvas context is not available.");
@@ -461,7 +461,7 @@ function k(e) {
461
461
  }, "image/jpeg", .9);
462
462
  });
463
463
  }
464
- async function A() {
464
+ async function O() {
465
465
  if (typeof document > "u" || !document.body) return null;
466
466
  let t = await e(document.body, {
467
467
  backgroundColor: "#ffffff",
@@ -473,7 +473,7 @@ async function A() {
473
473
  }
474
474
  //#endregion
475
475
  //#region src/service/detection-event-service.ts
476
- var j = class e {
476
+ var ne = class e {
477
477
  static NO_FACE_STARTUP_GRACE_MS = 1500;
478
478
  services;
479
479
  detectionEventLocked = !1;
@@ -489,12 +489,12 @@ var j = class e {
489
489
  this.reset();
490
490
  return;
491
491
  }
492
- if (v(e)) {
492
+ if (g(e)) {
493
493
  this.noFaceStartedAt = void 0, this.clearLock();
494
494
  return;
495
495
  }
496
496
  if (this.detectionEventLocked || this.detectionEventInFlight) return;
497
- let n = g(e);
497
+ let n = ee(e);
498
498
  if (!n) {
499
499
  this.noFaceStartedAt = void 0;
500
500
  return;
@@ -531,11 +531,11 @@ var j = class e {
531
531
  }
532
532
  async uploadWebcamImage(e) {
533
533
  if (!(e instanceof HTMLVideoElement) || e.videoWidth === 0 || e.videoHeight === 0) return;
534
- let t = await k(e);
534
+ let t = await D(e);
535
535
  return this.uploadImage(t, "webcam.jpg");
536
536
  }
537
537
  async uploadMonitorImage() {
538
- let e = this.services.options.captureMonitorImage ? await this.services.options.captureMonitorImage() : await A();
538
+ let e = this.services.options.captureMonitorImage ? await this.services.options.captureMonitorImage() : await O();
539
539
  if (!e) return;
540
540
  let t = typeof File < "u" && e instanceof File ? e.name : "monitor.jpg";
541
541
  return this.uploadImage(e, t);
@@ -552,8 +552,8 @@ var j = class e {
552
552
  }
553
553
  shouldSendEvent(e, t) {
554
554
  switch (e) {
555
- case "mobileDevice": return this.services.userPreferences.mobileDetectionEnabled && M(t.phoneDetections) >= this.services.userPreferences.mobileDetectionThreshold;
556
- case "twoFacesDetected": return this.services.userPreferences.multiPersonDetectionEnabled && M(t.faceDetections) >= this.services.userPreferences.faceDetectionThreshold;
555
+ case "mobileDevice": return this.services.userPreferences.mobileDetectionEnabled && k(t.phoneDetections) >= this.services.options.confidenceThreshold;
556
+ case "twoFacesDetected": return this.services.userPreferences.multiPersonDetectionEnabled && k(t.faceDetections) >= this.services.userPreferences.faceDetectionThreshold;
557
557
  case "noFaceDetected": return this.services.userPreferences.noPersonDetectionEnabled;
558
558
  }
559
559
  }
@@ -585,12 +585,12 @@ var j = class e {
585
585
  }
586
586
  }
587
587
  };
588
- function M(e) {
589
- return e.reduce((e, t) => Math.max(e, t.confidence), 0);
588
+ function k(e) {
589
+ return e.reduce((e, t) => Math.max(e, t.score), 0);
590
590
  }
591
591
  //#endregion
592
592
  //#region src/detect/inference-worker.ts?worker&url
593
- var N = "" + new URL("assets/inference-worker-CnALqzXa.js", import.meta.url).href, P = class {
593
+ var A = "" + new URL("assets/inference-worker-BTPzhc2n.js", import.meta.url).href, j = class {
594
594
  worker;
595
595
  nextRequestId = 1;
596
596
  pendingRequests = /* @__PURE__ */ new Map();
@@ -615,6 +615,7 @@ var N = "" + new URL("assets/inference-worker-CnALqzXa.js", import.meta.url).hre
615
615
  iouThreshold: e.iouThreshold,
616
616
  maxDetections: e.maxDetections,
617
617
  debug: e.debug,
618
+ inputRotation: e.inputRotation ?? "none",
618
619
  phoneRotationFallback: e.phoneRotationFallback,
619
620
  phoneRotationFallbackMinIntervalMs: e.phoneRotationFallbackMinIntervalMs
620
621
  }, t);
@@ -632,7 +633,7 @@ var N = "" + new URL("assets/inference-worker-CnALqzXa.js", import.meta.url).hre
632
633
  });
633
634
  }
634
635
  getWorker() {
635
- return this.worker || (this.worker = new Worker(N, {
636
+ return this.worker || (this.worker = new Worker(A, {
636
637
  name: "MonitorDogInference",
637
638
  type: "module"
638
639
  }), this.worker.addEventListener("message", this.handleMessage), this.worker.addEventListener("error", this.handleError), this.worker.addEventListener("messageerror", this.handleError)), this.worker;
@@ -658,15 +659,15 @@ var N = "" + new URL("assets/inference-worker-CnALqzXa.js", import.meta.url).hre
658
659
  };
659
660
  //#endregion
660
661
  //#region src/detect/preprocess.ts
661
- async function F(e) {
662
- let { sourceWidth: t, sourceHeight: n } = I(e);
662
+ async function M(e) {
663
+ let { sourceWidth: t, sourceHeight: n } = N(e);
663
664
  if (e instanceof ImageData) return {
664
665
  kind: "rgba",
665
666
  data: new Uint8ClampedArray(e.data),
666
667
  sourceWidth: t,
667
668
  sourceHeight: n
668
669
  };
669
- if (L() && R()) try {
670
+ if (P() && F()) try {
670
671
  return {
671
672
  kind: "bitmap",
672
673
  bitmap: await createImageBitmap(e),
@@ -674,9 +675,9 @@ async function F(e) {
674
675
  sourceHeight: n
675
676
  };
676
677
  } catch {}
677
- return z(e, t, n);
678
+ return I(e, t, n);
678
679
  }
679
- function I(e) {
680
+ function N(e) {
680
681
  return e instanceof ImageData ? {
681
682
  sourceWidth: e.width,
682
683
  sourceHeight: e.height
@@ -691,13 +692,13 @@ function I(e) {
691
692
  sourceHeight: e.height
692
693
  };
693
694
  }
694
- function L() {
695
+ function P() {
695
696
  return typeof createImageBitmap == "function";
696
697
  }
697
- function R() {
698
+ function F() {
698
699
  return typeof OffscreenCanvas == "function";
699
700
  }
700
- function z(e, t, n) {
701
+ function I(e, t, n) {
701
702
  let r = document.createElement("canvas"), i = r.getContext("2d");
702
703
  if (!i) throw Error("2D canvas context is not available.");
703
704
  return r.width = t, r.height = n, i.drawImage(e, 0, 0, t, n), {
@@ -708,19 +709,44 @@ function z(e, t, n) {
708
709
  };
709
710
  }
710
711
  //#endregion
712
+ //#region src/detect/rotation-fallback.ts
713
+ function L(e, t, n) {
714
+ return e.map((e) => z(e, t, n));
715
+ }
716
+ function R(e, t, n, r) {
717
+ if (e.phoneDetected || t.phoneDetections.length === 0) return e;
718
+ let i = L(t.phoneDetections, n, r);
719
+ return {
720
+ ...e,
721
+ phoneDetected: i.length > 0,
722
+ phoneCount: i.length,
723
+ phoneDetections: i
724
+ };
725
+ }
726
+ function z(e, t, n) {
727
+ return {
728
+ ...e,
729
+ x: B(t - (e.x + e.width), 0, t),
730
+ y: B(n - (e.y + e.height), 0, n)
731
+ };
732
+ }
733
+ function B(e, t, n) {
734
+ return Math.min(Math.max(e, t), n);
735
+ }
736
+ //#endregion
711
737
  //#region src/video.ts
712
- function B(e) {
738
+ function V(e) {
713
739
  return e.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA && e.videoWidth > 0 && e.videoHeight > 0 && !e.paused && !e.ended;
714
740
  }
715
- function V(e, t = 1e4) {
716
- return H(e) ? Promise.resolve() : new Promise((n, r) => {
741
+ function H(e, t = 1e4) {
742
+ return U(e) ? Promise.resolve() : new Promise((n, r) => {
717
743
  let i = window.setTimeout(() => {
718
744
  o(), r(/* @__PURE__ */ Error("Timed out waiting for webcam video metadata."));
719
745
  }, t), a = window.setInterval(s, 100), o = () => {
720
746
  window.clearTimeout(i), window.clearInterval(a), e.removeEventListener("loadedmetadata", c), e.removeEventListener("loadeddata", c), e.removeEventListener("canplay", c), e.removeEventListener("playing", c), e.removeEventListener("resize", c), e.removeEventListener("error", l);
721
747
  };
722
748
  function s() {
723
- H(e) && (o(), n());
749
+ U(e) && (o(), n());
724
750
  }
725
751
  let c = () => {
726
752
  s();
@@ -730,16 +756,18 @@ function V(e, t = 1e4) {
730
756
  e.addEventListener("loadedmetadata", c, { once: !0 }), e.addEventListener("loadeddata", c, { once: !0 }), e.addEventListener("canplay", c, { once: !0 }), e.addEventListener("playing", c, { once: !0 }), e.addEventListener("resize", c, { once: !0 }), e.addEventListener("error", l, { once: !0 });
731
757
  });
732
758
  }
733
- function H(e) {
759
+ function U(e) {
734
760
  return e.readyState >= HTMLMediaElement.HAVE_METADATA && e.videoWidth > 0 && e.videoHeight > 0;
735
761
  }
736
762
  //#endregion
737
763
  //#region src/service/detect-service.ts
738
- var U = class {
764
+ var W = class {
739
765
  services;
740
- inferenceWorker;
766
+ primaryInferenceWorker;
767
+ rotationInferenceWorker;
741
768
  loadPromise;
742
769
  lastInferenceMemoryErrorAt = 0;
770
+ lastParallelPhoneRotationFallbackAt = -Infinity;
743
771
  constructor(e) {
744
772
  this.services = e;
745
773
  }
@@ -748,27 +776,26 @@ var U = class {
748
776
  }
749
777
  async detect(e) {
750
778
  await this.load();
751
- let t = this.services.options, n = t.debug ? performance.now() : 0, r = t.debug ? performance.now() : 0, i = await F(e), a = t.debug ? performance.now() : 0, o = await this.getInferenceWorker().run({
752
- source: i,
753
- inputSize: t.inputSize,
754
- inputType: t.inputType,
755
- confidenceThreshold: t.confidenceThreshold,
756
- faceConfidenceThreshold: t.faceConfidenceThreshold,
757
- iouThreshold: t.iouThreshold,
758
- maxDetections: t.maxDetections,
759
- debug: !!t.debug,
760
- phoneRotationFallback: t.phoneRotationFallback,
761
- phoneRotationFallbackMinIntervalMs: t.phoneRotationFallbackMinIntervalMs
762
- });
779
+ let t = this.services.options, n = t.debug ? performance.now() : 0, r = t.debug ? performance.now() : 0, i = r, a;
780
+ if (this.shouldUseParallelPhoneRotationFallback(t) && this.shouldRunParallelPhoneRotationFallback(t)) {
781
+ let [n, r] = await Promise.all([M(e), M(e)]);
782
+ i = t.debug ? performance.now() : 0, a = await this.runParallelPhoneRotationFallback(n, r, t);
783
+ } else {
784
+ let n = await M(e);
785
+ i = t.debug ? performance.now() : 0, a = await this.runWorkerInference(this.getInferenceWorker(), n, t, {
786
+ inputRotation: "none",
787
+ phoneRotationFallback: t.phoneRotationFallback && t.phoneRotationFallbackExecution === "sequential"
788
+ });
789
+ }
763
790
  if (t.debug) {
764
791
  let e = performance.now();
765
792
  console.info("[MonitorDog] detect frame", {
766
- sourceMs: W(a - r),
767
- workerRoundtripMs: W(e - a),
768
- totalMs: W(e - n)
793
+ sourceMs: G(i - r),
794
+ workerRoundtripMs: G(e - i),
795
+ totalMs: G(e - n)
769
796
  });
770
797
  }
771
- return o;
798
+ return a;
772
799
  }
773
800
  toPublicResult(e) {
774
801
  return {
@@ -784,7 +811,7 @@ var U = class {
784
811
  let t = !1, n, r = this.services.options.detectionIntervalMs, i = async () => {
785
812
  if (!t) {
786
813
  try {
787
- if (!this.services.shouldPauseDetection && B(e)) {
814
+ if (!this.services.shouldPauseDetection && V(e)) {
788
815
  let n = await this.detect(e);
789
816
  if (t) return;
790
817
  try {
@@ -799,7 +826,7 @@ var U = class {
799
826
  if (t) return;
800
827
  await this.services.detectionEvents.handleDetectionResult(n, e).catch((e) => {
801
828
  this.services.options.onError?.(e);
802
- }), v(n) && this.services.detectionEvents.clearTransientState();
829
+ }), g(n) && this.services.detectionEvents.clearTransientState();
803
830
  }
804
831
  } catch (e) {
805
832
  this.handleDetectionLoopError(e);
@@ -815,7 +842,7 @@ var U = class {
815
842
  let e = this.services.options, t = await this.services.camera.createWebcamStream(e.constraints), n = this.services.camera, r = !e.video, i = e.video ?? document.createElement("video"), a = i.muted, o = i.playsInline, s = i.srcObject;
816
843
  i.muted = !0, i.playsInline = !0, i.srcObject = t;
817
844
  try {
818
- await Promise.all([i.play(), V(i)]);
845
+ await Promise.all([i.play(), H(i)]);
819
846
  } catch (e) {
820
847
  throw n.stopStream(t), i.pause(), r ? i.srcObject = null : (i.muted = a, i.playsInline = o, i.srcObject = s), e;
821
848
  }
@@ -832,7 +859,32 @@ var U = class {
832
859
  };
833
860
  }
834
861
  dispose() {
835
- this.inferenceWorker?.terminate(), this.inferenceWorker = void 0, this.loadPromise = void 0, this.services.detectionEvents.reset();
862
+ this.primaryInferenceWorker?.terminate(), this.rotationInferenceWorker?.terminate(), this.primaryInferenceWorker = void 0, this.rotationInferenceWorker = void 0, this.loadPromise = void 0, this.lastParallelPhoneRotationFallbackAt = -Infinity, this.services.detectionEvents.reset();
863
+ }
864
+ async runParallelPhoneRotationFallback(e, t, n) {
865
+ let r = e.sourceWidth, i = e.sourceHeight, [a, o] = await Promise.all([this.runWorkerInference(this.getInferenceWorker(), e, n, {
866
+ inputRotation: "none",
867
+ phoneRotationFallback: !1
868
+ }), this.runWorkerInference(this.getRotationInferenceWorker(), t, n, {
869
+ inputRotation: "rotate180",
870
+ phoneRotationFallback: !1
871
+ })]);
872
+ return R(a, o, r, i);
873
+ }
874
+ runWorkerInference(e, t, n, r) {
875
+ return e.run({
876
+ source: t,
877
+ inputSize: n.inputSize,
878
+ inputType: n.inputType,
879
+ confidenceThreshold: n.confidenceThreshold,
880
+ faceConfidenceThreshold: n.faceConfidenceThreshold,
881
+ iouThreshold: n.iouThreshold,
882
+ maxDetections: n.maxDetections,
883
+ debug: !!n.debug,
884
+ inputRotation: r.inputRotation,
885
+ phoneRotationFallback: r.phoneRotationFallback,
886
+ phoneRotationFallbackMinIntervalMs: n.phoneRotationFallbackMinIntervalMs
887
+ });
836
888
  }
837
889
  handleDetectionLoopError(e) {
838
890
  this.isInferenceMemoryError(e) && this.recoverFromInferenceMemoryError(), this.services.options.onError?.(e);
@@ -843,7 +895,7 @@ var U = class {
843
895
  e - this.lastInferenceMemoryErrorAt < 1e4 || (this.lastInferenceMemoryErrorAt = e);
844
896
  }
845
897
  resetInferenceWorker() {
846
- this.inferenceWorker?.terminate(), this.inferenceWorker = void 0, this.loadPromise = void 0;
898
+ this.primaryInferenceWorker?.terminate(), this.rotationInferenceWorker?.terminate(), this.primaryInferenceWorker = void 0, this.rotationInferenceWorker = void 0, this.loadPromise = void 0, this.lastParallelPhoneRotationFallbackAt = -Infinity;
847
899
  }
848
900
  degradeModelForMemoryPressure() {
849
901
  this.services.degradeInferenceModelForMemoryPressure();
@@ -853,7 +905,17 @@ var U = class {
853
905
  return /out of memory|oom|memory access out of bounds|cannot enlarge memory|array buffer allocation|bad allocation|allocation failed/i.test(t);
854
906
  }
855
907
  getInferenceWorker() {
856
- return this.inferenceWorker ||= new P(), this.inferenceWorker;
908
+ return this.primaryInferenceWorker ||= new j(), this.primaryInferenceWorker;
909
+ }
910
+ getRotationInferenceWorker() {
911
+ return this.rotationInferenceWorker ||= new j(), this.rotationInferenceWorker;
912
+ }
913
+ shouldUseParallelPhoneRotationFallback(e) {
914
+ return e.phoneRotationFallback && e.phoneRotationFallbackExecution === "parallel";
915
+ }
916
+ shouldRunParallelPhoneRotationFallback(e) {
917
+ let t = performance.now();
918
+ return t - this.lastParallelPhoneRotationFallbackAt < e.phoneRotationFallbackMinIntervalMs ? !1 : (this.lastParallelPhoneRotationFallbackAt = t, !0);
857
919
  }
858
920
  async loadInferenceWorker() {
859
921
  try {
@@ -871,21 +933,25 @@ var U = class {
871
933
  async loadInferenceWorkerWithOptions() {
872
934
  let e = await this.services.auth.getValidAccessToken();
873
935
  if (!e) throw Error("MonitorDog login is required before loading detection.");
874
- let t = this.services.options;
875
- await this.getInferenceWorker().load({
936
+ let t = this.services.options, n = {
876
937
  apiBaseUrl: t.apiBaseUrl,
877
938
  accessToken: e,
878
939
  inputSize: t.inputSize,
879
940
  runtimeAssetBaseUrl: t.runtimeAssetBaseUrl
880
- });
941
+ };
942
+ if (this.shouldUseParallelPhoneRotationFallback(t)) {
943
+ await Promise.all([this.getInferenceWorker().load(n), this.getRotationInferenceWorker().load(n)]);
944
+ return;
945
+ }
946
+ await this.getInferenceWorker().load(n);
881
947
  }
882
948
  };
883
- function W(e) {
949
+ function G(e) {
884
950
  return Math.round(e * 10) / 10;
885
951
  }
886
952
  //#endregion
887
953
  //#region src/service/webcam-service.ts
888
- var G = class {
954
+ var K = class {
889
955
  services;
890
956
  isWebcamRunning = !1;
891
957
  stopCurrentWebcam;
@@ -977,7 +1043,7 @@ var G = class {
977
1043
  removeVisibilityListener() {
978
1044
  typeof document > "u" || document.removeEventListener("visibilitychange", this.handleVisibilityChange);
979
1045
  }
980
- }, K = class {
1046
+ }, q = class {
981
1047
  auth;
982
1048
  camera;
983
1049
  detectionEvents;
@@ -986,10 +1052,10 @@ var G = class {
986
1052
  onCameraDisconnect;
987
1053
  onLoginRequired;
988
1054
  #e = 0;
989
- #t = q();
1055
+ #t = J();
990
1056
  #n;
991
1057
  constructor(e) {
992
- this.#n = e, this.camera = new O(), this.auth = new T(this), this.detectionEvents = new j(this), this.detect = new U(this), this.webcam = new G(this);
1058
+ this.#n = e, this.camera = new E(), this.auth = new C(this), this.detectionEvents = new ne(this), this.detect = new W(this), this.webcam = new K(this);
993
1059
  }
994
1060
  get options() {
995
1061
  return Object.freeze({ ...this.#n() });
@@ -1006,6 +1072,9 @@ var G = class {
1006
1072
  updateRequiredPasswordFromServer(e) {
1007
1073
  this.#n().requiredPassword = e;
1008
1074
  }
1075
+ setPhoneConfidenceThreshold(e) {
1076
+ this.#n().phoneConfidenceThreshold = e, this.syncEffectivePhoneConfidenceThreshold();
1077
+ }
1009
1078
  degradeInferenceModelForMemoryPressure() {
1010
1079
  let e = this.#n();
1011
1080
  if (e.inputSize > 416) {
@@ -1022,14 +1091,18 @@ var G = class {
1022
1091
  }
1023
1092
  applyPolicyItems(e, t) {
1024
1093
  let n = { ...this.#t };
1025
- for (let t of e) Y(n, t);
1026
- this.#t = n, this.#n().confidenceThreshold = n.mobileDetectionThreshold, this.#n().faceConfidenceThreshold = n.faceDetectionThreshold, this.updateRequiredPasswordFromServer(!1);
1094
+ for (let t of e) X(n, t);
1095
+ this.#t = n, this.syncEffectivePhoneConfidenceThreshold(), this.#n().faceConfidenceThreshold = n.faceDetectionThreshold, this.updateRequiredPasswordFromServer(!1);
1027
1096
  }
1028
1097
  resetAuthenticatedState() {
1029
- this.#e = 0, this.#t = q(), this.#n().requiredPassword = !1, this.#n().confidenceThreshold = this.#t.mobileDetectionThreshold, this.#n().faceConfidenceThreshold = this.#t.faceDetectionThreshold;
1098
+ this.#e = 0, this.#t = J(), this.#n().requiredPassword = !1, this.syncEffectivePhoneConfidenceThreshold(), this.#n().faceConfidenceThreshold = this.#t.faceDetectionThreshold;
1099
+ }
1100
+ syncEffectivePhoneConfidenceThreshold() {
1101
+ let e = this.#n();
1102
+ e.confidenceThreshold = e.phoneConfidenceThreshold ?? this.#t.mobileDetectionThreshold;
1030
1103
  }
1031
1104
  };
1032
- function q() {
1105
+ function J() {
1033
1106
  return {
1034
1107
  mobileDetectionThreshold: .8,
1035
1108
  faceDetectionThreshold: .8,
@@ -1045,19 +1118,19 @@ function q() {
1045
1118
  multiPersonDetectionMode: "auto_lock"
1046
1119
  };
1047
1120
  }
1048
- function J(e) {
1121
+ function Y(e) {
1049
1122
  return e === "none";
1050
1123
  }
1051
- function Y(e, t) {
1052
- let n = t.policy, r = !J(t.policy), i = t.seconds * 1e3, a = "sensitivity" in t ? 1 - t.sensitivity / 100 : void 0;
1124
+ function X(e, t) {
1125
+ let n = t.policy, r = !Y(t.policy), i = t.seconds * 1e3, a = "sensitivity" in t ? 1 - t.sensitivity / 100 : void 0;
1053
1126
  switch (t.basic_event_uuid) {
1054
- case S("mobileDevice"):
1127
+ case b("mobileDevice"):
1055
1128
  e.mobileDetectionEnabled = r, e.mobileDetectionLockDuration = i, e.mobileDetectionMode = n, a !== void 0 && (e.mobileDetectionThreshold = a);
1056
1129
  break;
1057
- case S("twoFacesDetected"):
1130
+ case b("twoFacesDetected"):
1058
1131
  e.multiPersonDetectionEnabled = r, e.multiPersonLockDuration = i, e.multiPersonDetectionMode = n, a !== void 0 && (e.faceDetectionThreshold = a);
1059
1132
  break;
1060
- case S("noFaceDetected"):
1133
+ case b("noFaceDetected"):
1061
1134
  e.noPersonDetectionEnabled = r, e.noPersonLockDuration = i, e.noPersonDetectionMode = n;
1062
1135
  break;
1063
1136
  default: break;
@@ -1065,7 +1138,7 @@ function Y(e, t) {
1065
1138
  }
1066
1139
  //#endregion
1067
1140
  //#region src/index.ts
1068
- var X = class e {
1141
+ var Z = class e {
1069
1142
  #e;
1070
1143
  #t;
1071
1144
  #n = "anonymous";
@@ -1077,13 +1150,13 @@ var X = class e {
1077
1150
  return Q = new e(t), Q;
1078
1151
  }
1079
1152
  constructor(e) {
1080
- re(e);
1081
- let r = ne(), i = p(e.runtimeAssetBaseUrl);
1153
+ ce(e);
1154
+ let r = se(), i = p(e.runtimeAssetBaseUrl);
1082
1155
  this.#t = {
1083
1156
  ...e,
1084
1157
  apiBaseUrl: c(e.apiBaseUrl),
1085
1158
  runtimeAssetBaseUrl: i,
1086
- confidenceThreshold: t,
1159
+ confidenceThreshold: e.phoneConfidenceThreshold ?? .8,
1087
1160
  faceConfidenceThreshold: t,
1088
1161
  iouThreshold: n,
1089
1162
  maxDetections: 100,
@@ -1093,8 +1166,9 @@ var X = class e {
1093
1166
  requiredPassword: !1,
1094
1167
  eventReportingEnabled: e.eventReportingEnabled ?? !0,
1095
1168
  phoneRotationFallback: e.phoneRotationFallback ?? !1,
1096
- phoneRotationFallbackMinIntervalMs: e.phoneRotationFallbackMinIntervalMs ?? 500
1097
- }, this.#e = new K(() => this.#t), this.#e.onLoginRequired = () => this.resetLoggedOutState(), Object.freeze(this);
1169
+ phoneRotationFallbackMinIntervalMs: e.phoneRotationFallbackMinIntervalMs ?? 500,
1170
+ phoneRotationFallbackExecution: e.phoneRotationFallbackExecution ?? "sequential"
1171
+ }, this.#e = new q(() => this.#t), this.#e.onLoginRequired = () => this.resetLoggedOutState(), Object.freeze(this);
1098
1172
  }
1099
1173
  async load() {
1100
1174
  this.assertUsable(), this.assertAuthenticated("loading detection");
@@ -1166,6 +1240,9 @@ var X = class e {
1166
1240
  setEventReportingEnabled(e) {
1167
1241
  this.assertUsable(), this.#t.eventReportingEnabled = e, e || this.#e.detectionEvents.reset();
1168
1242
  }
1243
+ setPhoneConfidenceThreshold(e) {
1244
+ this.assertUsable(), $(e), this.#e.setPhoneConfidenceThreshold(e);
1245
+ }
1169
1246
  getUserPreferences() {
1170
1247
  return this.assertUsable(), this.#e.userPreferences;
1171
1248
  }
@@ -1228,7 +1305,7 @@ var X = class e {
1228
1305
  });
1229
1306
  } catch (e) {
1230
1307
  let t = this.createSdkError(this.getStartErrorCode(e), this.getStartErrorMessage(e), e);
1231
- throw this.transitionToError(t, Z(t.code) ? "blocked" : "idle"), this.#t.onError?.(t), t;
1308
+ throw this.transitionToError(t, re(t.code) ? "blocked" : "idle"), this.#t.onError?.(t), t;
1232
1309
  }
1233
1310
  }
1234
1311
  clearSessionState() {
@@ -1300,35 +1377,40 @@ var X = class e {
1300
1377
  return typeof DOMException < "u" && e instanceof DOMException && e.name === "NotReadableError";
1301
1378
  }
1302
1379
  };
1303
- function Z(e) {
1380
+ function re(e) {
1304
1381
  return e === "CAMERA_PERMISSION_DENIED" || e === "CAMERA_READ_FAILED";
1305
1382
  }
1306
1383
  var Q;
1307
- function $(e) {
1308
- return Q = new X(e), Q;
1384
+ function ie(e) {
1385
+ return Q = new Z(e), Q;
1309
1386
  }
1310
- async function ee(e) {
1311
- return X.init(e);
1387
+ async function ae(e) {
1388
+ return Z.init(e);
1312
1389
  }
1313
- function te() {
1390
+ function oe() {
1314
1391
  if (!Q) throw Error("MonitorDog is not configured. Call MonitorDogDetector.init(), createMonitorDogDetector(), or configureMonitorDogDetector() before using getDetector().");
1315
1392
  return Q;
1316
1393
  }
1317
- function ne() {
1394
+ function se() {
1318
1395
  if (typeof navigator > "u") return !1;
1319
1396
  let e = l();
1320
1397
  return e === "mobile" || e === "tablet";
1321
1398
  }
1322
- function re(e) {
1399
+ function ce(e) {
1323
1400
  if (!e || typeof e.apiBaseUrl != "string" || e.apiBaseUrl.length === 0) throw Error("MonitorDog apiBaseUrl is required.");
1324
1401
  if (typeof e.sessionTokenProvider != "function") throw Error("MonitorDog sessionTokenProvider is required.");
1325
1402
  if (typeof e.onDetect != "function") throw Error("MonitorDog onDetect callback is required.");
1326
1403
  if (e.runtimeAssetBaseUrl !== void 0 && p(e.runtimeAssetBaseUrl), e.modelInputSize !== void 0 && !d(e.modelInputSize)) throw Error("MonitorDog modelInputSize must be \"auto\", 320, 416, or 640.");
1327
1404
  if (e.phoneRotationFallback !== void 0 && typeof e.phoneRotationFallback != "boolean") throw Error("MonitorDog phoneRotationFallback must be a boolean when provided.");
1328
- if (e.phoneRotationFallbackMinIntervalMs !== void 0 && !ie(e.phoneRotationFallbackMinIntervalMs)) throw Error("MonitorDog phoneRotationFallbackMinIntervalMs must be a non-negative finite number when provided.");
1405
+ if (e.phoneRotationFallbackMinIntervalMs !== void 0 && !le(e.phoneRotationFallbackMinIntervalMs)) throw Error("MonitorDog phoneRotationFallbackMinIntervalMs must be a non-negative finite number when provided.");
1406
+ if (e.phoneRotationFallbackExecution !== void 0 && e.phoneRotationFallbackExecution !== "sequential" && e.phoneRotationFallbackExecution !== "parallel") throw Error("MonitorDog phoneRotationFallbackExecution must be \"sequential\" or \"parallel\" when provided.");
1407
+ $(e.phoneConfidenceThreshold);
1329
1408
  }
1330
- function ie(e) {
1409
+ function le(e) {
1331
1410
  return typeof e == "number" && Number.isFinite(e) && e >= 0;
1332
1411
  }
1412
+ function $(e) {
1413
+ if (e !== void 0 && (typeof e != "number" || !Number.isFinite(e) || e < 0 || e > 1)) throw Error("MonitorDog phoneConfidenceThreshold must be a finite number between 0 and 1 when provided.");
1414
+ }
1333
1415
  //#endregion
1334
- export { X as MonitorDogDetector, m as MonitorDogSdkError, $ as configureMonitorDogDetector, ee as createMonitorDogDetector, te as getDetector, h as isMonitorDogSdkError };
1416
+ export { Z as MonitorDogDetector, m as MonitorDogSdkError, ie as configureMonitorDogDetector, ae as createMonitorDogDetector, oe as getDetector, h as isMonitorDogSdkError };