easyproctor 2.3.0 → 2.3.2

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
@@ -11645,6 +11645,83 @@ var require_follow_redirects = __commonJS({
11645
11645
  }
11646
11646
  });
11647
11647
 
11648
+ // node_modules/file-saver/dist/FileSaver.min.js
11649
+ var require_FileSaver_min = __commonJS({
11650
+ "node_modules/file-saver/dist/FileSaver.min.js"(exports2, module2) {
11651
+ (function(a3, b3) {
11652
+ if ("function" == typeof define && define.amd) define([], b3);
11653
+ else if ("undefined" != typeof exports2) b3();
11654
+ else {
11655
+ b3(), a3.FileSaver = { exports: {} }.exports;
11656
+ }
11657
+ })(exports2, function() {
11658
+ "use strict";
11659
+ function b3(a4, b4) {
11660
+ return "undefined" == typeof b4 ? b4 = { autoBom: false } : "object" != typeof b4 && (console.warn("Deprecated: Expected third argument to be a object"), b4 = { autoBom: !b4 }), b4.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(a4.type) ? new Blob(["\uFEFF", a4], { type: a4.type }) : a4;
11661
+ }
11662
+ function c3(a4, b4, c4) {
11663
+ var d2 = new XMLHttpRequest();
11664
+ d2.open("GET", a4), d2.responseType = "blob", d2.onload = function() {
11665
+ g3(d2.response, b4, c4);
11666
+ }, d2.onerror = function() {
11667
+ console.error("could not download file");
11668
+ }, d2.send();
11669
+ }
11670
+ function d(a4) {
11671
+ var b4 = new XMLHttpRequest();
11672
+ b4.open("HEAD", a4, false);
11673
+ try {
11674
+ b4.send();
11675
+ } catch (a5) {
11676
+ }
11677
+ return 200 <= b4.status && 299 >= b4.status;
11678
+ }
11679
+ function e3(a4) {
11680
+ try {
11681
+ a4.dispatchEvent(new MouseEvent("click"));
11682
+ } catch (c4) {
11683
+ var b4 = document.createEvent("MouseEvents");
11684
+ b4.initMouseEvent("click", true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null), a4.dispatchEvent(b4);
11685
+ }
11686
+ }
11687
+ var f = "object" == typeof window && window.window === window ? window : "object" == typeof self && self.self === self ? self : "object" == typeof global && global.global === global ? global : void 0, a3 = f.navigator && /Macintosh/.test(navigator.userAgent) && /AppleWebKit/.test(navigator.userAgent) && !/Safari/.test(navigator.userAgent), g3 = f.saveAs || ("object" != typeof window || window !== f ? function() {
11688
+ } : "download" in HTMLAnchorElement.prototype && !a3 ? function(b4, g4, h2) {
11689
+ var i3 = f.URL || f.webkitURL, j3 = document.createElement("a");
11690
+ g4 = g4 || b4.name || "download", j3.download = g4, j3.rel = "noopener", "string" == typeof b4 ? (j3.href = b4, j3.origin === location.origin ? e3(j3) : d(j3.href) ? c3(b4, g4, h2) : e3(j3, j3.target = "_blank")) : (j3.href = i3.createObjectURL(b4), setTimeout(function() {
11691
+ i3.revokeObjectURL(j3.href);
11692
+ }, 4e4), setTimeout(function() {
11693
+ e3(j3);
11694
+ }, 0));
11695
+ } : "msSaveOrOpenBlob" in navigator ? function(f2, g4, h2) {
11696
+ if (g4 = g4 || f2.name || "download", "string" != typeof f2) navigator.msSaveOrOpenBlob(b3(f2, h2), g4);
11697
+ else if (d(f2)) c3(f2, g4, h2);
11698
+ else {
11699
+ var i3 = document.createElement("a");
11700
+ i3.href = f2, i3.target = "_blank", setTimeout(function() {
11701
+ e3(i3);
11702
+ });
11703
+ }
11704
+ } : function(b4, d2, e4, g4) {
11705
+ if (g4 = g4 || open("", "_blank"), g4 && (g4.document.title = g4.document.body.innerText = "downloading..."), "string" == typeof b4) return c3(b4, d2, e4);
11706
+ var h2 = "application/octet-stream" === b4.type, i3 = /constructor/i.test(f.HTMLElement) || f.safari, j3 = /CriOS\/[\d]+/.test(navigator.userAgent);
11707
+ if ((j3 || h2 && i3 || a3) && "undefined" != typeof FileReader) {
11708
+ var k3 = new FileReader();
11709
+ k3.onloadend = function() {
11710
+ var a4 = k3.result;
11711
+ a4 = j3 ? a4 : a4.replace(/^data:[^;]*;/, "data:attachment/file;"), g4 ? g4.location.href = a4 : location = a4, g4 = null;
11712
+ }, k3.readAsDataURL(b4);
11713
+ } else {
11714
+ var l2 = f.URL || f.webkitURL, m3 = l2.createObjectURL(b4);
11715
+ g4 ? g4.location = m3 : location.href = m3, g4 = null, setTimeout(function() {
11716
+ l2.revokeObjectURL(m3);
11717
+ }, 4e4);
11718
+ }
11719
+ });
11720
+ f.saveAs = g3.saveAs = g3, "undefined" != typeof module2 && (module2.exports = g3);
11721
+ });
11722
+ }
11723
+ });
11724
+
11648
11725
  // node_modules/@microsoft/signalr/dist/cjs/Errors.js
11649
11726
  var require_Errors = __commonJS({
11650
11727
  "node_modules/@microsoft/signalr/dist/cjs/Errors.js"(exports2) {
@@ -19390,83 +19467,6 @@ var require_lib = __commonJS({
19390
19467
  }
19391
19468
  });
19392
19469
 
19393
- // node_modules/file-saver/dist/FileSaver.min.js
19394
- var require_FileSaver_min = __commonJS({
19395
- "node_modules/file-saver/dist/FileSaver.min.js"(exports2, module2) {
19396
- (function(a3, b3) {
19397
- if ("function" == typeof define && define.amd) define([], b3);
19398
- else if ("undefined" != typeof exports2) b3();
19399
- else {
19400
- b3(), a3.FileSaver = { exports: {} }.exports;
19401
- }
19402
- })(exports2, function() {
19403
- "use strict";
19404
- function b3(a4, b4) {
19405
- return "undefined" == typeof b4 ? b4 = { autoBom: false } : "object" != typeof b4 && (console.warn("Deprecated: Expected third argument to be a object"), b4 = { autoBom: !b4 }), b4.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(a4.type) ? new Blob(["\uFEFF", a4], { type: a4.type }) : a4;
19406
- }
19407
- function c3(a4, b4, c4) {
19408
- var d2 = new XMLHttpRequest();
19409
- d2.open("GET", a4), d2.responseType = "blob", d2.onload = function() {
19410
- g3(d2.response, b4, c4);
19411
- }, d2.onerror = function() {
19412
- console.error("could not download file");
19413
- }, d2.send();
19414
- }
19415
- function d(a4) {
19416
- var b4 = new XMLHttpRequest();
19417
- b4.open("HEAD", a4, false);
19418
- try {
19419
- b4.send();
19420
- } catch (a5) {
19421
- }
19422
- return 200 <= b4.status && 299 >= b4.status;
19423
- }
19424
- function e3(a4) {
19425
- try {
19426
- a4.dispatchEvent(new MouseEvent("click"));
19427
- } catch (c4) {
19428
- var b4 = document.createEvent("MouseEvents");
19429
- b4.initMouseEvent("click", true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null), a4.dispatchEvent(b4);
19430
- }
19431
- }
19432
- var f = "object" == typeof window && window.window === window ? window : "object" == typeof self && self.self === self ? self : "object" == typeof global && global.global === global ? global : void 0, a3 = f.navigator && /Macintosh/.test(navigator.userAgent) && /AppleWebKit/.test(navigator.userAgent) && !/Safari/.test(navigator.userAgent), g3 = f.saveAs || ("object" != typeof window || window !== f ? function() {
19433
- } : "download" in HTMLAnchorElement.prototype && !a3 ? function(b4, g4, h2) {
19434
- var i3 = f.URL || f.webkitURL, j3 = document.createElement("a");
19435
- g4 = g4 || b4.name || "download", j3.download = g4, j3.rel = "noopener", "string" == typeof b4 ? (j3.href = b4, j3.origin === location.origin ? e3(j3) : d(j3.href) ? c3(b4, g4, h2) : e3(j3, j3.target = "_blank")) : (j3.href = i3.createObjectURL(b4), setTimeout(function() {
19436
- i3.revokeObjectURL(j3.href);
19437
- }, 4e4), setTimeout(function() {
19438
- e3(j3);
19439
- }, 0));
19440
- } : "msSaveOrOpenBlob" in navigator ? function(f2, g4, h2) {
19441
- if (g4 = g4 || f2.name || "download", "string" != typeof f2) navigator.msSaveOrOpenBlob(b3(f2, h2), g4);
19442
- else if (d(f2)) c3(f2, g4, h2);
19443
- else {
19444
- var i3 = document.createElement("a");
19445
- i3.href = f2, i3.target = "_blank", setTimeout(function() {
19446
- e3(i3);
19447
- });
19448
- }
19449
- } : function(b4, d2, e4, g4) {
19450
- if (g4 = g4 || open("", "_blank"), g4 && (g4.document.title = g4.document.body.innerText = "downloading..."), "string" == typeof b4) return c3(b4, d2, e4);
19451
- var h2 = "application/octet-stream" === b4.type, i3 = /constructor/i.test(f.HTMLElement) || f.safari, j3 = /CriOS\/[\d]+/.test(navigator.userAgent);
19452
- if ((j3 || h2 && i3 || a3) && "undefined" != typeof FileReader) {
19453
- var k3 = new FileReader();
19454
- k3.onloadend = function() {
19455
- var a4 = k3.result;
19456
- a4 = j3 ? a4 : a4.replace(/^data:[^;]*;/, "data:attachment/file;"), g4 ? g4.location.href = a4 : location = a4, g4 = null;
19457
- }, k3.readAsDataURL(b4);
19458
- } else {
19459
- var l2 = f.URL || f.webkitURL, m3 = l2.createObjectURL(b4);
19460
- g4 ? g4.location = m3 : location.href = m3, g4 = null, setTimeout(function() {
19461
- l2.revokeObjectURL(m3);
19462
- }, 4e4);
19463
- }
19464
- });
19465
- f.saveAs = g3.saveAs = g3, "undefined" != typeof module2 && (module2.exports = g3);
19466
- });
19467
- }
19468
- });
19469
-
19470
19470
  // src/index.ts
19471
19471
  var index_exports = {};
19472
19472
  __export(index_exports, {
@@ -27155,17 +27155,29 @@ var BackendService = class {
27155
27155
  jwt: this.token
27156
27156
  });
27157
27157
  }
27158
- async externalCameraStartSession() {
27158
+ async externalCameraCheckTransmission(externalSessionId) {
27159
27159
  return await this.makeRequest({
27160
- path: `/ExternalCamera/start-session`,
27160
+ path: `/ExternalCamera/send-action/${externalSessionId}`,
27161
27161
  method: "POST",
27162
- body: {},
27162
+ body: {
27163
+ command: "Check_Transmission"
27164
+ },
27165
+ jwt: this.token
27166
+ });
27167
+ }
27168
+ async externalCameraStartTransmission(externalSessionId, proctoringId2) {
27169
+ return await this.makeRequest({
27170
+ path: `/ExternalCamera/start-transmission/${externalSessionId}`,
27171
+ method: "POST",
27172
+ body: {
27173
+ proctoringId: proctoringId2
27174
+ },
27163
27175
  jwt: this.token
27164
27176
  });
27165
27177
  }
27166
- async externalCameraStart(proctoringId2) {
27178
+ async externalCameraStartSession() {
27167
27179
  return await this.makeRequest({
27168
- path: `/ExternalCamera/start/${proctoringId2}`,
27180
+ path: `/ExternalCamera/start-session`,
27169
27181
  method: "POST",
27170
27182
  body: {},
27171
27183
  jwt: this.token
@@ -27937,7 +27949,7 @@ var BROWSER_NOT_SUPPORTED = "browser_not_supported";
27937
27949
  var TOKEN_MISSING = "token_missing";
27938
27950
  var CREDENTIALS_MISSING = "credentials_missing";
27939
27951
  var SPY_SCAN_API_NOT_FOUND = "spy_scan_api_not_found";
27940
- var ERROR_ON_MOBILE_APP_NOT_FOUND = "error_on_mobile_app_not_found";
27952
+ var EXTERNAL_CAMERA_NOT_STARTED = "external_camera_not_started";
27941
27953
 
27942
27954
  // src/modules/objectDetection.ts
27943
27955
  var ObjectDetection = class extends BaseDetection {
@@ -29863,865 +29875,324 @@ var CapturePhoto = class {
29863
29875
  }
29864
29876
  };
29865
29877
 
29866
- // src/proctoring/ExternalCameraChecker.ts
29867
- var import_signalr = __toESM(require_cjs());
29868
- var import_qrcode = __toESM(require_lib());
29869
- var ActionMessage = class {
29870
- };
29871
- var ExternalCameraStatusEnum = /* @__PURE__ */ ((ExternalCameraStatusEnum2) => {
29872
- ExternalCameraStatusEnum2[ExternalCameraStatusEnum2["WAITING"] = -1] = "WAITING";
29873
- ExternalCameraStatusEnum2[ExternalCameraStatusEnum2["STARTED"] = 0] = "STARTED";
29874
- ExternalCameraStatusEnum2[ExternalCameraStatusEnum2["QR_CODE"] = 1] = "QR_CODE";
29875
- ExternalCameraStatusEnum2[ExternalCameraStatusEnum2["POSITION"] = 2] = "POSITION";
29876
- ExternalCameraStatusEnum2[ExternalCameraStatusEnum2["FINISHED"] = 3] = "FINISHED";
29877
- ExternalCameraStatusEnum2[ExternalCameraStatusEnum2["ERROR"] = 9] = "ERROR";
29878
- return ExternalCameraStatusEnum2;
29879
- })(ExternalCameraStatusEnum || {});
29880
- var _ExternalCameraChecker = class _ExternalCameraChecker {
29881
- constructor(context, onRealtimeAlertsCallback) {
29882
- this.proctoringId = "";
29883
- this.capturePhotoUrl = "";
29884
- this.qrCodeBase64Image = "";
29885
- this.waitingPositionValidation = false;
29886
- this.externalSessionId = null;
29887
- this.currentStep = 0 /* STARTED */;
29888
- this.connection = null;
29889
- this.context = context;
29890
- this.onRealtimeAlertsCallback = onRealtimeAlertsCallback;
29891
- console.log("context -> ", context);
29892
- this.backend = new BackendService({
29893
- type: (context == null ? void 0 : context.type) || "prod",
29894
- token: context.token
29895
- });
29896
- this.currentStep = -1 /* WAITING */;
29878
+ // src/extension/extension.ts
29879
+ var Extension = class {
29880
+ constructor() {
29881
+ this.hasExtension = false;
29882
+ this.tryes = 0;
29883
+ this.responseStart = false;
29897
29884
  }
29898
- async setProctoringId(proctoringId2) {
29899
- this.proctoringId = proctoringId2;
29885
+ start() {
29886
+ let timer;
29887
+ return new Promise((resolve, reject) => {
29888
+ window.postMessage({ type: "easyproctor", func: "startExtensionEasyproctor" }, "*");
29889
+ timer = setInterval(() => {
29890
+ if (this.tryes > 10) {
29891
+ clearInterval(timer);
29892
+ reject(new Error("N\xE3o foi poss\xEDvel se conectar com a extens\xE3o"));
29893
+ }
29894
+ if (this.responseStart) {
29895
+ clearInterval(timer);
29896
+ resolve(this.responseStart);
29897
+ }
29898
+ this.tryes++;
29899
+ }, 1e3);
29900
+ });
29900
29901
  }
29901
- getExternalCameraSessionId() {
29902
- return "" + this.externalSessionId;
29902
+ sendVerifyMsg(link, token) {
29903
+ window.postMessage({ type: "easyproctor", func: "verifyExtensionEasyproctor", url: link, token }, "*");
29903
29904
  }
29904
- async reset() {
29905
- if (this.connection) {
29906
- const actionMessage = new ActionMessage();
29907
- actionMessage.command = "Reset";
29908
- console.log("Enviando comando 'Reset' para o aplicativo...");
29909
- this.connection.invoke(
29910
- "SendAction",
29911
- this.externalSessionId,
29912
- actionMessage
29913
- );
29905
+ verify(event) {
29906
+ if (event.source == window && event.data.sender && event.data.sender === "easyproctor-extension" && event.data.message_name && event.data.message_name === "progress") {
29907
+ this.options.onProgress && this.options.onProgress(100);
29914
29908
  }
29915
- }
29916
- async takePicture(waitingPositionValidation, onTakePictureCallback) {
29917
- if (this.connection) {
29918
- this.waitingPositionValidation = waitingPositionValidation;
29919
- this.onTakePictureCallback = onTakePictureCallback;
29920
- const actionMessage = new ActionMessage();
29921
- actionMessage.command = "Capture";
29922
- console.log("Enviando comando 'Capture' para o aplicativo...");
29923
- this.connection.invoke(
29924
- "SendAction",
29925
- this.externalSessionId,
29926
- actionMessage
29927
- );
29928
- } else {
29929
- throw new Error("N\xE3o existe conex\xE3o de camera externa ativa.");
29909
+ if (event.source == window && event.data.sender && event.data.sender === "easyproctor-extension" && event.data.message_name && event.data.message_name === "start") {
29910
+ this.responseStart = true;
29930
29911
  }
29912
+ return new Promise((resolve, reject) => {
29913
+ if (event.source == window && event.data.sender && event.data.sender === "easyproctor-extension" && event.data.message_name && event.data.message_name === "version") {
29914
+ this.hasExtension = true;
29915
+ resolve(this.hasExtension);
29916
+ }
29917
+ });
29931
29918
  }
29932
- async startSession(onQrCodeReadedCallback) {
29933
- try {
29934
- this.onQrCodeReadedCallback = onQrCodeReadedCallback;
29935
- if (this.connection)
29936
- this.disconnectWebSocket();
29937
- this.initializeWebSocketConnection();
29938
- const response = await this.backend.externalCameraStartSession();
29939
- this.externalSessionId = response.externalSessionId;
29940
- console.log(this.externalSessionId);
29941
- this.currentStep = 0 /* STARTED */;
29942
- const pairingObject = {
29943
- externalSessionId: this.externalSessionId,
29944
- token: this.context.token,
29945
- ambient: this.context.type
29946
- };
29947
- const pairingDataString = JSON.stringify(pairingObject);
29948
- this.qrCodeBase64Image = await import_qrcode.default.toDataURL(pairingDataString);
29949
- console.log(this.qrCodeBase64Image);
29950
- return this.qrCodeBase64Image;
29951
- } catch (error) {
29952
- this.disconnectWebSocket();
29953
- return Promise.reject(error);
29954
- }
29919
+ addEventListener() {
29920
+ window.addEventListener("message", (event) => this.verify(event));
29955
29921
  }
29956
- // teste com UI
29957
- async checkExternalCamera() {
29958
- this.currentStep = 0 /* STARTED */;
29959
- if (_ExternalCameraChecker.isModalOpen) {
29960
- return Promise.reject("O modal de verifica\xE7\xE3o j\xE1 est\xE1 aberto.");
29922
+ };
29923
+
29924
+ // src/modules/onChangeDevices.ts
29925
+ var onChangeDevices = class {
29926
+ constructor(repositoryDevices, proctoringId2) {
29927
+ this.repositoryDevices = repositoryDevices;
29928
+ this.proctoringId = proctoringId2;
29929
+ }
29930
+ startRecording(options) {
29931
+ navigator.mediaDevices.ondevicechange = () => {
29932
+ this.onChangeDevices(options);
29933
+ };
29934
+ }
29935
+ async onChangeDevices(options) {
29936
+ const devices = await enumarateDevices();
29937
+ const isSameDevice = (a3, b3) => a3.label === b3.label && a3.id === b3.id;
29938
+ const onlyInLeft = (left, right, compareFunction) => left.filter((leftValue) => !right.some((rightValue) => compareFunction(leftValue, rightValue)));
29939
+ const response = await this.repositoryDevices.getDevices("devices");
29940
+ const defaultDevice = { label: "", id: "" };
29941
+ const copy = { cameras: (response == null ? void 0 : response.cameras) || [defaultDevice], microphones: (response == null ? void 0 : response.microphones) || [defaultDevice] };
29942
+ let resultCameras;
29943
+ let resultMicrophones;
29944
+ if (devices.cameras.length != (copy == null ? void 0 : copy.cameras.length)) {
29945
+ resultCameras = devices.cameras.length > (copy == null ? void 0 : copy.cameras.length) ? onlyInLeft(devices.cameras, copy == null ? void 0 : copy.cameras, isSameDevice) : onlyInLeft(copy == null ? void 0 : copy.cameras, devices.cameras, isSameDevice);
29946
+ resultCameras = resultCameras.filter((item) => item.id != "default");
29961
29947
  }
29962
- _ExternalCameraChecker.isModalOpen = true;
29948
+ if (devices.microphones.length != (copy == null ? void 0 : copy.microphones.length)) {
29949
+ resultMicrophones = devices.microphones.length > (copy == null ? void 0 : copy.microphones.length) ? onlyInLeft(devices.microphones, copy == null ? void 0 : copy.microphones, isSameDevice) : onlyInLeft(copy == null ? void 0 : copy.microphones, devices.microphones, isSameDevice);
29950
+ resultMicrophones = resultMicrophones.filter((item) => item.id != "default" && item.id != "communications");
29951
+ }
29952
+ const devicesChanged = {
29953
+ cameras: resultCameras || [],
29954
+ microphones: resultMicrophones || [],
29955
+ status: devices.cameras.length > (copy == null ? void 0 : copy.cameras.length) || devices.microphones.length > (copy == null ? void 0 : copy.microphones.length) ? "in" : "out"
29956
+ };
29957
+ await this.repositoryDevices.save({ ...devices, id: "devices", status: devices.cameras.length > (copy == null ? void 0 : copy.cameras.length) || devices.microphones.length > (copy == null ? void 0 : copy.microphones.length) ? "in" : "out" });
29958
+ if (options.status && (devicesChanged.cameras.length != 0 || devicesChanged.microphones.length != 0)) {
29959
+ trackers.registerChangeDevice(this.proctoringId, devicesChanged.status, JSON.stringify(devicesChanged, null, 2));
29960
+ options.status(devicesChanged);
29961
+ }
29962
+ }
29963
+ };
29964
+
29965
+ // src/new-flow/download/downloadService.ts
29966
+ var import_file_saver = __toESM(require_FileSaver_min());
29967
+ var DownloadService = class {
29968
+ constructor(proctoringId2) {
29969
+ this.loadingBoolean = true;
29970
+ this.proctoringId = proctoringId2;
29971
+ }
29972
+ async upload(data, token) {
29973
+ const { file, onProgress } = data;
29963
29974
  try {
29964
- await this.startSession(() => {
29965
- });
29966
- return await this.buildInterface();
29967
- } catch (error) {
29968
- console.error("Erro ao iniciar verifica\xE7\xE3o:", error);
29969
- this.closeCheckExternalCamera();
29970
- return Promise.reject(error);
29975
+ trackers.registerDownloadFile(this.proctoringId, `File to download
29976
+ File name: ${file.name}
29977
+ File type: ${file.type}
29978
+ File size: ${file.size}}`);
29979
+ (0, import_file_saver.saveAs)(file);
29980
+ this.loadingBoolean = false;
29981
+ clearInterval(this.loadingInterval);
29982
+ onProgress && onProgress(Math.round(100));
29983
+ } catch (err) {
29984
+ file && this.proctoringId && trackers.registerError(this.proctoringId, `Failed on machine download
29985
+ File name: ${file.name}
29986
+ File type: ${file.type}
29987
+ File size: ${file.size}`);
29988
+ throw new Error(`Error on machine download`);
29971
29989
  }
29972
29990
  }
29973
- buildInterface() {
29974
- return new Promise((resolve, reject) => {
29975
- this.resolvePromise = resolve;
29976
- const fullBg = document.createElement("div");
29977
- fullBg.setAttribute("id", "externalCameraCheck");
29978
- this.applyStyles(fullBg, {
29979
- backgroundColor: "rgba(0,0,0,0.4)",
29980
- zIndex: "1000",
29981
- position: "fixed",
29982
- top: "0",
29983
- left: "0",
29984
- height: "100vh",
29985
- width: "100%",
29986
- display: "flex",
29987
- alignItems: "center",
29988
- justifyContent: "center"
29989
- });
29990
- const modal = document.createElement("div");
29991
- this.applyStyles(modal, {
29992
- backgroundColor: "#fff",
29993
- zIndex: "1001",
29994
- width: "500px",
29995
- borderRadius: "10px",
29996
- display: "flex",
29997
- flexDirection: "column",
29998
- alignItems: "center"
29999
- });
30000
- const h3 = document.createElement("h3");
30001
- h3.innerText = "Configura\xE7\xE3o de ambiente externo";
30002
- this.applyStyles(h3, {
30003
- color: "rgba(0, 0, 0, .7)",
30004
- fontWeight: "bold",
30005
- fontSize: "20px",
30006
- marginBottom: "15px",
30007
- padding: "20px 0px",
30008
- borderBottom: "2px solid rgba(0, 0, 0, .1)",
30009
- width: "100%",
30010
- textAlign: "center"
30011
- });
30012
- const contentArea = document.createElement("div");
30013
- contentArea.id = "external-camera-content";
30014
- this.applyStyles(contentArea, {
30015
- width: "100%",
30016
- padding: "20px 40px",
30017
- boxSizing: "border-box",
30018
- minHeight: "300px",
30019
- display: "flex",
30020
- flexDirection: "column",
30021
- justifyContent: "center",
30022
- alignItems: "center"
30023
- });
30024
- const divBtn = document.createElement("div");
30025
- this.applyStyles(divBtn, {
30026
- width: "100%",
30027
- display: "flex",
30028
- alignItems: "center",
30029
- justifyContent: "center",
30030
- borderTop: "2px solid rgba(0, 0, 0, .1)"
30031
- });
30032
- const buttonCancel = document.createElement("button");
30033
- buttonCancel.innerText = "Cancelar";
30034
- this.applyStyles(buttonCancel, {
30035
- width: "100%",
30036
- height: "70px",
30037
- backgroundColor: "#FFF",
30038
- border: "none",
30039
- color: "rgba(0, 0, 0, .7)",
30040
- fontWeight: "bold",
30041
- borderRadius: "0 0 0 10px",
30042
- cursor: "pointer"
30043
- });
30044
- buttonCancel.addEventListener("click", () => {
30045
- var _a2;
30046
- const actionMessage = new ActionMessage();
30047
- actionMessage.command = "Cancel";
30048
- console.log("Enviando comando 'Cancel' para o aplicativo...");
30049
- (_a2 = this.connection) == null ? void 0 : _a2.invoke(
30050
- "SendAction",
30051
- this.externalSessionId,
30052
- actionMessage
30053
- );
30054
- this.closeCheckExternalCamera();
30055
- resolve({ result: false });
30056
- });
30057
- const buttonContinue = document.createElement("button");
30058
- buttonContinue.innerText = "Continuar";
30059
- buttonContinue.id = "external-camera-continue";
30060
- this.applyStyles(buttonContinue, {
30061
- width: "100%",
30062
- height: "70px",
30063
- backgroundColor: "#FFF",
30064
- border: "none",
30065
- color: "rgba(0, 0, 0, .7)",
30066
- fontWeight: "bold",
30067
- borderRadius: "0 0 10px 0",
30068
- cursor: "pointer",
30069
- borderLeft: "2px solid rgba(0, 0, 0, .1)"
30070
- });
30071
- divBtn.appendChild(buttonCancel);
30072
- divBtn.appendChild(buttonContinue);
30073
- modal.appendChild(h3);
30074
- modal.appendChild(contentArea);
30075
- modal.appendChild(divBtn);
30076
- fullBg.appendChild(modal);
30077
- document.body.appendChild(fullBg);
30078
- this.renderCurrentStep();
30079
- });
29991
+ };
29992
+
29993
+ // src/new-flow/proctoring/ProctoringRecorder.ts
29994
+ var ProctoringRecorder = class {
29995
+ constructor(session, recorders) {
29996
+ this.session = session;
29997
+ this.recorders = recorders;
30080
29998
  }
30081
- renderCurrentStep() {
30082
- const contentArea = document.getElementById("external-camera-content");
30083
- if (!contentArea) return;
30084
- contentArea.innerHTML = "";
30085
- switch (this.currentStep) {
30086
- case 0 /* STARTED */:
30087
- this.renderQRCodeStep(contentArea);
30088
- break;
30089
- case 1 /* QR_CODE */:
30090
- this.renderPhotoStep(contentArea);
30091
- break;
30092
- case 2 /* POSITION */:
30093
- this.renderImageStep(contentArea);
30094
- break;
30095
- default:
30096
- break;
29999
+ async startAll() {
30000
+ this.session.start();
30001
+ for (const rec of this.recorders) {
30002
+ await rec.startRecording({ retry: false });
30097
30003
  }
30098
30004
  }
30099
- /**
30100
- * Passo 1: Renderiza o QR Code e as instruções.
30101
- */
30102
- renderQRCodeStep(container) {
30103
- const qrCanvas = document.createElement("canvas");
30104
- qrCanvas.id = "qr-code-canvas";
30105
- const instructions = document.createElement("p");
30106
- instructions.innerText = "Aponte a c\xE2mera do seu celular para o QR Code para iniciar a verifica\xE7\xE3o do ambiente.";
30107
- this.applyStyles(instructions, {
30108
- textAlign: "center",
30109
- color: "#555",
30110
- marginTop: "20px"
30111
- });
30112
- const ctx = qrCanvas.getContext("2d");
30113
- const img = new Image();
30114
- img.onload = () => {
30115
- const targetWidth = 250;
30116
- const scale = targetWidth / img.width;
30117
- const targetHeight = img.height * scale;
30118
- qrCanvas.width = targetWidth;
30119
- qrCanvas.height = targetHeight;
30120
- if (ctx)
30121
- ctx.drawImage(img, 0, 0, targetWidth, targetHeight);
30122
- };
30123
- img.src = this.qrCodeBase64Image;
30124
- container.appendChild(qrCanvas);
30125
- container.appendChild(instructions);
30126
- const continueBtn = document.getElementById(
30127
- "external-camera-continue"
30128
- );
30129
- continueBtn.disabled = true;
30130
- this.applyStyles(continueBtn, { color: "#ccc", cursor: "not-allowed" });
30005
+ async pauseAll() {
30006
+ this.session.pause();
30007
+ for (const rec of this.recorders) {
30008
+ await rec.pauseRecording();
30009
+ }
30131
30010
  }
30132
- /**
30133
- * Passo 2: Renderiza a etapa de captura
30134
- */
30135
- renderPhotoStep(container) {
30136
- const image = document.createElement("img");
30137
- image.id = "img-photo";
30138
- image.src = "https://easyproctor-public.s3.us-east-2.amazonaws.com/images/photo_icon.png";
30139
- this.applyStyles(image, {
30140
- maxWidth: "100%",
30141
- maxHeight: "300px",
30142
- borderRadius: "8px"
30143
- });
30144
- container.appendChild(image);
30145
- const instructions = document.createElement("photo-message");
30146
- instructions.id = "photo-message";
30147
- instructions.innerText = "Clique no bot\xE3o abaixo para realizar a captura da foto do ambiente.";
30148
- this.applyStyles(instructions, {
30149
- textAlign: "center",
30150
- color: "#555",
30151
- marginTop: "20px"
30152
- });
30153
- container.appendChild(instructions);
30154
- const positionCaptureButton = document.createElement("button");
30155
- positionCaptureButton.innerText = "Capturar foto";
30156
- positionCaptureButton.id = "position-capture-button";
30157
- this.applyStyles(positionCaptureButton, {
30158
- marginTop: "30px",
30159
- padding: "12px 20px",
30160
- fontSize: "16px",
30161
- fontWeight: "bold",
30162
- color: "white",
30163
- backgroundColor: "#16A34A",
30164
- border: "none",
30165
- borderRadius: "8px",
30166
- cursor: "pointer",
30167
- transition: "background-color 0.2s"
30168
- });
30169
- positionCaptureButton.onclick = () => {
30170
- if (this.connection) {
30171
- const instructions2 = document.getElementById("photo-message");
30172
- if (instructions2)
30173
- instructions2.innerText = "N\xE3o saia da posi\xE7\xE3o atual, estamos validando o ambiente...";
30174
- this.takePicture(true, () => {
30175
- });
30176
- positionCaptureButton.disabled = true;
30177
- this.applyStyles(positionCaptureButton, {
30178
- backgroundColor: "#9CA3AF",
30179
- cursor: "not-allowed"
30180
- });
30181
- }
30182
- };
30183
- container.appendChild(positionCaptureButton);
30184
- const continueBtn = document.getElementById(
30185
- "external-camera-continue"
30186
- );
30187
- continueBtn.disabled = true;
30188
- this.applyStyles(continueBtn, { color: "#ccc", cursor: "not-allowed" });
30011
+ async resumeAll() {
30012
+ this.session.resume();
30013
+ for (const rec of this.recorders) {
30014
+ await rec.resumeRecording();
30015
+ }
30189
30016
  }
30190
- /**
30191
- * Passo 3: Renderiza a imagem capturada.
30192
- */
30193
- renderImageStep(container) {
30194
- container.innerHTML = "";
30195
- const image = document.createElement("img");
30196
- image.src = "data:image/jpeg;base64," + this.capturePhotoUrl;
30197
- this.applyStyles(image, {
30198
- maxWidth: "100%",
30199
- maxHeight: "300px",
30200
- borderRadius: "8px"
30201
- });
30202
- container.appendChild(image);
30203
- const instructions = document.createElement("photo-message");
30204
- instructions.id = "photo-message";
30205
- instructions.innerText = "Verifica\xE7\xE3o finalizada com sucesso.";
30206
- this.applyStyles(instructions, {
30207
- textAlign: "center",
30208
- color: "#555",
30209
- marginTop: "20px"
30210
- });
30211
- container.appendChild(instructions);
30212
- const continueBtn = document.getElementById(
30213
- "external-camera-continue"
30214
- );
30215
- continueBtn.disabled = false;
30216
- continueBtn.innerText = "Concluir";
30217
- this.applyStyles(continueBtn, {
30218
- width: "100%",
30219
- height: "70px",
30220
- backgroundColor: "#FFF",
30221
- border: "none",
30222
- color: "rgba(0, 0, 0, .7)",
30223
- fontWeight: "bold",
30224
- borderRadius: "0 0 10px 0",
30225
- cursor: "pointer",
30226
- borderLeft: "2px solid rgba(0, 0, 0, .1)"
30227
- });
30228
- continueBtn.onclick = () => {
30229
- this.closeCheckExternalCamera();
30230
- this.resolvePromise({ result: true });
30231
- };
30017
+ async stopAll() {
30018
+ for (const rec of this.recorders) {
30019
+ await rec.stopRecording();
30020
+ }
30021
+ this.session.stop();
30232
30022
  }
30233
- nextState() {
30234
- this.renderCurrentStep();
30023
+ async saveAllOnSession() {
30024
+ for (const rec of this.recorders) {
30025
+ await rec.saveOnSession(this.session);
30026
+ }
30235
30027
  }
30236
- // --- LÓGICA DE WEBSOCKET ---
30237
- async initializeWebSocketConnection() {
30238
- const hubUrl = this.backend.getSocketUrl();
30239
- this.connection = new import_signalr.HubConnectionBuilder().withUrl(hubUrl, {
30240
- accessTokenFactory: () => this.context.token,
30241
- transport: import_signalr.HttpTransportType.WebSockets,
30242
- withCredentials: false
30243
- }).withAutomaticReconnect().configureLogging(import_signalr.LogLevel.Information).build();
30244
- this.connection.on(
30245
- "ReceiveMessage",
30246
- (sessionId, messageStr) => {
30247
- console.log("sessionId: ", sessionId);
30248
- console.log("Message: ", messageStr);
30249
- if (sessionId !== this.externalSessionId) {
30250
- console.warn("Sess\xE3o diferente!");
30251
- return;
30028
+ };
30029
+
30030
+ // src/new-flow/proctoring/ProctoringUploader.ts
30031
+ var ProctoringUploader = class {
30032
+ constructor(session, proctoringId2, uploadServices) {
30033
+ this.session = session;
30034
+ this.proctoringId = proctoringId2;
30035
+ this.uploadServices = uploadServices;
30036
+ }
30037
+ async upload(token, progress) {
30038
+ await this.uploadRecordings(token, progress);
30039
+ }
30040
+ async uploadRecordings(token, onProgress) {
30041
+ await this.uploadAllFiles(token, onProgress);
30042
+ if (!this.session.hasSomethingToUpload) {
30043
+ this.session.setUploaded();
30044
+ }
30045
+ }
30046
+ async uploadAllFiles(token, globalOnProgres) {
30047
+ for (let i3 = 0; i3 < this.session.recordings.length; i3++) {
30048
+ const rec = this.session.recordings[i3];
30049
+ if (rec.upload) {
30050
+ continue;
30051
+ }
30052
+ const onProgress = (percentage) => {
30053
+ const relativePercentage = (i3 * 100 + percentage) / this.session.recordings.length;
30054
+ if (globalOnProgres) {
30055
+ globalOnProgres(relativePercentage);
30252
30056
  }
30253
- try {
30254
- const messageKey = messageStr;
30255
- const message = ExternalCameraStatusEnum[messageKey];
30256
- console.log("Mensagem -> ", message);
30257
- this.handleWebSocketMessage(message);
30258
- } catch (e3) {
30259
- console.error("Erro ao processar mensagem do WebSocket:", e3);
30057
+ };
30058
+ const result = await this.uploadFile(rec, token, onProgress).catch(
30059
+ () => void 0
30060
+ );
30061
+ if (result) {
30062
+ if (!rec.upload) {
30063
+ rec.upload = {
30064
+ storage: "upload" /* none */,
30065
+ awsUrl: "",
30066
+ azureUrl: ""
30067
+ };
30260
30068
  }
30261
- }
30262
- );
30263
- this.connection.on(
30264
- "ReceiveAction",
30265
- (sessionId, actionMessage) => {
30266
- console.log("sessionId: ", sessionId);
30267
- console.log("Message: ", actionMessage);
30268
- if (sessionId !== this.externalSessionId) {
30269
- console.warn("Sess\xE3o diferente!");
30270
- return;
30069
+ if (result.uploaded) {
30070
+ rec.upload.storage = result.storage;
30271
30071
  }
30272
- try {
30273
- this.handleWebSocketAction(actionMessage);
30274
- } catch (e3) {
30275
- console.error("Erro ao processar mensagem do WebSocket:", e3);
30072
+ if (result.storage === "upload" /* none */) {
30073
+ result.url && (rec.upload.azureUrl = result.url);
30074
+ } else {
30075
+ result.url && (rec.upload.awsUrl = result.url);
30276
30076
  }
30277
30077
  }
30278
- );
30279
- try {
30280
- await this.connection.start();
30281
- console.log("Conectado ao Hub SignalR com sucesso!");
30282
- } catch (err) {
30283
- console.error("Falha ao conectar ou entrar no grupo do SignalR: ", err);
30284
- throw new Error("N\xE3o foi poss\xEDvel conectar ao servi\xE7o em tempo real.");
30078
+ }
30079
+ if (globalOnProgres) {
30080
+ globalOnProgres(100);
30285
30081
  }
30286
30082
  }
30287
- /**
30288
- * 7. Processa as ações recebidas e atualiza a UI.
30289
- */
30290
- handleWebSocketAction(action) {
30291
- const positionCaptureButton = document.getElementById("position-capture-button");
30292
- const instructions = document.getElementById("photo-message");
30293
- switch (action.command) {
30294
- case "Capture_Error":
30295
- if (positionCaptureButton) {
30296
- this.applyStyles(positionCaptureButton, {
30297
- marginTop: "30px",
30298
- padding: "12px 20px",
30299
- fontSize: "16px",
30300
- fontWeight: "bold",
30301
- color: "white",
30302
- backgroundColor: "#16A34A",
30303
- border: "none",
30304
- borderRadius: "8px",
30305
- cursor: "pointer",
30306
- transition: "background-color 0.2s"
30307
- });
30308
- positionCaptureButton.disabled = false;
30309
- }
30310
- if (instructions)
30311
- instructions.innerText = action.message + "\nClique no bot\xE3o novamente para uma nova captura.";
30312
- if (this.waitingPositionValidation == true)
30313
- this.onTakePictureCallback({
30314
- photo: this.capturePhotoUrl,
30315
- errorMessage: action.message,
30316
- success: false
30317
- });
30318
- break;
30319
- case "CapturePhoto":
30320
- this.capturePhotoUrl = "" + action.message;
30321
- const image = document.getElementById("img-photo");
30322
- if (image)
30323
- image.src = "data:image/jpeg;base64," + this.capturePhotoUrl;
30324
- if (this.waitingPositionValidation == false)
30325
- this.onTakePictureCallback({
30326
- photo: this.capturePhotoUrl
30327
- });
30328
- break;
30329
- case "Cancel":
30330
- this.closeCheckExternalCamera();
30331
- break;
30332
- case "EnvironmentAlert":
30333
- this.onRealtimeAlertsCallback({
30334
- status: "ALERT",
30335
- description: action.message,
30336
- type: "environment_alert"
30337
- });
30338
- break;
30339
- }
30340
- }
30341
- /**
30342
- * 7. Processa as mensagens recebidas e atualiza a UI.
30343
- */
30344
- handleWebSocketMessage(status) {
30345
- this.currentStep = status;
30346
- switch (status) {
30347
- case 1 /* QR_CODE */:
30348
- if (this.currentStep === 1) {
30349
- this.nextState();
30350
- this.onQrCodeReadedCallback(true);
30083
+ async uploadFile(rec, token, onProgress) {
30084
+ for await (const uploadService of this.uploadServices) {
30085
+ const result = await uploadService.upload(
30086
+ {
30087
+ file: rec.file,
30088
+ onProgress: (progress) => {
30089
+ if (onProgress) onProgress(progress);
30090
+ }
30091
+ },
30092
+ token
30093
+ );
30094
+ if (result) {
30095
+ let fileType = "";
30096
+ if (rec.file.name.search("camera") !== -1) {
30097
+ fileType = "Camera";
30098
+ } else if (rec.file.name.search("screen") !== -1) {
30099
+ fileType = "Screen";
30100
+ } else if (rec.file.name.search("audio") !== -1) {
30101
+ fileType = "Audio";
30351
30102
  }
30352
- break;
30353
- case 2 /* POSITION */:
30354
- this.nextState();
30355
- if (this.waitingPositionValidation == true)
30356
- this.onTakePictureCallback({
30357
- photo: this.capturePhotoUrl,
30358
- success: true
30359
- });
30360
- break;
30361
- case 3 /* FINISHED */:
30362
- this.closeCheckExternalCamera();
30363
- break;
30364
- case 9 /* ERROR */:
30365
- console.error("Erro recebido do processo de c\xE2mera externa.");
30366
- this.closeCheckExternalCamera();
30367
- this.resolvePromise({ result: false });
30368
- break;
30103
+ trackers.registerUploadFile(this.proctoringId, `Upload File
30104
+ Name: ${rec.file.name}
30105
+ Type: ${rec.file.type}
30106
+ Size: ${rec.file.size}`, fileType);
30107
+ return result;
30108
+ }
30369
30109
  }
30110
+ throw new Error("Could not upload");
30370
30111
  }
30371
- /**
30372
- * 8. Desconecta do WebSocket de forma limpa.
30373
- */
30374
- async disconnectWebSocket() {
30375
- if (this.connection) {
30376
- try {
30377
- await this.connection.stop();
30378
- console.log("Desconectado do SignalR.");
30379
- } catch (err) {
30380
- console.error("Erro ao desconectar do SignalR:", err);
30381
- } finally {
30382
- this.connection = null;
30383
- }
30112
+ };
30113
+
30114
+ // src/new-flow/recorders/AlertRecorder.ts
30115
+ var AlertRecorder = class {
30116
+ constructor(options, optionsProctoring) {
30117
+ this.alerts = [];
30118
+ this.onLostFocusCallback = options.onLostFocusCallback;
30119
+ this.onFocusCallback = options.onFocusCallback;
30120
+ this.optionsProctoring = optionsProctoring;
30121
+ }
30122
+ async startRecording() {
30123
+ this.startTime = new Date(Date.now());
30124
+ if (this.optionsProctoring.captureScreen) {
30125
+ window.addEventListener("blur", () => this.onLostFocus());
30126
+ window.addEventListener("focus", () => this.onReturnFocus());
30384
30127
  }
30385
30128
  }
30386
- /**
30387
- * Limpa os recursos, desconecta o WebSocket e remove o modal da tela.
30388
- */
30389
- closeCheckExternalCamera() {
30390
- _ExternalCameraChecker.isModalOpen = false;
30391
- this.disconnectWebSocket();
30392
- const checkDiv = document.querySelector("#externalCameraCheck");
30393
- checkDiv == null ? void 0 : checkDiv.remove();
30129
+ async pauseRecording() {
30130
+ window.removeEventListener("blur", () => this.onLostFocus());
30131
+ window.removeEventListener("focus", () => this.onReturnFocus());
30394
30132
  }
30395
- /**
30396
- * Função auxiliar para aplicar estilos.
30397
- */
30398
- applyStyles(element, styles) {
30399
- for (const property in styles) {
30400
- element.style[property] = styles[property];
30133
+ async resumeRecording() {
30134
+ if (this.optionsProctoring.captureScreen) {
30135
+ window.addEventListener("blur", () => this.onLostFocus());
30136
+ window.addEventListener("focus", () => this.onReturnFocus());
30401
30137
  }
30402
30138
  }
30403
- };
30404
- _ExternalCameraChecker.isModalOpen = false;
30405
- var ExternalCameraChecker = _ExternalCameraChecker;
30406
-
30407
- // src/extension/extension.ts
30408
- var Extension = class {
30409
- constructor() {
30410
- this.hasExtension = false;
30411
- this.tryes = 0;
30412
- this.responseStart = false;
30139
+ async stopRecording() {
30140
+ window.removeEventListener("blur", () => this.onLostFocus());
30141
+ window.removeEventListener("focus", () => this.onReturnFocus());
30413
30142
  }
30414
- start() {
30415
- let timer;
30416
- return new Promise((resolve, reject) => {
30417
- window.postMessage({ type: "easyproctor", func: "startExtensionEasyproctor" }, "*");
30418
- timer = setInterval(() => {
30419
- if (this.tryes > 10) {
30420
- clearInterval(timer);
30421
- reject(new Error("N\xE3o foi poss\xEDvel se conectar com a extens\xE3o"));
30422
- }
30423
- if (this.responseStart) {
30424
- clearInterval(timer);
30425
- resolve(this.responseStart);
30426
- }
30427
- this.tryes++;
30428
- }, 1e3);
30143
+ async saveOnSession(session) {
30144
+ this.alerts.forEach((alert) => {
30145
+ session.addAlert(alert);
30429
30146
  });
30430
30147
  }
30431
- sendVerifyMsg(link, token) {
30432
- window.postMessage({ type: "easyproctor", func: "verifyExtensionEasyproctor", url: link, token }, "*");
30433
- }
30434
- verify(event) {
30435
- if (event.source == window && event.data.sender && event.data.sender === "easyproctor-extension" && event.data.message_name && event.data.message_name === "progress") {
30436
- this.options.onProgress && this.options.onProgress(100);
30437
- }
30438
- if (event.source == window && event.data.sender && event.data.sender === "easyproctor-extension" && event.data.message_name && event.data.message_name === "start") {
30439
- this.responseStart = true;
30148
+ onLostFocus() {
30149
+ var _a2;
30150
+ if (Date.now() - ((_a2 = this.startTime) == null ? void 0 : _a2.getTime()) > 1e4) {
30151
+ this.onLostFocusCallback();
30152
+ this.alerts.push({
30153
+ begin: Date.now() - this.startTime.getTime(),
30154
+ end: 0,
30155
+ alert: 25 /* LostFocus */,
30156
+ type: 3 /* Screen */
30157
+ });
30440
30158
  }
30441
- return new Promise((resolve, reject) => {
30442
- if (event.source == window && event.data.sender && event.data.sender === "easyproctor-extension" && event.data.message_name && event.data.message_name === "version") {
30443
- this.hasExtension = true;
30444
- resolve(this.hasExtension);
30445
- }
30446
- });
30447
30159
  }
30448
- addEventListener() {
30449
- window.addEventListener("message", (event) => this.verify(event));
30160
+ onReturnFocus() {
30161
+ const lastAlert = this.alerts[this.alerts.length - 1];
30162
+ if (lastAlert) {
30163
+ this.onFocusCallback();
30164
+ lastAlert.end = Date.now() - this.startTime.getTime();
30165
+ }
30450
30166
  }
30451
30167
  };
30452
30168
 
30453
- // src/modules/onChangeDevices.ts
30454
- var onChangeDevices = class {
30455
- constructor(repositoryDevices, proctoringId2) {
30456
- this.repositoryDevices = repositoryDevices;
30457
- this.proctoringId = proctoringId2;
30458
- }
30459
- startRecording(options) {
30460
- navigator.mediaDevices.ondevicechange = () => {
30461
- this.onChangeDevices(options);
30169
+ // src/new-flow/recorders/AudioRecorder.ts
30170
+ var AudioRecorder = class {
30171
+ constructor(options, audioParams) {
30172
+ this.blobs = [];
30173
+ this.options = {
30174
+ cameraId: void 0,
30175
+ microphoneId: void 0
30462
30176
  };
30177
+ this.audioParams = {
30178
+ recordingBitrate: 128
30179
+ };
30180
+ audioParams && (this.audioParams = audioParams);
30181
+ options && (this.options = options);
30463
30182
  }
30464
- async onChangeDevices(options) {
30465
- const devices = await enumarateDevices();
30466
- const isSameDevice = (a3, b3) => a3.label === b3.label && a3.id === b3.id;
30467
- const onlyInLeft = (left, right, compareFunction) => left.filter((leftValue) => !right.some((rightValue) => compareFunction(leftValue, rightValue)));
30468
- const response = await this.repositoryDevices.getDevices("devices");
30469
- const defaultDevice = { label: "", id: "" };
30470
- const copy = { cameras: (response == null ? void 0 : response.cameras) || [defaultDevice], microphones: (response == null ? void 0 : response.microphones) || [defaultDevice] };
30471
- let resultCameras;
30472
- let resultMicrophones;
30473
- if (devices.cameras.length != (copy == null ? void 0 : copy.cameras.length)) {
30474
- resultCameras = devices.cameras.length > (copy == null ? void 0 : copy.cameras.length) ? onlyInLeft(devices.cameras, copy == null ? void 0 : copy.cameras, isSameDevice) : onlyInLeft(copy == null ? void 0 : copy.cameras, devices.cameras, isSameDevice);
30475
- resultCameras = resultCameras.filter((item) => item.id != "default");
30476
- }
30477
- if (devices.microphones.length != (copy == null ? void 0 : copy.microphones.length)) {
30478
- resultMicrophones = devices.microphones.length > (copy == null ? void 0 : copy.microphones.length) ? onlyInLeft(devices.microphones, copy == null ? void 0 : copy.microphones, isSameDevice) : onlyInLeft(copy == null ? void 0 : copy.microphones, devices.microphones, isSameDevice);
30479
- resultMicrophones = resultMicrophones.filter((item) => item.id != "default" && item.id != "communications");
30480
- }
30481
- const devicesChanged = {
30482
- cameras: resultCameras || [],
30483
- microphones: resultMicrophones || [],
30484
- status: devices.cameras.length > (copy == null ? void 0 : copy.cameras.length) || devices.microphones.length > (copy == null ? void 0 : copy.microphones.length) ? "in" : "out"
30183
+ async startRecording() {
30184
+ const constraints = {
30185
+ audio: { deviceId: this.options.microphoneId || "default" }
30485
30186
  };
30486
- await this.repositoryDevices.save({ ...devices, id: "devices", status: devices.cameras.length > (copy == null ? void 0 : copy.cameras.length) || devices.microphones.length > (copy == null ? void 0 : copy.microphones.length) ? "in" : "out" });
30487
- if (options.status && (devicesChanged.cameras.length != 0 || devicesChanged.microphones.length != 0)) {
30488
- trackers.registerChangeDevice(this.proctoringId, devicesChanged.status, JSON.stringify(devicesChanged, null, 2));
30489
- options.status(devicesChanged);
30490
- }
30187
+ this.audioStream = await navigator.mediaDevices.getUserMedia(constraints);
30188
+ const { startRecording, stopRecording, pauseRecording, resumeRecording } = recorder(this.audioStream, this.blobs, void 0, void 0, true);
30189
+ this.recordingStart = startRecording;
30190
+ this.recordingStop = stopRecording;
30191
+ this.recordingPause = pauseRecording;
30192
+ this.recordingResume = resumeRecording;
30193
+ this.recordingStart();
30491
30194
  }
30492
- };
30493
-
30494
- // src/new-flow/download/downloadService.ts
30495
- var import_file_saver = __toESM(require_FileSaver_min());
30496
- var DownloadService = class {
30497
- constructor(proctoringId2) {
30498
- this.loadingBoolean = true;
30499
- this.proctoringId = proctoringId2;
30500
- }
30501
- async upload(data, token) {
30502
- const { file, onProgress } = data;
30503
- try {
30504
- trackers.registerDownloadFile(this.proctoringId, `File to download
30505
- File name: ${file.name}
30506
- File type: ${file.type}
30507
- File size: ${file.size}}`);
30508
- (0, import_file_saver.saveAs)(file);
30509
- this.loadingBoolean = false;
30510
- clearInterval(this.loadingInterval);
30511
- onProgress && onProgress(Math.round(100));
30512
- } catch (err) {
30513
- file && this.proctoringId && trackers.registerError(this.proctoringId, `Failed on machine download
30514
- File name: ${file.name}
30515
- File type: ${file.type}
30516
- File size: ${file.size}`);
30517
- throw new Error(`Error on machine download`);
30518
- }
30519
- }
30520
- };
30521
-
30522
- // src/new-flow/proctoring/ProctoringRecorder.ts
30523
- var ProctoringRecorder = class {
30524
- constructor(session, recorders) {
30525
- this.session = session;
30526
- this.recorders = recorders;
30527
- }
30528
- async startAll() {
30529
- this.session.start();
30530
- for (const rec of this.recorders) {
30531
- await rec.startRecording({ retry: false });
30532
- }
30533
- }
30534
- async pauseAll() {
30535
- this.session.pause();
30536
- for (const rec of this.recorders) {
30537
- await rec.pauseRecording();
30538
- }
30539
- }
30540
- async resumeAll() {
30541
- this.session.resume();
30542
- for (const rec of this.recorders) {
30543
- await rec.resumeRecording();
30544
- }
30545
- }
30546
- async stopAll() {
30547
- for (const rec of this.recorders) {
30548
- await rec.stopRecording();
30549
- }
30550
- this.session.stop();
30551
- }
30552
- async saveAllOnSession() {
30553
- for (const rec of this.recorders) {
30554
- await rec.saveOnSession(this.session);
30555
- }
30556
- }
30557
- };
30558
-
30559
- // src/new-flow/proctoring/ProctoringUploader.ts
30560
- var ProctoringUploader = class {
30561
- constructor(session, proctoringId2, uploadServices) {
30562
- this.session = session;
30563
- this.proctoringId = proctoringId2;
30564
- this.uploadServices = uploadServices;
30565
- }
30566
- async upload(token, progress) {
30567
- await this.uploadRecordings(token, progress);
30568
- }
30569
- async uploadRecordings(token, onProgress) {
30570
- await this.uploadAllFiles(token, onProgress);
30571
- if (!this.session.hasSomethingToUpload) {
30572
- this.session.setUploaded();
30573
- }
30574
- }
30575
- async uploadAllFiles(token, globalOnProgres) {
30576
- for (let i3 = 0; i3 < this.session.recordings.length; i3++) {
30577
- const rec = this.session.recordings[i3];
30578
- if (rec.upload) {
30579
- continue;
30580
- }
30581
- const onProgress = (percentage) => {
30582
- const relativePercentage = (i3 * 100 + percentage) / this.session.recordings.length;
30583
- if (globalOnProgres) {
30584
- globalOnProgres(relativePercentage);
30585
- }
30586
- };
30587
- const result = await this.uploadFile(rec, token, onProgress).catch(
30588
- () => void 0
30589
- );
30590
- if (result) {
30591
- if (!rec.upload) {
30592
- rec.upload = {
30593
- storage: "upload" /* none */,
30594
- awsUrl: "",
30595
- azureUrl: ""
30596
- };
30597
- }
30598
- if (result.uploaded) {
30599
- rec.upload.storage = result.storage;
30600
- }
30601
- if (result.storage === "upload" /* none */) {
30602
- result.url && (rec.upload.azureUrl = result.url);
30603
- } else {
30604
- result.url && (rec.upload.awsUrl = result.url);
30605
- }
30606
- }
30607
- }
30608
- if (globalOnProgres) {
30609
- globalOnProgres(100);
30610
- }
30611
- }
30612
- async uploadFile(rec, token, onProgress) {
30613
- for await (const uploadService of this.uploadServices) {
30614
- const result = await uploadService.upload(
30615
- {
30616
- file: rec.file,
30617
- onProgress: (progress) => {
30618
- if (onProgress) onProgress(progress);
30619
- }
30620
- },
30621
- token
30622
- );
30623
- if (result) {
30624
- let fileType = "";
30625
- if (rec.file.name.search("camera") !== -1) {
30626
- fileType = "Camera";
30627
- } else if (rec.file.name.search("screen") !== -1) {
30628
- fileType = "Screen";
30629
- } else if (rec.file.name.search("audio") !== -1) {
30630
- fileType = "Audio";
30631
- }
30632
- trackers.registerUploadFile(this.proctoringId, `Upload File
30633
- Name: ${rec.file.name}
30634
- Type: ${rec.file.type}
30635
- Size: ${rec.file.size}`, fileType);
30636
- return result;
30637
- }
30638
- }
30639
- throw new Error("Could not upload");
30640
- }
30641
- };
30642
-
30643
- // src/new-flow/recorders/AlertRecorder.ts
30644
- var AlertRecorder = class {
30645
- constructor(options, optionsProctoring) {
30646
- this.alerts = [];
30647
- this.onLostFocusCallback = options.onLostFocusCallback;
30648
- this.onFocusCallback = options.onFocusCallback;
30649
- this.optionsProctoring = optionsProctoring;
30650
- }
30651
- async startRecording() {
30652
- this.startTime = new Date(Date.now());
30653
- if (this.optionsProctoring.captureScreen) {
30654
- window.addEventListener("blur", () => this.onLostFocus());
30655
- window.addEventListener("focus", () => this.onReturnFocus());
30656
- }
30657
- }
30658
- async pauseRecording() {
30659
- window.removeEventListener("blur", () => this.onLostFocus());
30660
- window.removeEventListener("focus", () => this.onReturnFocus());
30661
- }
30662
- async resumeRecording() {
30663
- if (this.optionsProctoring.captureScreen) {
30664
- window.addEventListener("blur", () => this.onLostFocus());
30665
- window.addEventListener("focus", () => this.onReturnFocus());
30666
- }
30667
- }
30668
- async stopRecording() {
30669
- window.removeEventListener("blur", () => this.onLostFocus());
30670
- window.removeEventListener("focus", () => this.onReturnFocus());
30671
- }
30672
- async saveOnSession(session) {
30673
- this.alerts.forEach((alert) => {
30674
- session.addAlert(alert);
30675
- });
30676
- }
30677
- onLostFocus() {
30678
- var _a2;
30679
- if (Date.now() - ((_a2 = this.startTime) == null ? void 0 : _a2.getTime()) > 1e4) {
30680
- this.onLostFocusCallback();
30681
- this.alerts.push({
30682
- begin: Date.now() - this.startTime.getTime(),
30683
- end: 0,
30684
- alert: 25 /* LostFocus */,
30685
- type: 3 /* Screen */
30686
- });
30687
- }
30688
- }
30689
- onReturnFocus() {
30690
- const lastAlert = this.alerts[this.alerts.length - 1];
30691
- if (lastAlert) {
30692
- this.onFocusCallback();
30693
- lastAlert.end = Date.now() - this.startTime.getTime();
30694
- }
30695
- }
30696
- };
30697
-
30698
- // src/new-flow/recorders/AudioRecorder.ts
30699
- var AudioRecorder = class {
30700
- constructor(options, audioParams) {
30701
- this.blobs = [];
30702
- this.options = {
30703
- cameraId: void 0,
30704
- microphoneId: void 0
30705
- };
30706
- this.audioParams = {
30707
- recordingBitrate: 128
30708
- };
30709
- audioParams && (this.audioParams = audioParams);
30710
- options && (this.options = options);
30711
- }
30712
- async startRecording() {
30713
- const constraints = {
30714
- audio: { deviceId: this.options.microphoneId || "default" }
30715
- };
30716
- this.audioStream = await navigator.mediaDevices.getUserMedia(constraints);
30717
- const { startRecording, stopRecording, pauseRecording, resumeRecording } = recorder(this.audioStream, this.blobs, void 0, void 0, true);
30718
- this.recordingStart = startRecording;
30719
- this.recordingStop = stopRecording;
30720
- this.recordingPause = pauseRecording;
30721
- this.recordingResume = resumeRecording;
30722
- this.recordingStart();
30723
- }
30724
- async pauseRecording() {
30195
+ async pauseRecording() {
30725
30196
  }
30726
30197
  async resumeRecording() {
30727
30198
  }
@@ -32982,7 +32453,7 @@ var NoiseRecorder = class {
32982
32453
  async stopRecording() {
32983
32454
  clearInterval(this.intervalNoiseDetection);
32984
32455
  await this.stopSoundRecord();
32985
- await this.volumeMeter.stop();
32456
+ await this.volumeMeter && this.volumeMeter.stop();
32986
32457
  this.audioWorkletNode && this.audioWorkletNode.disconnect();
32987
32458
  }
32988
32459
  async pauseRecording() {
@@ -33036,6 +32507,7 @@ var NoiseRecorder = class {
33036
32507
  }
33037
32508
  }
33038
32509
  async stopSoundRecord() {
32510
+ if (!this.audioRecorder) return;
33039
32511
  this.audioRecorder.stopRecording && await this.audioRecorder.stopRecording();
33040
32512
  this.recordingEndTime = Date.now() - this.examStartTime;
33041
32513
  if (this.optionsProctoring.proctoringType !== "REALTIME") return;
@@ -33204,241 +32676,990 @@ var ScreenRecorder = class {
33204
32676
  throw MULTIPLE_MONITORS_DETECTED;
33205
32677
  }
33206
32678
  }
33207
- const sharedFirstScreen = tracks.find((el) => {
33208
- return ["screen:0:0", "Primary Monitor"].includes(el.label);
33209
- }) != null;
33210
- const sharedScreen = tracks.find((el) => {
33211
- return ["screen:0:0", "Primary Monitor", ""].includes(el.label) || ["screen:"].some((substring) => el.label.includes(substring));
33212
- }) != null;
33213
- const sharedNotAllowed = tracks.find((el) => {
33214
- return ["web-contents-media-stream", "window"].some((substring) => el.label.includes(substring));
33215
- }) != null;
33216
- if (!sharedFirstScreen && allowOnlyFirstMonitor) {
33217
- tracks.forEach((el) => {
33218
- el.stop();
32679
+ const sharedFirstScreen = tracks.find((el) => {
32680
+ return ["screen:0:0", "Primary Monitor"].includes(el.label);
32681
+ }) != null;
32682
+ const sharedScreen = tracks.find((el) => {
32683
+ return ["screen:0:0", "Primary Monitor", ""].includes(el.label) || ["screen:"].some((substring) => el.label.includes(substring));
32684
+ }) != null;
32685
+ const sharedNotAllowed = tracks.find((el) => {
32686
+ return ["web-contents-media-stream", "window"].some((substring) => el.label.includes(substring));
32687
+ }) != null;
32688
+ if (!sharedFirstScreen && allowOnlyFirstMonitor) {
32689
+ tracks.forEach((el) => {
32690
+ el.stop();
32691
+ });
32692
+ throw NOT_SHARED_FIRST_SCREEN;
32693
+ } else if (!sharedScreen || sharedNotAllowed) {
32694
+ tracks.forEach((el) => {
32695
+ el.stop();
32696
+ });
32697
+ throw NOT_SHARED_SCREEN;
32698
+ }
32699
+ const { startRecording, stopRecording } = recorder(this.screenStream, this.blobs, this.options.onBufferSizeError, onBufferSizeErrorCallback);
32700
+ this.recordingStart = startRecording;
32701
+ this.recordingStop = stopRecording;
32702
+ this.recordingStart();
32703
+ }
32704
+ async pauseRecording() {
32705
+ }
32706
+ async resumeRecording() {
32707
+ }
32708
+ async stopRecording() {
32709
+ this.recordingStop && await this.recordingStop();
32710
+ }
32711
+ async saveOnSession(session) {
32712
+ session.addRecording({
32713
+ device: "",
32714
+ file: new File(this.blobs, `EP_${session.id}_screen_0.webm`, {
32715
+ type: "video/webm"
32716
+ }),
32717
+ origin: "Screen" /* Screen */
32718
+ });
32719
+ }
32720
+ };
32721
+
32722
+ // src/new-flow/repository/IndexDbSessionRepository.ts
32723
+ var IndexDbSessionRepository = class {
32724
+ constructor(dbName, storeName) {
32725
+ this.dbName = "EasyProctorDb";
32726
+ this.dbVersion = 2;
32727
+ this.storeName = "exams2";
32728
+ this.dbName = dbName;
32729
+ this.storeName = storeName;
32730
+ }
32731
+ async save(data) {
32732
+ const { transaction, store } = await this.connectToStore("readwrite");
32733
+ return this.processRequest(store.put(data), transaction).then(() => {
32734
+ });
32735
+ }
32736
+ async delete(id) {
32737
+ const { transaction, store } = await this.connectToStore("readwrite");
32738
+ return this.processRequest(store.delete(id), transaction);
32739
+ }
32740
+ async get(id) {
32741
+ const { transaction, store } = await this.connectToStore("readwrite");
32742
+ return this.processRequest(
32743
+ store.get(id),
32744
+ transaction
32745
+ ).catch(() => void 0);
32746
+ }
32747
+ async getDevices(id) {
32748
+ const { transaction, store } = await this.connectToStore("readwrite");
32749
+ return this.processRequest(
32750
+ store.get(id),
32751
+ transaction
32752
+ ).catch(() => void 0);
32753
+ }
32754
+ async list() {
32755
+ const { transaction, store } = await this.connectToStore("readonly");
32756
+ return this.processRequest(store.getAll(), transaction);
32757
+ }
32758
+ async clear() {
32759
+ const { transaction, store } = await this.connectToStore("readwrite");
32760
+ return this.processRequest(store.clear(), transaction);
32761
+ }
32762
+ async processRequest(request, transaction) {
32763
+ return new Promise((resolve, reject) => {
32764
+ request.onerror = (event) => {
32765
+ var _a2;
32766
+ reject((_a2 = request.error) == null ? void 0 : _a2.message);
32767
+ };
32768
+ request.onsuccess = (event) => {
32769
+ transaction.commit();
32770
+ resolve(request.result);
32771
+ };
32772
+ });
32773
+ }
32774
+ async hasSessions() {
32775
+ const list = await this.list();
32776
+ return list.length > 0;
32777
+ }
32778
+ async connectToStore(mode) {
32779
+ const connection = await this.connect();
32780
+ const db = connection.result;
32781
+ const transaction = db.transaction(this.storeName, mode);
32782
+ const store = transaction.objectStore(this.storeName);
32783
+ return { transaction, store };
32784
+ }
32785
+ async connect() {
32786
+ if (this.connection) return this.connection;
32787
+ return new Promise((resolve, reject) => {
32788
+ const request = window.indexedDB.open(this.dbName, this.dbVersion);
32789
+ request.onerror = (event) => {
32790
+ reject("Can't connect to IndexedDB");
32791
+ };
32792
+ request.onupgradeneeded = (event) => {
32793
+ const db = request.result;
32794
+ db.onerror = (event2) => {
32795
+ };
32796
+ db.createObjectStore(this.storeName, { keyPath: "id" });
32797
+ };
32798
+ request.onsuccess = (event) => {
32799
+ this.connection = request;
32800
+ resolve(request);
32801
+ };
32802
+ });
32803
+ }
32804
+ };
32805
+
32806
+ // src/utils/browserInformations.ts
32807
+ function fnBrowserDetect() {
32808
+ const userAgent = navigator.userAgent;
32809
+ let browserName;
32810
+ if (userAgent.match(/chrome|chromium|crios/i)) {
32811
+ browserName = "chrome";
32812
+ } else if (userAgent.match(/firefox|fxios/i)) {
32813
+ browserName = "firefox";
32814
+ } else if (userAgent.match(/safari/i)) {
32815
+ browserName = "safari";
32816
+ } else if (userAgent.match(/opr\//i)) {
32817
+ browserName = "opera";
32818
+ } else if (userAgent.match(/edg/i)) {
32819
+ browserName = "edge";
32820
+ } else {
32821
+ browserName = "No browser detection";
32822
+ }
32823
+ return browserName;
32824
+ }
32825
+
32826
+ // src/utils/geolocation.ts
32827
+ function getGeolocation() {
32828
+ return new Promise((resolve, reject) => {
32829
+ window.navigator.geolocation.getCurrentPosition(resolve, reject);
32830
+ });
32831
+ }
32832
+
32833
+ // src/utils/verifyVersion.ts
32834
+ function versionVerify() {
32835
+ const agentStr = window.navigator.userAgent.split("SEB/");
32836
+ if (agentStr.length > 1)
32837
+ return agentStr[1];
32838
+ else return "1.0.0.0";
32839
+ }
32840
+
32841
+ // src/proctoring/Auth.ts
32842
+ var Auth = class {
32843
+ constructor(cpf, backend) {
32844
+ this.cpf = cpf;
32845
+ this.backend = backend;
32846
+ this.capturePhoto = new CapturePhoto();
32847
+ }
32848
+ async login() {
32849
+ const capture = await this.capturePhoto.takePicture(
32850
+ "Login com biometria facial",
32851
+ "Encaixe seu rosto no formato e clique no bot\xE3o abaixo",
32852
+ { width: 1280, height: 720 }
32853
+ );
32854
+ this.loading();
32855
+ return new Promise((resolve, reject) => {
32856
+ this.backend.loginAuth(this.cpf, capture.base64.substr(22, capture.base64.length)).then((resp) => {
32857
+ this.token = resp.token;
32858
+ const authLoader = document.querySelector("#authLoader");
32859
+ authLoader == null ? void 0 : authLoader.remove();
32860
+ this.backend.token = this.token;
32861
+ resolve(this.token);
32862
+ }).catch((e3) => {
32863
+ console.log(e3);
32864
+ const authLoader = document.querySelector("#authLoader");
32865
+ authLoader == null ? void 0 : authLoader.remove();
32866
+ reject(e3);
32867
+ });
32868
+ });
32869
+ }
32870
+ loading() {
32871
+ const fullBg = document.createElement("div");
32872
+ fullBg.setAttribute("id", "authLoader");
32873
+ fullBg.style.backgroundColor = "rgba(0,0,0,0.4)";
32874
+ fullBg.style.zIndex = "1000";
32875
+ fullBg.style.position = "fixed";
32876
+ fullBg.style.top = "0";
32877
+ fullBg.style.left = "0";
32878
+ fullBg.style.height = "100vh";
32879
+ fullBg.style.width = "100%";
32880
+ fullBg.style.display = "flex";
32881
+ fullBg.style.alignItems = "center";
32882
+ fullBg.style.justifyContent = "center";
32883
+ const loader = document.createElement("div");
32884
+ loader.setAttribute("class", "loader");
32885
+ fullBg.appendChild(loader);
32886
+ document.body.appendChild(fullBg);
32887
+ const styles = `
32888
+ .loader {
32889
+ border: 6px solid #f3f3f3;
32890
+ border-radius: 50%;
32891
+ border-top: 6px solid #16a34a;
32892
+ width: 50px;
32893
+ height: 50px;
32894
+ -webkit-animation: spin 2s linear infinite; /* Safari */
32895
+ animation: spin 2s linear infinite;
32896
+ }
32897
+
32898
+ /* Safari */
32899
+ @-webkit-keyframes spin {
32900
+ 0% { -webkit-transform: rotate(0deg); }
32901
+ 100% { -webkit-transform: rotate(360deg); }
32902
+ }
32903
+
32904
+ @keyframes spin {
32905
+ 0% { transform: rotate(0deg); }
32906
+ 100% { transform: rotate(360deg); }
32907
+ }
32908
+ `;
32909
+ const styleSheet = document.createElement("style");
32910
+ styleSheet.innerHTML = styles;
32911
+ document.head.appendChild(styleSheet);
32912
+ }
32913
+ };
32914
+
32915
+ // src/proctoring/ExternalCameraChecker.ts
32916
+ var import_signalr = __toESM(require_cjs());
32917
+ var import_qrcode = __toESM(require_lib());
32918
+ var ActionMessage = class {
32919
+ };
32920
+ var ExternalCameraStatusEnum = /* @__PURE__ */ ((ExternalCameraStatusEnum2) => {
32921
+ ExternalCameraStatusEnum2[ExternalCameraStatusEnum2["WAITING"] = -1] = "WAITING";
32922
+ ExternalCameraStatusEnum2[ExternalCameraStatusEnum2["STARTED"] = 0] = "STARTED";
32923
+ ExternalCameraStatusEnum2[ExternalCameraStatusEnum2["QR_CODE"] = 1] = "QR_CODE";
32924
+ ExternalCameraStatusEnum2[ExternalCameraStatusEnum2["POSITION"] = 2] = "POSITION";
32925
+ ExternalCameraStatusEnum2[ExternalCameraStatusEnum2["FINISHED"] = 3] = "FINISHED";
32926
+ ExternalCameraStatusEnum2[ExternalCameraStatusEnum2["ERROR"] = 9] = "ERROR";
32927
+ return ExternalCameraStatusEnum2;
32928
+ })(ExternalCameraStatusEnum || {});
32929
+ var _ExternalCameraChecker = class _ExternalCameraChecker {
32930
+ constructor(context, onRealtimeAlertsCallback) {
32931
+ this.proctoringId = "";
32932
+ this.capturePhotoUrl = "";
32933
+ this.qrCodeBase64Image = "";
32934
+ this.transmissionOk = false;
32935
+ this.waitingPositionValidation = false;
32936
+ this.externalSessionId = null;
32937
+ this.currentStep = 0 /* STARTED */;
32938
+ this.connection = null;
32939
+ this.context = context;
32940
+ this.onRealtimeAlertsCallback = onRealtimeAlertsCallback;
32941
+ console.log("context -> ", context);
32942
+ this.backend = new BackendService({
32943
+ type: (context == null ? void 0 : context.type) || "prod",
32944
+ token: context.token
32945
+ });
32946
+ this.currentStep = -1 /* WAITING */;
32947
+ }
32948
+ getExternalCameraSessionId() {
32949
+ return "" + this.externalSessionId;
32950
+ }
32951
+ async checkTransmission() {
32952
+ try {
32953
+ this.transmissionOk = false;
32954
+ const response = await this.backend.externalCameraCheckTransmission("" + this.externalSessionId);
32955
+ console.log(response);
32956
+ let attempts = 0;
32957
+ while (!this.transmissionOk && attempts <= 5) {
32958
+ await new Promise((resolve) => setTimeout(resolve, 2e3));
32959
+ attempts = attempts + 1;
32960
+ }
32961
+ if (!this.transmissionOk)
32962
+ throw new Error("Timed out na checagem da transmiss\xE3o!");
32963
+ } catch (error) {
32964
+ console.error("Erro ao checar a transmiss\xE3o:", error);
32965
+ throw new Error("N\xE3o foi poss\xEDvel checar a transmiss\xE3o." + error);
32966
+ }
32967
+ }
32968
+ async startTransmission(proctoringId2) {
32969
+ try {
32970
+ this.proctoringId = proctoringId2;
32971
+ const response = await this.backend.externalCameraStartTransmission("" + this.externalSessionId, proctoringId2);
32972
+ console.log(response);
32973
+ } catch (error) {
32974
+ console.error("Erro ao iniciar transmiss\xE3o:", error);
32975
+ throw new Error("N\xE3o foi poss\xEDvel iniciar a transmiss\xE3o.");
32976
+ }
32977
+ }
32978
+ async goToPositionGuide() {
32979
+ if (this.connection) {
32980
+ const actionMessage = new ActionMessage();
32981
+ actionMessage.command = "Position_Guide";
32982
+ console.log("Enviando comando 'Position_Guide' para o aplicativo...");
32983
+ this.connection.invoke(
32984
+ "SendAction",
32985
+ this.externalSessionId,
32986
+ actionMessage
32987
+ );
32988
+ }
32989
+ }
32990
+ async reset() {
32991
+ if (this.connection) {
32992
+ const actionMessage = new ActionMessage();
32993
+ actionMessage.command = "Reset";
32994
+ console.log("Enviando comando 'Reset' para o aplicativo...");
32995
+ this.connection.invoke(
32996
+ "SendAction",
32997
+ this.externalSessionId,
32998
+ actionMessage
32999
+ );
33000
+ }
33001
+ }
33002
+ async takePicture(waitingPositionValidation, onTakePictureCallback) {
33003
+ if (this.connection) {
33004
+ this.waitingPositionValidation = waitingPositionValidation;
33005
+ this.onTakePictureCallback = onTakePictureCallback;
33006
+ const actionMessage = new ActionMessage();
33007
+ actionMessage.command = "Capture";
33008
+ console.log("Enviando comando 'Capture' para o aplicativo...");
33009
+ this.connection.invoke(
33010
+ "SendAction",
33011
+ this.externalSessionId,
33012
+ actionMessage
33013
+ );
33014
+ } else {
33015
+ throw new Error("N\xE3o existe conex\xE3o de camera externa ativa.");
33016
+ }
33017
+ }
33018
+ async startSession(onQrCodeReadedCallback) {
33019
+ try {
33020
+ this.onQrCodeReadedCallback = onQrCodeReadedCallback;
33021
+ if (this.connection)
33022
+ this.disconnectWebSocket();
33023
+ this.initializeWebSocketConnection();
33024
+ await this.reset();
33025
+ const response = await this.backend.externalCameraStartSession();
33026
+ this.externalSessionId = response.externalSessionId;
33027
+ console.log(this.externalSessionId);
33028
+ this.currentStep = 0 /* STARTED */;
33029
+ const pairingObject = {
33030
+ externalSessionId: this.externalSessionId,
33031
+ token: this.context.token,
33032
+ ambient: this.context.type
33033
+ };
33034
+ const pairingDataString = JSON.stringify(pairingObject);
33035
+ this.qrCodeBase64Image = await import_qrcode.default.toDataURL(pairingDataString);
33036
+ console.log(this.qrCodeBase64Image);
33037
+ return this.qrCodeBase64Image;
33038
+ } catch (error) {
33039
+ this.disconnectWebSocket();
33040
+ return Promise.reject(error);
33041
+ }
33042
+ }
33043
+ // teste com UI
33044
+ async checkExternalCamera() {
33045
+ this.currentStep = 0 /* STARTED */;
33046
+ if (_ExternalCameraChecker.isModalOpen) {
33047
+ return Promise.reject("O modal de verifica\xE7\xE3o j\xE1 est\xE1 aberto.");
33048
+ }
33049
+ _ExternalCameraChecker.isModalOpen = true;
33050
+ try {
33051
+ await this.startSession(() => {
33052
+ });
33053
+ return await this.buildInterface();
33054
+ } catch (error) {
33055
+ console.error("Erro ao iniciar verifica\xE7\xE3o:", error);
33056
+ this.closeCheckExternalCamera();
33057
+ return Promise.reject(error);
33058
+ }
33059
+ }
33060
+ buildInterface() {
33061
+ return new Promise((resolve, reject) => {
33062
+ this.resolvePromise = resolve;
33063
+ const fullBg = document.createElement("div");
33064
+ fullBg.setAttribute("id", "externalCameraCheck");
33065
+ this.applyStyles(fullBg, {
33066
+ backgroundColor: "rgba(0,0,0,0.4)",
33067
+ zIndex: "1000",
33068
+ position: "fixed",
33069
+ top: "0",
33070
+ left: "0",
33071
+ height: "100vh",
33072
+ width: "100%",
33073
+ display: "flex",
33074
+ alignItems: "center",
33075
+ justifyContent: "center"
33076
+ });
33077
+ const modal = document.createElement("div");
33078
+ this.applyStyles(modal, {
33079
+ backgroundColor: "#fff",
33080
+ zIndex: "1001",
33081
+ width: "500px",
33082
+ borderRadius: "10px",
33083
+ display: "flex",
33084
+ flexDirection: "column",
33085
+ alignItems: "center"
33086
+ });
33087
+ const h3 = document.createElement("h3");
33088
+ h3.innerText = "Conectar dispositivo m\xF3vel";
33089
+ this.applyStyles(h3, {
33090
+ color: "rgba(0, 0, 0, .7)",
33091
+ fontWeight: "bold",
33092
+ fontSize: "20px",
33093
+ marginBottom: "15px",
33094
+ padding: "20px 0px",
33095
+ borderBottom: "2px solid rgba(0, 0, 0, .1)",
33096
+ width: "100%",
33097
+ textAlign: "center"
33098
+ });
33099
+ const contentArea = document.createElement("div");
33100
+ contentArea.id = "external-camera-content";
33101
+ this.applyStyles(contentArea, {
33102
+ width: "100%",
33103
+ padding: "20px 40px",
33104
+ boxSizing: "border-box",
33105
+ minHeight: "300px",
33106
+ display: "flex",
33107
+ flexDirection: "column",
33108
+ justifyContent: "center",
33109
+ alignItems: "center"
33110
+ });
33111
+ const divBtn = document.createElement("div");
33112
+ this.applyStyles(divBtn, {
33113
+ width: "100%",
33114
+ display: "flex",
33115
+ alignItems: "center",
33116
+ justifyContent: "center",
33117
+ borderTop: "2px solid rgba(0, 0, 0, .1)"
33118
+ });
33119
+ const buttonCancel = document.createElement("button");
33120
+ buttonCancel.innerText = "Cancelar";
33121
+ this.applyStyles(buttonCancel, {
33122
+ width: "100%",
33123
+ height: "70px",
33124
+ backgroundColor: "#FFF",
33125
+ border: "none",
33126
+ color: "rgba(0, 0, 0, .7)",
33127
+ fontWeight: "bold",
33128
+ borderRadius: "0 0 0 10px",
33129
+ cursor: "pointer"
33130
+ });
33131
+ buttonCancel.addEventListener("click", () => {
33132
+ var _a2;
33133
+ const actionMessage = new ActionMessage();
33134
+ actionMessage.command = "Cancel";
33135
+ console.log("Enviando comando 'Cancel' para o aplicativo...");
33136
+ (_a2 = this.connection) == null ? void 0 : _a2.invoke(
33137
+ "SendAction",
33138
+ this.externalSessionId,
33139
+ actionMessage
33140
+ );
33141
+ this.closeCheckExternalCamera();
33142
+ resolve({ result: false });
33143
+ });
33144
+ const buttonContinue = document.createElement("button");
33145
+ buttonContinue.innerText = "Continuar";
33146
+ buttonContinue.id = "external-camera-continue";
33147
+ this.applyStyles(buttonContinue, {
33148
+ width: "100%",
33149
+ height: "70px",
33150
+ backgroundColor: "#FFF",
33151
+ border: "none",
33152
+ color: "rgba(0, 0, 0, .7)",
33153
+ fontWeight: "bold",
33154
+ borderRadius: "0 0 10px 0",
33155
+ cursor: "pointer",
33156
+ borderLeft: "2px solid rgba(0, 0, 0, .1)"
33157
+ });
33158
+ divBtn.appendChild(buttonCancel);
33159
+ divBtn.appendChild(buttonContinue);
33160
+ modal.appendChild(h3);
33161
+ modal.appendChild(contentArea);
33162
+ modal.appendChild(divBtn);
33163
+ fullBg.appendChild(modal);
33164
+ document.body.appendChild(fullBg);
33165
+ this.renderCurrentStep();
33166
+ });
33167
+ }
33168
+ renderCurrentStep() {
33169
+ const contentArea = document.getElementById("external-camera-content");
33170
+ if (!contentArea) return;
33171
+ contentArea.innerHTML = "";
33172
+ switch (this.currentStep) {
33173
+ case 0 /* STARTED */:
33174
+ this.renderQRCodeStep(contentArea);
33175
+ break;
33176
+ case 1 /* QR_CODE */:
33177
+ this.renderPhotoStep(contentArea);
33178
+ break;
33179
+ case 2 /* POSITION */:
33180
+ this.renderImageStep(contentArea);
33181
+ break;
33182
+ default:
33183
+ break;
33184
+ }
33185
+ }
33186
+ /**
33187
+ * Passo 1: Renderiza o QR Code e as instruções.
33188
+ */
33189
+ renderQRCodeStep(container) {
33190
+ const qrCanvas = document.createElement("canvas");
33191
+ qrCanvas.id = "qr-code-canvas";
33192
+ const instructions = document.createElement("p");
33193
+ instructions.innerText = "Aponte a c\xE2mera do seu celular para o QR Code para iniciar a verifica\xE7\xE3o do ambiente.";
33194
+ this.applyStyles(instructions, {
33195
+ textAlign: "center",
33196
+ color: "#555",
33197
+ marginTop: "20px"
33198
+ });
33199
+ const ctx = qrCanvas.getContext("2d");
33200
+ const img = new Image();
33201
+ img.onload = () => {
33202
+ const targetWidth = 250;
33203
+ const scale = targetWidth / img.width;
33204
+ const targetHeight = img.height * scale;
33205
+ qrCanvas.width = targetWidth;
33206
+ qrCanvas.height = targetHeight;
33207
+ if (ctx)
33208
+ ctx.drawImage(img, 0, 0, targetWidth, targetHeight);
33209
+ };
33210
+ img.src = this.qrCodeBase64Image;
33211
+ container.appendChild(qrCanvas);
33212
+ container.appendChild(instructions);
33213
+ const continueBtn = document.getElementById(
33214
+ "external-camera-continue"
33215
+ );
33216
+ continueBtn.disabled = true;
33217
+ this.applyStyles(continueBtn, { color: "#ccc", cursor: "not-allowed" });
33218
+ }
33219
+ /**
33220
+ * Passo 2: Renderiza a etapa de captura
33221
+ */
33222
+ renderPhotoStep(container) {
33223
+ const instructions = document.createElement("p");
33224
+ instructions.id = "photo-message";
33225
+ instructions.innerText = "Clique no bot\xE3o abaixo para realizar a captura da foto do ambiente.";
33226
+ this.applyStyles(instructions, {
33227
+ textAlign: "center",
33228
+ color: "#555",
33229
+ marginBottom: "20px",
33230
+ fontSize: "14px",
33231
+ display: "-webkit-box",
33232
+ overflow: "hidden",
33233
+ textOverflow: "ellipsis"
33234
+ });
33235
+ instructions.style.webkitLineClamp = "3";
33236
+ instructions.style.webkitBoxOrient = "vertical";
33237
+ container.appendChild(instructions);
33238
+ const errorBanner = document.createElement("div");
33239
+ errorBanner.id = "photo-error-banner";
33240
+ errorBanner.innerText = "Foto fora do padr\xE3o esperado.";
33241
+ this.applyStyles(errorBanner, {
33242
+ backgroundColor: "#FEE2E2",
33243
+ color: "#DC2626",
33244
+ padding: "12px 15px",
33245
+ borderRadius: "8px",
33246
+ textAlign: "center",
33247
+ fontSize: "12px",
33248
+ fontWeight: "400",
33249
+ marginBottom: "15px",
33250
+ display: "none"
33251
+ // Hidden by default, can be shown when needed
33252
+ });
33253
+ container.appendChild(errorBanner);
33254
+ const card = document.createElement("div");
33255
+ this.applyStyles(card, {
33256
+ backgroundColor: "#fff",
33257
+ borderRadius: "8px",
33258
+ padding: "20px",
33259
+ display: "flex",
33260
+ gap: "20px",
33261
+ alignItems: "flex-start",
33262
+ border: "1px solid #e5e5e5",
33263
+ marginBottom: "20px"
33264
+ });
33265
+ const iconContainer = document.createElement("div");
33266
+ iconContainer.id = "photo-icon-container";
33267
+ this.applyStyles(iconContainer, {
33268
+ backgroundColor: "#f5f5f5",
33269
+ borderRadius: "8px",
33270
+ width: "120px",
33271
+ height: "160px",
33272
+ minWidth: "120px",
33273
+ minHeight: "160px",
33274
+ display: "flex",
33275
+ alignItems: "center",
33276
+ justifyContent: "center",
33277
+ flexShrink: "0",
33278
+ overflow: "hidden"
33279
+ });
33280
+ if (this.capturePhotoUrl && this.capturePhotoUrl.trim() !== "") {
33281
+ const capturedImage = document.createElement("img");
33282
+ capturedImage.id = "img-photo";
33283
+ const base64Data = this.capturePhotoUrl.startsWith("data:") ? this.capturePhotoUrl : "data:image/jpeg;base64," + this.capturePhotoUrl;
33284
+ capturedImage.src = base64Data;
33285
+ this.applyStyles(capturedImage, {
33286
+ width: "100%",
33287
+ height: "100%",
33288
+ objectFit: "contain",
33289
+ objectPosition: "center",
33290
+ borderRadius: "8px",
33291
+ display: "block"
33292
+ });
33293
+ iconContainer.appendChild(capturedImage);
33294
+ } else {
33295
+ const cameraIcon = document.createElement("div");
33296
+ cameraIcon.innerHTML = `
33297
+ <svg width="40" height="40" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
33298
+ <path d="M23 19C23 19.5304 22.7893 20.0391 22.4142 20.4142C22.0391 20.7893 21.5304 21 21 21H3C2.46957 21 1.96086 20.7893 1.58579 20.4142C1.21071 20.0391 1 19.5304 1 19V8C1 7.46957 1.21071 6.96086 1.58579 6.58579C1.96086 6.21071 2.46957 6 3 6H7L9 4H15L17 6H21C21.5304 6 22.0391 6.21071 22.4142 6.58579C22.7893 6.96086 23 7.46957 23 8V19Z" stroke="#666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
33299
+ <path d="M12 17C14.2091 17 16 15.2091 16 13C16 10.7909 14.2091 9 12 9C9.79086 9 8 10.7909 8 13C8 15.2091 9.79086 17 12 17Z" stroke="#666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
33300
+ </svg>
33301
+ `;
33302
+ iconContainer.appendChild(cameraIcon);
33303
+ }
33304
+ card.appendChild(iconContainer);
33305
+ const contentSide = document.createElement("div");
33306
+ this.applyStyles(contentSide, {
33307
+ flex: "1",
33308
+ display: "flex",
33309
+ flexDirection: "column",
33310
+ gap: "15px"
33311
+ });
33312
+ const heading = document.createElement("h4");
33313
+ heading.innerText = "Capture uma foto n\xEDtida";
33314
+ this.applyStyles(heading, {
33315
+ margin: "0",
33316
+ fontSize: "16px",
33317
+ fontWeight: "bold",
33318
+ color: "#333"
33319
+ });
33320
+ contentSide.appendChild(heading);
33321
+ const checklist = document.createElement("div");
33322
+ this.applyStyles(checklist, {
33323
+ display: "flex",
33324
+ flexDirection: "column",
33325
+ gap: "10px"
33326
+ });
33327
+ const checklistItems = [
33328
+ "Boa ilumina\xE7\xE3o e sem reflexos",
33329
+ "Mostre a mesa, cadeira e ambiente",
33330
+ "Evite pessoas ao fundo"
33331
+ ];
33332
+ checklistItems.forEach((itemText) => {
33333
+ const item = document.createElement("div");
33334
+ this.applyStyles(item, {
33335
+ display: "flex",
33336
+ alignItems: "center",
33337
+ gap: "8px",
33338
+ fontSize: "14px",
33339
+ color: "#555"
33219
33340
  });
33220
- throw NOT_SHARED_FIRST_SCREEN;
33221
- } else if (!sharedScreen || sharedNotAllowed) {
33222
- tracks.forEach((el) => {
33223
- el.stop();
33341
+ const checkmark = document.createElement("span");
33342
+ checkmark.innerHTML = `
33343
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
33344
+ <circle cx="10" cy="10" r="9" stroke="#16A34A" stroke-width="2" fill="none"/>
33345
+ <path d="M6 10L9 13L14 7" stroke="#16A34A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
33346
+ </svg>
33347
+ `;
33348
+ this.applyStyles(checkmark, {
33349
+ display: "inline-flex",
33350
+ alignItems: "center",
33351
+ justifyContent: "center",
33352
+ width: "20px",
33353
+ height: "20px",
33354
+ flexShrink: "0"
33224
33355
  });
33225
- throw NOT_SHARED_SCREEN;
33226
- }
33227
- const { startRecording, stopRecording } = recorder(this.screenStream, this.blobs, this.options.onBufferSizeError, onBufferSizeErrorCallback);
33228
- this.recordingStart = startRecording;
33229
- this.recordingStop = stopRecording;
33230
- this.recordingStart();
33231
- }
33232
- async pauseRecording() {
33233
- }
33234
- async resumeRecording() {
33235
- }
33236
- async stopRecording() {
33237
- this.recordingStop && await this.recordingStop();
33238
- }
33239
- async saveOnSession(session) {
33240
- session.addRecording({
33241
- device: "",
33242
- file: new File(this.blobs, `EP_${session.id}_screen_0.webm`, {
33243
- type: "video/webm"
33244
- }),
33245
- origin: "Screen" /* Screen */
33356
+ const text = document.createElement("span");
33357
+ text.innerText = itemText;
33358
+ item.appendChild(checkmark);
33359
+ item.appendChild(text);
33360
+ checklist.appendChild(item);
33246
33361
  });
33247
- }
33248
- };
33249
-
33250
- // src/new-flow/repository/IndexDbSessionRepository.ts
33251
- var IndexDbSessionRepository = class {
33252
- constructor(dbName, storeName) {
33253
- this.dbName = "EasyProctorDb";
33254
- this.dbVersion = 2;
33255
- this.storeName = "exams2";
33256
- this.dbName = dbName;
33257
- this.storeName = storeName;
33258
- }
33259
- async save(data) {
33260
- const { transaction, store } = await this.connectToStore("readwrite");
33261
- return this.processRequest(store.put(data), transaction).then(() => {
33362
+ contentSide.appendChild(checklist);
33363
+ const positionCaptureButton = document.createElement("button");
33364
+ positionCaptureButton.innerText = "Capturar foto";
33365
+ positionCaptureButton.id = "position-capture-button";
33366
+ this.applyStyles(positionCaptureButton, {
33367
+ marginTop: "10px",
33368
+ padding: "12px 24px",
33369
+ fontSize: "14px",
33370
+ fontWeight: "bold",
33371
+ color: "white",
33372
+ backgroundColor: "#16A34A",
33373
+ border: "none",
33374
+ borderRadius: "6px",
33375
+ cursor: "pointer",
33376
+ transition: "background-color 0.2s",
33377
+ alignSelf: "flex-start"
33262
33378
  });
33379
+ positionCaptureButton.onclick = () => {
33380
+ if (this.connection) {
33381
+ const instructions2 = document.getElementById("photo-message");
33382
+ if (instructions2)
33383
+ instructions2.innerText = "N\xE3o saia da posi\xE7\xE3o atual, estamos validando o ambiente...";
33384
+ errorBanner.style.display = "none";
33385
+ this.takePicture(true, () => {
33386
+ });
33387
+ positionCaptureButton.disabled = true;
33388
+ this.applyStyles(positionCaptureButton, {
33389
+ backgroundColor: "#9CA3AF",
33390
+ cursor: "not-allowed"
33391
+ });
33392
+ }
33393
+ };
33394
+ contentSide.appendChild(positionCaptureButton);
33395
+ card.appendChild(contentSide);
33396
+ container.appendChild(card);
33397
+ const tipSection = document.createElement("div");
33398
+ this.applyStyles(tipSection, {
33399
+ marginTop: "10px",
33400
+ fontSize: "13px",
33401
+ color: "#666"
33402
+ });
33403
+ const tipLabel = document.createElement("span");
33404
+ tipLabel.innerText = "Dica: ";
33405
+ tipLabel.style.fontWeight = "bold";
33406
+ const tipText = document.createElement("span");
33407
+ tipText.innerText = "mantenha o celular est\xE1vel durante todo o processo.";
33408
+ tipSection.appendChild(tipLabel);
33409
+ tipSection.appendChild(tipText);
33410
+ container.appendChild(tipSection);
33411
+ const continueBtn = document.getElementById(
33412
+ "external-camera-continue"
33413
+ );
33414
+ continueBtn.disabled = true;
33415
+ this.applyStyles(continueBtn, { color: "#ccc", cursor: "not-allowed" });
33263
33416
  }
33264
- async delete(id) {
33265
- const { transaction, store } = await this.connectToStore("readwrite");
33266
- return this.processRequest(store.delete(id), transaction);
33267
- }
33268
- async get(id) {
33269
- const { transaction, store } = await this.connectToStore("readwrite");
33270
- return this.processRequest(
33271
- store.get(id),
33272
- transaction
33273
- ).catch(() => void 0);
33274
- }
33275
- async getDevices(id) {
33276
- const { transaction, store } = await this.connectToStore("readwrite");
33277
- return this.processRequest(
33278
- store.get(id),
33279
- transaction
33280
- ).catch(() => void 0);
33281
- }
33282
- async list() {
33283
- const { transaction, store } = await this.connectToStore("readonly");
33284
- return this.processRequest(store.getAll(), transaction);
33285
- }
33286
- async clear() {
33287
- const { transaction, store } = await this.connectToStore("readwrite");
33288
- return this.processRequest(store.clear(), transaction);
33289
- }
33290
- async processRequest(request, transaction) {
33291
- return new Promise((resolve, reject) => {
33292
- request.onerror = (event) => {
33293
- var _a2;
33294
- reject((_a2 = request.error) == null ? void 0 : _a2.message);
33295
- };
33296
- request.onsuccess = (event) => {
33297
- transaction.commit();
33298
- resolve(request.result);
33299
- };
33417
+ /**
33418
+ * Passo 3: Renderiza a imagem capturada.
33419
+ */
33420
+ renderImageStep(container) {
33421
+ container.innerHTML = "";
33422
+ const image = document.createElement("img");
33423
+ image.src = "data:image/jpeg;base64," + this.capturePhotoUrl;
33424
+ this.applyStyles(image, {
33425
+ maxWidth: "100%",
33426
+ maxHeight: "300px",
33427
+ borderRadius: "8px"
33428
+ });
33429
+ container.appendChild(image);
33430
+ const instructions = document.createElement("photo-message");
33431
+ instructions.id = "photo-message";
33432
+ instructions.innerText = "Verifica\xE7\xE3o finalizada com sucesso.";
33433
+ this.applyStyles(instructions, {
33434
+ textAlign: "center",
33435
+ color: "#555",
33436
+ marginTop: "20px"
33437
+ });
33438
+ container.appendChild(instructions);
33439
+ const continueBtn = document.getElementById(
33440
+ "external-camera-continue"
33441
+ );
33442
+ continueBtn.disabled = false;
33443
+ continueBtn.innerText = "Concluir";
33444
+ this.applyStyles(continueBtn, {
33445
+ width: "100%",
33446
+ height: "70px",
33447
+ backgroundColor: "#FFF",
33448
+ border: "none",
33449
+ color: "rgba(0, 0, 0, .7)",
33450
+ fontWeight: "bold",
33451
+ borderRadius: "0 0 10px 0",
33452
+ cursor: "pointer",
33453
+ borderLeft: "2px solid rgba(0, 0, 0, .1)"
33300
33454
  });
33455
+ continueBtn.onclick = () => {
33456
+ this.closeCheckExternalCamera();
33457
+ this.resolvePromise({ result: true });
33458
+ };
33301
33459
  }
33302
- async hasSessions() {
33303
- const list = await this.list();
33304
- return list.length > 0;
33460
+ nextState() {
33461
+ this.renderCurrentStep();
33305
33462
  }
33306
- async connectToStore(mode) {
33307
- const connection = await this.connect();
33308
- const db = connection.result;
33309
- const transaction = db.transaction(this.storeName, mode);
33310
- const store = transaction.objectStore(this.storeName);
33311
- return { transaction, store };
33463
+ // --- LÓGICA DE WEBSOCKET ---
33464
+ async initializeWebSocketConnection() {
33465
+ const hubUrl = this.backend.getSocketUrl();
33466
+ this.connection = new import_signalr.HubConnectionBuilder().withUrl(hubUrl, {
33467
+ accessTokenFactory: () => this.context.token,
33468
+ transport: import_signalr.HttpTransportType.WebSockets,
33469
+ withCredentials: false
33470
+ }).withAutomaticReconnect().configureLogging(import_signalr.LogLevel.Information).build();
33471
+ this.connection.on(
33472
+ "ReceiveMessage",
33473
+ (sessionId, messageStr) => {
33474
+ console.log("sessionId: ", sessionId);
33475
+ console.log("Message: ", messageStr);
33476
+ if (sessionId !== this.externalSessionId) {
33477
+ console.warn("Sess\xE3o diferente!");
33478
+ return;
33479
+ }
33480
+ try {
33481
+ const messageKey = messageStr;
33482
+ const message = ExternalCameraStatusEnum[messageKey];
33483
+ console.log("Mensagem -> ", message);
33484
+ this.handleWebSocketMessage(message);
33485
+ } catch (e3) {
33486
+ console.error("Erro ao processar mensagem do WebSocket:", e3);
33487
+ }
33488
+ }
33489
+ );
33490
+ this.connection.on(
33491
+ "ReceiveAction",
33492
+ (sessionId, actionMessage) => {
33493
+ console.log("sessionId: ", sessionId);
33494
+ console.log("Message: ", actionMessage);
33495
+ if (sessionId !== this.externalSessionId) {
33496
+ console.warn("Sess\xE3o diferente!");
33497
+ return;
33498
+ }
33499
+ try {
33500
+ this.handleWebSocketAction(actionMessage);
33501
+ } catch (e3) {
33502
+ console.error("Erro ao processar mensagem do WebSocket:", e3);
33503
+ }
33504
+ }
33505
+ );
33506
+ try {
33507
+ await this.connection.start();
33508
+ console.log("Conectado ao Hub SignalR com sucesso!");
33509
+ } catch (err) {
33510
+ console.error("Falha ao conectar ou entrar no grupo do SignalR: ", err);
33511
+ throw new Error("N\xE3o foi poss\xEDvel conectar ao servi\xE7o em tempo real.");
33512
+ }
33312
33513
  }
33313
- async connect() {
33314
- if (this.connection) return this.connection;
33315
- return new Promise((resolve, reject) => {
33316
- const request = window.indexedDB.open(this.dbName, this.dbVersion);
33317
- request.onerror = (event) => {
33318
- reject("Can't connect to IndexedDB");
33319
- };
33320
- request.onupgradeneeded = (event) => {
33321
- const db = request.result;
33322
- db.onerror = (event2) => {
33323
- };
33324
- db.createObjectStore(this.storeName, { keyPath: "id" });
33325
- };
33326
- request.onsuccess = (event) => {
33327
- this.connection = request;
33328
- resolve(request);
33329
- };
33330
- });
33514
+ /**
33515
+ * 7. Processa as ações recebidas e atualiza a UI.
33516
+ */
33517
+ handleWebSocketAction(action) {
33518
+ const positionCaptureButton = document.getElementById("position-capture-button");
33519
+ const instructions = document.getElementById("photo-message");
33520
+ const errorBanner = document.getElementById("photo-error-banner");
33521
+ switch (action.command) {
33522
+ case "Capture_Error":
33523
+ if (positionCaptureButton) {
33524
+ this.applyStyles(positionCaptureButton, {
33525
+ marginTop: "30px",
33526
+ padding: "12px 20px",
33527
+ fontSize: "16px",
33528
+ fontWeight: "bold",
33529
+ color: "white",
33530
+ backgroundColor: "#16A34A",
33531
+ border: "none",
33532
+ borderRadius: "8px",
33533
+ cursor: "pointer",
33534
+ transition: "background-color 0.2s"
33535
+ });
33536
+ positionCaptureButton.disabled = false;
33537
+ }
33538
+ if (instructions)
33539
+ instructions.innerText = "" + action.message;
33540
+ if (errorBanner)
33541
+ errorBanner.style.display = "flex";
33542
+ if (this.waitingPositionValidation == true)
33543
+ this.onTakePictureCallback({
33544
+ photo: this.capturePhotoUrl,
33545
+ errorMessage: action.message,
33546
+ success: false
33547
+ });
33548
+ break;
33549
+ case "CapturePhoto":
33550
+ this.capturePhotoUrl = "" + action.message;
33551
+ const iconContainer = document.getElementById("photo-icon-container");
33552
+ if (iconContainer && this.capturePhotoUrl && this.capturePhotoUrl.trim() !== "") {
33553
+ let image = document.getElementById("img-photo");
33554
+ if (!image) {
33555
+ iconContainer.innerHTML = "";
33556
+ image = document.createElement("img");
33557
+ image.id = "img-photo";
33558
+ this.applyStyles(image, {
33559
+ width: "100%",
33560
+ height: "100%",
33561
+ objectFit: "contain",
33562
+ objectPosition: "center",
33563
+ borderRadius: "8px",
33564
+ display: "block"
33565
+ });
33566
+ iconContainer.appendChild(image);
33567
+ }
33568
+ const base64Data = this.capturePhotoUrl.startsWith("data:") ? this.capturePhotoUrl : "data:image/jpeg;base64," + this.capturePhotoUrl;
33569
+ image.src = base64Data;
33570
+ image.onload = () => {
33571
+ console.log("Image loaded successfully in icon container");
33572
+ };
33573
+ image.onerror = (e3) => {
33574
+ console.error("Error loading image:", e3);
33575
+ };
33576
+ }
33577
+ if (this.waitingPositionValidation == false)
33578
+ this.onTakePictureCallback({
33579
+ photo: this.capturePhotoUrl
33580
+ });
33581
+ break;
33582
+ case "Check_Transmission":
33583
+ if (action.message == "Transmission_OK")
33584
+ this.transmissionOk = true;
33585
+ break;
33586
+ case "Cancel":
33587
+ this.closeCheckExternalCamera();
33588
+ break;
33589
+ case "EnvironmentAlert":
33590
+ this.onRealtimeAlertsCallback({
33591
+ status: "ALERT",
33592
+ description: action.message,
33593
+ type: "environment_alert"
33594
+ });
33595
+ break;
33596
+ }
33331
33597
  }
33332
- };
33333
-
33334
- // src/utils/browserInformations.ts
33335
- function fnBrowserDetect() {
33336
- const userAgent = navigator.userAgent;
33337
- let browserName;
33338
- if (userAgent.match(/chrome|chromium|crios/i)) {
33339
- browserName = "chrome";
33340
- } else if (userAgent.match(/firefox|fxios/i)) {
33341
- browserName = "firefox";
33342
- } else if (userAgent.match(/safari/i)) {
33343
- browserName = "safari";
33344
- } else if (userAgent.match(/opr\//i)) {
33345
- browserName = "opera";
33346
- } else if (userAgent.match(/edg/i)) {
33347
- browserName = "edge";
33348
- } else {
33349
- browserName = "No browser detection";
33598
+ /**
33599
+ * 7. Processa as mensagens recebidas e atualiza a UI.
33600
+ */
33601
+ handleWebSocketMessage(status) {
33602
+ this.currentStep = status;
33603
+ switch (status) {
33604
+ case 1 /* QR_CODE */:
33605
+ if (this.currentStep === 1) {
33606
+ this.nextState();
33607
+ this.onQrCodeReadedCallback(true);
33608
+ }
33609
+ break;
33610
+ case 2 /* POSITION */:
33611
+ this.nextState();
33612
+ if (this.waitingPositionValidation == true)
33613
+ this.onTakePictureCallback({
33614
+ photo: this.capturePhotoUrl,
33615
+ success: true
33616
+ });
33617
+ break;
33618
+ case 3 /* FINISHED */:
33619
+ this.closeCheckExternalCamera();
33620
+ break;
33621
+ case 9 /* ERROR */:
33622
+ console.error("Erro recebido do processo de c\xE2mera externa.");
33623
+ this.closeCheckExternalCamera();
33624
+ this.resolvePromise({ result: false });
33625
+ break;
33626
+ }
33350
33627
  }
33351
- return browserName;
33352
- }
33353
-
33354
- // src/utils/geolocation.ts
33355
- function getGeolocation() {
33356
- return new Promise((resolve, reject) => {
33357
- window.navigator.geolocation.getCurrentPosition(resolve, reject);
33358
- });
33359
- }
33360
-
33361
- // src/utils/verifyVersion.ts
33362
- function versionVerify() {
33363
- const agentStr = window.navigator.userAgent.split("SEB/");
33364
- if (agentStr.length > 1)
33365
- return agentStr[1];
33366
- else return "1.0.0.0";
33367
- }
33368
-
33369
- // src/proctoring/Auth.ts
33370
- var Auth = class {
33371
- constructor(cpf, backend) {
33372
- this.cpf = cpf;
33373
- this.backend = backend;
33374
- this.capturePhoto = new CapturePhoto();
33628
+ /**
33629
+ * 8. Desconecta do WebSocket de forma limpa.
33630
+ */
33631
+ async disconnectWebSocket() {
33632
+ if (this.connection) {
33633
+ try {
33634
+ await this.connection.stop();
33635
+ console.log("Desconectado do SignalR.");
33636
+ } catch (err) {
33637
+ console.error("Erro ao desconectar do SignalR:", err);
33638
+ } finally {
33639
+ this.connection = null;
33640
+ }
33641
+ }
33375
33642
  }
33376
- async login() {
33377
- const capture = await this.capturePhoto.takePicture(
33378
- "Login com biometria facial",
33379
- "Encaixe seu rosto no formato e clique no bot\xE3o abaixo",
33380
- { width: 1280, height: 720 }
33381
- );
33382
- this.loading();
33383
- return new Promise((resolve, reject) => {
33384
- this.backend.loginAuth(this.cpf, capture.base64.substr(22, capture.base64.length)).then((resp) => {
33385
- this.token = resp.token;
33386
- const authLoader = document.querySelector("#authLoader");
33387
- authLoader == null ? void 0 : authLoader.remove();
33388
- this.backend.token = this.token;
33389
- resolve(this.token);
33390
- }).catch((e3) => {
33391
- console.log(e3);
33392
- const authLoader = document.querySelector("#authLoader");
33393
- authLoader == null ? void 0 : authLoader.remove();
33394
- reject(e3);
33395
- });
33396
- });
33643
+ /**
33644
+ * Limpa os recursos, desconecta o WebSocket e remove o modal da tela.
33645
+ */
33646
+ closeCheckExternalCamera() {
33647
+ _ExternalCameraChecker.isModalOpen = false;
33648
+ this.disconnectWebSocket();
33649
+ const checkDiv = document.querySelector("#externalCameraCheck");
33650
+ checkDiv == null ? void 0 : checkDiv.remove();
33397
33651
  }
33398
- loading() {
33399
- const fullBg = document.createElement("div");
33400
- fullBg.setAttribute("id", "authLoader");
33401
- fullBg.style.backgroundColor = "rgba(0,0,0,0.4)";
33402
- fullBg.style.zIndex = "1000";
33403
- fullBg.style.position = "fixed";
33404
- fullBg.style.top = "0";
33405
- fullBg.style.left = "0";
33406
- fullBg.style.height = "100vh";
33407
- fullBg.style.width = "100%";
33408
- fullBg.style.display = "flex";
33409
- fullBg.style.alignItems = "center";
33410
- fullBg.style.justifyContent = "center";
33411
- const loader = document.createElement("div");
33412
- loader.setAttribute("class", "loader");
33413
- fullBg.appendChild(loader);
33414
- document.body.appendChild(fullBg);
33415
- const styles = `
33416
- .loader {
33417
- border: 6px solid #f3f3f3;
33418
- border-radius: 50%;
33419
- border-top: 6px solid #16a34a;
33420
- width: 50px;
33421
- height: 50px;
33422
- -webkit-animation: spin 2s linear infinite; /* Safari */
33423
- animation: spin 2s linear infinite;
33424
- }
33425
-
33426
- /* Safari */
33427
- @-webkit-keyframes spin {
33428
- 0% { -webkit-transform: rotate(0deg); }
33429
- 100% { -webkit-transform: rotate(360deg); }
33430
- }
33431
-
33432
- @keyframes spin {
33433
- 0% { transform: rotate(0deg); }
33434
- 100% { transform: rotate(360deg); }
33435
- }
33436
- `;
33437
- const styleSheet = document.createElement("style");
33438
- styleSheet.innerHTML = styles;
33439
- document.head.appendChild(styleSheet);
33652
+ /**
33653
+ * Função auxiliar para aplicar estilos.
33654
+ */
33655
+ applyStyles(element, styles) {
33656
+ for (const property in styles) {
33657
+ element.style[property] = styles[property];
33658
+ }
33440
33659
  }
33441
33660
  };
33661
+ _ExternalCameraChecker.isModalOpen = false;
33662
+ var ExternalCameraChecker = _ExternalCameraChecker;
33442
33663
 
33443
33664
  // src/proctoring/proctoring.ts
33444
33665
  var Proctoring = class {
@@ -33498,6 +33719,7 @@ var Proctoring = class {
33498
33719
  "devices"
33499
33720
  );
33500
33721
  ((_a2 = this.context.credentials) == null ? void 0 : _a2.cpf) && (this.auth = new Auth(this.context.credentials.cpf, this.backend));
33722
+ this.appChecker = new ExternalCameraChecker(this.context, (response) => this.onRealtimeAlertsCallback(response));
33501
33723
  }
33502
33724
  setOnStopSharingScreenCallback(cb) {
33503
33725
  this.onStopSharingScreenCallback = () => {
@@ -33588,27 +33810,6 @@ var Proctoring = class {
33588
33810
  if (!((_a2 = this.context.credentials) == null ? void 0 : _a2.cpf)) throw CREDENTIALS_MISSING;
33589
33811
  this.context.token = await this.auth.login();
33590
33812
  }
33591
- async startExternalCameraSession(cb) {
33592
- try {
33593
- this.appChecker = new ExternalCameraChecker(
33594
- this.context,
33595
- (response) => this.onRealtimeAlertsCallback(response)
33596
- );
33597
- await this.appChecker.startSession(cb);
33598
- } catch (error) {
33599
- throw ERROR_ON_MOBILE_APP_NOT_FOUND;
33600
- }
33601
- }
33602
- // public async startExternalCameraTransmission(){
33603
- // try {
33604
- // if (this.appChecker == null) {
33605
- // throw EXTERNAL_CAMERA_NOT_STARTED;
33606
- // }
33607
- // await this.appChecker.startTransmission();
33608
- // } catch(error: any) {
33609
- // throw ERROR_ON_MOBILE_APP_NOT_FOUND;
33610
- // }
33611
- // }
33612
33813
  async start(options = getDefaultProctoringOptions, _videoOptions = {}) {
33613
33814
  var _a2;
33614
33815
  try {
@@ -33654,18 +33855,11 @@ var Proctoring = class {
33654
33855
  this.proctoringId = startResponse.id;
33655
33856
  try {
33656
33857
  if (options == null ? void 0 : options.useExternalCamera) {
33657
- this.appChecker = new ExternalCameraChecker(
33658
- this.context,
33659
- (response) => this.onRealtimeAlertsCallback(response)
33660
- );
33661
- this.appChecker.setProctoringId(this.proctoringId);
33662
- await this.appChecker.checkExternalCamera();
33858
+ await this.appChecker.startTransmission(this.proctoringId);
33663
33859
  }
33664
33860
  } catch (error) {
33665
- throw ERROR_ON_MOBILE_APP_NOT_FOUND;
33861
+ throw EXTERNAL_CAMERA_NOT_STARTED;
33666
33862
  }
33667
- if (options == null ? void 0 : options.useExternalCamera)
33668
- await this.appChecker.initializeWebSocketConnection();
33669
33863
  this.allRecorders.cameraRecorder.setProctoringId(this.proctoringId);
33670
33864
  this.allRecorders.noiseRecorder.setProctoringId(this.proctoringId);
33671
33865
  this.proctoringSession.setProctoringId(this.proctoringId);
@@ -34153,8 +34347,6 @@ function useProctoring(proctoringOptions, enviromentConfig = "prod") {
34153
34347
  };
34154
34348
  const proctoring = new Proctoring(parameters);
34155
34349
  const checker = new DeviceCheckerService(parameters);
34156
- const externalChecker = new ExternalCameraChecker(parameters, () => {
34157
- });
34158
34350
  const signTerm = new SignTerm(parameters);
34159
34351
  const photo = new CapturePhoto();
34160
34352
  const login = proctoring.login.bind(proctoring);
@@ -34170,10 +34362,11 @@ function useProctoring(proctoringOptions, enviromentConfig = "prod") {
34170
34362
  const onRealtimeAlerts = proctoring.onRealtimeAlerts.bind(proctoring);
34171
34363
  const signInTerms = signTerm.signInTerms.bind(signTerm);
34172
34364
  const checkDevices = checker.checkDevices.bind(checker);
34173
- const checkExternalCamera = externalChecker.checkExternalCamera.bind(externalChecker);
34174
- const startExternalCameraSession = externalChecker.startSession.bind(externalChecker);
34175
- const takeExternalCameraPicture = externalChecker.takePicture.bind(externalChecker);
34176
- const resetExternalCameraSession = externalChecker.reset.bind(externalChecker);
34365
+ const checkExternalCamera = proctoring.appChecker.checkExternalCamera.bind(proctoring.appChecker);
34366
+ const startExternalCameraSession = proctoring.appChecker.startSession.bind(proctoring.appChecker);
34367
+ const takeExternalCameraPicture = proctoring.appChecker.takePicture.bind(proctoring.appChecker);
34368
+ const goToExternalCameraPositionStep = proctoring.appChecker.goToPositionGuide.bind(proctoring.appChecker);
34369
+ const startExternalCameraTransmission = proctoring.appChecker.startTransmission.bind(proctoring.appChecker);
34177
34370
  const runCheckDevicesFlow = checker.runCheckDevicesFlow.bind(checker);
34178
34371
  const changeSelectedDevice = checker.changeSelectedDevice.bind(checker);
34179
34372
  const capturePhoto = photo.takePicture.bind(photo);
@@ -34201,7 +34394,8 @@ function useProctoring(proctoringOptions, enviromentConfig = "prod") {
34201
34394
  checkExternalCamera,
34202
34395
  startExternalCameraSession,
34203
34396
  takeExternalCameraPicture,
34204
- resetExternalCameraSession
34397
+ goToExternalCameraPositionStep,
34398
+ startExternalCameraTransmission
34205
34399
  };
34206
34400
  }
34207
34401