easyproctor-hml 2.7.0 → 2.7.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/esm/index.js CHANGED
@@ -13551,8 +13551,8 @@ var _ChunkStorageService = class _ChunkStorageService {
13551
13551
  }
13552
13552
  };
13553
13553
  _ChunkStorageService.DB_NAME = "EasyProctorChunksDb";
13554
- /** Incrementado para v2 para recriar índices com tipos numéricos em vez de boolean */
13555
- _ChunkStorageService.DB_VERSION = 2;
13554
+ /** v2: índices numéricos; v3: payload como ArrayBuffer em vez de Blob (Safari iOS). */
13555
+ _ChunkStorageService.DB_VERSION = 3;
13556
13556
  _ChunkStorageService.STORE_NAME = "chunks";
13557
13557
  var ChunkStorageService = _ChunkStorageService;
13558
13558
 
@@ -13734,32 +13734,41 @@ var BackgroundUploadService = class _BackgroundUploadService {
13734
13734
  console.log(`[BackgroundUpload] ${pendingChunks.length} chunks pendentes encontrados. Modo final: ${isFinal}`);
13735
13735
  let virtualStart = this.totalBytesPurged;
13736
13736
  const chunksWithMeta = allChunks.map((c3) => {
13737
+ const byteLen = c3.arrayBuffer.byteLength;
13737
13738
  const start = virtualStart;
13738
- const end = start + c3.blob.size - 1;
13739
- virtualStart += c3.blob.size;
13739
+ const end = start + byteLen - 1;
13740
+ virtualStart += byteLen;
13740
13741
  return { chunk: c3, start, end };
13741
13742
  });
13742
- let combinedBlobParts = [];
13743
+ const sliceParts = [];
13743
13744
  let lastProcessedChunkId = null;
13744
13745
  let finalChunkIndex = 0;
13745
13746
  let mimeType = pendingChunks[0].mimeType;
13746
13747
  for (const meta of chunksWithMeta) {
13747
13748
  if (this.currentOffset > meta.end) continue;
13748
13749
  const sliceStart = Math.max(0, this.currentOffset - meta.start);
13749
- const chunkSlice = meta.chunk.blob.slice(sliceStart);
13750
- combinedBlobParts.push(chunkSlice);
13750
+ const view = new Uint8Array(meta.chunk.arrayBuffer);
13751
+ sliceParts.push(view.subarray(sliceStart));
13751
13752
  lastProcessedChunkId = meta.chunk.id;
13752
13753
  finalChunkIndex = meta.chunk.chunkIndex;
13753
13754
  }
13754
- if (combinedBlobParts.length === 0 && !isFinal) {
13755
+ if (sliceParts.length === 0 && !isFinal) {
13755
13756
  this.isProcessing = false;
13756
13757
  return;
13757
13758
  }
13758
- let fullBlob = new Blob(combinedBlobParts, { type: mimeType });
13759
- let sendableSize = fullBlob.size;
13759
+ const combinedLength = sliceParts.reduce((acc, p3) => acc + p3.length, 0);
13760
+ const combined = new Uint8Array(combinedLength);
13761
+ {
13762
+ let off = 0;
13763
+ for (const p3 of sliceParts) {
13764
+ combined.set(p3, off);
13765
+ off += p3.length;
13766
+ }
13767
+ }
13768
+ let sendableSize = combined.byteLength;
13760
13769
  let totalSizeForHeader = void 0;
13761
13770
  if (!isFinal) {
13762
- sendableSize = Math.floor(fullBlob.size / this.GCS_CHUNK_SIZE) * this.GCS_CHUNK_SIZE;
13771
+ sendableSize = Math.floor(combined.byteLength / this.GCS_CHUNK_SIZE) * this.GCS_CHUNK_SIZE;
13763
13772
  if (sendableSize === 0) {
13764
13773
  console.log("[BackgroundUpload] Dados insuficientes para atingir 256KB. Aguardando novo chunk...");
13765
13774
  this.isProcessing = false;
@@ -13768,9 +13777,14 @@ var BackgroundUploadService = class _BackgroundUploadService {
13768
13777
  } else {
13769
13778
  totalSizeForHeader = virtualStart;
13770
13779
  }
13771
- const blobToSend = fullBlob.slice(0, sendableSize);
13780
+ const payload = sendableSize === combined.byteLength ? combined : combined.subarray(0, sendableSize);
13772
13781
  try {
13773
- await this.uploadData(blobToSend, mimeType, finalChunkIndex, totalSizeForHeader);
13782
+ await this.uploadData(
13783
+ payload.byteLength > 0 ? payload : null,
13784
+ mimeType,
13785
+ finalChunkIndex,
13786
+ totalSizeForHeader
13787
+ );
13774
13788
  for (const meta of chunksWithMeta) {
13775
13789
  if (meta.chunk.uploaded === 0 && meta.end < this.currentOffset) {
13776
13790
  await this.chunkStorage.markAsUploaded(meta.chunk.id);
@@ -13781,7 +13795,10 @@ var BackgroundUploadService = class _BackgroundUploadService {
13781
13795
  }
13782
13796
  if (this.config.cleanAfterUpload) {
13783
13797
  const chunksToClear = chunksWithMeta.filter((meta) => meta.chunk.uploaded === 1 || meta.chunk.uploaded === 0 && meta.end < this.currentOffset);
13784
- const sizePurged = chunksToClear.reduce((acc, meta) => acc + meta.chunk.blob.size, 0);
13798
+ const sizePurged = chunksToClear.reduce(
13799
+ (acc, meta) => acc + meta.chunk.arrayBuffer.byteLength,
13800
+ 0
13801
+ );
13785
13802
  await this.chunkStorage.clearUploadedChunks(this.proctoringId);
13786
13803
  if (sizePurged > 0) {
13787
13804
  this.totalBytesPurged += sizePurged;
@@ -13805,7 +13822,8 @@ var BackgroundUploadService = class _BackgroundUploadService {
13805
13822
  /**
13806
13823
  * Faz o upload bruto de dados para a sessão GCS.
13807
13824
  */
13808
- async uploadData(blob, mimeType, chunkIndex, totalSize) {
13825
+ async uploadData(body, mimeType, chunkIndex, totalSize) {
13826
+ var _a2;
13809
13827
  const fileName = `EP_${this.proctoringId}_camera_0.webm`;
13810
13828
  if (!this.sessionUrl) {
13811
13829
  const initiateUrl = await this.backend.initiateUpload(this.token, `${this.proctoringId}/${fileName}`, mimeType);
@@ -13836,16 +13854,28 @@ var BackgroundUploadService = class _BackgroundUploadService {
13836
13854
  } else {
13837
13855
  console.log(`[BackgroundUpload] Usando sess\xE3o GCS existente: ${this.sessionUrl}`);
13838
13856
  }
13857
+ const size = (_a2 = body == null ? void 0 : body.byteLength) != null ? _a2 : 0;
13839
13858
  const start = this.currentOffset;
13840
- const end = start + blob.size - 1;
13859
+ const end = start + size - 1;
13841
13860
  const totalHeader = totalSize !== void 0 ? totalSize.toString() : "*";
13842
- const contentRangeHeader = blob.size === 0 && totalSize !== void 0 ? `bytes */${totalHeader}` : `bytes ${start}-${end}/${totalHeader}`;
13843
- console.log(`[BackgroundUpload] Enviando ${blob.size > 0 ? "dados" : "finaliza\xE7\xE3o"}: ${contentRangeHeader} (Size: ${blob.size})`);
13861
+ const contentRangeHeader = size === 0 && totalSize !== void 0 ? `bytes */${totalHeader}` : `bytes ${start}-${end}/${totalHeader}`;
13862
+ console.log(
13863
+ `[BackgroundUpload] Enviando ${size > 0 ? "dados" : "finaliza\xE7\xE3o"}: ${contentRangeHeader} (Size: ${size})`
13864
+ );
13865
+ let uploadBody = null;
13866
+ if (size > 0 && body) {
13867
+ const raw = body.buffer;
13868
+ if (raw instanceof ArrayBuffer) {
13869
+ uploadBody = body.byteOffset === 0 && body.byteLength === raw.byteLength ? raw : raw.slice(body.byteOffset, body.byteOffset + body.byteLength);
13870
+ } else {
13871
+ uploadBody = new ArrayBuffer(body.byteLength);
13872
+ new Uint8Array(uploadBody).set(body);
13873
+ }
13874
+ }
13844
13875
  const response = await fetch(this.sessionUrl, {
13845
13876
  method: "PUT",
13846
13877
  headers: { "Content-Range": contentRangeHeader },
13847
- body: blob.size > 0 ? blob : null
13848
- // Usa null para garantir corpo vazio se necessário
13878
+ body: uploadBody
13849
13879
  });
13850
13880
  console.log(`[BackgroundUpload] Resposta GCS (uploadData): ${response.status}`);
13851
13881
  if (response.status !== 200 && response.status !== 201 && response.status !== 308) {
@@ -13858,13 +13888,13 @@ var BackgroundUploadService = class _BackgroundUploadService {
13858
13888
  const lastByte = parseInt(rangeHeader.split("-")[1], 10);
13859
13889
  this.currentOffset = lastByte + 1;
13860
13890
  } else {
13861
- this.currentOffset += blob.size;
13891
+ this.currentOffset += size;
13862
13892
  }
13863
13893
  this.saveSessionState();
13864
13894
  trackers.registerUploadFile(
13865
13895
  this.proctoringId,
13866
13896
  `GCS Stream Upload
13867
- Size: ${blob.size}
13897
+ Size: ${size}
13868
13898
  Range: ${start}-${end}
13869
13899
  Last Index: ${chunkIndex}`,
13870
13900
  "CameraChunk"
@@ -14383,16 +14413,19 @@ Setting: ${JSON.stringify(settings, null, 2)}`
14383
14413
  }
14384
14414
  if (this.isChunkEnabled) {
14385
14415
  if (this.backgroundUpload) {
14416
+ trackers.registerError(this.proctoringId, `Flush e parada do background upload`);
14386
14417
  try {
14387
14418
  if (this.pendingChunkSaves.length > 0) {
14388
14419
  console.log(`[CameraRecorder] Aguardando ${this.pendingChunkSaves.length} salvamentos de chunks pendentes...`);
14389
14420
  await Promise.all(this.pendingChunkSaves);
14390
14421
  }
14391
14422
  await this.backgroundUpload.flush();
14423
+ this.backgroundUpload.stop();
14392
14424
  } catch (e3) {
14393
14425
  console.warn("[CameraRecorder] Erro ao fazer flush dos chunks:", e3);
14426
+ trackers.registerError(this.proctoringId, `Flush Chunks
14427
+ Error: ${e3}`);
14394
14428
  }
14395
- this.backgroundUpload.stop();
14396
14429
  }
14397
14430
  this.removeLifecycleListeners();
14398
14431
  this.persistSessionState("FINISHED");
@@ -14407,10 +14440,11 @@ Setting: ${JSON.stringify(settings, null, 2)}`
14407
14440
  const savePromise = (async () => {
14408
14441
  var _a2;
14409
14442
  try {
14443
+ const arrayBuffer = await blob.arrayBuffer();
14410
14444
  await this.chunkStorage.saveChunk({
14411
14445
  proctoringId: this.proctoringId,
14412
14446
  chunkIndex: this.chunkIndex,
14413
- blob,
14447
+ arrayBuffer,
14414
14448
  timestamp: Date.now(),
14415
14449
  uploaded: 0,
14416
14450
  mimeType: ((_a2 = this.recorderOptions) == null ? void 0 : _a2.mimeType) || "video/webm"
@@ -14418,6 +14452,8 @@ Setting: ${JSON.stringify(settings, null, 2)}`
14418
14452
  this.chunkIndex++;
14419
14453
  console.log(`[CameraRecorder] Chunk ${this.chunkIndex - 1} salvo no IndexedDB.`);
14420
14454
  } catch (error) {
14455
+ trackers.registerError(this.proctoringId, `Save Chunk
14456
+ Error: ${error}`);
14421
14457
  console.error("[CameraRecorder] Erro ao salvar chunk no IndexedDB:", error);
14422
14458
  }
14423
14459
  })();
@@ -16267,16 +16303,14 @@ var CapturePhoto = class {
16267
16303
  divBtn.appendChild(retakeBtn);
16268
16304
  divBtn.appendChild(confirmBtn);
16269
16305
  this.shot();
16270
- video.style.display = "none";
16271
- image.style.display = "block";
16306
+ this.closeInterface();
16307
+ resolve({ base64: this.base64 });
16272
16308
  });
16273
16309
  retakeBtn.addEventListener("click", () => {
16274
16310
  divBtn.appendChild(closeModalBtn);
16275
16311
  divBtn.appendChild(takePhotoBtn);
16276
16312
  divBtn.removeChild(retakeBtn);
16277
16313
  divBtn.removeChild(confirmBtn);
16278
- video.style.display = "block";
16279
- image.style.display = "none";
16280
16314
  });
16281
16315
  confirmBtn.addEventListener("click", () => {
16282
16316
  this.closeInterface();
@@ -16352,8 +16386,8 @@ var CapturePhoto = class {
16352
16386
  }
16353
16387
  };
16354
16388
 
16355
- // src/extension/extensionEasyProctor.ts
16356
- var ExtensionEasyProctor = class {
16389
+ // src/extension/extension.ts
16390
+ var Extension = class {
16357
16391
  constructor() {
16358
16392
  this.hasExtension = false;
16359
16393
  this.tryes = 0;
@@ -16398,89 +16432,6 @@ var ExtensionEasyProctor = class {
16398
16432
  }
16399
16433
  };
16400
16434
 
16401
- // src/extension/extensionEasyCatcher.ts
16402
- var ExtensionEasyCatcher = class {
16403
- constructor(options) {
16404
- this.hasExtension = false;
16405
- this.tryes = 0;
16406
- this.responseStart = false;
16407
- this.options = options || {};
16408
- }
16409
- /**
16410
- * Verifica se a extensão está instalada e ativa.
16411
- * Retorna o número da versão se encontrada, ou lança erro após timeout.
16412
- */
16413
- checkExtensionInstalled(timeoutMs = 2e3) {
16414
- return new Promise((resolve, reject) => {
16415
- let handled = false;
16416
- const handler = (event) => {
16417
- if (event.source === window && event.data.sender === "easyproctor-extension" && event.data.message_name === "version") {
16418
- handled = true;
16419
- window.removeEventListener("message", handler);
16420
- resolve(event.data.message);
16421
- }
16422
- };
16423
- window.addEventListener("message", handler);
16424
- window.postMessage({
16425
- type: "easycatcher",
16426
- func: "verifyExtensionEasycatcher"
16427
- }, "*");
16428
- setTimeout(() => {
16429
- if (!handled) {
16430
- window.removeEventListener("message", handler);
16431
- reject(new Error("Extens\xE3o n\xE3o detectada ou n\xE3o respondeu."));
16432
- }
16433
- }, timeoutMs);
16434
- });
16435
- }
16436
- /**
16437
- * Solicita o JSON da sessão atual capturado pela extensão.
16438
- */
16439
- getSessionData(timeoutMs = 5e3) {
16440
- return new Promise((resolve, reject) => {
16441
- let handled = false;
16442
- const handler = (event) => {
16443
- if (event.source === window && event.data.sender === "easyproctor-extension" && event.data.message_name === "data_response") {
16444
- handled = true;
16445
- window.removeEventListener("message", handler);
16446
- resolve(event.data.payload);
16447
- }
16448
- };
16449
- window.addEventListener("message", handler);
16450
- window.postMessage({
16451
- type: "easycatcher",
16452
- func: "getDataExtensionEasycatcher"
16453
- }, "*");
16454
- setTimeout(() => {
16455
- if (!handled) {
16456
- window.removeEventListener("message", handler);
16457
- reject(new Error("Timeout ao aguardar dados da extens\xE3o."));
16458
- }
16459
- }, timeoutMs);
16460
- });
16461
- }
16462
- start() {
16463
- return new Promise((resolve, reject) => {
16464
- let handled = false;
16465
- const handler = (event) => {
16466
- if (event.source === window && event.data.sender === "easyproctor-extension" && event.data.message_name === "started_confirmed") {
16467
- handled = true;
16468
- window.removeEventListener("message", handler);
16469
- resolve(true);
16470
- }
16471
- };
16472
- window.addEventListener("message", handler);
16473
- window.postMessage({ type: "easycatcher", func: "startExtensionEasycatcher" }, "*");
16474
- setTimeout(() => {
16475
- if (!handled) {
16476
- window.removeEventListener("message", handler);
16477
- reject(new Error("Timeout: Extens\xE3o n\xE3o confirmou o in\xEDcio."));
16478
- }
16479
- }, 3e3);
16480
- });
16481
- }
16482
- };
16483
-
16484
16435
  // src/modules/onChangeDevices.ts
16485
16436
  var onChangeDevices = class {
16486
16437
  constructor(repositoryDevices, proctoringId2, sessionOptions, allRecorders) {
@@ -23655,10 +23606,7 @@ var Proctoring = class {
23655
23606
  if (this.context.token === void 0) {
23656
23607
  throw TOKEN_MISSING;
23657
23608
  }
23658
- if (options.useChallenge) {
23659
- this.extensionEasycatcher = new ExtensionEasyCatcher();
23660
- }
23661
- this.extension = new ExtensionEasyProctor();
23609
+ this.extension = new Extension();
23662
23610
  this.extension.addEventListener();
23663
23611
  const baseURL = this.backend.selectBaseUrl(this.context.type);
23664
23612
  const devices = await enumarateDevices();
@@ -24042,61 +23990,6 @@ Error: ` + error
24042
23990
  _screenStream: (_a2 = this.allRecorders.screenRecorder) == null ? void 0 : _a2.screenStream
24043
23991
  };
24044
23992
  }
24045
- async startChallenge(templateId) {
24046
- var _a2;
24047
- if (!this.sessionOptions.useChallenge) {
24048
- throw new Error("useChallenge is set as false on start method");
24049
- }
24050
- await this.extensionEasycatcher.checkExtensionInstalled().catch((err) => {
24051
- throw new Error("EasyCatcher Extension is not installed");
24052
- });
24053
- this.extensionEasycatcher.start();
24054
- const start = Date.now() - ((_a2 = this.allRecorders.cameraRecorder.getStartTime()) == null ? void 0 : _a2.getTime()) || 0;
24055
- await this.backend.startChallenge({
24056
- proctoringId: this.proctoringId,
24057
- templateId,
24058
- start
24059
- }).then((resp) => {
24060
- console.log(resp);
24061
- this.challengeId = resp.id;
24062
- }).catch((reason) => {
24063
- trackers.registerError(
24064
- this.proctoringId,
24065
- "N\xE3o foi poss\xEDvel iniciar desafio!"
24066
- );
24067
- throw reason;
24068
- });
24069
- this.isChallengeRunning = true;
24070
- }
24071
- async stopChallenge() {
24072
- var _a2;
24073
- if (!this.isChallengeRunning) {
24074
- throw new Error("Challenge not started");
24075
- }
24076
- try {
24077
- const sessionData = await this.extensionEasycatcher.getSessionData();
24078
- const end = Date.now() - ((_a2 = this.allRecorders.cameraRecorder.getStartTime()) == null ? void 0 : _a2.getTime()) || 0;
24079
- await this.backend.stopChallenge(
24080
- this.challengeId,
24081
- {
24082
- end,
24083
- data: sessionData
24084
- }
24085
- ).catch((reason) => {
24086
- trackers.registerError(
24087
- this.proctoringId,
24088
- "N\xE3o foi poss\xEDvel finalizar o desafio no backend!"
24089
- );
24090
- return void 0;
24091
- });
24092
- this.isChallengeRunning = false;
24093
- } catch (error) {
24094
- trackers.registerError(
24095
- this.proctoringId,
24096
- "Erro ao recuperar dados da extens\xE3o: " + error.message
24097
- );
24098
- }
24099
- }
24100
23993
  };
24101
23994
 
24102
23995
  // src/proctoring/SignTerm.ts
@@ -24325,8 +24218,6 @@ function useProctoring(proctoringOptions, enviromentConfig = "prod") {
24325
24218
  return originalStart(parameters2, videoOptions);
24326
24219
  };
24327
24220
  const finish = proctoring.finish.bind(proctoring);
24328
- const startChallenge = proctoring.startChallenge.bind(proctoring);
24329
- const stopChallenge = proctoring.stopChallenge.bind(proctoring);
24330
24221
  const pause = proctoring.pause.bind(proctoring);
24331
24222
  const resume = proctoring.resume.bind(proctoring);
24332
24223
  const onFocus = proctoring.setOnFocusCallback.bind(proctoring);
@@ -24351,8 +24242,6 @@ function useProctoring(proctoringOptions, enviromentConfig = "prod") {
24351
24242
  login,
24352
24243
  start,
24353
24244
  finish,
24354
- startChallenge,
24355
- stopChallenge,
24356
24245
  onFocus,
24357
24246
  onLostFocus,
24358
24247
  onChangeDevices: onChangeDevices2,
@@ -1,5 +1,5 @@
1
1
  import { ProctoringFinisherOptions } from "../proctoring/proctoring";
2
- export declare class ExtensionEasyProctor {
2
+ export declare class Extension {
3
3
  hasExtension: boolean;
4
4
  tryes: number;
5
5
  responseStart: boolean;