feat(web): support decoding zstd-compressed logs via fzstd in frontend

This commit is contained in:
duorameng
2026-07-09 20:30:41 +08:00
parent 9cc5ff6642
commit 516a91acc2
4 changed files with 31 additions and 1 deletions
+7
View File
@@ -24,6 +24,7 @@
"clsx": "^2.1.1", "clsx": "^2.1.1",
"cronstrue": "^3.14.0", "cronstrue": "^3.14.0",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"fzstd": "^0.1.1",
"lucide-react": "^0.562.0", "lucide-react": "^0.562.0",
"lucide-vue-next": "^0.562.0", "lucide-vue-next": "^0.562.0",
"monaco-editor": "^0.52.0", "monaco-editor": "^0.52.0",
@@ -4573,6 +4574,12 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/fzstd": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/fzstd/-/fzstd-0.1.1.tgz",
"integrity": "sha512-dkuVSOKKwh3eas5VkJy1AW1vFpet8TA/fGmVA5krThl8YcOVE/8ZIoEA1+U1vEn5ckxxhLirSdY837azmbaNHA==",
"license": "MIT"
},
"node_modules/generator-function": { "node_modules/generator-function": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz",
+1
View File
@@ -25,6 +25,7 @@
"clsx": "^2.1.1", "clsx": "^2.1.1",
"cronstrue": "^3.14.0", "cronstrue": "^3.14.0",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"fzstd": "^0.1.1",
"lucide-react": "^0.562.0", "lucide-react": "^0.562.0",
"lucide-vue-next": "^0.562.0", "lucide-vue-next": "^0.562.0",
"monaco-editor": "^0.52.0", "monaco-editor": "^0.52.0",
+4
View File
@@ -0,0 +1,4 @@
declare module 'fzstd' {
export function decompress(data: Uint8Array): Uint8Array;
export function compress(data: Uint8Array, level?: number): Uint8Array;
}
+19 -1
View File
@@ -1,18 +1,36 @@
import pako from 'pako' import pako from 'pako'
import { decompress } from 'fzstd'
export function decompressFromBase64(compressed: string): string { export function decompressFromBase64(compressed: string): string {
if (!compressed) return '' if (!compressed) return ''
try { try {
let isZstd = false
let dataToDecode = compressed
if (compressed.startsWith('zstd:')) {
isZstd = true
dataToDecode = compressed.slice(5)
}
// Decode base64 to binary // Decode base64 to binary
const binaryString = atob(compressed) const binaryString = atob(dataToDecode)
const bytes = new Uint8Array(binaryString.length) const bytes = new Uint8Array(binaryString.length)
for (let i = 0; i < binaryString.length; i++) { for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i) bytes[i] = binaryString.charCodeAt(i)
} }
if (isZstd) {
// Decompress Zstd
const decompressedBytes = decompress(bytes)
return new TextDecoder().decode(decompressedBytes)
}
// Decompress zlib // Decompress zlib
const decompressed = pako.inflate(bytes, { to: 'string' }) const decompressed = pako.inflate(bytes, { to: 'string' })
return decompressed return decompressed
} catch (e) { } catch (e) {
console.error('Failed to decompress data:', e)
return compressed return compressed
} }
} }