easyproctor-hml 2.7.14 → 3.0.0

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/index.js CHANGED
@@ -26625,6 +26625,9 @@ var FaceDetection = class extends BaseDetection {
26625
26625
  if (this.emmitedFaceAlert) {
26626
26626
  this.handleOk("face_stop", "face_detection_on_stream");
26627
26627
  }
26628
+ this.numFacesSent = -1;
26629
+ this.emmitedPositionAlert = false;
26630
+ this.emmitedFaceAlert = false;
26628
26631
  }
26629
26632
  // displayVideoDetections(result: { detections: any; }) {
26630
26633
  // // console.log(result);
@@ -30796,7 +30799,8 @@ var getDefaultProctoringOptions = {
30796
30799
  useSpyScan: false,
30797
30800
  useExternalCamera: false,
30798
30801
  useChallenge: false,
30799
- screenRecorderOptions: { width: 1280, height: 720 }
30802
+ screenRecorderOptions: { width: 1280, height: 720 },
30803
+ auto: false
30800
30804
  };
30801
30805
 
30802
30806
  // src/proctoring/options/ProctoringVideoOptions.ts
@@ -31002,6 +31006,9 @@ function recorder(stream4, buffer, onBufferSizeError = false, onBufferSizeErrorC
31002
31006
  console.log("stopRecording Recorder n\xE3o est\xE1 em estado recording");
31003
31007
  resolve();
31004
31008
  }
31009
+ stream4.getTracks().forEach((el) => {
31010
+ el.stop();
31011
+ });
31005
31012
  });
31006
31013
  }
31007
31014
  function pauseRecording() {
@@ -31359,56 +31366,6 @@ var ObjectDetection = class extends BaseDetection {
31359
31366
  }
31360
31367
  };
31361
31368
 
31362
- // src/new-flow/recorders/VolumeMeter.ts
31363
- var VolumeMeter = class {
31364
- constructor(stream4) {
31365
- this.volume = null;
31366
- this.animationFrameId = null;
31367
- this.stream = stream4;
31368
- }
31369
- async start(options = {}) {
31370
- return new Promise((resolve, reject) => {
31371
- try {
31372
- this.audioContext = new AudioContext();
31373
- this.analyser = this.audioContext.createAnalyser();
31374
- this.microphone = this.audioContext.createMediaStreamSource(this.stream);
31375
- this.analyser.smoothingTimeConstant = 0.8;
31376
- this.analyser.fftSize = 1024;
31377
- this.microphone.connect(this.analyser);
31378
- const processAudio = () => {
31379
- const array = new Uint8Array(this.analyser.frequencyBinCount);
31380
- this.analyser.getByteFrequencyData(array);
31381
- const arraySum = array.reduce((a3, value) => a3 + value, 0);
31382
- const average = arraySum / array.length;
31383
- this.setVolume(average);
31384
- options.setVolume && options.setVolume(average);
31385
- this.animationFrameId = requestAnimationFrame(processAudio);
31386
- };
31387
- this.animationFrameId = requestAnimationFrame(processAudio);
31388
- resolve(true);
31389
- } catch (error) {
31390
- this.stop();
31391
- reject(`Error: ${error}`);
31392
- }
31393
- });
31394
- }
31395
- stop() {
31396
- var _a2, _b, _c2;
31397
- if (this.animationFrameId !== null) {
31398
- cancelAnimationFrame(this.animationFrameId);
31399
- }
31400
- (_a2 = this.audioContext) == null ? void 0 : _a2.close();
31401
- (_b = this.microphone) == null ? void 0 : _b.disconnect();
31402
- (_c2 = this.analyser) == null ? void 0 : _c2.disconnect();
31403
- }
31404
- getVolume() {
31405
- return this.volume;
31406
- }
31407
- setVolume(value) {
31408
- this.volume = value;
31409
- }
31410
- };
31411
-
31412
31369
  // src/new-flow/chunk/ChunkStorageService.ts
31413
31370
  var _ChunkStorageService = class _ChunkStorageService {
31414
31371
  constructor() {
@@ -31425,13 +31382,7 @@ var _ChunkStorageService = class _ChunkStorageService {
31425
31382
  _ChunkStorageService.DB_VERSION
31426
31383
  );
31427
31384
  request.onerror = () => {
31428
- var _a2, _b;
31429
- console.error("IndexedDB error:", request.error);
31430
- reject(
31431
- new Error(
31432
- `N\xE3o foi poss\xEDvel conectar ao IndexedDB para chunks: ${(_a2 = request.error) == null ? void 0 : _a2.name} - ${(_b = request.error) == null ? void 0 : _b.message}`
31433
- )
31434
- );
31385
+ reject(new Error("N\xE3o foi poss\xEDvel conectar ao IndexedDB para chunks."));
31435
31386
  };
31436
31387
  request.onupgradeneeded = () => {
31437
31388
  const db = request.result;
@@ -31654,8 +31605,8 @@ var _ChunkStorageService = class _ChunkStorageService {
31654
31605
  }
31655
31606
  };
31656
31607
  _ChunkStorageService.DB_NAME = "EasyProctorChunksDb";
31657
- /** Incrementado para v2 para recriar índices com tipos numéricos em vez de boolean */
31658
- _ChunkStorageService.DB_VERSION = 2;
31608
+ /** v2: índices uploaded numéricos; v3: campo arrayBuffer em vez de blob */
31609
+ _ChunkStorageService.DB_VERSION = 3;
31659
31610
  _ChunkStorageService.STORE_NAME = "chunks";
31660
31611
  var ChunkStorageService = _ChunkStorageService;
31661
31612
 
@@ -31838,8 +31789,9 @@ var BackgroundUploadService = class _BackgroundUploadService {
31838
31789
  let virtualStart = this.totalBytesPurged;
31839
31790
  const chunksWithMeta = allChunks.map((c3) => {
31840
31791
  const start = virtualStart;
31841
- const end = start + c3.blob.size - 1;
31842
- virtualStart += c3.blob.size;
31792
+ const byteLength = c3.arrayBuffer.byteLength;
31793
+ const end = start + byteLength - 1;
31794
+ virtualStart += byteLength;
31843
31795
  return { chunk: c3, start, end };
31844
31796
  });
31845
31797
  let combinedBlobParts = [];
@@ -31849,8 +31801,8 @@ var BackgroundUploadService = class _BackgroundUploadService {
31849
31801
  for (const meta of chunksWithMeta) {
31850
31802
  if (this.currentOffset > meta.end) continue;
31851
31803
  const sliceStart = Math.max(0, this.currentOffset - meta.start);
31852
- const chunkSlice = meta.chunk.blob.slice(sliceStart);
31853
- combinedBlobParts.push(chunkSlice);
31804
+ const sliceBuf = meta.chunk.arrayBuffer.slice(sliceStart);
31805
+ combinedBlobParts.push(new Blob([sliceBuf]));
31854
31806
  lastProcessedChunkId = meta.chunk.id;
31855
31807
  finalChunkIndex = meta.chunk.chunkIndex;
31856
31808
  }
@@ -31884,7 +31836,10 @@ var BackgroundUploadService = class _BackgroundUploadService {
31884
31836
  }
31885
31837
  if (this.config.cleanAfterUpload) {
31886
31838
  const chunksToClear = chunksWithMeta.filter((meta) => meta.chunk.uploaded === 1 || meta.chunk.uploaded === 0 && meta.end < this.currentOffset);
31887
- const sizePurged = chunksToClear.reduce((acc, meta) => acc + meta.chunk.blob.size, 0);
31839
+ const sizePurged = chunksToClear.reduce(
31840
+ (acc, meta) => acc + meta.chunk.arrayBuffer.byteLength,
31841
+ 0
31842
+ );
31888
31843
  await this.chunkStorage.clearUploadedChunks(this.proctoringId);
31889
31844
  if (sizePurged > 0) {
31890
31845
  this.totalBytesPurged += sizePurged;
@@ -32088,7 +32043,6 @@ var _CameraRecorder = class _CameraRecorder {
32088
32043
  this.currentRetries = 0;
32089
32044
  this.packageCount = 0;
32090
32045
  this.failedUploads = 0;
32091
- this.noiseWait = 20;
32092
32046
  this.options = options;
32093
32047
  this.videoOptions = videoOptions;
32094
32048
  this.backend = backend;
@@ -32510,10 +32464,11 @@ Setting: ${JSON.stringify(settings, null, 2)}`
32510
32464
  const savePromise = (async () => {
32511
32465
  var _a2;
32512
32466
  try {
32467
+ const arrayBuffer = await blob.arrayBuffer();
32513
32468
  await this.chunkStorage.saveChunk({
32514
32469
  proctoringId: this.proctoringId,
32515
32470
  chunkIndex: this.chunkIndex,
32516
- blob,
32471
+ arrayBuffer,
32517
32472
  timestamp: Date.now(),
32518
32473
  uploaded: 0,
32519
32474
  mimeType: ((_a2 = this.recorderOptions) == null ? void 0 : _a2.mimeType) || "video/webm"
@@ -32668,35 +32623,36 @@ Setting: ${JSON.stringify(settings, null, 2)}`
32668
32623
  const settings = this.cameraStream.getVideoTracks()[0].getSettings();
32669
32624
  const settingsAudio = this.cameraStream.getAudioTracks()[0].getSettings();
32670
32625
  if (this.options.proctoringType == "VIDEO" || this.options.proctoringType == "REALTIME" || this.options.proctoringType == "IMAGE" && ((_a2 = this.paramsConfig.imageBehaviourParameters) == null ? void 0 : _a2.saveVideo)) {
32626
+ let isUploaded = false;
32671
32627
  if (this.isChunkEnabled) {
32672
- const isStable = await this.checkInternetStability();
32673
- if (isStable) {
32674
- } else {
32675
- if (this.backend && this.backendToken && this.proctoringId) {
32676
- const fileName = `EP_${this.proctoringId}_camera_0.webm`;
32677
- const objectName = `${this.proctoringId}/${fileName}`;
32678
- const isUploaded = await this.backend.checkUpload(this.backendToken, objectName, "video/webm");
32679
- if (isUploaded) {
32680
- this.chunkStorage && await this.chunkStorage.clearAllChunks(session.id);
32681
- return;
32682
- }
32683
- }
32628
+ if (this.backend && this.backendToken && this.proctoringId) {
32629
+ const fileName = `EP_${this.proctoringId}_camera_0.webm`;
32630
+ const objectName = `${this.proctoringId}/${fileName}`;
32631
+ isUploaded = await this.backend.checkUpload(this.backendToken, objectName, "video/webm");
32632
+ this.chunkStorage && await this.chunkStorage.clearAllChunks(session.id);
32684
32633
  }
32685
32634
  }
32686
- const rawBlob = new Blob(this.blobs, {
32687
- type: ((_b = this.recorderOptions) == null ? void 0 : _b.mimeType) || "video/webm"
32688
- });
32689
- const fixedBlob = await fixWebmDuration(rawBlob, this.duration);
32690
- session.addRecording({
32691
- device: `Audio
32635
+ if (!isUploaded) {
32636
+ const rawBlob = new Blob(this.blobs, {
32637
+ type: ((_b = this.recorderOptions) == null ? void 0 : _b.mimeType) || "video/webm"
32638
+ });
32639
+ let finalBlob = rawBlob;
32640
+ if (typeof fixWebmDuration === "function") {
32641
+ finalBlob = await fixWebmDuration(rawBlob, this.duration);
32642
+ } else {
32643
+ console.warn("fixWebmDuration n\xE3o dispon\xEDvel");
32644
+ }
32645
+ session.addRecording({
32646
+ device: `Audio
32692
32647
  Sample Rate: ${settingsAudio.sampleRate}
32693
32648
  Sample Size: ${settingsAudio.sampleSize}
32694
32649
 
32695
32650
  Video:
32696
32651
  ${JSON.stringify(this.recorderOptions)}`,
32697
- arrayBuffer: await fixedBlob.arrayBuffer(),
32698
- origin: "Camera" /* Camera */
32699
- });
32652
+ arrayBuffer: await finalBlob.arrayBuffer(),
32653
+ origin: "Camera" /* Camera */
32654
+ });
32655
+ }
32700
32656
  }
32701
32657
  }
32702
32658
  async getFile(file, name, type) {
@@ -32709,51 +32665,6 @@ Setting: ${JSON.stringify(settings, null, 2)}`
32709
32665
  });
32710
32666
  });
32711
32667
  }
32712
- /**
32713
- * Verifica se a internet está estável para realizar o upload do vídeo na íntegra.
32714
- */
32715
- async checkInternetStability() {
32716
- var _a2;
32717
- if (!navigator.onLine) return false;
32718
- try {
32719
- const controller = new AbortController();
32720
- const timeoutId = setTimeout(() => controller.abort(), 5e3);
32721
- const baseUrl = (_a2 = this.backend) == null ? void 0 : _a2.getBaseUrl();
32722
- if (!baseUrl) return true;
32723
- const response = await fetch(`${baseUrl}/Client/health`, {
32724
- method: "GET",
32725
- signal: controller.signal
32726
- });
32727
- clearTimeout(timeoutId);
32728
- return response.status < 500;
32729
- } catch (e3) {
32730
- console.warn("[CameraRecorder] Internet inst\xE1vel ou lenta detectada para upload integral.");
32731
- return false;
32732
- }
32733
- }
32734
- onNoiseDetected() {
32735
- var _a2, _b, _c2;
32736
- if (this.options.proctoringType === "REALTIME") return;
32737
- if (!this.volumeMeter && this.cameraStream) {
32738
- this.volumeMeter = new VolumeMeter(this.cameraStream);
32739
- this.volumeMeter.start().catch((e3) => {
32740
- console.log(e3);
32741
- this.volumeMeter = void 0;
32742
- });
32743
- }
32744
- const volume = (_b = (_a2 = this.volumeMeter) == null ? void 0 : _a2.getVolume()) != null ? _b : 0;
32745
- if (volume >= (((_c2 = this.paramsConfig.audioBehaviourParameters) == null ? void 0 : _c2.noiseLimit) || 40)) {
32746
- if (this.noiseWait >= 20) {
32747
- this.options.onRealtimeAlertsCallback({
32748
- status: "ALERT",
32749
- description: "Barulho detectado",
32750
- type: "audio_detection_on_stream"
32751
- });
32752
- this.noiseWait = 0;
32753
- }
32754
- }
32755
- this.noiseWait++;
32756
- }
32757
32668
  };
32758
32669
  // ========================
32759
32670
  // Chunk & Lifecycle
@@ -32764,10 +32675,62 @@ _CameraRecorder.CHUNK_TIMESLICE_MS = 6e4;
32764
32675
  _CameraRecorder.LS_SESSION_KEY = "ep_proctoring_session";
32765
32676
  var CameraRecorder = _CameraRecorder;
32766
32677
 
32678
+ // src/new-flow/recorders/VolumeMeter.ts
32679
+ var VolumeMeter = class {
32680
+ constructor(stream4) {
32681
+ this.volume = null;
32682
+ this.animationFrameId = null;
32683
+ this.stream = stream4;
32684
+ }
32685
+ async start(options = {}) {
32686
+ return new Promise((resolve, reject) => {
32687
+ try {
32688
+ this.audioContext = new AudioContext();
32689
+ this.analyser = this.audioContext.createAnalyser();
32690
+ this.microphone = this.audioContext.createMediaStreamSource(this.stream);
32691
+ this.analyser.smoothingTimeConstant = 0.8;
32692
+ this.analyser.fftSize = 1024;
32693
+ this.microphone.connect(this.analyser);
32694
+ const processAudio = () => {
32695
+ const array = new Uint8Array(this.analyser.frequencyBinCount);
32696
+ this.analyser.getByteFrequencyData(array);
32697
+ const arraySum = array.reduce((a3, value) => a3 + value, 0);
32698
+ const average = arraySum / array.length;
32699
+ this.setVolume(average);
32700
+ options.setVolume && options.setVolume(average);
32701
+ this.animationFrameId = requestAnimationFrame(processAudio);
32702
+ };
32703
+ this.animationFrameId = requestAnimationFrame(processAudio);
32704
+ resolve(true);
32705
+ } catch (error) {
32706
+ this.stop();
32707
+ reject(`Error: ${error}`);
32708
+ }
32709
+ });
32710
+ }
32711
+ stop() {
32712
+ var _a2, _b, _c2;
32713
+ if (this.animationFrameId !== null) {
32714
+ cancelAnimationFrame(this.animationFrameId);
32715
+ }
32716
+ (_a2 = this.audioContext) == null ? void 0 : _a2.close();
32717
+ (_b = this.microphone) == null ? void 0 : _b.disconnect();
32718
+ (_c2 = this.analyser) == null ? void 0 : _c2.disconnect();
32719
+ }
32720
+ getVolume() {
32721
+ return this.volume;
32722
+ }
32723
+ setVolume(value) {
32724
+ this.volume = value;
32725
+ }
32726
+ };
32727
+
32767
32728
  // src/new-flow/checkers/DeviceCheckerUI.ts
32768
32729
  var DeviceCheckerUI = class {
32769
32730
  constructor(options = getDefaultProctoringOptions, _videoOptions) {
32770
32731
  this.videoOptions = { width: 1080, height: 720, minWidth: 0, minHeight: 0 };
32732
+ this.autoConfirmTimer = null;
32733
+ this.autoConfirmSeconds = 5;
32771
32734
  this.options = {
32772
32735
  ...getDefaultProctoringOptions,
32773
32736
  ...options,
@@ -33533,9 +33496,53 @@ var DeviceCheckerUI = class {
33533
33496
  }));
33534
33497
  }
33535
33498
  closeModal() {
33499
+ this.stopAutoConfirm();
33536
33500
  const checkDevices = document.querySelector("#checkDevices");
33537
33501
  checkDevices == null ? void 0 : checkDevices.remove();
33538
33502
  }
33503
+ verifyAutoConfirm(status) {
33504
+ var _a2;
33505
+ if (!((_a2 = this.options) == null ? void 0 : _a2.auto)) return;
33506
+ let isAllGreen = status.allowedResolution && status.allowedPositionFace && status.allowedAmbient && status.allowedMicrophone;
33507
+ if (this.options.useSpyScan) {
33508
+ isAllGreen = isAllGreen && status.allowedSpyScan === true;
33509
+ }
33510
+ if (isAllGreen) {
33511
+ if (!this.autoConfirmTimer) {
33512
+ this.startAutoConfirm();
33513
+ }
33514
+ } else {
33515
+ if (this.autoConfirmTimer) {
33516
+ this.stopAutoConfirm();
33517
+ }
33518
+ }
33519
+ }
33520
+ startAutoConfirm() {
33521
+ this.autoConfirmSeconds = 5;
33522
+ const btn = document.getElementById("confirmBtn");
33523
+ if (btn && !btn.disabled) {
33524
+ btn.innerText = `Continuando em ${this.autoConfirmSeconds}s...`;
33525
+ this.autoConfirmTimer = setInterval(() => {
33526
+ this.autoConfirmSeconds--;
33527
+ if (this.autoConfirmSeconds <= 0) {
33528
+ this.stopAutoConfirm();
33529
+ btn.click();
33530
+ } else {
33531
+ btn.innerText = `Continuando em ${this.autoConfirmSeconds}s...`;
33532
+ }
33533
+ }, 1e3);
33534
+ }
33535
+ }
33536
+ stopAutoConfirm() {
33537
+ if (this.autoConfirmTimer) {
33538
+ clearInterval(this.autoConfirmTimer);
33539
+ this.autoConfirmTimer = null;
33540
+ }
33541
+ const btn = document.getElementById("confirmBtn");
33542
+ if (btn) {
33543
+ btn.innerText = "Continuar";
33544
+ }
33545
+ }
33539
33546
  modalActions(closeCheckDevices) {
33540
33547
  const cancelBtn = document.getElementById("cancelBtn");
33541
33548
  const confirmBtn = document.getElementById("confirmBtn");
@@ -33902,6 +33909,7 @@ var _DeviceCheckerService = class _DeviceCheckerService {
33902
33909
  }
33903
33910
  }
33904
33911
  onUpdateCallback() {
33912
+ var _a2;
33905
33913
  if (typeof this.onUpdateCb === "function") {
33906
33914
  this.onUpdateCb({
33907
33915
  allowedResolution: this.allowedResolution,
@@ -33912,6 +33920,15 @@ var _DeviceCheckerService = class _DeviceCheckerService {
33912
33920
  faceDetectionAlerts: this.faceDetectionAlerts
33913
33921
  });
33914
33922
  }
33923
+ if (((_a2 = this.options) == null ? void 0 : _a2.auto) && this.DeviceCheckerUI) {
33924
+ this.DeviceCheckerUI.verifyAutoConfirm({
33925
+ allowedResolution: this.allowedResolution,
33926
+ allowedPositionFace: this.allowedPositionFace,
33927
+ allowedAmbient: this.allowedAmbient,
33928
+ allowedMicrophone: this.allowedMicrophone,
33929
+ allowedSpyScan: this.allowedSpyScan
33930
+ });
33931
+ }
33915
33932
  }
33916
33933
  async checkDevices(options = getDefaultProctoringOptions, _videoOptions = getDefaultProctoringVideoOptions) {
33917
33934
  var _a2;
@@ -34118,16 +34135,19 @@ var _DeviceCheckerService = class _DeviceCheckerService {
34118
34135
  }).finally(() => {
34119
34136
  this.DeviceCheckerUI && this.DeviceCheckerUI.waitingSpyDevices(false);
34120
34137
  this.DeviceCheckerUI && this.allowedSpyScan != null && this.DeviceCheckerUI.isSpyDevicesUI(this.allowedSpyScan);
34138
+ this.onUpdateCallback();
34121
34139
  });
34122
34140
  } else {
34123
34141
  this.allowedSpyScan = false;
34124
34142
  this.DeviceCheckerUI && this.DeviceCheckerUI.waitingSpyDevices(false);
34125
34143
  this.DeviceCheckerUI && this.DeviceCheckerUI.isSpyDevicesUI(this.allowedSpyScan);
34144
+ this.onUpdateCallback();
34126
34145
  }
34127
34146
  } catch (error) {
34128
34147
  this.allowedSpyScan = false;
34129
34148
  this.DeviceCheckerUI && this.DeviceCheckerUI.waitingSpyDevices(false);
34130
34149
  this.DeviceCheckerUI && this.DeviceCheckerUI.isSpyDevicesUI(this.allowedSpyScan);
34150
+ this.onUpdateCallback();
34131
34151
  console.log(error);
34132
34152
  }
34133
34153
  }
@@ -34447,8 +34467,8 @@ var CapturePhoto = class {
34447
34467
  }
34448
34468
  };
34449
34469
 
34450
- // src/extension/extension.ts
34451
- var Extension = class {
34470
+ // src/extension/extensionEasyProctor.ts
34471
+ var ExtensionEasyProctor = class {
34452
34472
  constructor() {
34453
34473
  this.hasExtension = false;
34454
34474
  this.tryes = 0;
@@ -34493,6 +34513,89 @@ var Extension = class {
34493
34513
  }
34494
34514
  };
34495
34515
 
34516
+ // src/extension/extensionEasyCatcher.ts
34517
+ var ExtensionEasyCatcher = class {
34518
+ constructor(options) {
34519
+ this.hasExtension = false;
34520
+ this.tryes = 0;
34521
+ this.responseStart = false;
34522
+ this.options = options || {};
34523
+ }
34524
+ /**
34525
+ * Verifica se a extensão está instalada e ativa.
34526
+ * Retorna o número da versão se encontrada, ou lança erro após timeout.
34527
+ */
34528
+ checkExtensionInstalled(timeoutMs = 2e3) {
34529
+ return new Promise((resolve, reject) => {
34530
+ let handled = false;
34531
+ const handler = (event) => {
34532
+ if (event.source === window && event.data.sender === "easyproctor-extension" && event.data.message_name === "version") {
34533
+ handled = true;
34534
+ window.removeEventListener("message", handler);
34535
+ resolve(event.data.message);
34536
+ }
34537
+ };
34538
+ window.addEventListener("message", handler);
34539
+ window.postMessage({
34540
+ type: "easycatcher",
34541
+ func: "verifyExtensionEasycatcher"
34542
+ }, "*");
34543
+ setTimeout(() => {
34544
+ if (!handled) {
34545
+ window.removeEventListener("message", handler);
34546
+ reject(new Error("Extens\xE3o n\xE3o detectada ou n\xE3o respondeu."));
34547
+ }
34548
+ }, timeoutMs);
34549
+ });
34550
+ }
34551
+ /**
34552
+ * Solicita o JSON da sessão atual capturado pela extensão.
34553
+ */
34554
+ getSessionData(timeoutMs = 5e3) {
34555
+ return new Promise((resolve, reject) => {
34556
+ let handled = false;
34557
+ const handler = (event) => {
34558
+ if (event.source === window && event.data.sender === "easyproctor-extension" && event.data.message_name === "data_response") {
34559
+ handled = true;
34560
+ window.removeEventListener("message", handler);
34561
+ resolve(event.data.payload);
34562
+ }
34563
+ };
34564
+ window.addEventListener("message", handler);
34565
+ window.postMessage({
34566
+ type: "easycatcher",
34567
+ func: "getDataExtensionEasycatcher"
34568
+ }, "*");
34569
+ setTimeout(() => {
34570
+ if (!handled) {
34571
+ window.removeEventListener("message", handler);
34572
+ reject(new Error("Timeout ao aguardar dados da extens\xE3o."));
34573
+ }
34574
+ }, timeoutMs);
34575
+ });
34576
+ }
34577
+ start() {
34578
+ return new Promise((resolve, reject) => {
34579
+ let handled = false;
34580
+ const handler = (event) => {
34581
+ if (event.source === window && event.data.sender === "easyproctor-extension" && event.data.message_name === "started_confirmed") {
34582
+ handled = true;
34583
+ window.removeEventListener("message", handler);
34584
+ resolve(true);
34585
+ }
34586
+ };
34587
+ window.addEventListener("message", handler);
34588
+ window.postMessage({ type: "easycatcher", func: "startExtensionEasycatcher" }, "*");
34589
+ setTimeout(() => {
34590
+ if (!handled) {
34591
+ window.removeEventListener("message", handler);
34592
+ reject(new Error("Timeout: Extens\xE3o n\xE3o confirmou o in\xEDcio."));
34593
+ }
34594
+ }, 3e3);
34595
+ });
34596
+ }
34597
+ };
34598
+
34496
34599
  // src/modules/onChangeDevices.ts
34497
34600
  var onChangeDevices = class {
34498
34601
  constructor(repositoryDevices, proctoringId2, sessionOptions, allRecorders) {
@@ -38820,7 +38923,10 @@ var Proctoring = class {
38820
38923
  if (this.context.token === void 0) {
38821
38924
  throw TOKEN_MISSING;
38822
38925
  }
38823
- this.extension = new Extension();
38926
+ if (options.useChallenge) {
38927
+ this.extensionEasycatcher = new ExtensionEasyCatcher();
38928
+ }
38929
+ this.extension = new ExtensionEasyProctor();
38824
38930
  this.extension.addEventListener();
38825
38931
  const baseURL = this.backend.selectBaseUrl(this.context.type);
38826
38932
  const devices = await enumarateDevices();
@@ -38888,20 +38994,6 @@ var Proctoring = class {
38888
38994
  } catch (error) {
38889
38995
  throw SAFE_BROWSER_API_NOT_FOUND;
38890
38996
  }
38891
- this.allRecorders.cameraRecorder.onVisibilityRestored = () => {
38892
- console.log("[Proctoring] Usu\xE1rio retornou ao browser.");
38893
- this.onVisibilityRestoredCallback();
38894
- };
38895
- if (this.sessionOptions.proctoringType === "REALTIME" && !isSafeBrowser()) {
38896
- try {
38897
- await BackgroundUploadService.recoverPendingUploads(
38898
- this.backend,
38899
- this.context.token
38900
- );
38901
- } catch (e3) {
38902
- console.warn("[Proctoring] Erro ao recuperar chunks de sess\xE3o anterior:", e3);
38903
- }
38904
- }
38905
38997
  try {
38906
38998
  console.log("Starting recorders");
38907
38999
  await this.recorder.startAll();
@@ -38982,7 +39074,9 @@ Error: ${error}`
38982
39074
  this.appChecker && await this.appChecker.disconnectWebSocket();
38983
39075
  await this.recorder.saveAllOnSession();
38984
39076
  await this.sendPendingRealtimeAlerts();
39077
+ trackers.registerError(this.proctoringId, `finish this.repository.save starting`);
38985
39078
  await this.repository.save(this.proctoringSession);
39079
+ trackers.registerError(this.proctoringId, `finish this.repository.save finished`);
38986
39080
  let uploader;
38987
39081
  let uploaderServices;
38988
39082
  if (versionVerify() !== "1.0.0.0") {
@@ -39204,6 +39298,61 @@ Error: ` + error
39204
39298
  _screenStream: (_a2 = this.allRecorders.screenRecorder) == null ? void 0 : _a2.screenStream
39205
39299
  };
39206
39300
  }
39301
+ async startChallenge(templateId) {
39302
+ var _a2;
39303
+ if (!this.sessionOptions.useChallenge) {
39304
+ throw new Error("useChallenge is set as false on start method");
39305
+ }
39306
+ await this.extensionEasycatcher.checkExtensionInstalled().catch((err) => {
39307
+ throw new Error("EasyCatcher Extension is not installed");
39308
+ });
39309
+ this.extensionEasycatcher.start();
39310
+ const start = Date.now() - ((_a2 = this.allRecorders.cameraRecorder.getStartTime()) == null ? void 0 : _a2.getTime()) || 0;
39311
+ await this.backend.startChallenge({
39312
+ proctoringId: this.proctoringId,
39313
+ templateId,
39314
+ start
39315
+ }).then((resp) => {
39316
+ console.log(resp);
39317
+ this.challengeId = resp.id;
39318
+ }).catch((reason) => {
39319
+ trackers.registerError(
39320
+ this.proctoringId,
39321
+ "N\xE3o foi poss\xEDvel iniciar desafio!"
39322
+ );
39323
+ throw reason;
39324
+ });
39325
+ this.isChallengeRunning = true;
39326
+ }
39327
+ async stopChallenge() {
39328
+ var _a2;
39329
+ if (!this.isChallengeRunning) {
39330
+ throw new Error("Challenge not started");
39331
+ }
39332
+ try {
39333
+ const sessionData = await this.extensionEasycatcher.getSessionData();
39334
+ const end = Date.now() - ((_a2 = this.allRecorders.cameraRecorder.getStartTime()) == null ? void 0 : _a2.getTime()) || 0;
39335
+ await this.backend.stopChallenge(
39336
+ this.challengeId,
39337
+ {
39338
+ end,
39339
+ data: sessionData
39340
+ }
39341
+ ).catch((reason) => {
39342
+ trackers.registerError(
39343
+ this.proctoringId,
39344
+ "N\xE3o foi poss\xEDvel finalizar o desafio no backend!"
39345
+ );
39346
+ return void 0;
39347
+ });
39348
+ this.isChallengeRunning = false;
39349
+ } catch (error) {
39350
+ trackers.registerError(
39351
+ this.proctoringId,
39352
+ "Erro ao recuperar dados da extens\xE3o: " + error.message
39353
+ );
39354
+ }
39355
+ }
39207
39356
  };
39208
39357
 
39209
39358
  // src/proctoring/SignTerm.ts
@@ -39432,6 +39581,8 @@ function useProctoring(proctoringOptions, enviromentConfig = "prod") {
39432
39581
  return originalStart(parameters2, videoOptions);
39433
39582
  };
39434
39583
  const finish = proctoring.finish.bind(proctoring);
39584
+ const startChallenge = proctoring.startChallenge.bind(proctoring);
39585
+ const stopChallenge = proctoring.stopChallenge.bind(proctoring);
39435
39586
  const pause = proctoring.pause.bind(proctoring);
39436
39587
  const resume = proctoring.resume.bind(proctoring);
39437
39588
  const onFocus = proctoring.setOnFocusCallback.bind(proctoring);
@@ -39456,6 +39607,8 @@ function useProctoring(proctoringOptions, enviromentConfig = "prod") {
39456
39607
  login,
39457
39608
  start,
39458
39609
  finish,
39610
+ startChallenge,
39611
+ stopChallenge,
39459
39612
  onFocus,
39460
39613
  onLostFocus,
39461
39614
  onChangeDevices: onChangeDevices2,
@@ -12,6 +12,8 @@ export declare class DeviceCheckerUI {
12
12
  videoOptions: ProctoringVideoOptions;
13
13
  cameraRecorder: CameraRecorder;
14
14
  volumeMeter: VolumeMeter | undefined;
15
+ private autoConfirmTimer;
16
+ private autoConfirmSeconds;
15
17
  constructor(options: ProctoringSessionOptions | undefined, _videoOptions: ProctoringVideoOptions);
16
18
  checkDevicesInterface(): void;
17
19
  setSelectOption(options: ProctoringSessionOptions, changeSelectedDevice: (arg0: {
@@ -29,6 +31,15 @@ export declare class DeviceCheckerUI {
29
31
  }): any;
30
32
  }): Promise<void>;
31
33
  closeModal(): void;
34
+ verifyAutoConfirm(status: {
35
+ allowedResolution: boolean;
36
+ allowedPositionFace: boolean;
37
+ allowedAmbient: boolean;
38
+ allowedMicrophone: boolean;
39
+ allowedSpyScan: boolean | null;
40
+ }): void;
41
+ private startAutoConfirm;
42
+ private stopAutoConfirm;
32
43
  modalActions(closeCheckDevices: {
33
44
  (): Promise<void>;
34
45
  (): void;
@@ -2,7 +2,7 @@ export interface VideoChunk {
2
2
  id?: number;
3
3
  proctoringId: string;
4
4
  chunkIndex: number;
5
- blob: Blob;
5
+ arrayBuffer: ArrayBuffer;
6
6
  timestamp: number;
7
7
  uploaded: number;
8
8
  mimeType: string;