easyproctor-hml 2.7.5 → 2.7.6

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
@@ -13476,13 +13476,8 @@ var _ChunkStorageService = class _ChunkStorageService {
13476
13476
  async clearAllChunks(proctoringId2) {
13477
13477
  const db = await this.connect();
13478
13478
  return new Promise((resolve, reject) => {
13479
- const transaction = db.transaction(
13480
- _ChunkStorageService.STORE_NAME,
13481
- "readwrite"
13482
- );
13483
- const store = transaction.objectStore(
13484
- _ChunkStorageService.STORE_NAME
13485
- );
13479
+ const transaction = db.transaction(_ChunkStorageService.STORE_NAME, "readwrite");
13480
+ const store = transaction.objectStore(_ChunkStorageService.STORE_NAME);
13486
13481
  const index = store.index("proctoringId");
13487
13482
  const range = IDBKeyRange.only(proctoringId2);
13488
13483
  const request = index.openCursor(range);
@@ -13491,34 +13486,13 @@ var _ChunkStorageService = class _ChunkStorageService {
13491
13486
  if (cursor) {
13492
13487
  cursor.delete();
13493
13488
  cursor.continue();
13489
+ } else {
13490
+ resolve();
13494
13491
  }
13495
13492
  };
13496
13493
  request.onerror = () => {
13497
13494
  var _a2;
13498
- reject(
13499
- new Error(
13500
- `Erro ao limpar chunks: ${(_a2 = request.error) == null ? void 0 : _a2.message}`
13501
- )
13502
- );
13503
- };
13504
- transaction.oncomplete = () => {
13505
- resolve();
13506
- };
13507
- transaction.onerror = () => {
13508
- var _a2;
13509
- reject(
13510
- new Error(
13511
- `Transaction error: ${(_a2 = transaction.error) == null ? void 0 : _a2.message}`
13512
- )
13513
- );
13514
- };
13515
- transaction.onabort = () => {
13516
- var _a2;
13517
- reject(
13518
- new Error(
13519
- `Transaction aborted: ${(_a2 = transaction.error) == null ? void 0 : _a2.message}`
13520
- )
13521
- );
13495
+ return reject(new Error(`Erro ao limpar todos os chunks: ${(_a2 = request.error) == null ? void 0 : _a2.message}`));
13522
13496
  };
13523
13497
  });
13524
13498
  }
@@ -13577,8 +13551,8 @@ var _ChunkStorageService = class _ChunkStorageService {
13577
13551
  }
13578
13552
  };
13579
13553
  _ChunkStorageService.DB_NAME = "EasyProctorChunksDb";
13580
- /** v2: índices numéricos; v3: payload como ArrayBuffer em vez de Blob (Safari iOS). */
13581
- _ChunkStorageService.DB_VERSION = 3;
13554
+ /** Incrementado para v2 para recriar índices com tipos numéricos em vez de boolean */
13555
+ _ChunkStorageService.DB_VERSION = 2;
13582
13556
  _ChunkStorageService.STORE_NAME = "chunks";
13583
13557
  var ChunkStorageService = _ChunkStorageService;
13584
13558
 
@@ -13760,41 +13734,32 @@ var BackgroundUploadService = class _BackgroundUploadService {
13760
13734
  console.log(`[BackgroundUpload] ${pendingChunks.length} chunks pendentes encontrados. Modo final: ${isFinal}`);
13761
13735
  let virtualStart = this.totalBytesPurged;
13762
13736
  const chunksWithMeta = allChunks.map((c3) => {
13763
- const byteLen = c3.arrayBuffer.byteLength;
13764
13737
  const start = virtualStart;
13765
- const end = start + byteLen - 1;
13766
- virtualStart += byteLen;
13738
+ const end = start + c3.blob.size - 1;
13739
+ virtualStart += c3.blob.size;
13767
13740
  return { chunk: c3, start, end };
13768
13741
  });
13769
- const sliceParts = [];
13742
+ let combinedBlobParts = [];
13770
13743
  let lastProcessedChunkId = null;
13771
13744
  let finalChunkIndex = 0;
13772
13745
  let mimeType = pendingChunks[0].mimeType;
13773
13746
  for (const meta of chunksWithMeta) {
13774
13747
  if (this.currentOffset > meta.end) continue;
13775
13748
  const sliceStart = Math.max(0, this.currentOffset - meta.start);
13776
- const view = new Uint8Array(meta.chunk.arrayBuffer);
13777
- sliceParts.push(view.subarray(sliceStart));
13749
+ const chunkSlice = meta.chunk.blob.slice(sliceStart);
13750
+ combinedBlobParts.push(chunkSlice);
13778
13751
  lastProcessedChunkId = meta.chunk.id;
13779
13752
  finalChunkIndex = meta.chunk.chunkIndex;
13780
13753
  }
13781
- if (sliceParts.length === 0 && !isFinal) {
13754
+ if (combinedBlobParts.length === 0 && !isFinal) {
13782
13755
  this.isProcessing = false;
13783
13756
  return;
13784
13757
  }
13785
- const combinedLength = sliceParts.reduce((acc, p3) => acc + p3.length, 0);
13786
- const combined = new Uint8Array(combinedLength);
13787
- {
13788
- let off = 0;
13789
- for (const p3 of sliceParts) {
13790
- combined.set(p3, off);
13791
- off += p3.length;
13792
- }
13793
- }
13794
- let sendableSize = combined.byteLength;
13758
+ let fullBlob = new Blob(combinedBlobParts, { type: mimeType });
13759
+ let sendableSize = fullBlob.size;
13795
13760
  let totalSizeForHeader = void 0;
13796
13761
  if (!isFinal) {
13797
- sendableSize = Math.floor(combined.byteLength / this.GCS_CHUNK_SIZE) * this.GCS_CHUNK_SIZE;
13762
+ sendableSize = Math.floor(fullBlob.size / this.GCS_CHUNK_SIZE) * this.GCS_CHUNK_SIZE;
13798
13763
  if (sendableSize === 0) {
13799
13764
  console.log("[BackgroundUpload] Dados insuficientes para atingir 256KB. Aguardando novo chunk...");
13800
13765
  this.isProcessing = false;
@@ -13803,14 +13768,9 @@ var BackgroundUploadService = class _BackgroundUploadService {
13803
13768
  } else {
13804
13769
  totalSizeForHeader = virtualStart;
13805
13770
  }
13806
- const payload = sendableSize === combined.byteLength ? combined : combined.subarray(0, sendableSize);
13771
+ const blobToSend = fullBlob.slice(0, sendableSize);
13807
13772
  try {
13808
- await this.uploadData(
13809
- payload.byteLength > 0 ? payload : null,
13810
- mimeType,
13811
- finalChunkIndex,
13812
- totalSizeForHeader
13813
- );
13773
+ await this.uploadData(blobToSend, mimeType, finalChunkIndex, totalSizeForHeader);
13814
13774
  for (const meta of chunksWithMeta) {
13815
13775
  if (meta.chunk.uploaded === 0 && meta.end < this.currentOffset) {
13816
13776
  await this.chunkStorage.markAsUploaded(meta.chunk.id);
@@ -13821,10 +13781,7 @@ var BackgroundUploadService = class _BackgroundUploadService {
13821
13781
  }
13822
13782
  if (this.config.cleanAfterUpload) {
13823
13783
  const chunksToClear = chunksWithMeta.filter((meta) => meta.chunk.uploaded === 1 || meta.chunk.uploaded === 0 && meta.end < this.currentOffset);
13824
- const sizePurged = chunksToClear.reduce(
13825
- (acc, meta) => acc + meta.chunk.arrayBuffer.byteLength,
13826
- 0
13827
- );
13784
+ const sizePurged = chunksToClear.reduce((acc, meta) => acc + meta.chunk.blob.size, 0);
13828
13785
  await this.chunkStorage.clearUploadedChunks(this.proctoringId);
13829
13786
  if (sizePurged > 0) {
13830
13787
  this.totalBytesPurged += sizePurged;
@@ -13848,8 +13805,7 @@ var BackgroundUploadService = class _BackgroundUploadService {
13848
13805
  /**
13849
13806
  * Faz o upload bruto de dados para a sessão GCS.
13850
13807
  */
13851
- async uploadData(body, mimeType, chunkIndex, totalSize) {
13852
- var _a2;
13808
+ async uploadData(blob, mimeType, chunkIndex, totalSize) {
13853
13809
  const fileName = `EP_${this.proctoringId}_camera_0.webm`;
13854
13810
  if (!this.sessionUrl) {
13855
13811
  const initiateUrl = await this.backend.initiateUpload(this.token, `${this.proctoringId}/${fileName}`, mimeType);
@@ -13880,28 +13836,16 @@ var BackgroundUploadService = class _BackgroundUploadService {
13880
13836
  } else {
13881
13837
  console.log(`[BackgroundUpload] Usando sess\xE3o GCS existente: ${this.sessionUrl}`);
13882
13838
  }
13883
- const size = (_a2 = body == null ? void 0 : body.byteLength) != null ? _a2 : 0;
13884
13839
  const start = this.currentOffset;
13885
- const end = start + size - 1;
13840
+ const end = start + blob.size - 1;
13886
13841
  const totalHeader = totalSize !== void 0 ? totalSize.toString() : "*";
13887
- const contentRangeHeader = size === 0 && totalSize !== void 0 ? `bytes */${totalHeader}` : `bytes ${start}-${end}/${totalHeader}`;
13888
- console.log(
13889
- `[BackgroundUpload] Enviando ${size > 0 ? "dados" : "finaliza\xE7\xE3o"}: ${contentRangeHeader} (Size: ${size})`
13890
- );
13891
- let uploadBody = null;
13892
- if (size > 0 && body) {
13893
- const raw = body.buffer;
13894
- if (raw instanceof ArrayBuffer) {
13895
- uploadBody = body.byteOffset === 0 && body.byteLength === raw.byteLength ? raw : raw.slice(body.byteOffset, body.byteOffset + body.byteLength);
13896
- } else {
13897
- uploadBody = new ArrayBuffer(body.byteLength);
13898
- new Uint8Array(uploadBody).set(body);
13899
- }
13900
- }
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})`);
13901
13844
  const response = await fetch(this.sessionUrl, {
13902
13845
  method: "PUT",
13903
13846
  headers: { "Content-Range": contentRangeHeader },
13904
- body: uploadBody
13847
+ body: blob.size > 0 ? blob : null
13848
+ // Usa null para garantir corpo vazio se necessário
13905
13849
  });
13906
13850
  console.log(`[BackgroundUpload] Resposta GCS (uploadData): ${response.status}`);
13907
13851
  if (response.status !== 200 && response.status !== 201 && response.status !== 308) {
@@ -13914,13 +13858,13 @@ var BackgroundUploadService = class _BackgroundUploadService {
13914
13858
  const lastByte = parseInt(rangeHeader.split("-")[1], 10);
13915
13859
  this.currentOffset = lastByte + 1;
13916
13860
  } else {
13917
- this.currentOffset += size;
13861
+ this.currentOffset += blob.size;
13918
13862
  }
13919
13863
  this.saveSessionState();
13920
13864
  trackers.registerUploadFile(
13921
13865
  this.proctoringId,
13922
13866
  `GCS Stream Upload
13923
- Size: ${size}
13867
+ Size: ${blob.size}
13924
13868
  Range: ${start}-${end}
13925
13869
  Last Index: ${chunkIndex}`,
13926
13870
  "CameraChunk"
@@ -14439,23 +14383,19 @@ Setting: ${JSON.stringify(settings, null, 2)}`
14439
14383
  }
14440
14384
  if (this.isChunkEnabled) {
14441
14385
  if (this.backgroundUpload) {
14442
- trackers.registerError(this.proctoringId, `Flush e parada do background upload`);
14443
14386
  try {
14444
14387
  if (this.pendingChunkSaves.length > 0) {
14445
14388
  console.log(`[CameraRecorder] Aguardando ${this.pendingChunkSaves.length} salvamentos de chunks pendentes...`);
14446
14389
  await Promise.all(this.pendingChunkSaves);
14447
14390
  }
14448
14391
  await this.backgroundUpload.flush();
14449
- this.backgroundUpload.stop();
14450
14392
  } catch (e3) {
14451
14393
  console.warn("[CameraRecorder] Erro ao fazer flush dos chunks:", e3);
14452
- trackers.registerError(this.proctoringId, `Flush Chunks
14453
- Error: ${e3}`);
14454
14394
  }
14395
+ this.backgroundUpload.stop();
14455
14396
  }
14456
14397
  this.removeLifecycleListeners();
14457
14398
  this.persistSessionState("FINISHED");
14458
- trackers.registerError(this.proctoringId, `Finalizando flush e parada do background upload`);
14459
14399
  }
14460
14400
  }
14461
14401
  /**
@@ -14467,11 +14407,10 @@ Setting: ${JSON.stringify(settings, null, 2)}`
14467
14407
  const savePromise = (async () => {
14468
14408
  var _a2;
14469
14409
  try {
14470
- const arrayBuffer = await blob.arrayBuffer();
14471
14410
  await this.chunkStorage.saveChunk({
14472
14411
  proctoringId: this.proctoringId,
14473
14412
  chunkIndex: this.chunkIndex,
14474
- arrayBuffer,
14413
+ blob,
14475
14414
  timestamp: Date.now(),
14476
14415
  uploaded: 0,
14477
14416
  mimeType: ((_a2 = this.recorderOptions) == null ? void 0 : _a2.mimeType) || "video/webm"
@@ -14479,8 +14418,6 @@ Setting: ${JSON.stringify(settings, null, 2)}`
14479
14418
  this.chunkIndex++;
14480
14419
  console.log(`[CameraRecorder] Chunk ${this.chunkIndex - 1} salvo no IndexedDB.`);
14481
14420
  } catch (error) {
14482
- trackers.registerError(this.proctoringId, `Save Chunk
14483
- Error: ${error}`);
14484
14421
  console.error("[CameraRecorder] Erro ao salvar chunk no IndexedDB:", error);
14485
14422
  }
14486
14423
  })();
@@ -14629,7 +14566,6 @@ Setting: ${JSON.stringify(settings, null, 2)}`
14629
14566
  const settingsAudio = this.cameraStream.getAudioTracks()[0].getSettings();
14630
14567
  if (this.options.proctoringType == "VIDEO" || this.options.proctoringType == "REALTIME" || this.options.proctoringType == "IMAGE" && ((_a2 = this.paramsConfig.imageBehaviourParameters) == null ? void 0 : _a2.saveVideo)) {
14631
14568
  let videoFile;
14632
- trackers.registerError(this.proctoringId, `saveOnSession iniciando`);
14633
14569
  if (this.isChunkEnabled) {
14634
14570
  const isStable = await this.checkInternetStability();
14635
14571
  if (isStable) {
@@ -14638,19 +14574,13 @@ Setting: ${JSON.stringify(settings, null, 2)}`
14638
14574
  const fileName = `EP_${this.proctoringId}_camera_0.webm`;
14639
14575
  const objectName = `${this.proctoringId}/${fileName}`;
14640
14576
  const isUploaded = await this.backend.checkUpload(this.backendToken, objectName, "video/webm");
14641
- trackers.registerError(this.proctoringId, `Limpa o armazenamento local pois o v\xEDdeo j\xE1 est\xE1 no servidor`);
14642
14577
  if (isUploaded) {
14643
- try {
14644
- this.chunkStorage && await this.chunkStorage.clearAllChunks(session.id);
14645
- } catch (e3) {
14646
- trackers.registerError(this.proctoringId, `Erro ao limpar o armazenamento local: ${e3}`);
14647
- }
14578
+ this.chunkStorage && await this.chunkStorage.clearAllChunks(session.id);
14648
14579
  return;
14649
14580
  }
14650
14581
  }
14651
14582
  }
14652
14583
  }
14653
- trackers.registerError(this.proctoringId, `saveOnSession gerando v\xEDdeo a partir do buffer em mem\xF3ria (\xEDntegra)`);
14654
14584
  const rawBlob = new Blob(this.blobs, {
14655
14585
  type: ((_b = this.recorderOptions) == null ? void 0 : _b.mimeType) || "video/webm"
14656
14586
  });
@@ -14671,7 +14601,6 @@ Setting: ${JSON.stringify(settings, null, 2)}`
14671
14601
  origin: "Camera" /* Camera */
14672
14602
  });
14673
14603
  }
14674
- trackers.registerError(this.proctoringId, `saveOnSession finalizado`);
14675
14604
  }
14676
14605
  async getFile(file, name, type) {
14677
14606
  return new Promise((resolve, reject) => {
@@ -23806,6 +23735,7 @@ Error: ${error}`
23806
23735
  trackers.registerError(this.proctoringId, `finish sendPendingRealtimeAlerts`);
23807
23736
  await this.sendPendingRealtimeAlerts();
23808
23737
  trackers.registerError(this.proctoringId, `finish this.repository.save`);
23738
+ await this.repository.save(this.proctoringSession);
23809
23739
  let uploader;
23810
23740
  let uploaderServices;
23811
23741
  trackers.registerError(this.proctoringId, `finish uploader`);
package/index.js CHANGED
@@ -31573,13 +31573,8 @@ var _ChunkStorageService = class _ChunkStorageService {
31573
31573
  async clearAllChunks(proctoringId2) {
31574
31574
  const db = await this.connect();
31575
31575
  return new Promise((resolve, reject) => {
31576
- const transaction = db.transaction(
31577
- _ChunkStorageService.STORE_NAME,
31578
- "readwrite"
31579
- );
31580
- const store = transaction.objectStore(
31581
- _ChunkStorageService.STORE_NAME
31582
- );
31576
+ const transaction = db.transaction(_ChunkStorageService.STORE_NAME, "readwrite");
31577
+ const store = transaction.objectStore(_ChunkStorageService.STORE_NAME);
31583
31578
  const index = store.index("proctoringId");
31584
31579
  const range = IDBKeyRange.only(proctoringId2);
31585
31580
  const request = index.openCursor(range);
@@ -31588,34 +31583,13 @@ var _ChunkStorageService = class _ChunkStorageService {
31588
31583
  if (cursor) {
31589
31584
  cursor.delete();
31590
31585
  cursor.continue();
31586
+ } else {
31587
+ resolve();
31591
31588
  }
31592
31589
  };
31593
31590
  request.onerror = () => {
31594
31591
  var _a2;
31595
- reject(
31596
- new Error(
31597
- `Erro ao limpar chunks: ${(_a2 = request.error) == null ? void 0 : _a2.message}`
31598
- )
31599
- );
31600
- };
31601
- transaction.oncomplete = () => {
31602
- resolve();
31603
- };
31604
- transaction.onerror = () => {
31605
- var _a2;
31606
- reject(
31607
- new Error(
31608
- `Transaction error: ${(_a2 = transaction.error) == null ? void 0 : _a2.message}`
31609
- )
31610
- );
31611
- };
31612
- transaction.onabort = () => {
31613
- var _a2;
31614
- reject(
31615
- new Error(
31616
- `Transaction aborted: ${(_a2 = transaction.error) == null ? void 0 : _a2.message}`
31617
- )
31618
- );
31592
+ return reject(new Error(`Erro ao limpar todos os chunks: ${(_a2 = request.error) == null ? void 0 : _a2.message}`));
31619
31593
  };
31620
31594
  });
31621
31595
  }
@@ -31674,8 +31648,8 @@ var _ChunkStorageService = class _ChunkStorageService {
31674
31648
  }
31675
31649
  };
31676
31650
  _ChunkStorageService.DB_NAME = "EasyProctorChunksDb";
31677
- /** v2: índices numéricos; v3: payload como ArrayBuffer em vez de Blob (Safari iOS). */
31678
- _ChunkStorageService.DB_VERSION = 3;
31651
+ /** Incrementado para v2 para recriar índices com tipos numéricos em vez de boolean */
31652
+ _ChunkStorageService.DB_VERSION = 2;
31679
31653
  _ChunkStorageService.STORE_NAME = "chunks";
31680
31654
  var ChunkStorageService = _ChunkStorageService;
31681
31655
 
@@ -31857,41 +31831,32 @@ var BackgroundUploadService = class _BackgroundUploadService {
31857
31831
  console.log(`[BackgroundUpload] ${pendingChunks.length} chunks pendentes encontrados. Modo final: ${isFinal}`);
31858
31832
  let virtualStart = this.totalBytesPurged;
31859
31833
  const chunksWithMeta = allChunks.map((c3) => {
31860
- const byteLen = c3.arrayBuffer.byteLength;
31861
31834
  const start = virtualStart;
31862
- const end = start + byteLen - 1;
31863
- virtualStart += byteLen;
31835
+ const end = start + c3.blob.size - 1;
31836
+ virtualStart += c3.blob.size;
31864
31837
  return { chunk: c3, start, end };
31865
31838
  });
31866
- const sliceParts = [];
31839
+ let combinedBlobParts = [];
31867
31840
  let lastProcessedChunkId = null;
31868
31841
  let finalChunkIndex = 0;
31869
31842
  let mimeType = pendingChunks[0].mimeType;
31870
31843
  for (const meta of chunksWithMeta) {
31871
31844
  if (this.currentOffset > meta.end) continue;
31872
31845
  const sliceStart = Math.max(0, this.currentOffset - meta.start);
31873
- const view = new Uint8Array(meta.chunk.arrayBuffer);
31874
- sliceParts.push(view.subarray(sliceStart));
31846
+ const chunkSlice = meta.chunk.blob.slice(sliceStart);
31847
+ combinedBlobParts.push(chunkSlice);
31875
31848
  lastProcessedChunkId = meta.chunk.id;
31876
31849
  finalChunkIndex = meta.chunk.chunkIndex;
31877
31850
  }
31878
- if (sliceParts.length === 0 && !isFinal) {
31851
+ if (combinedBlobParts.length === 0 && !isFinal) {
31879
31852
  this.isProcessing = false;
31880
31853
  return;
31881
31854
  }
31882
- const combinedLength = sliceParts.reduce((acc, p3) => acc + p3.length, 0);
31883
- const combined = new Uint8Array(combinedLength);
31884
- {
31885
- let off = 0;
31886
- for (const p3 of sliceParts) {
31887
- combined.set(p3, off);
31888
- off += p3.length;
31889
- }
31890
- }
31891
- let sendableSize = combined.byteLength;
31855
+ let fullBlob = new Blob(combinedBlobParts, { type: mimeType });
31856
+ let sendableSize = fullBlob.size;
31892
31857
  let totalSizeForHeader = void 0;
31893
31858
  if (!isFinal) {
31894
- sendableSize = Math.floor(combined.byteLength / this.GCS_CHUNK_SIZE) * this.GCS_CHUNK_SIZE;
31859
+ sendableSize = Math.floor(fullBlob.size / this.GCS_CHUNK_SIZE) * this.GCS_CHUNK_SIZE;
31895
31860
  if (sendableSize === 0) {
31896
31861
  console.log("[BackgroundUpload] Dados insuficientes para atingir 256KB. Aguardando novo chunk...");
31897
31862
  this.isProcessing = false;
@@ -31900,14 +31865,9 @@ var BackgroundUploadService = class _BackgroundUploadService {
31900
31865
  } else {
31901
31866
  totalSizeForHeader = virtualStart;
31902
31867
  }
31903
- const payload = sendableSize === combined.byteLength ? combined : combined.subarray(0, sendableSize);
31868
+ const blobToSend = fullBlob.slice(0, sendableSize);
31904
31869
  try {
31905
- await this.uploadData(
31906
- payload.byteLength > 0 ? payload : null,
31907
- mimeType,
31908
- finalChunkIndex,
31909
- totalSizeForHeader
31910
- );
31870
+ await this.uploadData(blobToSend, mimeType, finalChunkIndex, totalSizeForHeader);
31911
31871
  for (const meta of chunksWithMeta) {
31912
31872
  if (meta.chunk.uploaded === 0 && meta.end < this.currentOffset) {
31913
31873
  await this.chunkStorage.markAsUploaded(meta.chunk.id);
@@ -31918,10 +31878,7 @@ var BackgroundUploadService = class _BackgroundUploadService {
31918
31878
  }
31919
31879
  if (this.config.cleanAfterUpload) {
31920
31880
  const chunksToClear = chunksWithMeta.filter((meta) => meta.chunk.uploaded === 1 || meta.chunk.uploaded === 0 && meta.end < this.currentOffset);
31921
- const sizePurged = chunksToClear.reduce(
31922
- (acc, meta) => acc + meta.chunk.arrayBuffer.byteLength,
31923
- 0
31924
- );
31881
+ const sizePurged = chunksToClear.reduce((acc, meta) => acc + meta.chunk.blob.size, 0);
31925
31882
  await this.chunkStorage.clearUploadedChunks(this.proctoringId);
31926
31883
  if (sizePurged > 0) {
31927
31884
  this.totalBytesPurged += sizePurged;
@@ -31945,8 +31902,7 @@ var BackgroundUploadService = class _BackgroundUploadService {
31945
31902
  /**
31946
31903
  * Faz o upload bruto de dados para a sessão GCS.
31947
31904
  */
31948
- async uploadData(body, mimeType, chunkIndex, totalSize) {
31949
- var _a2;
31905
+ async uploadData(blob, mimeType, chunkIndex, totalSize) {
31950
31906
  const fileName = `EP_${this.proctoringId}_camera_0.webm`;
31951
31907
  if (!this.sessionUrl) {
31952
31908
  const initiateUrl = await this.backend.initiateUpload(this.token, `${this.proctoringId}/${fileName}`, mimeType);
@@ -31977,28 +31933,16 @@ var BackgroundUploadService = class _BackgroundUploadService {
31977
31933
  } else {
31978
31934
  console.log(`[BackgroundUpload] Usando sess\xE3o GCS existente: ${this.sessionUrl}`);
31979
31935
  }
31980
- const size = (_a2 = body == null ? void 0 : body.byteLength) != null ? _a2 : 0;
31981
31936
  const start = this.currentOffset;
31982
- const end = start + size - 1;
31937
+ const end = start + blob.size - 1;
31983
31938
  const totalHeader = totalSize !== void 0 ? totalSize.toString() : "*";
31984
- const contentRangeHeader = size === 0 && totalSize !== void 0 ? `bytes */${totalHeader}` : `bytes ${start}-${end}/${totalHeader}`;
31985
- console.log(
31986
- `[BackgroundUpload] Enviando ${size > 0 ? "dados" : "finaliza\xE7\xE3o"}: ${contentRangeHeader} (Size: ${size})`
31987
- );
31988
- let uploadBody = null;
31989
- if (size > 0 && body) {
31990
- const raw = body.buffer;
31991
- if (raw instanceof ArrayBuffer) {
31992
- uploadBody = body.byteOffset === 0 && body.byteLength === raw.byteLength ? raw : raw.slice(body.byteOffset, body.byteOffset + body.byteLength);
31993
- } else {
31994
- uploadBody = new ArrayBuffer(body.byteLength);
31995
- new Uint8Array(uploadBody).set(body);
31996
- }
31997
- }
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})`);
31998
31941
  const response = await fetch(this.sessionUrl, {
31999
31942
  method: "PUT",
32000
31943
  headers: { "Content-Range": contentRangeHeader },
32001
- body: uploadBody
31944
+ body: blob.size > 0 ? blob : null
31945
+ // Usa null para garantir corpo vazio se necessário
32002
31946
  });
32003
31947
  console.log(`[BackgroundUpload] Resposta GCS (uploadData): ${response.status}`);
32004
31948
  if (response.status !== 200 && response.status !== 201 && response.status !== 308) {
@@ -32011,13 +31955,13 @@ var BackgroundUploadService = class _BackgroundUploadService {
32011
31955
  const lastByte = parseInt(rangeHeader.split("-")[1], 10);
32012
31956
  this.currentOffset = lastByte + 1;
32013
31957
  } else {
32014
- this.currentOffset += size;
31958
+ this.currentOffset += blob.size;
32015
31959
  }
32016
31960
  this.saveSessionState();
32017
31961
  trackers.registerUploadFile(
32018
31962
  this.proctoringId,
32019
31963
  `GCS Stream Upload
32020
- Size: ${size}
31964
+ Size: ${blob.size}
32021
31965
  Range: ${start}-${end}
32022
31966
  Last Index: ${chunkIndex}`,
32023
31967
  "CameraChunk"
@@ -32536,23 +32480,19 @@ Setting: ${JSON.stringify(settings, null, 2)}`
32536
32480
  }
32537
32481
  if (this.isChunkEnabled) {
32538
32482
  if (this.backgroundUpload) {
32539
- trackers.registerError(this.proctoringId, `Flush e parada do background upload`);
32540
32483
  try {
32541
32484
  if (this.pendingChunkSaves.length > 0) {
32542
32485
  console.log(`[CameraRecorder] Aguardando ${this.pendingChunkSaves.length} salvamentos de chunks pendentes...`);
32543
32486
  await Promise.all(this.pendingChunkSaves);
32544
32487
  }
32545
32488
  await this.backgroundUpload.flush();
32546
- this.backgroundUpload.stop();
32547
32489
  } catch (e3) {
32548
32490
  console.warn("[CameraRecorder] Erro ao fazer flush dos chunks:", e3);
32549
- trackers.registerError(this.proctoringId, `Flush Chunks
32550
- Error: ${e3}`);
32551
32491
  }
32492
+ this.backgroundUpload.stop();
32552
32493
  }
32553
32494
  this.removeLifecycleListeners();
32554
32495
  this.persistSessionState("FINISHED");
32555
- trackers.registerError(this.proctoringId, `Finalizando flush e parada do background upload`);
32556
32496
  }
32557
32497
  }
32558
32498
  /**
@@ -32564,11 +32504,10 @@ Setting: ${JSON.stringify(settings, null, 2)}`
32564
32504
  const savePromise = (async () => {
32565
32505
  var _a2;
32566
32506
  try {
32567
- const arrayBuffer = await blob.arrayBuffer();
32568
32507
  await this.chunkStorage.saveChunk({
32569
32508
  proctoringId: this.proctoringId,
32570
32509
  chunkIndex: this.chunkIndex,
32571
- arrayBuffer,
32510
+ blob,
32572
32511
  timestamp: Date.now(),
32573
32512
  uploaded: 0,
32574
32513
  mimeType: ((_a2 = this.recorderOptions) == null ? void 0 : _a2.mimeType) || "video/webm"
@@ -32576,8 +32515,6 @@ Setting: ${JSON.stringify(settings, null, 2)}`
32576
32515
  this.chunkIndex++;
32577
32516
  console.log(`[CameraRecorder] Chunk ${this.chunkIndex - 1} salvo no IndexedDB.`);
32578
32517
  } catch (error) {
32579
- trackers.registerError(this.proctoringId, `Save Chunk
32580
- Error: ${error}`);
32581
32518
  console.error("[CameraRecorder] Erro ao salvar chunk no IndexedDB:", error);
32582
32519
  }
32583
32520
  })();
@@ -32726,7 +32663,6 @@ Setting: ${JSON.stringify(settings, null, 2)}`
32726
32663
  const settingsAudio = this.cameraStream.getAudioTracks()[0].getSettings();
32727
32664
  if (this.options.proctoringType == "VIDEO" || this.options.proctoringType == "REALTIME" || this.options.proctoringType == "IMAGE" && ((_a2 = this.paramsConfig.imageBehaviourParameters) == null ? void 0 : _a2.saveVideo)) {
32728
32665
  let videoFile;
32729
- trackers.registerError(this.proctoringId, `saveOnSession iniciando`);
32730
32666
  if (this.isChunkEnabled) {
32731
32667
  const isStable = await this.checkInternetStability();
32732
32668
  if (isStable) {
@@ -32735,19 +32671,13 @@ Setting: ${JSON.stringify(settings, null, 2)}`
32735
32671
  const fileName = `EP_${this.proctoringId}_camera_0.webm`;
32736
32672
  const objectName = `${this.proctoringId}/${fileName}`;
32737
32673
  const isUploaded = await this.backend.checkUpload(this.backendToken, objectName, "video/webm");
32738
- trackers.registerError(this.proctoringId, `Limpa o armazenamento local pois o v\xEDdeo j\xE1 est\xE1 no servidor`);
32739
32674
  if (isUploaded) {
32740
- try {
32741
- this.chunkStorage && await this.chunkStorage.clearAllChunks(session.id);
32742
- } catch (e3) {
32743
- trackers.registerError(this.proctoringId, `Erro ao limpar o armazenamento local: ${e3}`);
32744
- }
32675
+ this.chunkStorage && await this.chunkStorage.clearAllChunks(session.id);
32745
32676
  return;
32746
32677
  }
32747
32678
  }
32748
32679
  }
32749
32680
  }
32750
- trackers.registerError(this.proctoringId, `saveOnSession gerando v\xEDdeo a partir do buffer em mem\xF3ria (\xEDntegra)`);
32751
32681
  const rawBlob = new Blob(this.blobs, {
32752
32682
  type: ((_b = this.recorderOptions) == null ? void 0 : _b.mimeType) || "video/webm"
32753
32683
  });
@@ -32768,7 +32698,6 @@ Setting: ${JSON.stringify(settings, null, 2)}`
32768
32698
  origin: "Camera" /* Camera */
32769
32699
  });
32770
32700
  }
32771
- trackers.registerError(this.proctoringId, `saveOnSession finalizado`);
32772
32701
  }
32773
32702
  async getFile(file, name, type) {
32774
32703
  return new Promise((resolve, reject) => {
@@ -39055,6 +38984,7 @@ Error: ${error}`
39055
38984
  trackers.registerError(this.proctoringId, `finish sendPendingRealtimeAlerts`);
39056
38985
  await this.sendPendingRealtimeAlerts();
39057
38986
  trackers.registerError(this.proctoringId, `finish this.repository.save`);
38987
+ await this.repository.save(this.proctoringSession);
39058
38988
  let uploader;
39059
38989
  let uploaderServices;
39060
38990
  trackers.registerError(this.proctoringId, `finish uploader`);
@@ -2,7 +2,7 @@ export interface VideoChunk {
2
2
  id?: number;
3
3
  proctoringId: string;
4
4
  chunkIndex: number;
5
- arrayBuffer: ArrayBuffer;
5
+ blob: Blob;
6
6
  timestamp: number;
7
7
  uploaded: number;
8
8
  mimeType: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "easyproctor-hml",
3
- "version": "2.7.5",
3
+ "version": "2.7.6",
4
4
  "description": "Modulo web de gravação do EasyProctor",
5
5
  "main": "./index.js",
6
6
  "module": "./esm/index.js",