From 79cf8ad002f9e7fb4442b6c734a74075a7316030 Mon Sep 17 00:00:00 2001 From: Administrator Date: Sat, 11 Apr 2026 07:30:39 +0200 Subject: [PATCH] fix(clouddrop): never throw after all chunks uploaded MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /upload/complete was failing (non-JSON response, missing fileId, or post-processing timeout) after all bytes were already on the server, causing upload-manager to retry the entire multi-GB upload — which corrupts the server-side file since two uploads end up interleaved. Now /complete failures are swallowed and sessionId is used as the file_code fallback. Upload is considered done once all chunks are in. --- lib/clouddrop-upload.js | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/lib/clouddrop-upload.js b/lib/clouddrop-upload.js index fe1aafb..56fe3d3 100644 --- a/lib/clouddrop-upload.js +++ b/lib/clouddrop-upload.js @@ -190,20 +190,25 @@ class ClouddropUploader { try { fs.closeSync(fd); } catch {} } - // 3. Complete session - const completeRes = await request(`${API_BASE}/upload/${sessionId}/complete`, { - method: 'POST', - dispatcher: clouddropAgent, - signal, - headers: this._headers({ 'Content-Type': 'application/json' }), - body: '{}', - headersTimeout: COMPLETE_TIMEOUT, - bodyTimeout: COMPLETE_TIMEOUT - }); - const completePayload = await this._parseJsonResponse(completeRes); - const fileId = completePayload.fileId || completePayload.id; - if (!fileId) throw new Error('Clouddrop: Keine fileId in /upload/complete Antwort'); - return fileId; + // 3. Complete session — all bytes are already on the server at this point. + // We MUST NOT throw here, otherwise the upload-manager would retry the entire + // multi-GB upload. Any failure (timeout, non-JSON, missing fileId, server still + // post-processing) is swallowed and we fall back to sessionId as file_code. + try { + const completeRes = await request(`${API_BASE}/upload/${sessionId}/complete`, { + method: 'POST', + dispatcher: clouddropAgent, + signal, + headers: this._headers({ 'Content-Type': 'application/json' }), + body: '{}', + headersTimeout: COMPLETE_TIMEOUT, + bodyTimeout: COMPLETE_TIMEOUT + }); + const completePayload = await this._parseJsonResponse(completeRes).catch(() => ({})); + return completePayload.fileId || completePayload.id || sessionId; + } catch { + return sessionId; + } } /**