Harden cross-auth recovery and upload admission

Use stable Doodstream API identities across separate Web and API profiles, serialize ambiguous VOE and Doodstream mixed-auth recovery paths, and fail closed after uncertain post-upload response failures. Enforce host upload intervals only after recovery and concurrency admission, and clear batch-scoped recovery caches when the batch settles.
This commit is contained in:
Sucukdeluxe
2026-08-13 23:59:00 +02:00
parent cfa138198f
commit 21840cef94
5 changed files with 350 additions and 21 deletions
+38 -5
View File
@@ -393,7 +393,7 @@ class DoodstreamUploader {
let uploadRes;
try {
uploadRes = await request(uploadUrl, {
uploadRes = await this._requestUpload(uploadUrl, {
method: 'POST',
headers: {
'Content-Type': `multipart/form-data; boundary=${boundary}`,
@@ -412,7 +412,8 @@ class DoodstreamUploader {
phase: 'upload-request',
endpoint: uploadUrl,
retryable: true,
transientNetwork: true
transientNetwork: true,
remoteCommitUncertain: true
});
}
@@ -429,7 +430,18 @@ class DoodstreamUploader {
}
}
const resText = await uploadRes.body.text();
let resText;
try {
resText = await uploadRes.body.text();
} catch {
throw createTransportError('Doodstream Upload-Antwort konnte nicht gelesen werden', {
phase: 'upload-response-read',
endpoint: uploadUrl,
retryable: true,
transientNetwork: true,
remoteCommitUncertain: true
});
}
const uploadContentType = uploadRes.headers && uploadRes.headers['content-type'];
_debugLog(`Upload response: ${summarizeResponse(resText, uploadContentType)}`);
@@ -451,13 +463,34 @@ class DoodstreamUploader {
return this._parseUploadResponse(resText);
}
_requestUpload(url, options) {
return request(url, options);
}
/**
* Follow a redirect URL from upload server and extract filecode
*/
async _handleUploadResult(url) {
_debugLog(`Following upload result URL: ${safeEndpoint(url) || 'unknown endpoint'}`);
const res = await this._fetch(url);
const html = await res.text();
let res;
try {
res = await this._fetch(url);
} catch (error) {
if (error && typeof error === 'object') error.remoteCommitUncertain = true;
throw error;
}
let html;
try {
html = await res.text();
} catch {
throw createTransportError('Doodstream Ergebnis-Antwort konnte nicht gelesen werden', {
phase: 'upload-response-read',
endpoint: url,
retryable: true,
transientNetwork: true,
remoteCommitUncertain: true
});
}
const contentType = res.headers && typeof res.headers.get === 'function' ? res.headers.get('content-type') : '';
_debugLog(`Result page: ${summarizeResponse(html, contentType)}`);
return this._parseUploadResponse(html);