Beginne mit dem validate-only endpoint POST /v1/uploads:validate; er prüft sizeBytes, expectedHashes.sha256, archiveManifest und buildMetadata, ohne eine Session, ein storage object oder einen audit write zu erstellen. Creator automation öffnet danach POST /v1/uploads, sendet archive bytes direkt in private Cloudflare R2 über eine signed single PUT URL oder signed multipart parts, erneuert parts mit POST /v1/uploads/{upload_id}/parts, prüft GET /v1/uploads/{upload_id}, schließt mit POST /v1/uploads/{upload_id}/complete ab und storniert mit POST /v1/uploads/{upload_id}/abort. Die Next.js API erhält nur metadata und lifecycle calls, niemals den archive body. Große multipart Sessions bleiben 48 Stunden aktiv, jede signed URL 15 Minuten. status.progress liefert uploadedBytes, percent, totalParts und provider-confirmed completedParts mit ETags, damit Website, CLI und GitHub Action nach einer Unterbrechung nur missing parts fortsetzen. Ein private staging object kann vor complete, size/content type/archive format validation und security processing nicht published werden; ein bounded cleanup job bricht expired multipart uploads ab oder löscht incomplete single objects. Complete liefert einen async job, solange scan, metadata extraction, indexing hooks oder final promotion laufen; poll job.statusEndpoint. queued und processing sind non-terminal, succeeded, rejected, failed und cancelled sind terminal. job.progress zeigt ehrlich 0/1 completion statt eines geschätzten scan percentage. createdAt, updatedAt, startedAt, completedAt, retry attempts, nextAttemptAt und der stabile terminal reason unterscheiden active, retrying und finished work, ohne provider prose offenzulegen. Kanonische lifecycleStatus Werte sind draft, uploading, uploaded, validating, scanning, quarantined, ready, published, failed und cancelled; legacy status bleibt ein compatibility alias. expectedSha256 bleibt ein legacy alias und sha256_mismatch lehnt den Upload vor promotion ab. Idempotency-Key bleibt für create und complete retries stabil. Version request metadata unterstützt version, changelog, file_category, game_slug, game_versions, loader_platforms, dependencies, requirements und build_metadata; eine wiederholte logische Version liefert duplicate_version. metadata-only edits erfordern keinen erneuten upload bytes. Der security worker claimt durable jobs atomar, wiederholt transient failures und verschiebt exhausted oder ungeprüfte uploads in quarantine. Die ZIP policy liefert archive_dangerous_entry, archive_encrypted_entry, archive_symlink_entry, archive_duplicate_path oder archive_path_traversal; nested archives werden bis Tiefe 3 rekursiv geprüft; unzulässige executable-Szenarien gelten als unsafe, während jede Datei über dem ClamAV-Streamlimit manual review erfordert.
Der isolierte archive-security-worker prüft das immutable scan seal: den vollständigen SHA-256, die ZIP/7z/RAR-Struktur und den ClamAV-Verdict. Auch die Wiederverwendung eines Exact-SHA-Clean-Cache verlangt dasselbe Format, dieselbe Policy-Version, Engine und Signaturdatenbank. Transiente Fehler erhalten höchstens drei Versuche; unbekannte Ergebnisse, veraltete Datenbanken und Ressourcenlimits werden nie clean und halten die Datei privat in Quarantäne/Prüfung.
Numerische Upload-Defaults: Single PUT bis 100 MiB; Multipart Parts mit 16 MiB und Concurrency 4; ein Signing Request enthält höchstens 4 Parts und begrenzt die Payload in Flight auf 64 MiB; ein Archiv ist auf 20 GiB begrenzt. Der authentifizierte Upload-Byte-Bucket beträgt 24 GiB. Ein Live-R2-Capacity-Probe bestätigte 64 MiB Upload/Download mit gleichem SHA-256, RSS Delta unter 384 MiB und verpflichtendem Cleanup; das Profil 64 MiB × 4 wurde wegen Überschreitung des Memory Budgets abgelehnt.
Wenn complete einen nicht terminalen Job mit Status queued oder processing erzeugt, lautet die HTTP-Antwort 202 Accepted und der Location-Header entspricht exakt job.statusEndpoint. Ist der Job bereits terminal (succeeded, rejected, failed oder cancelled), einschließlich eines idempotenten Replays dieses terminalen Ergebnisses, liefert complete 200 OK, ohne den Side Effect zu wiederholen.
Ein Replay von POST /v1/uploads mit demselben Body und Idempotency-Key liefert die ursprüngliche durable Session mit neu signierten Upload-Anweisungen. Jede single PUT URL hat höchstens eine 900-second Lease, die der Server nach dem Signing und vor der Response unter Row Lock checkpointet; ein abort-winning Checkpoint verwirft die URL-Response. Sende alle zurückgegebenen Header einschließlich If-None-Match: *. Ein conditional 412 ist ein ambiguous existing write: Überschreibe Staging nicht, sondern rufe denselben complete Endpoint auf, wo HEAD, immutable Seal und SHA-256 authoritative sind. Signed URLs und Provider-Upload-IDs werden nie im generischen Idempotency-Datensatz gespeichert; prüfe nach einem mehrdeutigen Create-Timeout zuerst die Upload-Session, bevor du eine neue Mutation startest.
Nutze für polling guidance retry.retryable, retry.strategy, retry.attempt, retry.maxAttempts, retry.nextAttemptAt und retry.retryAfterSeconds. Eine HTTP response kann dieselbe Mindestverzögerung über Retry-After angeben.
Das manuelle Mod-Upload-Formular der Website nutzt dieselben Upload-Session-Dienste und dasselbe private R2-Backend. Es zeigt Dateiübertragung und Sicherheitsprüfung, bewahrt einen erstellten Mod-Entwurf nach einer Netzwerkunterbrechung auf und verwendet vom Speicheranbieter bestätigte Multipart-Teile erneut, wenn dieselbe Datei gewählt wird. Vor dem Multipart-Commit prüft der Server die exakte Größe und den Provider-ETag/MD5 jedes Teils erneut; danach verifiziert der asynchrone Trust-Worker den SHA-256 des gesamten Objekts vor ready/publish. Unter Einstellungen > Entwickler siehst du aktuelle Sessions, Scan-Fehler sowie den Quarantäne- und Prüfstatus.