easyproctor-hml 2.7.9 → 2.7.11
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 +66 -116
- package/index.js +66 -116
- package/new-flow/chunk/BackgroundUploadService.d.ts +0 -1
- package/new-flow/chunk/ChunkStorageService.d.ts +2 -3
- package/package.json +1 -1
- package/unpkg/easyproctor.min.js +33 -33
package/index.js
CHANGED
|
@@ -31414,16 +31414,6 @@ var _ChunkStorageService = class _ChunkStorageService {
|
|
|
31414
31414
|
constructor() {
|
|
31415
31415
|
this.db = null;
|
|
31416
31416
|
}
|
|
31417
|
-
/**
|
|
31418
|
-
* WebKit pode falhar em IDB.add/put com "Error preparing Blob/File data..." se o
|
|
31419
|
-
* ArrayBuffer ainda estiver associado ao Blob (ex.: blob.arrayBuffer()) ou no
|
|
31420
|
-
* round-trip get→put do mesmo registro. Esta cópia remove qualquer vínculo.
|
|
31421
|
-
*/
|
|
31422
|
-
static detachedArrayBufferCopy(src) {
|
|
31423
|
-
const next = new Uint8Array(src.byteLength);
|
|
31424
|
-
next.set(new Uint8Array(src));
|
|
31425
|
-
return next.buffer;
|
|
31426
|
-
}
|
|
31427
31417
|
/**
|
|
31428
31418
|
* Abre a conexão com o IndexedDB, criando o banco e o object store se necessário.
|
|
31429
31419
|
*/
|
|
@@ -31463,18 +31453,10 @@ var _ChunkStorageService = class _ChunkStorageService {
|
|
|
31463
31453
|
*/
|
|
31464
31454
|
async saveChunk(chunk) {
|
|
31465
31455
|
const db = await this.connect();
|
|
31466
|
-
const record = {
|
|
31467
|
-
proctoringId: chunk.proctoringId,
|
|
31468
|
-
chunkIndex: chunk.chunkIndex,
|
|
31469
|
-
arrayBuffer: _ChunkStorageService.detachedArrayBufferCopy(chunk.arrayBuffer),
|
|
31470
|
-
timestamp: chunk.timestamp,
|
|
31471
|
-
uploaded: chunk.uploaded,
|
|
31472
|
-
mimeType: chunk.mimeType
|
|
31473
|
-
};
|
|
31474
31456
|
return new Promise((resolve, reject) => {
|
|
31475
31457
|
const transaction = db.transaction(_ChunkStorageService.STORE_NAME, "readwrite");
|
|
31476
31458
|
const store = transaction.objectStore(_ChunkStorageService.STORE_NAME);
|
|
31477
|
-
const request = store.add(
|
|
31459
|
+
const request = store.add(chunk);
|
|
31478
31460
|
request.onsuccess = () => {
|
|
31479
31461
|
resolve(request.result);
|
|
31480
31462
|
};
|
|
@@ -31531,35 +31513,36 @@ var _ChunkStorageService = class _ChunkStorageService {
|
|
|
31531
31513
|
});
|
|
31532
31514
|
}
|
|
31533
31515
|
/**
|
|
31534
|
-
*
|
|
31516
|
+
* Marca um chunk como enviado (uploaded = 1).
|
|
31535
31517
|
*/
|
|
31536
|
-
async
|
|
31537
|
-
if (chunkIds.length === 0) return;
|
|
31518
|
+
async markAsUploaded(chunkId) {
|
|
31538
31519
|
const db = await this.connect();
|
|
31539
31520
|
return new Promise((resolve, reject) => {
|
|
31540
31521
|
const transaction = db.transaction(_ChunkStorageService.STORE_NAME, "readwrite");
|
|
31541
31522
|
const store = transaction.objectStore(_ChunkStorageService.STORE_NAME);
|
|
31542
|
-
|
|
31543
|
-
|
|
31544
|
-
|
|
31545
|
-
|
|
31546
|
-
|
|
31547
|
-
|
|
31548
|
-
|
|
31549
|
-
|
|
31523
|
+
const getRequest = store.get(chunkId);
|
|
31524
|
+
getRequest.onsuccess = () => {
|
|
31525
|
+
const chunk = getRequest.result;
|
|
31526
|
+
if (!chunk) {
|
|
31527
|
+
resolve();
|
|
31528
|
+
return;
|
|
31529
|
+
}
|
|
31530
|
+
chunk.uploaded = 1;
|
|
31531
|
+
const putRequest = store.put(chunk);
|
|
31532
|
+
putRequest.onsuccess = () => resolve();
|
|
31533
|
+
putRequest.onerror = () => {
|
|
31534
|
+
var _a2;
|
|
31535
|
+
return reject(new Error(`Erro ao marcar chunk como enviado: ${(_a2 = putRequest.error) == null ? void 0 : _a2.message}`));
|
|
31536
|
+
};
|
|
31550
31537
|
};
|
|
31551
|
-
|
|
31552
|
-
var _a2
|
|
31553
|
-
return reject(new Error(`
|
|
31538
|
+
getRequest.onerror = () => {
|
|
31539
|
+
var _a2;
|
|
31540
|
+
return reject(new Error(`Erro ao buscar chunk para marcar: ${(_a2 = getRequest.error) == null ? void 0 : _a2.message}`));
|
|
31554
31541
|
};
|
|
31555
|
-
for (const id of chunkIds) {
|
|
31556
|
-
store.delete(id);
|
|
31557
|
-
}
|
|
31558
31542
|
});
|
|
31559
31543
|
}
|
|
31560
31544
|
/**
|
|
31561
|
-
* Remove
|
|
31562
|
-
* Usa openKeyCursor + delete por primaryKey para não materializar o valor (WebKit/iOS).
|
|
31545
|
+
* Remove todos os chunks já enviados de um proctoringId para liberar espaço.
|
|
31563
31546
|
*/
|
|
31564
31547
|
async clearUploadedChunks(proctoringId2) {
|
|
31565
31548
|
const db = await this.connect();
|
|
@@ -31568,11 +31551,11 @@ var _ChunkStorageService = class _ChunkStorageService {
|
|
|
31568
31551
|
const store = transaction.objectStore(_ChunkStorageService.STORE_NAME);
|
|
31569
31552
|
const index = store.index("proctoringId_uploaded");
|
|
31570
31553
|
const range = IDBKeyRange.only([proctoringId2, 1]);
|
|
31571
|
-
const request = index.
|
|
31554
|
+
const request = index.openCursor(range);
|
|
31572
31555
|
request.onsuccess = () => {
|
|
31573
31556
|
const cursor = request.result;
|
|
31574
31557
|
if (cursor) {
|
|
31575
|
-
|
|
31558
|
+
cursor.delete();
|
|
31576
31559
|
cursor.continue();
|
|
31577
31560
|
} else {
|
|
31578
31561
|
resolve();
|
|
@@ -31594,11 +31577,11 @@ var _ChunkStorageService = class _ChunkStorageService {
|
|
|
31594
31577
|
const store = transaction.objectStore(_ChunkStorageService.STORE_NAME);
|
|
31595
31578
|
const index = store.index("proctoringId");
|
|
31596
31579
|
const range = IDBKeyRange.only(proctoringId2);
|
|
31597
|
-
const request = index.
|
|
31580
|
+
const request = index.openCursor(range);
|
|
31598
31581
|
request.onsuccess = () => {
|
|
31599
31582
|
const cursor = request.result;
|
|
31600
31583
|
if (cursor) {
|
|
31601
|
-
|
|
31584
|
+
cursor.delete();
|
|
31602
31585
|
cursor.continue();
|
|
31603
31586
|
} else {
|
|
31604
31587
|
resolve();
|
|
@@ -31665,8 +31648,8 @@ var _ChunkStorageService = class _ChunkStorageService {
|
|
|
31665
31648
|
}
|
|
31666
31649
|
};
|
|
31667
31650
|
_ChunkStorageService.DB_NAME = "EasyProctorChunksDb";
|
|
31668
|
-
/** v2
|
|
31669
|
-
_ChunkStorageService.DB_VERSION =
|
|
31651
|
+
/** Incrementado para v2 para recriar índices com tipos numéricos em vez de boolean */
|
|
31652
|
+
_ChunkStorageService.DB_VERSION = 2;
|
|
31670
31653
|
_ChunkStorageService.STORE_NAME = "chunks";
|
|
31671
31654
|
var ChunkStorageService = _ChunkStorageService;
|
|
31672
31655
|
|
|
@@ -31826,8 +31809,7 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
31826
31809
|
* @param isFinal Se true, não alinha a 256KB e fecha a sessão com /TOTAL no header.
|
|
31827
31810
|
*/
|
|
31828
31811
|
async processQueue(isFinal = false) {
|
|
31829
|
-
var _a2, _b
|
|
31830
|
-
console.log(`[BackgroundUpload] processQueue init`);
|
|
31812
|
+
var _a2, _b;
|
|
31831
31813
|
if (this.isProcessing) return;
|
|
31832
31814
|
this.isProcessing = true;
|
|
31833
31815
|
try {
|
|
@@ -31840,10 +31822,8 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
31840
31822
|
return;
|
|
31841
31823
|
}
|
|
31842
31824
|
}
|
|
31843
|
-
console.log(`[BackgroundUpload] processQueue syncOffset ok`);
|
|
31844
31825
|
const allChunks = await this.chunkStorage.getAllChunks(this.proctoringId);
|
|
31845
31826
|
const pendingChunks = allChunks.filter((c3) => c3.uploaded === 0);
|
|
31846
|
-
console.log(`[BackgroundUpload] processQueue getAllChunks ok`);
|
|
31847
31827
|
if (pendingChunks.length === 0 && !isFinal) {
|
|
31848
31828
|
this.isProcessing = false;
|
|
31849
31829
|
return;
|
|
@@ -31852,34 +31832,31 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
31852
31832
|
let virtualStart = this.totalBytesPurged;
|
|
31853
31833
|
const chunksWithMeta = allChunks.map((c3) => {
|
|
31854
31834
|
const start = virtualStart;
|
|
31855
|
-
const end = start + c3.
|
|
31856
|
-
virtualStart += c3.
|
|
31835
|
+
const end = start + c3.blob.size - 1;
|
|
31836
|
+
virtualStart += c3.blob.size;
|
|
31857
31837
|
return { chunk: c3, start, end };
|
|
31858
31838
|
});
|
|
31859
|
-
|
|
31839
|
+
let combinedBlobParts = [];
|
|
31860
31840
|
let lastProcessedChunkId = null;
|
|
31861
31841
|
let finalChunkIndex = 0;
|
|
31862
|
-
|
|
31863
|
-
console.log(`[BackgroundUpload] passo 1 ok`);
|
|
31842
|
+
let mimeType = pendingChunks[0].mimeType;
|
|
31864
31843
|
for (const meta of chunksWithMeta) {
|
|
31865
31844
|
if (this.currentOffset > meta.end) continue;
|
|
31866
31845
|
const sliceStart = Math.max(0, this.currentOffset - meta.start);
|
|
31867
|
-
const chunkSlice = meta.chunk.
|
|
31868
|
-
|
|
31846
|
+
const chunkSlice = meta.chunk.blob.slice(sliceStart);
|
|
31847
|
+
combinedBlobParts.push(chunkSlice);
|
|
31869
31848
|
lastProcessedChunkId = meta.chunk.id;
|
|
31870
31849
|
finalChunkIndex = meta.chunk.chunkIndex;
|
|
31871
31850
|
}
|
|
31872
|
-
|
|
31873
|
-
if (combinedBufferParts.length === 0 && !isFinal) {
|
|
31851
|
+
if (combinedBlobParts.length === 0 && !isFinal) {
|
|
31874
31852
|
this.isProcessing = false;
|
|
31875
31853
|
return;
|
|
31876
31854
|
}
|
|
31877
|
-
|
|
31878
|
-
|
|
31879
|
-
let sendableSize = fullBuffer.byteLength;
|
|
31855
|
+
let fullBlob = new Blob(combinedBlobParts, { type: mimeType });
|
|
31856
|
+
let sendableSize = fullBlob.size;
|
|
31880
31857
|
let totalSizeForHeader = void 0;
|
|
31881
31858
|
if (!isFinal) {
|
|
31882
|
-
sendableSize = Math.floor(
|
|
31859
|
+
sendableSize = Math.floor(fullBlob.size / this.GCS_CHUNK_SIZE) * this.GCS_CHUNK_SIZE;
|
|
31883
31860
|
if (sendableSize === 0) {
|
|
31884
31861
|
console.log("[BackgroundUpload] Dados insuficientes para atingir 256KB. Aguardando novo chunk...");
|
|
31885
31862
|
this.isProcessing = false;
|
|
@@ -31888,47 +31865,33 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
31888
31865
|
} else {
|
|
31889
31866
|
totalSizeForHeader = virtualStart;
|
|
31890
31867
|
}
|
|
31891
|
-
|
|
31892
|
-
const bufferToSend = sendableSize < fullBuffer.byteLength ? fullBuffer.slice(0, sendableSize) : fullBuffer;
|
|
31868
|
+
const blobToSend = fullBlob.slice(0, sendableSize);
|
|
31893
31869
|
try {
|
|
31894
|
-
await this.uploadData(
|
|
31895
|
-
|
|
31896
|
-
|
|
31897
|
-
|
|
31898
|
-
);
|
|
31899
|
-
const sizePurged = fullySent.reduce(
|
|
31900
|
-
(acc, meta) => acc + meta.chunk.arrayBuffer.byteLength,
|
|
31901
|
-
0
|
|
31902
|
-
);
|
|
31903
|
-
const idsToDelete = fullySent.map((m3) => m3.chunk.id);
|
|
31904
|
-
if (idsToDelete.length > 0) {
|
|
31905
|
-
await this.chunkStorage.deleteChunkIds(idsToDelete);
|
|
31906
|
-
for (const meta of fullySent) {
|
|
31870
|
+
await this.uploadData(blobToSend, mimeType, finalChunkIndex, totalSizeForHeader);
|
|
31871
|
+
for (const meta of chunksWithMeta) {
|
|
31872
|
+
if (meta.chunk.uploaded === 0 && meta.end < this.currentOffset) {
|
|
31873
|
+
await this.chunkStorage.markAsUploaded(meta.chunk.id);
|
|
31907
31874
|
this.retryCount.delete(meta.chunk.id);
|
|
31908
|
-
(
|
|
31909
|
-
console.log(
|
|
31910
|
-
`[BackgroundUpload] Chunk ${meta.chunk.chunkIndex} removido do IndexedDB ap\xF3s upload.`
|
|
31911
|
-
);
|
|
31875
|
+
(_a2 = this.onChunkUploaded) == null ? void 0 : _a2.call(this, meta.chunk.id, meta.chunk.chunkIndex);
|
|
31876
|
+
console.log(`[BackgroundUpload] Chunk ${meta.chunk.chunkIndex} marcado como enviado.`);
|
|
31912
31877
|
}
|
|
31913
31878
|
}
|
|
31914
|
-
|
|
31915
|
-
|
|
31916
|
-
|
|
31917
|
-
|
|
31918
|
-
|
|
31919
|
-
|
|
31920
|
-
|
|
31921
|
-
`[BackgroundUpload] ${sizePurged} bytes limpos do armazenamento local. Total purgado: ${this.totalBytesPurged}`
|
|
31922
|
-
|
|
31879
|
+
if (this.config.cleanAfterUpload) {
|
|
31880
|
+
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);
|
|
31882
|
+
await this.chunkStorage.clearUploadedChunks(this.proctoringId);
|
|
31883
|
+
if (sizePurged > 0) {
|
|
31884
|
+
this.totalBytesPurged += sizePurged;
|
|
31885
|
+
this.saveSessionState();
|
|
31886
|
+
console.log(`[BackgroundUpload] ${sizePurged} bytes limpos do armazenamento local. Total purgado: ${this.totalBytesPurged}`);
|
|
31887
|
+
}
|
|
31923
31888
|
}
|
|
31924
|
-
console.log(`[BackgroundUpload] passo 8 ok`);
|
|
31925
31889
|
if (isFinal) {
|
|
31926
31890
|
this.clearSessionState();
|
|
31927
31891
|
}
|
|
31928
|
-
console.log(`[BackgroundUpload] passo 9 ok`);
|
|
31929
31892
|
} catch (error) {
|
|
31930
31893
|
console.error("[BackgroundUpload] Falha no upload:", error);
|
|
31931
|
-
(
|
|
31894
|
+
(_b = this.onUploadError) == null ? void 0 : _b.call(this, lastProcessedChunkId || 0, error);
|
|
31932
31895
|
}
|
|
31933
31896
|
} catch (error) {
|
|
31934
31897
|
console.error("[BackgroundUpload] Erro ao processar fila:", error);
|
|
@@ -31939,18 +31902,7 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
31939
31902
|
/**
|
|
31940
31903
|
* Faz o upload bruto de dados para a sessão GCS.
|
|
31941
31904
|
*/
|
|
31942
|
-
|
|
31943
|
-
if (parts.length === 0) return new ArrayBuffer(0);
|
|
31944
|
-
const total = parts.reduce((sum, p3) => sum + p3.byteLength, 0);
|
|
31945
|
-
const merged = new Uint8Array(total);
|
|
31946
|
-
let offset = 0;
|
|
31947
|
-
for (const p3 of parts) {
|
|
31948
|
-
merged.set(new Uint8Array(p3), offset);
|
|
31949
|
-
offset += p3.byteLength;
|
|
31950
|
-
}
|
|
31951
|
-
return merged.buffer.byteLength === total ? merged.buffer : merged.buffer.slice(merged.byteOffset, merged.byteOffset + merged.byteLength);
|
|
31952
|
-
}
|
|
31953
|
-
async uploadData(data, mimeType, chunkIndex, totalSize) {
|
|
31905
|
+
async uploadData(blob, mimeType, chunkIndex, totalSize) {
|
|
31954
31906
|
const fileName = `EP_${this.proctoringId}_camera_0.webm`;
|
|
31955
31907
|
if (!this.sessionUrl) {
|
|
31956
31908
|
const initiateUrl = await this.backend.initiateUpload(this.token, `${this.proctoringId}/${fileName}`, mimeType);
|
|
@@ -31982,16 +31934,15 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
31982
31934
|
console.log(`[BackgroundUpload] Usando sess\xE3o GCS existente: ${this.sessionUrl}`);
|
|
31983
31935
|
}
|
|
31984
31936
|
const start = this.currentOffset;
|
|
31985
|
-
const end = start +
|
|
31937
|
+
const end = start + blob.size - 1;
|
|
31986
31938
|
const totalHeader = totalSize !== void 0 ? totalSize.toString() : "*";
|
|
31987
|
-
const contentRangeHeader =
|
|
31988
|
-
console.log(
|
|
31989
|
-
`[BackgroundUpload] Enviando ${data.byteLength > 0 ? "dados" : "finaliza\xE7\xE3o"}: ${contentRangeHeader} (Size: ${data.byteLength})`
|
|
31990
|
-
);
|
|
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})`);
|
|
31991
31941
|
const response = await fetch(this.sessionUrl, {
|
|
31992
31942
|
method: "PUT",
|
|
31993
31943
|
headers: { "Content-Range": contentRangeHeader },
|
|
31994
|
-
body:
|
|
31944
|
+
body: blob.size > 0 ? blob : null
|
|
31945
|
+
// Usa null para garantir corpo vazio se necessário
|
|
31995
31946
|
});
|
|
31996
31947
|
console.log(`[BackgroundUpload] Resposta GCS (uploadData): ${response.status}`);
|
|
31997
31948
|
if (response.status !== 200 && response.status !== 201 && response.status !== 308) {
|
|
@@ -32004,13 +31955,13 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
32004
31955
|
const lastByte = parseInt(rangeHeader.split("-")[1], 10);
|
|
32005
31956
|
this.currentOffset = lastByte + 1;
|
|
32006
31957
|
} else {
|
|
32007
|
-
this.currentOffset +=
|
|
31958
|
+
this.currentOffset += blob.size;
|
|
32008
31959
|
}
|
|
32009
31960
|
this.saveSessionState();
|
|
32010
31961
|
trackers.registerUploadFile(
|
|
32011
31962
|
this.proctoringId,
|
|
32012
31963
|
`GCS Stream Upload
|
|
32013
|
-
Size: ${
|
|
31964
|
+
Size: ${blob.size}
|
|
32014
31965
|
Range: ${start}-${end}
|
|
32015
31966
|
Last Index: ${chunkIndex}`,
|
|
32016
31967
|
"CameraChunk"
|
|
@@ -32145,7 +32096,7 @@ var _CameraRecorder = class _CameraRecorder {
|
|
|
32145
32096
|
* 2. E (`useChunkRecording` foi explicitamente setado como true OU o dispositivo é mobile)
|
|
32146
32097
|
*/
|
|
32147
32098
|
get isChunkEnabled() {
|
|
32148
|
-
return
|
|
32099
|
+
return false;
|
|
32149
32100
|
}
|
|
32150
32101
|
setProctoringId(proctoringId2) {
|
|
32151
32102
|
this.proctoringId = proctoringId2;
|
|
@@ -32549,15 +32500,14 @@ Setting: ${JSON.stringify(settings, null, 2)}`
|
|
|
32549
32500
|
* Salva o chunk no IndexedDB para persistência e recuperação.
|
|
32550
32501
|
*/
|
|
32551
32502
|
async handleNewChunk(blob, idx) {
|
|
32552
|
-
if (!this.proctoringId || !this.chunkStorage
|
|
32503
|
+
if (!this.proctoringId || !this.chunkStorage) return;
|
|
32553
32504
|
const savePromise = (async () => {
|
|
32554
32505
|
var _a2;
|
|
32555
32506
|
try {
|
|
32556
|
-
const arrayBuffer = await blob.arrayBuffer();
|
|
32557
32507
|
await this.chunkStorage.saveChunk({
|
|
32558
32508
|
proctoringId: this.proctoringId,
|
|
32559
32509
|
chunkIndex: this.chunkIndex,
|
|
32560
|
-
|
|
32510
|
+
blob,
|
|
32561
32511
|
timestamp: Date.now(),
|
|
32562
32512
|
uploaded: 0,
|
|
32563
32513
|
mimeType: ((_a2 = this.recorderOptions) == null ? void 0 : _a2.mimeType) || "video/webm"
|
|
@@ -32,7 +32,6 @@ export declare class BackgroundUploadService {
|
|
|
32
32
|
flush(): Promise<void>;
|
|
33
33
|
private syncOffset;
|
|
34
34
|
private processQueue;
|
|
35
|
-
private static concatArrayBuffers;
|
|
36
35
|
private uploadData;
|
|
37
36
|
static recoverPendingUploads(backend: BackendService, token: string): Promise<string[]>;
|
|
38
37
|
private sleep;
|
|
@@ -2,7 +2,7 @@ export interface VideoChunk {
|
|
|
2
2
|
id?: number;
|
|
3
3
|
proctoringId: string;
|
|
4
4
|
chunkIndex: number;
|
|
5
|
-
|
|
5
|
+
blob: Blob;
|
|
6
6
|
timestamp: number;
|
|
7
7
|
uploaded: number;
|
|
8
8
|
mimeType: string;
|
|
@@ -12,12 +12,11 @@ export declare class ChunkStorageService {
|
|
|
12
12
|
private static readonly DB_VERSION;
|
|
13
13
|
private static readonly STORE_NAME;
|
|
14
14
|
private db;
|
|
15
|
-
private static detachedArrayBufferCopy;
|
|
16
15
|
connect(): Promise<IDBDatabase>;
|
|
17
16
|
saveChunk(chunk: Omit<VideoChunk, "id">): Promise<number>;
|
|
18
17
|
getPendingChunks(proctoringId: string): Promise<VideoChunk[]>;
|
|
19
18
|
getAllChunks(proctoringId: string): Promise<VideoChunk[]>;
|
|
20
|
-
|
|
19
|
+
markAsUploaded(chunkId: number): Promise<void>;
|
|
21
20
|
clearUploadedChunks(proctoringId: string): Promise<void>;
|
|
22
21
|
clearAllChunks(proctoringId: string): Promise<void>;
|
|
23
22
|
hasAnyPendingChunks(): Promise<boolean>;
|