Add quak helper list-missing-thumbnails and fix-missing-thumbnails
Some checks failed
check / check (push) Failing after 8s
Some checks failed
check / check (push) Failing after 8s
list-missing-thumbnails: iterates all files across all collections, fetches each thumbnail from the CDN, reports any that are missing or empty. Deduplicates by file ID across collections. fix-missing-thumbnails: for each missing thumbnail, downloads the original file, generates a 720px JPEG thumbnail via sharp, encrypts it with secretstream push (encryptBlob), uploads to a presigned URL, and registers the new thumbnail via PUT /files/thumbnail. New crypto: encryptBlob (secretstream push, single chunk TAG_FINAL). New ApiClient methods: getUploadURL, putFile, putJSON, updateThumbnail. New Client method: getApiClient() for modules that need raw API access. Deps: sharp 0.34.5 (image processing), @types/sharp 0.32.0.
This commit is contained in:
@@ -162,6 +162,52 @@ export class ApiClient {
|
||||
return resp.body;
|
||||
}
|
||||
|
||||
async getUploadURL(
|
||||
contentLength: number,
|
||||
contentMD5: string,
|
||||
): Promise<{ objectKey: string; url: string }> {
|
||||
return this.postJSON("/files/upload-url", {
|
||||
contentLength,
|
||||
contentMD5,
|
||||
});
|
||||
}
|
||||
|
||||
async putFile(presignedURL: string, data: Uint8Array): Promise<void> {
|
||||
const resp = await this._fetch(presignedURL, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/octet-stream",
|
||||
"Content-Length": String(data.length),
|
||||
},
|
||||
body: data,
|
||||
});
|
||||
if (!resp.ok) {
|
||||
throw new Error(`PUT to presigned URL failed: HTTP ${resp.status}`);
|
||||
}
|
||||
}
|
||||
|
||||
async putJSON<T>(path: string, body: unknown): Promise<T> {
|
||||
const url = `${this.apiOrigin}${path}`;
|
||||
const resp = await this._fetch(url, {
|
||||
method: "PUT",
|
||||
headers: this.headers({ "Content-Type": "application/json" }),
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
await this.throwIfError(resp);
|
||||
return (await resp.json()) as T;
|
||||
}
|
||||
|
||||
async updateThumbnail(
|
||||
fileID: number,
|
||||
objectKey: string,
|
||||
decryptionHeader: string,
|
||||
): Promise<void> {
|
||||
await this.putJSON("/files/thumbnail", {
|
||||
fileID,
|
||||
thumbnail: { objectKey, decryptionHeader },
|
||||
});
|
||||
}
|
||||
|
||||
async getThumbnailStream(
|
||||
fileID: number,
|
||||
): Promise<ReadableStream<Uint8Array>> {
|
||||
|
||||
Reference in New Issue
Block a user