feat: add task workflow and asset downloads

This commit is contained in:
inman
2026-05-29 12:32:02 +08:00
parent f9c3393f84
commit 63e62d444c
61 changed files with 2773 additions and 2181 deletions

View File

@@ -181,19 +181,20 @@ export async function readLocalServedFile(area: "uploads" | "generated-results",
}
}
export async function readLegacyPublicFile(pathParts: string[]): Promise<{
export async function readAssetForDownload(asset: Asset): Promise<{
bytes: Buffer;
contentType: string;
} | null> {
const filePath = join(process.cwd(), "runtime", "nianxx-play", "public", ...pathParts);
try {
return {
bytes: await readFile(filePath),
contentType: contentTypeForPath(filePath)
};
} catch {
return null;
}
const local = await readLocalAsset(asset);
if (local) return local;
if (!/^https?:\/\//i.test(asset.url)) return null;
const response = await fetch(asset.url);
if (!response.ok) return null;
return {
bytes: Buffer.from(await response.arrayBuffer()),
contentType: response.headers.get("content-type") || contentTypeForPath(new URL(asset.url).pathname)
};
}
export async function deleteStoredAsset(asset: Asset): Promise<void> {
@@ -218,6 +219,30 @@ export async function deleteStoredAsset(asset: Asset): Promise<void> {
}
}
async function readLocalAsset(asset: Asset): Promise<{
bytes: Buffer;
contentType: string;
} | null> {
const localPath = localServedPathParts(asset.storagePath) || localServedPathParts(asset.url);
if (!localPath) return null;
return readLocalServedFile(localPath.area, localPath.pathParts);
}
function localServedPathParts(value?: string): {
area: "uploads" | "generated-results";
pathParts: string[];
} | null {
if (!value) return null;
const clean = value.replace(/^\/+/, "");
if (clean.startsWith("uploads/")) {
return { area: "uploads", pathParts: clean.slice("uploads/".length).split("/").filter(Boolean) };
}
if (clean.startsWith("generated-results/")) {
return { area: "generated-results", pathParts: clean.slice("generated-results/".length).split("/").filter(Boolean) };
}
return null;
}
async function storeBuffer(input: {
bytes: Buffer;
fileName: string;