Optimize admin performance and split render surface

This commit is contained in:
2026-04-11 13:59:58 -07:00
parent 4c6982bf68
commit e9aa82e1e1
28 changed files with 3396 additions and 2526 deletions
+58 -4
View File
@@ -1,3 +1,4 @@
import { createHash } from "node:crypto";
import { watch } from "node:fs";
import { mkdir, rm, writeFile } from "node:fs/promises";
import path from "node:path";
@@ -62,6 +63,56 @@ const fileExtensionFor = (mimeType: string, filename?: string) => {
return fallback || ".bin";
};
const createRevision = (value: unknown) => createHash("sha1").update(JSON.stringify(value)).digest("hex");
const getProgramRevision = (state: Awaited<ReturnType<StateStore["read"]>>) =>
createRevision({
cues: state.cues.map((cue) => ({
id: cue.id,
orderIndex: cue.orderIndex,
sceneDefinitionId: cue.sceneDefinitionId,
effectPresetId: cue.effectPresetId,
updated: [cue.transitionIn, cue.transitionOut, cue.assetIds, cue.notes, cue.triggerMode, cue.durationMs, cue.nextCueId, cue.collectionId]
})),
safeSceneCueId: state.showConfig.safeSceneCueId
});
const getLibraryRevision = (state: Awaited<ReturnType<StateStore["read"]>>) =>
createRevision({
photoAssets: state.photoAssets.map((asset) => ({
id: asset.id,
submissionId: asset.submissionId,
moderationStatus: asset.moderationStatus,
processingStatus: asset.processingStatus,
thumbKey: asset.thumbKey,
previewKey: asset.previewKey,
renderKey: asset.renderKey,
approvedAt: asset.approvedAt
})),
submissions: state.submissions.map((submission) => ({
id: submission.id,
status: submission.status,
contributorName: submission.contributorName,
lovedOneName: submission.lovedOneName,
displayName: submission.displayName,
caption: submission.caption,
promptAnswer: submission.promptAnswer,
notes: submission.notes,
source: submission.source
})),
collections: state.collections.map((collection) => ({
id: collection.id,
assetIds: collection.assetIds,
coverAssetId: collection.coverAssetId
}))
});
const createAdminBootstrapPayload = (state: Awaited<ReturnType<StateStore["read"]>>) => ({
...state,
libraryRevision: getLibraryRevision(state),
programRevision: getProgramRevision(state)
});
const normalizeMimeType = (mimeType: string | undefined, filename?: string) => {
const normalized = mimeType?.toLowerCase().trim() ?? "";
if (allowedMimeTypes.has(normalized)) {
@@ -282,7 +333,7 @@ export const buildServer = async () => {
service: "api"
}));
app.get("/api/admin/bootstrap", async () => store.read());
app.get("/api/admin/bootstrap", async () => createAdminBootstrapPayload(await store.read()));
app.get("/api/admin/live", async () => {
const state = await store.read();
const pendingCount = state.photoAssets.filter((asset) => {
@@ -296,7 +347,9 @@ export const buildServer = async () => {
return {
cues: state.cues,
pendingCount,
approvedCount: state.photoAssets.filter((asset) => asset.moderationStatus === "approved").length
approvedCount: state.photoAssets.filter((asset) => asset.moderationStatus === "approved").length,
libraryRevision: getLibraryRevision(state),
programRevision: getProgramRevision(state)
};
});
app.get("/api/admin/library", async () => {
@@ -304,7 +357,8 @@ export const buildServer = async () => {
return {
photoAssets: state.photoAssets,
submissions: state.submissions,
collections: state.collections
collections: state.collections,
revision: getLibraryRevision(state)
};
});
@@ -315,7 +369,7 @@ export const buildServer = async () => {
app.get("/api/assets", async () => (await store.read()).photoAssets);
app.get("/api/submissions", async () => (await store.read()).submissions);
app.get("/api/show-config", async () => (await store.read()).showConfig);
app.post("/api/library/rescan", async () => syncLibrary());
app.post("/api/library/rescan", async () => createAdminBootstrapPayload(await syncLibrary()));
app.put<{ Params: { submissionId: string }; Body: SubmissionUpdatePayload }>(
"/api/submissions/:submissionId",