Update document UI, tabular reviews, and storage caching

This commit is contained in:
willchen96 2026-05-18 00:21:40 +08:00
parent 2bbb628891
commit 4f3384334a
26 changed files with 856 additions and 341 deletions

View file

@ -1,4 +1,3 @@
import { promisify } from "util";
import JSZip from "jszip";
let _convert:
@ -8,7 +7,26 @@ let _convert:
async function getConvert() {
if (!_convert) {
const libre = await import("libreoffice-convert");
_convert = promisify(libre.default.convert.bind(libre.default));
const convert = libre.default.convert.bind(libre.default) as (
buf: Buffer,
ext: string,
filter: undefined,
callback?: (err: Error | null, result: Buffer) => void,
) => Promise<Buffer> | void;
_convert = (buf, ext, filter) =>
new Promise<Buffer>((resolve, reject) => {
try {
const maybePromise = convert(buf, ext, filter, (err, result) => {
if (err) reject(err);
else resolve(result);
});
if (maybePromise && typeof maybePromise.then === "function") {
maybePromise.then(resolve, reject);
}
} catch (err) {
reject(err);
}
});
}
return _convert;
}

View file

@ -17,16 +17,21 @@ import {
} from "@aws-sdk/client-s3";
import { getSignedUrl as awsGetSignedUrl } from "@aws-sdk/s3-request-presigner";
let cachedClient: S3Client | undefined;
function getClient(): S3Client {
return new S3Client({
region: "auto",
endpoint: process.env.R2_ENDPOINT_URL!,
forcePathStyle: true,
credentials: {
accessKeyId: process.env.R2_ACCESS_KEY_ID!,
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,
},
});
if (!cachedClient) {
cachedClient = new S3Client({
region: "auto",
endpoint: process.env.R2_ENDPOINT_URL!,
forcePathStyle: true,
credentials: {
accessKeyId: process.env.R2_ACCESS_KEY_ID!,
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,
},
});
}
return cachedClient;
}
const BUCKET = process.env.R2_BUCKET_NAME ?? "mike";
@ -37,6 +42,14 @@ export const storageEnabled = Boolean(
process.env.R2_SECRET_ACCESS_KEY,
);
function requireStorageConfig(): void {
if (!storageEnabled) {
throw new Error(
"R2_ENDPOINT_URL, R2_ACCESS_KEY_ID, and R2_SECRET_ACCESS_KEY must be set",
);
}
}
// ---------------------------------------------------------------------------
// Upload
// ---------------------------------------------------------------------------
@ -46,6 +59,7 @@ export async function uploadFile(
content: ArrayBuffer,
contentType: string,
): Promise<void> {
requireStorageConfig();
const client = getClient();
await client.send(
new PutObjectCommand({