1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
/*
* SPDX-FileCopyrightText: 2023-2024 The Refinery Authors <https://refinery.tools/>
*
* SPDX-License-Identifier: EPL-2.0
*/
import { Zstd } from '@hpcc-js/wasm-zstd';
import type {
CompressResponse,
CompressorRequest,
DecompressResponse,
ErrorResponse,
} from './compressionMessages';
const CONTENT_TYPE = 'application/octet-stream';
const URI_PREFIX = `data:${CONTENT_TYPE};base64,`;
async function base64Encode(buffer: Uint8Array): Promise<string> {
const uri = await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = () => reject(reader.error);
reader.readAsDataURL(new File([buffer], '', { type: CONTENT_TYPE }));
});
if (typeof uri !== 'string') {
throw new Error(`Unexpected FileReader result type: ${typeof uri}`);
}
const base64 = uri.substring(URI_PREFIX.length);
return base64.replace(/[+/]/g, (c) => {
if (c === '+') {
return '-';
}
if (c === '/') {
return '_';
}
return c;
});
}
async function base64Decode(compressedText: string): Promise<Uint8Array> {
const base64 = compressedText.replace(/[-_]/g, (c) => {
if (c === '-') {
return '+';
}
if (c === '_') {
return '/';
}
return c;
});
const result = await fetch(`${URI_PREFIX}${base64}`);
return new Uint8Array(await result.arrayBuffer());
}
let zstd: Zstd | undefined;
globalThis.onmessage = (event) => {
(async () => {
if (zstd === undefined) {
// Since we don't have types for the deep import, we have to cast here.
zstd = await Zstd.load();
}
// Since the render thread will only send us valid messages,
// we can save a bit of bundle size by using a cast instead of `parse`
// to avoid having to include `zod` in the worker.
const message = event.data as CompressorRequest;
if (message.request === 'compress') {
const encoder = new TextEncoder();
const encodedBuffer = encoder.encode(message.text);
const compressedBuffer = zstd.compress(encodedBuffer, 3);
const compressedText = await base64Encode(compressedBuffer);
globalThis.postMessage({
response: 'compressed',
compressedText,
} satisfies CompressResponse);
} else if (message.request === 'decompress') {
const decodedBuffer = await base64Decode(message.compressedText);
const uncompressedBuffer = zstd.decompress(decodedBuffer);
const decoder = new TextDecoder();
const text = decoder.decode(uncompressedBuffer);
globalThis.postMessage({
response: 'decompressed',
text,
} satisfies DecompressResponse);
} else {
throw new Error(`Unknown request: ${JSON.stringify(event.data)}`);
}
})().catch((error) => {
globalThis.postMessage({
response: 'error',
message: String(error),
} satisfies ErrorResponse);
});
};
|