easyproctor 2.5.2 → 2.5.3

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
@@ -26076,6 +26076,14 @@ var BaseDetection = class {
26076
26076
  return "Face n\xE3o centralizada, mova-se para cima";
26077
26077
  case "wrong_face_position_move_bottom_detected":
26078
26078
  return "Face n\xE3o centralizada, mova-se para baixo";
26079
+ case "face_turned_left_detected":
26080
+ return "Face virada para a esquerda, centralize-a";
26081
+ case "face_turned_right_detected":
26082
+ return "Face virada para a direita, centralize-a";
26083
+ case "face_turned_up_detected":
26084
+ return "Face virada para cima, centralize-a";
26085
+ case "face_turned_down_detected":
26086
+ return "Face virada para baixo, centralize-a";
26079
26087
  default:
26080
26088
  return description;
26081
26089
  }
@@ -26106,7 +26114,14 @@ function buildVideoPreview() {
26106
26114
  // src/modules/faceDetection.ts
26107
26115
  var FaceDetection = class extends BaseDetection {
26108
26116
  constructor(options, paramsConfig, classVideo = "videoPreviewFrameDetection", classDiv = "liveViewFrameDetection") {
26109
- super("FaceDetector", `https://storage.googleapis.com/mediapipe-models/face_detector/blaze_face_short_range/float16/1/blaze_face_short_range.tflite`, options, paramsConfig, classVideo, classDiv);
26117
+ super(
26118
+ "FaceDetector",
26119
+ `https://storage.googleapis.com/mediapipe-models/face_detector/blaze_face_short_range/float16/1/blaze_face_short_range.tflite`,
26120
+ options,
26121
+ paramsConfig,
26122
+ classVideo,
26123
+ classDiv
26124
+ );
26110
26125
  this.emmitedPositionAlert = false;
26111
26126
  this.emmitedFaceAlert = false;
26112
26127
  }
@@ -26252,8 +26267,8 @@ var FaceDetection = class extends BaseDetection {
26252
26267
  for (const keypoint of detection.keypoints) {
26253
26268
  const keypointEl = document.createElement("span");
26254
26269
  keypointEl.className = "key-point";
26255
- let kpX = keypoint.x < 2 ? keypoint.x * videoElement.videoWidth : keypoint.x;
26256
- let kpY = keypoint.y < 2 ? keypoint.y * videoElement.videoHeight : keypoint.y;
26270
+ const kpX = keypoint.x < 2 ? keypoint.x * videoElement.videoWidth : keypoint.x;
26271
+ const kpY = keypoint.y < 2 ? keypoint.y * videoElement.videoHeight : keypoint.y;
26257
26272
  const mirroredKpX = videoElement.videoWidth - kpX;
26258
26273
  const screenX = mirroredKpX * scaleX;
26259
26274
  const screenY = kpY * scaleY;
@@ -26292,55 +26307,87 @@ var FaceDetection = class extends BaseDetection {
26292
26307
  }
26293
26308
  }
26294
26309
  if (result.detections.length === 0) return;
26295
- let face = result.detections[0].boundingBox;
26296
- let video = document.getElementById(this.classVideo);
26310
+ let failedFacePosition = false;
26311
+ const video = document.getElementById(this.classVideo);
26297
26312
  const imageWidth = video.videoWidth;
26298
26313
  const imageHeight = video.videoHeight;
26299
- let failedFacePosition = false;
26314
+ const detection = result.detections[0];
26315
+ const face = detection.boundingBox;
26316
+ const keypoints = detection.keypoints;
26317
+ const rightEye = keypoints[0];
26318
+ const leftEye = keypoints[1];
26319
+ const mouth = keypoints[3];
26320
+ const rightEar = keypoints[4];
26321
+ const leftEar = keypoints[5];
26322
+ const nose = keypoints[2];
26300
26323
  if (imageWidth > imageHeight) {
26301
26324
  if (face.height / imageHeight > 0.7) {
26302
- !this.emmitedPositionAlert && this.handleAlert("wrong_face_size_detected", "position_detection_on_stream");
26325
+ !this.emmitedPositionAlert && this.handleAlert(
26326
+ "wrong_face_size_detected",
26327
+ "position_detection_on_stream"
26328
+ );
26303
26329
  failedFacePosition = true;
26304
26330
  this.emmitedPositionAlert = true;
26305
26331
  } else if (face.width / imageWidth > 0.7) {
26306
- !this.emmitedPositionAlert && this.handleAlert("wrong_face_size_detected", "position_detection_on_stream");
26332
+ !this.emmitedPositionAlert && this.handleAlert(
26333
+ "wrong_face_size_detected",
26334
+ "position_detection_on_stream"
26335
+ );
26307
26336
  this.emmitedPositionAlert = true;
26308
26337
  failedFacePosition = true;
26309
26338
  }
26310
26339
  }
26311
- let start = [face.originX, face.originY];
26312
- let end = [face.originX + face.width, face.originY + face.height];
26340
+ const start = [face.originX, face.originY];
26341
+ const end = [face.originX + face.width, face.originY + face.height];
26313
26342
  if (start[0] < 0.1 * face.width || start[1] < 0.2 * face.height || end[0] > imageWidth - 0.1 * face.width || end[1] > imageHeight - 5) {
26314
- !this.emmitedPositionAlert && this.handleAlert("wrong_face_position_edge_detected", "position_detection_on_stream");
26343
+ !this.emmitedPositionAlert && this.handleAlert(
26344
+ "wrong_face_position_edge_detected",
26345
+ "position_detection_on_stream"
26346
+ );
26315
26347
  this.emmitedPositionAlert = true;
26316
26348
  failedFacePosition = true;
26317
26349
  }
26318
- let leftGap = start[0];
26319
- let rightGap = imageWidth - end[0];
26320
- let topGap = start[1];
26321
- let bottomGap = imageHeight - end[1];
26350
+ const leftGap = start[0];
26351
+ const rightGap = imageWidth - end[0];
26352
+ const topGap = start[1];
26353
+ const bottomGap = imageHeight - end[1];
26322
26354
  if (leftGap > 2 * rightGap) {
26323
- !this.emmitedPositionAlert && this.handleAlert("wrong_face_position_move_right_detected", "position_detection_on_stream");
26355
+ !this.emmitedPositionAlert && this.handleAlert(
26356
+ "wrong_face_position_move_right_detected",
26357
+ "position_detection_on_stream"
26358
+ );
26324
26359
  this.emmitedPositionAlert = true;
26325
26360
  failedFacePosition = true;
26326
26361
  }
26327
26362
  if (topGap > 4 * bottomGap) {
26328
- !this.emmitedPositionAlert && this.handleAlert("wrong_face_position_move_top_detected", "position_detection_on_stream");
26363
+ !this.emmitedPositionAlert && this.handleAlert(
26364
+ "wrong_face_position_move_top_detected",
26365
+ "position_detection_on_stream"
26366
+ );
26329
26367
  this.emmitedPositionAlert = true;
26330
26368
  failedFacePosition = true;
26331
26369
  }
26332
26370
  if (rightGap > 2 * leftGap) {
26333
- !this.emmitedPositionAlert && this.handleAlert("wrong_face_position_move_left_detected", "position_detection_on_stream");
26371
+ !this.emmitedPositionAlert && this.handleAlert(
26372
+ "wrong_face_position_move_left_detected",
26373
+ "position_detection_on_stream"
26374
+ );
26334
26375
  this.emmitedPositionAlert = true;
26335
26376
  failedFacePosition = true;
26336
26377
  }
26337
26378
  if (bottomGap > 3 * topGap) {
26338
- !this.emmitedPositionAlert && this.handleAlert("wrong_face_position_move_bottom_detected", "position_detection_on_stream");
26379
+ !this.emmitedPositionAlert && this.handleAlert(
26380
+ "wrong_face_position_move_bottom_detected",
26381
+ "position_detection_on_stream"
26382
+ );
26339
26383
  this.emmitedPositionAlert = true;
26340
26384
  failedFacePosition = true;
26341
26385
  }
26342
26386
  if (failedFacePosition == false) {
26343
- this.emmitedPositionAlert && this.handleOk("ok_position_face_detected", "position_detection_on_stream");
26387
+ this.emmitedPositionAlert && this.handleOk(
26388
+ "ok_position_face_detected",
26389
+ "position_detection_on_stream"
26390
+ );
26344
26391
  this.emmitedPositionAlert = false;
26345
26392
  }
26346
26393
  }
@@ -29869,12 +29916,12 @@ var BackendService = class {
29869
29916
  });
29870
29917
  return result.data;
29871
29918
  }
29872
- async verifyFace(proctoringId2, faceImage) {
29919
+ async verifyFace(proctoringId2, faceImage, retry) {
29873
29920
  const result = await this.makeRequestAxios({
29874
29921
  path: `/Realtime/verify-face`,
29875
29922
  method: "POST",
29876
29923
  jwt: this.token,
29877
- body: { "proctoringId": proctoringId2, "base64": faceImage }
29924
+ body: { "proctoringId": proctoringId2, "base64": faceImage, "retry": retry }
29878
29925
  });
29879
29926
  return result.data;
29880
29927
  }
@@ -30750,7 +30797,6 @@ var CameraRecorder = class {
30750
30797
  noiseLimit: 40
30751
30798
  },
30752
30799
  imageBehaviourParameters: {
30753
- frames: 40,
30754
30800
  useUploadImage: true,
30755
30801
  uploadInterval: 20,
30756
30802
  saveVideo: true
@@ -30762,7 +30808,6 @@ var CameraRecorder = class {
30762
30808
  }
30763
30809
  };
30764
30810
  // private imageParams: ImageParameters = {
30765
- // frames: 40,
30766
30811
  // useUploadImage: true,
30767
30812
  // uploadInterval: 20,
30768
30813
  // saveVideo: true
@@ -31671,8 +31716,20 @@ var DeviceCheckerUI = class {
31671
31716
  );
31672
31717
  checkmark_FacePosition.appendChild(checkmark_stem_FacePosition);
31673
31718
  checkmark_FacePosition.appendChild(checkmark_kick_FacePosition);
31719
+ const info_FacePosition = document.createElement("span");
31720
+ const info_stem_FacePosition = document.createElement("div");
31721
+ const info_kick_FacePosition = document.createElement("div");
31722
+ info_FacePosition.style.marginLeft = "10px";
31723
+ info_FacePosition.setAttribute("class", "info");
31724
+ info_FacePosition.setAttribute("id", "info_FacePosition");
31725
+ info_FacePosition.style.display = "none";
31726
+ info_stem_FacePosition.setAttribute("class", "info_stem");
31727
+ info_kick_FacePosition.setAttribute("class", "info_kick");
31728
+ info_FacePosition.appendChild(info_stem_FacePosition);
31729
+ info_FacePosition.appendChild(info_kick_FacePosition);
31674
31730
  alertDivFacePosition.appendChild(checkmark_FacePosition);
31675
31731
  alertDivFacePosition.appendChild(facePositionAlert);
31732
+ alertDivFacePosition.appendChild(info_FacePosition);
31676
31733
  const alertDivAmbientVerify = document.createElement("div");
31677
31734
  alertDivAmbientVerify.setAttribute("class", "alert-div");
31678
31735
  alertDivAmbientVerify.setAttribute("id", "alertDivAmbientVerify");
@@ -32003,6 +32060,8 @@ var DeviceCheckerUI = class {
32003
32060
  realtimeAlertsUI(response) {
32004
32061
  const facePositionAlert = document.getElementById("facePositionAlert");
32005
32062
  const ambientVerifyAlert = document.getElementById("ambientVerifyAlert");
32063
+ const alertDivFacePosition = document.getElementById("alertDivFacePosition");
32064
+ const info_FacePosition = document.getElementById("info_FacePosition");
32006
32065
  const checkmark_FacePosition = document.getElementById("checkmark_FacePosition");
32007
32066
  const checkmark_stem_FacePosition = document.getElementById("checkmark_stem_FacePosition");
32008
32067
  const checkmark_kick_FacePosition = document.getElementById("checkmark_kick_FacePosition");
@@ -32013,6 +32072,8 @@ var DeviceCheckerUI = class {
32013
32072
  if (response.status === "OK") {
32014
32073
  facePositionAlert && (facePositionAlert.style.color = "#16A34A");
32015
32074
  ambientVerifyAlert && (ambientVerifyAlert.style.color = "#16A34A");
32075
+ alertDivFacePosition && alertDivFacePosition.setAttribute("title", ``);
32076
+ info_FacePosition && (info_FacePosition.style.display = "none");
32016
32077
  alertDivAmbientVerify && alertDivAmbientVerify.setAttribute("title", ``);
32017
32078
  if (checkmark_FacePosition) {
32018
32079
  checkmark_FacePosition.setAttribute("class", "checkmark");
@@ -32027,6 +32088,8 @@ var DeviceCheckerUI = class {
32027
32088
  } else {
32028
32089
  if (checkmark_FacePosition && (response.type === "position_detection_on_stream" || response.type === "face_detection_on_stream")) {
32029
32090
  facePositionAlert && (facePositionAlert.style.color = "#FF0000");
32091
+ info_FacePosition && (info_FacePosition.style.display = "block");
32092
+ alertDivFacePosition && alertDivFacePosition.setAttribute("title", response.description);
32030
32093
  checkmark_FacePosition.setAttribute("class", "checkmark_error");
32031
32094
  checkmark_stem_FacePosition.setAttribute("class", "checkmark_stem_error");
32032
32095
  checkmark_kick_FacePosition.setAttribute("class", "checkmark_kick_error");
@@ -33137,64 +33200,186 @@ var ProctoringUploader = class {
33137
33200
  var AlertRecorder = class {
33138
33201
  constructor(options, optionsProctoring) {
33139
33202
  this.alerts = [];
33203
+ // Variáveis para controle de inatividade
33204
+ this.lastActivityTime = Date.now();
33205
+ this.IDLE_THRESHOLD_MS = 3e4;
33206
+ // ==========================================
33207
+ // HANDLERS (Funções Arrow para preservar o 'this')
33208
+ // ==========================================
33209
+ // 1. LOST / RETURN FOCUS
33210
+ this.handleLostFocus = () => {
33211
+ if (this.getRelativeTime() > 1e4) {
33212
+ const alertPayload = {
33213
+ begin: this.getRelativeTime(),
33214
+ end: 0,
33215
+ alert: 25 /* FocusOff */,
33216
+ type: 3 /* Screen */
33217
+ };
33218
+ this.onLostFocusCallback(alertPayload);
33219
+ this.alerts.push(alertPayload);
33220
+ }
33221
+ };
33222
+ this.handleReturnFocus = () => {
33223
+ const lastAlert = this.alerts[this.alerts.length - 1];
33224
+ if (lastAlert) {
33225
+ this.onFocusCallback({
33226
+ begin: lastAlert.begin,
33227
+ end: this.getRelativeTime(),
33228
+ alert: 25 /* FocusOff */,
33229
+ type: 3 /* Screen */
33230
+ });
33231
+ lastAlert.end = this.getRelativeTime();
33232
+ }
33233
+ };
33234
+ // 2. SPLIT SCREEN DETECTION
33235
+ this.handleResize = () => {
33236
+ clearTimeout(this.resizeTimeout);
33237
+ this.resizeTimeout = setTimeout(() => {
33238
+ const screenWidth = window.screen.availWidth;
33239
+ const windowWidth = window.outerWidth;
33240
+ if (windowWidth < screenWidth * 0.85) {
33241
+ const msg = `Split Screen Detectado: Janela ocupa ${(windowWidth / screenWidth * 100).toFixed(0)}% da tela`;
33242
+ this.createAlert(200 /* System */, 3 /* Screen */, msg);
33243
+ this.onRealtimeAlertCallback && this.onRealtimeAlertCallback({
33244
+ status: "ALERT",
33245
+ description: msg,
33246
+ type: "split_screen"
33247
+ });
33248
+ }
33249
+ }, 1e3);
33250
+ };
33251
+ // 3. DETECÇÃO DE INATIVIDADE (NO INPUT)
33252
+ this.handleUserActivity = (e3) => {
33253
+ this.lastActivityTime = Date.now();
33254
+ console.log("\u{1F449} handleUserActivity", e3);
33255
+ };
33256
+ // 5. CLIPBOARD HANDLERS
33257
+ this.handleCopy = (e3) => {
33258
+ e3.preventDefault();
33259
+ const msg = "Tentativa de Copiar (Clipboard)";
33260
+ this.createAlert(100 /* ForbiddenAction */, 6 /* System */, msg);
33261
+ this.onRealtimeAlertCallback && this.onRealtimeAlertCallback({
33262
+ status: "ALERT",
33263
+ description: msg,
33264
+ type: "clipboard_copy"
33265
+ });
33266
+ };
33267
+ this.handleCut = (e3) => {
33268
+ e3.preventDefault();
33269
+ const msg = "Tentativa de Recortar (Clipboard)";
33270
+ this.createAlert(100 /* ForbiddenAction */, 6 /* System */, msg);
33271
+ this.onRealtimeAlertCallback && this.onRealtimeAlertCallback({
33272
+ status: "ALERT",
33273
+ description: msg,
33274
+ type: "clipboard_cut"
33275
+ });
33276
+ };
33277
+ this.handlePaste = (e3) => {
33278
+ e3.preventDefault();
33279
+ const msg = "Tentativa de Colar (Clipboard)";
33280
+ this.createAlert(100 /* ForbiddenAction */, 6 /* System */, msg);
33281
+ this.onRealtimeAlertCallback && this.onRealtimeAlertCallback({
33282
+ status: "ALERT",
33283
+ description: msg,
33284
+ type: "clipboard_paste"
33285
+ });
33286
+ };
33140
33287
  this.onLostFocusCallback = options.onLostFocusCallback;
33141
33288
  this.onFocusCallback = options.onFocusCallback;
33289
+ this.onRealtimeAlertCallback = options.onRealtimeAlertCallback;
33142
33290
  this.optionsProctoring = optionsProctoring;
33143
33291
  }
33144
33292
  async startRecording() {
33145
33293
  this.startTime = new Date(Date.now());
33146
- if (this.optionsProctoring.captureScreen) {
33147
- window.addEventListener("blur", () => this.onLostFocus());
33148
- window.addEventListener("focus", () => this.onReturnFocus());
33149
- }
33294
+ this.alerts = [];
33295
+ this.attachListeners();
33150
33296
  }
33151
33297
  async pauseRecording() {
33152
- window.removeEventListener("blur", () => this.onLostFocus());
33153
- window.removeEventListener("focus", () => this.onReturnFocus());
33298
+ this.detachListeners();
33154
33299
  }
33155
33300
  async resumeRecording() {
33156
- if (this.optionsProctoring.captureScreen) {
33157
- window.addEventListener("blur", () => this.onLostFocus());
33158
- window.addEventListener("focus", () => this.onReturnFocus());
33159
- }
33301
+ this.attachListeners();
33160
33302
  }
33161
33303
  async stopRecording() {
33162
- window.removeEventListener("blur", () => this.onLostFocus());
33163
- window.removeEventListener("focus", () => this.onReturnFocus());
33304
+ this.detachListeners();
33164
33305
  }
33165
33306
  async saveOnSession(session) {
33166
33307
  this.alerts.forEach((alert) => {
33167
33308
  session.addAlert(alert);
33168
33309
  });
33169
33310
  }
33170
- onLostFocus() {
33171
- var _a2;
33172
- if (Date.now() - ((_a2 = this.startTime) == null ? void 0 : _a2.getTime()) > 1e4) {
33173
- this.onLostFocusCallback({
33174
- begin: Date.now() - this.startTime.getTime(),
33175
- end: 0,
33176
- alert: 25 /* FocusOff */,
33177
- type: 3 /* Screen */
33178
- });
33179
- this.alerts.push({
33180
- begin: Date.now() - this.startTime.getTime(),
33181
- end: 0,
33182
- alert: 25 /* FocusOff */,
33183
- type: 3 /* Screen */
33184
- });
33185
- }
33311
+ // ==========================================
33312
+ // GERENCIAMENTO DE LISTENERS
33313
+ // ==========================================
33314
+ attachListeners() {
33315
+ if (this.optionsProctoring.captureScreen) {
33316
+ window.addEventListener("blur", this.handleLostFocus);
33317
+ window.addEventListener("focus", this.handleReturnFocus);
33318
+ window.addEventListener("resize", this.handleResize);
33319
+ window.document.addEventListener("copy", this.handleCopy);
33320
+ window.document.addEventListener("cut", this.handleCut);
33321
+ window.document.addEventListener("paste", this.handlePaste);
33322
+ }
33323
+ }
33324
+ detachListeners() {
33325
+ window.removeEventListener("blur", this.handleLostFocus);
33326
+ window.removeEventListener("focus", this.handleReturnFocus);
33327
+ window.removeEventListener("resize", this.handleResize);
33328
+ window.document.removeEventListener("copy", this.handleCopy);
33329
+ window.document.removeEventListener("cut", this.handleCut);
33330
+ window.document.removeEventListener("paste", this.handlePaste);
33331
+ }
33332
+ // private startIdleChecker() {
33333
+ // this.stopIdleChecker(); // Garante que não tenha duplicação
33334
+ // this.idleCheckInterval = setInterval(() => {
33335
+ // const idleTime = Date.now() - this.lastActivityTime;
33336
+ // if (idleTime > this.IDLE_THRESHOLD_MS) {
33337
+ // // Verifica se já não mandamos esse alerta recentemente para não floodar
33338
+ // const lastAlert = this.alerts[this.alerts.length - 1];
33339
+ // // Se o último alerta não foi de inatividade ou foi há muito tempo, cria novo
33340
+ // if (!lastAlert || lastAlert.alert !== AlertCategory.ForbiddenAction || (this.getRelativeTime() - lastAlert.begin > 5000)) {
33341
+ // const msg = "Usuário inativo por muito tempo";
33342
+ // // Assumindo ForbiddenAction ou outra categoria adequada
33343
+ // this.createAlert(AlertCategory.ForbiddenAction, AlertType.System, msg);
33344
+ // this.onRealtimeAlertCallback && this.onRealtimeAlertCallback({
33345
+ // status: 'ALERT',
33346
+ // description: msg,
33347
+ // type: 'user_idle'
33348
+ // });
33349
+ // }
33350
+ // }
33351
+ // }, 5000); // Checa a cada 5 segundos
33352
+ // }
33353
+ // private stopIdleChecker() {
33354
+ // if (this.idleCheckInterval) {
33355
+ // clearInterval(this.idleCheckInterval);
33356
+ // this.idleCheckInterval = null;
33357
+ // }
33358
+ // }
33359
+ // 4. BACKGROUND EVENTS (Eventos disparados manualmente)
33360
+ addBackgroundEvent(description, category = 200 /* System */) {
33361
+ this.createAlert(category, 6 /* System */, description);
33362
+ this.onRealtimeAlertCallback && this.onRealtimeAlertCallback({
33363
+ status: "ALERT",
33364
+ description,
33365
+ type: "background_event"
33366
+ });
33186
33367
  }
33187
- onReturnFocus() {
33188
- const lastAlert = this.alerts[this.alerts.length - 1];
33189
- if (lastAlert) {
33190
- this.onFocusCallback({
33191
- begin: lastAlert.begin,
33192
- end: Date.now() - this.startTime.getTime(),
33193
- alert: 25 /* FocusOff */,
33194
- type: 3 /* Screen */
33195
- });
33196
- lastAlert.end = Date.now() - this.startTime.getTime();
33197
- }
33368
+ // ==========================================
33369
+ // HELPERS
33370
+ // ==========================================
33371
+ getRelativeTime() {
33372
+ return Date.now() - this.startTime.getTime();
33373
+ }
33374
+ createAlert(category, type, description) {
33375
+ this.alerts.push({
33376
+ begin: this.getRelativeTime(),
33377
+ end: this.getRelativeTime(),
33378
+ // Eventos pontuais começam e terminam no mesmo ms (exceto focus)
33379
+ alert: category,
33380
+ type
33381
+ // description: description // Se sua interface Alert suportar descrição, descomente
33382
+ });
33198
33383
  }
33199
33384
  addAlert({ alert, type }) {
33200
33385
  this.alerts.push({
@@ -36769,7 +36954,6 @@ var Proctoring = class {
36769
36954
  noiseLimit: 40
36770
36955
  },
36771
36956
  imageBehaviourParameters: {
36772
- frames: 40,
36773
36957
  useUploadImage: true,
36774
36958
  uploadInterval: 20,
36775
36959
  saveVideo: true
@@ -36987,7 +37171,8 @@ var Proctoring = class {
36987
37171
  const alertRecorder = new AlertRecorder(
36988
37172
  {
36989
37173
  onFocusCallback: (response) => this.onFocusAlertRecorderCallback(response),
36990
- onLostFocusCallback: (response) => this.onLostFocusAlertRecorderCallback(response)
37174
+ onLostFocusCallback: (response) => this.onLostFocusAlertRecorderCallback(response),
37175
+ onRealtimeAlertCallback: (response) => this.onRealtimeAlertsCallback(response)
36991
37176
  },
36992
37177
  options
36993
37178
  );
@@ -37095,11 +37280,23 @@ Navigator: ${JSON.stringify(_navigator2)}`
37095
37280
  startResponse.screenStream = this.allRecorders.screenRecorder.screenStream;
37096
37281
  }
37097
37282
  this.state = "Recording" /* Recording */;
37098
- setTimeout(async () => {
37283
+ let verifyFirstFaceIntervalCount = 0;
37284
+ let verifyingFace = false;
37285
+ this.verifyFirstFaceInterval = setInterval(async () => {
37099
37286
  if (this.sessionOptions.proctoringType === "REALTIME") {
37100
- await this.backend.verifyFace(this.proctoringId, await this.allRecorders.cameraRecorder.getCurrentImageBase64());
37287
+ if (verifyingFace) return;
37288
+ verifyingFace = true;
37289
+ verifyFirstFaceIntervalCount++;
37290
+ try {
37291
+ var response = await this.backend.verifyFace(this.proctoringId, await this.allRecorders.cameraRecorder.getCurrentImageBase64(), verifyFirstFaceIntervalCount > 5 ? false : true);
37292
+ verifyingFace = false;
37293
+ clearInterval(this.verifyFirstFaceInterval);
37294
+ } catch (error) {
37295
+ verifyingFace = false;
37296
+ return;
37297
+ }
37101
37298
  }
37102
- }, 1e3);
37299
+ }, 1500);
37103
37300
  return startResponse;
37104
37301
  } catch (error) {
37105
37302
  console.log(error);
@@ -37236,6 +37433,9 @@ Upload Services: ${uploaderServices}`,
37236
37433
  await this.backend.externalCameraFinish(externalSessionId);
37237
37434
  }
37238
37435
  }
37436
+ if (this.verifyFirstFaceInterval) {
37437
+ clearInterval(this.verifyFirstFaceInterval);
37438
+ }
37239
37439
  this.state = "Stop" /* Stop */;
37240
37440
  } catch (error) {
37241
37441
  await this.cancel();
@@ -37570,12 +37770,12 @@ function useProctoring(proctoringOptions, enviromentConfig = "prod") {
37570
37770
  const photo = new CapturePhoto();
37571
37771
  const login = proctoring.login.bind(proctoring);
37572
37772
  const originalStart = proctoring.start.bind(proctoring);
37573
- const start = async (parameters2) => {
37773
+ const start = async (parameters2, videoOptions) => {
37574
37774
  const deviceResult = checker.getDeviceCheckResult();
37575
37775
  if (deviceResult) {
37576
37776
  proctoring.setDeviceCheckData(deviceResult);
37577
37777
  }
37578
- return originalStart(parameters2);
37778
+ return originalStart(parameters2, videoOptions);
37579
37779
  };
37580
37780
  const finish = proctoring.finish.bind(proctoring);
37581
37781
  const pause = proctoring.pause.bind(proctoring);
@@ -5,7 +5,6 @@ export type AudioBehaviourParameters = {
5
5
  noiseLimit?: number;
6
6
  };
7
7
  export type ImageBehaviourParameters = {
8
- frames?: number;
9
8
  useUploadImage?: boolean;
10
9
  uploadInterval?: number;
11
10
  saveVideo?: boolean;
@@ -39,7 +39,7 @@ export declare class BackendService {
39
39
  stopChallenge(challengeId: string, body: any): Promise<any>;
40
40
  startRealtimeAlert(body: any): Promise<any>;
41
41
  stopRealtimeAlert(body: any): Promise<any>;
42
- verifyFace(proctoringId: any, faceImage: any): Promise<any>;
42
+ verifyFace(proctoringId: any, faceImage: any, retry: boolean): Promise<any>;
43
43
  getServerHour(token: string): Promise<string>;
44
44
  private makeRequest;
45
45
  makeRequestAxios<R>(data: {
@@ -24,7 +24,9 @@ export declare enum AlertCategory {
24
24
  PotentialCamera = 32,
25
25
  SpyDeviceDisconnected = 33,
26
26
  StopSharingScreen = 34,
27
- ChangeDevices = 39
27
+ ChangeDevices = 39,
28
+ ForbiddenAction = 100,
29
+ System = 200
28
30
  }
29
31
  export declare enum FinishRealtimeWarningCategory {
30
32
  Face = 0,
@@ -36,7 +38,8 @@ export declare enum AlertType {
36
38
  Video = 2,
37
39
  Screen = 3,
38
40
  Image = 4,
39
- Environment = 5
41
+ Environment = 5,
42
+ System = 6
40
43
  }
41
44
  export interface Alert {
42
45
  begin: number;
@@ -6,18 +6,34 @@ export declare class AlertRecorder implements IRecorder {
6
6
  private startTime;
7
7
  private onLostFocusCallback;
8
8
  private onFocusCallback;
9
+ private onRealtimeAlertCallback?;
9
10
  private optionsProctoring;
11
+ private lastActivityTime;
12
+ private idleCheckInterval;
13
+ private readonly IDLE_THRESHOLD_MS;
14
+ private resizeTimeout;
10
15
  constructor(options: {
11
16
  onLostFocusCallback: (response: any) => void;
12
17
  onFocusCallback: (response: any) => void;
18
+ onRealtimeAlertCallback?: (response: any) => void;
13
19
  }, optionsProctoring: ProctoringSessionOptions);
14
20
  startRecording(): Promise<void>;
15
21
  pauseRecording(): Promise<void>;
16
22
  resumeRecording(): Promise<void>;
17
23
  stopRecording(): Promise<void>;
18
24
  saveOnSession(session: ProctoringSession): Promise<void>;
19
- private onLostFocus;
20
- private onReturnFocus;
25
+ private attachListeners;
26
+ private detachListeners;
27
+ private handleLostFocus;
28
+ private handleReturnFocus;
29
+ private handleResize;
30
+ private handleUserActivity;
31
+ addBackgroundEvent(description: string, category?: AlertCategory): void;
32
+ private handleCopy;
33
+ private handleCut;
34
+ private handlePaste;
35
+ private getRelativeTime;
36
+ private createAlert;
21
37
  addAlert({ alert, type }: {
22
38
  alert: AlertCategory;
23
39
  type: AlertType;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "easyproctor",
3
- "version": "2.5.2",
3
+ "version": "2.5.3",
4
4
  "description": "Modulo web de gravação do EasyProctor",
5
5
  "main": "./index.js",
6
6
  "module": "./esm/index.js",
@@ -55,6 +55,7 @@ export declare class Proctoring {
55
55
  private allRecorders;
56
56
  private spyCam;
57
57
  appChecker: ExternalCameraChecker;
58
+ private verifyFirstFaceInterval;
58
59
  private onStopSharingScreenCallback;
59
60
  setOnStopSharingScreenCallback(cb: () => void): void;
60
61
  private setOnLostFocusAlertRecorderCallback;
@@ -3,7 +3,7 @@ import enumarateDevices from "../modules/enumarateDevices";
3
3
  import { ProctoringContext } from "./proctoring";
4
4
  export declare function useProctoring(proctoringOptions: ProctoringContext, enviromentConfig?: string): {
5
5
  login: () => Promise<void>;
6
- start: (parameters: any) => Promise<import("../dtos/StartProctoringResponse").default>;
6
+ start: (parameters: any, videoOptions: any) => Promise<import("../dtos/StartProctoringResponse").default>;
7
7
  finish: (options?: import("./proctoring").ProctoringFinisherOptions) => Promise<void>;
8
8
  onFocus: (cb: () => void) => Promise<void>;
9
9
  onLostFocus: (cb: () => void) => Promise<void>;