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/index.js CHANGED
@@ -31648,8 +31648,8 @@ var _ChunkStorageService = class _ChunkStorageService {
31648
31648
  }
31649
31649
  };
31650
31650
  _ChunkStorageService.DB_NAME = "EasyProctorChunksDb";
31651
- /** Incrementado para v2 para recriar índices com tipos numéricos em vez de boolean */
31652
- _ChunkStorageService.DB_VERSION = 2;
31651
+ /** v2: índices numéricos; v3: payload como ArrayBuffer em vez de Blob (Safari iOS). */
31652
+ _ChunkStorageService.DB_VERSION = 3;
31653
31653
  _ChunkStorageService.STORE_NAME = "chunks";
31654
31654
  var ChunkStorageService = _ChunkStorageService;
31655
31655
 
@@ -31831,32 +31831,41 @@ var BackgroundUploadService = class _BackgroundUploadService {
31831
31831
  console.log(`[BackgroundUpload] ${pendingChunks.length} chunks pendentes encontrados. Modo final: ${isFinal}`);
31832
31832
  let virtualStart = this.totalBytesPurged;
31833
31833
  const chunksWithMeta = allChunks.map((c3) => {
31834
+ const byteLen = c3.arrayBuffer.byteLength;
31834
31835
  const start = virtualStart;
31835
- const end = start + c3.blob.size - 1;
31836
- virtualStart += c3.blob.size;
31836
+ const end = start + byteLen - 1;
31837
+ virtualStart += byteLen;
31837
31838
  return { chunk: c3, start, end };
31838
31839
  });
31839
- let combinedBlobParts = [];
31840
+ const sliceParts = [];
31840
31841
  let lastProcessedChunkId = null;
31841
31842
  let finalChunkIndex = 0;
31842
31843
  let mimeType = pendingChunks[0].mimeType;
31843
31844
  for (const meta of chunksWithMeta) {
31844
31845
  if (this.currentOffset > meta.end) continue;
31845
31846
  const sliceStart = Math.max(0, this.currentOffset - meta.start);
31846
- const chunkSlice = meta.chunk.blob.slice(sliceStart);
31847
- combinedBlobParts.push(chunkSlice);
31847
+ const view = new Uint8Array(meta.chunk.arrayBuffer);
31848
+ sliceParts.push(view.subarray(sliceStart));
31848
31849
  lastProcessedChunkId = meta.chunk.id;
31849
31850
  finalChunkIndex = meta.chunk.chunkIndex;
31850
31851
  }
31851
- if (combinedBlobParts.length === 0 && !isFinal) {
31852
+ if (sliceParts.length === 0 && !isFinal) {
31852
31853
  this.isProcessing = false;
31853
31854
  return;
31854
31855
  }
31855
- let fullBlob = new Blob(combinedBlobParts, { type: mimeType });
31856
- let sendableSize = fullBlob.size;
31856
+ const combinedLength = sliceParts.reduce((acc, p3) => acc + p3.length, 0);
31857
+ const combined = new Uint8Array(combinedLength);
31858
+ {
31859
+ let off = 0;
31860
+ for (const p3 of sliceParts) {
31861
+ combined.set(p3, off);
31862
+ off += p3.length;
31863
+ }
31864
+ }
31865
+ let sendableSize = combined.byteLength;
31857
31866
  let totalSizeForHeader = void 0;
31858
31867
  if (!isFinal) {
31859
- sendableSize = Math.floor(fullBlob.size / this.GCS_CHUNK_SIZE) * this.GCS_CHUNK_SIZE;
31868
+ sendableSize = Math.floor(combined.byteLength / this.GCS_CHUNK_SIZE) * this.GCS_CHUNK_SIZE;
31860
31869
  if (sendableSize === 0) {
31861
31870
  console.log("[BackgroundUpload] Dados insuficientes para atingir 256KB. Aguardando novo chunk...");
31862
31871
  this.isProcessing = false;
@@ -31865,9 +31874,14 @@ var BackgroundUploadService = class _BackgroundUploadService {
31865
31874
  } else {
31866
31875
  totalSizeForHeader = virtualStart;
31867
31876
  }
31868
- const blobToSend = fullBlob.slice(0, sendableSize);
31877
+ const payload = sendableSize === combined.byteLength ? combined : combined.subarray(0, sendableSize);
31869
31878
  try {
31870
- await this.uploadData(blobToSend, mimeType, finalChunkIndex, totalSizeForHeader);
31879
+ await this.uploadData(
31880
+ payload.byteLength > 0 ? payload : null,
31881
+ mimeType,
31882
+ finalChunkIndex,
31883
+ totalSizeForHeader
31884
+ );
31871
31885
  for (const meta of chunksWithMeta) {
31872
31886
  if (meta.chunk.uploaded === 0 && meta.end < this.currentOffset) {
31873
31887
  await this.chunkStorage.markAsUploaded(meta.chunk.id);
@@ -31878,7 +31892,10 @@ var BackgroundUploadService = class _BackgroundUploadService {
31878
31892
  }
31879
31893
  if (this.config.cleanAfterUpload) {
31880
31894
  const chunksToClear = chunksWithMeta.filter((meta) => meta.chunk.uploaded === 1 || meta.chunk.uploaded === 0 && meta.end < this.currentOffset);
31881
- const sizePurged = chunksToClear.reduce((acc, meta) => acc + meta.chunk.blob.size, 0);
31895
+ const sizePurged = chunksToClear.reduce(
31896
+ (acc, meta) => acc + meta.chunk.arrayBuffer.byteLength,
31897
+ 0
31898
+ );
31882
31899
  await this.chunkStorage.clearUploadedChunks(this.proctoringId);
31883
31900
  if (sizePurged > 0) {
31884
31901
  this.totalBytesPurged += sizePurged;
@@ -31902,7 +31919,8 @@ var BackgroundUploadService = class _BackgroundUploadService {
31902
31919
  /**
31903
31920
  * Faz o upload bruto de dados para a sessão GCS.
31904
31921
  */
31905
- async uploadData(blob, mimeType, chunkIndex, totalSize) {
31922
+ async uploadData(body, mimeType, chunkIndex, totalSize) {
31923
+ var _a2;
31906
31924
  const fileName = `EP_${this.proctoringId}_camera_0.webm`;
31907
31925
  if (!this.sessionUrl) {
31908
31926
  const initiateUrl = await this.backend.initiateUpload(this.token, `${this.proctoringId}/${fileName}`, mimeType);
@@ -31933,16 +31951,28 @@ var BackgroundUploadService = class _BackgroundUploadService {
31933
31951
  } else {
31934
31952
  console.log(`[BackgroundUpload] Usando sess\xE3o GCS existente: ${this.sessionUrl}`);
31935
31953
  }
31954
+ const size = (_a2 = body == null ? void 0 : body.byteLength) != null ? _a2 : 0;
31936
31955
  const start = this.currentOffset;
31937
- const end = start + blob.size - 1;
31956
+ const end = start + size - 1;
31938
31957
  const totalHeader = totalSize !== void 0 ? totalSize.toString() : "*";
31939
- const contentRangeHeader = blob.size === 0 && totalSize !== void 0 ? `bytes */${totalHeader}` : `bytes ${start}-${end}/${totalHeader}`;
31940
- console.log(`[BackgroundUpload] Enviando ${blob.size > 0 ? "dados" : "finaliza\xE7\xE3o"}: ${contentRangeHeader} (Size: ${blob.size})`);
31958
+ const contentRangeHeader = size === 0 && totalSize !== void 0 ? `bytes */${totalHeader}` : `bytes ${start}-${end}/${totalHeader}`;
31959
+ console.log(
31960
+ `[BackgroundUpload] Enviando ${size > 0 ? "dados" : "finaliza\xE7\xE3o"}: ${contentRangeHeader} (Size: ${size})`
31961
+ );
31962
+ let uploadBody = null;
31963
+ if (size > 0 && body) {
31964
+ const raw = body.buffer;
31965
+ if (raw instanceof ArrayBuffer) {
31966
+ uploadBody = body.byteOffset === 0 && body.byteLength === raw.byteLength ? raw : raw.slice(body.byteOffset, body.byteOffset + body.byteLength);
31967
+ } else {
31968
+ uploadBody = new ArrayBuffer(body.byteLength);
31969
+ new Uint8Array(uploadBody).set(body);
31970
+ }
31971
+ }
31941
31972
  const response = await fetch(this.sessionUrl, {
31942
31973
  method: "PUT",
31943
31974
  headers: { "Content-Range": contentRangeHeader },
31944
- body: blob.size > 0 ? blob : null
31945
- // Usa null para garantir corpo vazio se necessário
31975
+ body: uploadBody
31946
31976
  });
31947
31977
  console.log(`[BackgroundUpload] Resposta GCS (uploadData): ${response.status}`);
31948
31978
  if (response.status !== 200 && response.status !== 201 && response.status !== 308) {
@@ -31955,13 +31985,13 @@ var BackgroundUploadService = class _BackgroundUploadService {
31955
31985
  const lastByte = parseInt(rangeHeader.split("-")[1], 10);
31956
31986
  this.currentOffset = lastByte + 1;
31957
31987
  } else {
31958
- this.currentOffset += blob.size;
31988
+ this.currentOffset += size;
31959
31989
  }
31960
31990
  this.saveSessionState();
31961
31991
  trackers.registerUploadFile(
31962
31992
  this.proctoringId,
31963
31993
  `GCS Stream Upload
31964
- Size: ${blob.size}
31994
+ Size: ${size}
31965
31995
  Range: ${start}-${end}
31966
31996
  Last Index: ${chunkIndex}`,
31967
31997
  "CameraChunk"
@@ -32480,16 +32510,19 @@ Setting: ${JSON.stringify(settings, null, 2)}`
32480
32510
  }
32481
32511
  if (this.isChunkEnabled) {
32482
32512
  if (this.backgroundUpload) {
32513
+ trackers.registerError(this.proctoringId, `Flush e parada do background upload`);
32483
32514
  try {
32484
32515
  if (this.pendingChunkSaves.length > 0) {
32485
32516
  console.log(`[CameraRecorder] Aguardando ${this.pendingChunkSaves.length} salvamentos de chunks pendentes...`);
32486
32517
  await Promise.all(this.pendingChunkSaves);
32487
32518
  }
32488
32519
  await this.backgroundUpload.flush();
32520
+ this.backgroundUpload.stop();
32489
32521
  } catch (e3) {
32490
32522
  console.warn("[CameraRecorder] Erro ao fazer flush dos chunks:", e3);
32523
+ trackers.registerError(this.proctoringId, `Flush Chunks
32524
+ Error: ${e3}`);
32491
32525
  }
32492
- this.backgroundUpload.stop();
32493
32526
  }
32494
32527
  this.removeLifecycleListeners();
32495
32528
  this.persistSessionState("FINISHED");
@@ -32504,10 +32537,11 @@ Setting: ${JSON.stringify(settings, null, 2)}`
32504
32537
  const savePromise = (async () => {
32505
32538
  var _a2;
32506
32539
  try {
32540
+ const arrayBuffer = await blob.arrayBuffer();
32507
32541
  await this.chunkStorage.saveChunk({
32508
32542
  proctoringId: this.proctoringId,
32509
32543
  chunkIndex: this.chunkIndex,
32510
- blob,
32544
+ arrayBuffer,
32511
32545
  timestamp: Date.now(),
32512
32546
  uploaded: 0,
32513
32547
  mimeType: ((_a2 = this.recorderOptions) == null ? void 0 : _a2.mimeType) || "video/webm"
@@ -32515,6 +32549,8 @@ Setting: ${JSON.stringify(settings, null, 2)}`
32515
32549
  this.chunkIndex++;
32516
32550
  console.log(`[CameraRecorder] Chunk ${this.chunkIndex - 1} salvo no IndexedDB.`);
32517
32551
  } catch (error) {
32552
+ trackers.registerError(this.proctoringId, `Save Chunk
32553
+ Error: ${error}`);
32518
32554
  console.error("[CameraRecorder] Erro ao salvar chunk no IndexedDB:", error);
32519
32555
  }
32520
32556
  })();
@@ -34364,16 +34400,14 @@ var CapturePhoto = class {
34364
34400
  divBtn.appendChild(retakeBtn);
34365
34401
  divBtn.appendChild(confirmBtn);
34366
34402
  this.shot();
34367
- video.style.display = "none";
34368
- image.style.display = "block";
34403
+ this.closeInterface();
34404
+ resolve({ base64: this.base64 });
34369
34405
  });
34370
34406
  retakeBtn.addEventListener("click", () => {
34371
34407
  divBtn.appendChild(closeModalBtn);
34372
34408
  divBtn.appendChild(takePhotoBtn);
34373
34409
  divBtn.removeChild(retakeBtn);
34374
34410
  divBtn.removeChild(confirmBtn);
34375
- video.style.display = "block";
34376
- image.style.display = "none";
34377
34411
  });
34378
34412
  confirmBtn.addEventListener("click", () => {
34379
34413
  this.closeInterface();
@@ -34449,8 +34483,8 @@ var CapturePhoto = class {
34449
34483
  }
34450
34484
  };
34451
34485
 
34452
- // src/extension/extensionEasyProctor.ts
34453
- var ExtensionEasyProctor = class {
34486
+ // src/extension/extension.ts
34487
+ var Extension = class {
34454
34488
  constructor() {
34455
34489
  this.hasExtension = false;
34456
34490
  this.tryes = 0;
@@ -34495,89 +34529,6 @@ var ExtensionEasyProctor = class {
34495
34529
  }
34496
34530
  };
34497
34531
 
34498
- // src/extension/extensionEasyCatcher.ts
34499
- var ExtensionEasyCatcher = class {
34500
- constructor(options) {
34501
- this.hasExtension = false;
34502
- this.tryes = 0;
34503
- this.responseStart = false;
34504
- this.options = options || {};
34505
- }
34506
- /**
34507
- * Verifica se a extensão está instalada e ativa.
34508
- * Retorna o número da versão se encontrada, ou lança erro após timeout.
34509
- */
34510
- checkExtensionInstalled(timeoutMs = 2e3) {
34511
- return new Promise((resolve, reject) => {
34512
- let handled = false;
34513
- const handler = (event) => {
34514
- if (event.source === window && event.data.sender === "easyproctor-extension" && event.data.message_name === "version") {
34515
- handled = true;
34516
- window.removeEventListener("message", handler);
34517
- resolve(event.data.message);
34518
- }
34519
- };
34520
- window.addEventListener("message", handler);
34521
- window.postMessage({
34522
- type: "easycatcher",
34523
- func: "verifyExtensionEasycatcher"
34524
- }, "*");
34525
- setTimeout(() => {
34526
- if (!handled) {
34527
- window.removeEventListener("message", handler);
34528
- reject(new Error("Extens\xE3o n\xE3o detectada ou n\xE3o respondeu."));
34529
- }
34530
- }, timeoutMs);
34531
- });
34532
- }
34533
- /**
34534
- * Solicita o JSON da sessão atual capturado pela extensão.
34535
- */
34536
- getSessionData(timeoutMs = 5e3) {
34537
- return new Promise((resolve, reject) => {
34538
- let handled = false;
34539
- const handler = (event) => {
34540
- if (event.source === window && event.data.sender === "easyproctor-extension" && event.data.message_name === "data_response") {
34541
- handled = true;
34542
- window.removeEventListener("message", handler);
34543
- resolve(event.data.payload);
34544
- }
34545
- };
34546
- window.addEventListener("message", handler);
34547
- window.postMessage({
34548
- type: "easycatcher",
34549
- func: "getDataExtensionEasycatcher"
34550
- }, "*");
34551
- setTimeout(() => {
34552
- if (!handled) {
34553
- window.removeEventListener("message", handler);
34554
- reject(new Error("Timeout ao aguardar dados da extens\xE3o."));
34555
- }
34556
- }, timeoutMs);
34557
- });
34558
- }
34559
- start() {
34560
- return new Promise((resolve, reject) => {
34561
- let handled = false;
34562
- const handler = (event) => {
34563
- if (event.source === window && event.data.sender === "easyproctor-extension" && event.data.message_name === "started_confirmed") {
34564
- handled = true;
34565
- window.removeEventListener("message", handler);
34566
- resolve(true);
34567
- }
34568
- };
34569
- window.addEventListener("message", handler);
34570
- window.postMessage({ type: "easycatcher", func: "startExtensionEasycatcher" }, "*");
34571
- setTimeout(() => {
34572
- if (!handled) {
34573
- window.removeEventListener("message", handler);
34574
- reject(new Error("Timeout: Extens\xE3o n\xE3o confirmou o in\xEDcio."));
34575
- }
34576
- }, 3e3);
34577
- });
34578
- }
34579
- };
34580
-
34581
34532
  // src/modules/onChangeDevices.ts
34582
34533
  var onChangeDevices = class {
34583
34534
  constructor(repositoryDevices, proctoringId2, sessionOptions, allRecorders) {
@@ -38904,10 +38855,7 @@ var Proctoring = class {
38904
38855
  if (this.context.token === void 0) {
38905
38856
  throw TOKEN_MISSING;
38906
38857
  }
38907
- if (options.useChallenge) {
38908
- this.extensionEasycatcher = new ExtensionEasyCatcher();
38909
- }
38910
- this.extension = new ExtensionEasyProctor();
38858
+ this.extension = new Extension();
38911
38859
  this.extension.addEventListener();
38912
38860
  const baseURL = this.backend.selectBaseUrl(this.context.type);
38913
38861
  const devices = await enumarateDevices();
@@ -39291,61 +39239,6 @@ Error: ` + error
39291
39239
  _screenStream: (_a2 = this.allRecorders.screenRecorder) == null ? void 0 : _a2.screenStream
39292
39240
  };
39293
39241
  }
39294
- async startChallenge(templateId) {
39295
- var _a2;
39296
- if (!this.sessionOptions.useChallenge) {
39297
- throw new Error("useChallenge is set as false on start method");
39298
- }
39299
- await this.extensionEasycatcher.checkExtensionInstalled().catch((err) => {
39300
- throw new Error("EasyCatcher Extension is not installed");
39301
- });
39302
- this.extensionEasycatcher.start();
39303
- const start = Date.now() - ((_a2 = this.allRecorders.cameraRecorder.getStartTime()) == null ? void 0 : _a2.getTime()) || 0;
39304
- await this.backend.startChallenge({
39305
- proctoringId: this.proctoringId,
39306
- templateId,
39307
- start
39308
- }).then((resp) => {
39309
- console.log(resp);
39310
- this.challengeId = resp.id;
39311
- }).catch((reason) => {
39312
- trackers.registerError(
39313
- this.proctoringId,
39314
- "N\xE3o foi poss\xEDvel iniciar desafio!"
39315
- );
39316
- throw reason;
39317
- });
39318
- this.isChallengeRunning = true;
39319
- }
39320
- async stopChallenge() {
39321
- var _a2;
39322
- if (!this.isChallengeRunning) {
39323
- throw new Error("Challenge not started");
39324
- }
39325
- try {
39326
- const sessionData = await this.extensionEasycatcher.getSessionData();
39327
- const end = Date.now() - ((_a2 = this.allRecorders.cameraRecorder.getStartTime()) == null ? void 0 : _a2.getTime()) || 0;
39328
- await this.backend.stopChallenge(
39329
- this.challengeId,
39330
- {
39331
- end,
39332
- data: sessionData
39333
- }
39334
- ).catch((reason) => {
39335
- trackers.registerError(
39336
- this.proctoringId,
39337
- "N\xE3o foi poss\xEDvel finalizar o desafio no backend!"
39338
- );
39339
- return void 0;
39340
- });
39341
- this.isChallengeRunning = false;
39342
- } catch (error) {
39343
- trackers.registerError(
39344
- this.proctoringId,
39345
- "Erro ao recuperar dados da extens\xE3o: " + error.message
39346
- );
39347
- }
39348
- }
39349
39242
  };
39350
39243
 
39351
39244
  // src/proctoring/SignTerm.ts
@@ -39574,8 +39467,6 @@ function useProctoring(proctoringOptions, enviromentConfig = "prod") {
39574
39467
  return originalStart(parameters2, videoOptions);
39575
39468
  };
39576
39469
  const finish = proctoring.finish.bind(proctoring);
39577
- const startChallenge = proctoring.startChallenge.bind(proctoring);
39578
- const stopChallenge = proctoring.stopChallenge.bind(proctoring);
39579
39470
  const pause = proctoring.pause.bind(proctoring);
39580
39471
  const resume = proctoring.resume.bind(proctoring);
39581
39472
  const onFocus = proctoring.setOnFocusCallback.bind(proctoring);
@@ -39600,8 +39491,6 @@ function useProctoring(proctoringOptions, enviromentConfig = "prod") {
39600
39491
  login,
39601
39492
  start,
39602
39493
  finish,
39603
- startChallenge,
39604
- stopChallenge,
39605
39494
  onFocus,
39606
39495
  onLostFocus,
39607
39496
  onChangeDevices: onChangeDevices2,
@@ -2,7 +2,7 @@ export interface VideoChunk {
2
2
  id?: number;
3
3
  proctoringId: string;
4
4
  chunkIndex: number;
5
- blob: Blob;
5
+ arrayBuffer: ArrayBuffer;
6
6
  timestamp: number;
7
7
  uploaded: number;
8
8
  mimeType: string;
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "easyproctor-hml",
3
- "version": "2.7.0",
3
+ "version": "2.7.2",
4
4
  "description": "Modulo web de gravação do EasyProctor",
5
5
  "main": "./index.js",
6
6
  "module": "./esm/index.js",
7
- "unpkg": "./unpkg/easyproctor-hml.min.js",
7
+ "unpkg": "./unpkg/easyproctor.min.js",
8
8
  "types": "./index.d.ts",
9
9
  "keywords": [
10
10
  "proctoring"
@@ -41,7 +41,6 @@ export declare class Proctoring {
41
41
  private readonly repository;
42
42
  private readonly repositoryDevices;
43
43
  private extension;
44
- private extensionEasycatcher;
45
44
  private deviceData;
46
45
  private paramsConfig;
47
46
  private proctoringId;
@@ -101,8 +100,4 @@ export declare class Proctoring {
101
100
  audioStream?: MediaStream;
102
101
  _screenStream: MediaStream | undefined;
103
102
  }>;
104
- private isChallengeRunning;
105
- private challengeId;
106
- startChallenge(templateId: string): Promise<void>;
107
- stopChallenge(): Promise<void>;
108
103
  }
@@ -5,8 +5,6 @@ export declare function useProctoring(proctoringOptions: ProctoringContext, envi
5
5
  login: () => Promise<void>;
6
6
  start: (parameters: any, videoOptions: any) => Promise<import("../dtos/StartProctoringResponse").default>;
7
7
  finish: (options?: import("./proctoring").ProctoringFinisherOptions) => Promise<void>;
8
- startChallenge: (templateId: string) => Promise<void>;
9
- stopChallenge: () => Promise<void>;
10
8
  onFocus: (cb: () => void) => Promise<void>;
11
9
  onLostFocus: (cb: () => void) => Promise<void>;
12
10
  onChangeDevices: (options?: import("./proctoring").ProctoringChangeDevicesOptions) => Promise<void>;