decompress .json.zstd fetched by getSaveData

This commit is contained in:
Altair-sh
2026-09-23 18:24:45 +02:00
parent f1a60a208c
commit 7d64ab4809
6 changed files with 67 additions and 39 deletions
+16 -2
View File
@@ -3,6 +3,7 @@ import type { SaveUploadConfig } from '@/config/AppConfig'
import { GameEnum } from '@/config/games'
import { packSaveForUpload, StageCallback } from '@/lib/saveArchive/client'
import { OriginalFileType } from '@/lib/saveArchive/messages'
import { createZstdDecompressStream } from '@/lib/saveArchive/zstdStream'
export interface UploadSaveResponse {
id: string
@@ -86,7 +87,12 @@ export class SaveParserBackendService {
return await response.json()
}
// Fetches the fully parsed data for a save once its parsing is done.
/**
* Fetches the fully parsed data for a save once its parsing is done.
*
* The backend stores and serves that data as zstd compressed json, so the
* body is decompressed on the way in rather than read as text first.
*/
async getSaveData(id: string): Promise<Record<string, unknown>> {
const url = `${this.API_BASE}/getSaveData?id=${encodeURIComponent(id)}`
const response = await fetch(url)
@@ -97,8 +103,16 @@ export class SaveParserBackendService {
(await getBodyTextOrEmpty(response))
)
}
// A body is only missing on a response that cannot carry one, which a
// successful getSaveData never is.
if (!response.body) {
throw new Error('Failed to get parsed save: response has no body')
}
return await response.json()
// Decompresses as the bytes arrive, so the compressed json is never
// held whole; only the parsed object stays in memory.
const json = response.body.pipeThrough(createZstdDecompressStream())
return await new Response(json).json()
}
/**