mirror of
https://github.com/hanzo-apps/dataroom.git
synced 2026-11-02 22:04:20 +00:00
The client was already @hanzo/kv; only the vocabulary was still Redis. Every module, symbol and comment now says what it connects to: lib/redis.ts -> lib/kv.ts (exports kv, lockKv) lib/redis-job-store.ts -> lib/kv-job-store.ts (KvJobStore) lib/redis-download-job-store.ts -> lib/kv-download-job-store.ts lib/files/tus-redis-locker.ts -> lib/files/tus-kv-locker.ts (KvLocker, KvLock) lib/api/domains/redis.ts -> lib/api/domains/kv.ts (getKey) lib/redis/ -> lib/kv-queue/ KV_URL is now the only endpoint variable — the REDIS_URL fallback and the redis://localhost default are gone, and the default scheme is kv://, which @hanzo/kv parses natively (utils/index.js). .env.example gained the KV_URL it never documented, and lost UPSTASH_REDIS_REST_LOCKER_URL/TOKEN: nothing has read those since the client changed — the locker opens a second connection to the same KV, so there is no second endpoint to configure. The second connection is `lockKv`, not `locker`: both tus routes already have a local `const locker = new KvLocker(...)`, so naming the client `locker` made the lock take itself as its own client. Verified against the repo's own gate (npx tsc --noEmit): 100 errors before and after, 0 introduced, compared set-wise by file:line:code. Behaviour is untouched — this is naming, one connection string, and dead config. Co-authored-by: Hanzo Dev <[email protected]>
83 lines
2.5 KiB
TypeScript
83 lines
2.5 KiB
TypeScript
import { NextApiRequest, NextApiResponse } from "next";
|
|
|
|
import { getDataroomSessionByLinkIdInPagesRouter } from "@/lib/auth/dataroom-auth";
|
|
import { generateFreshPresignedUrl } from "@/lib/files/bulk-download-presign";
|
|
import prisma from "@/lib/prisma";
|
|
import { downloadJobStore } from "@/lib/kv-download-job-store";
|
|
|
|
export default async function handler(
|
|
req: NextApiRequest,
|
|
res: NextApiResponse,
|
|
) {
|
|
if (req.method !== "GET") {
|
|
res.setHeader("Allow", ["GET"]);
|
|
return res.status(405).end(`Method ${req.method} Not Allowed`);
|
|
}
|
|
|
|
const linkId = req.query.linkId as string;
|
|
const { jobId, partIndex } = req.query as {
|
|
jobId: string;
|
|
partIndex: string;
|
|
};
|
|
if (!linkId || !jobId || partIndex == null) {
|
|
return res
|
|
.status(400)
|
|
.json({ error: "linkId, jobId and partIndex required" });
|
|
}
|
|
|
|
const session = await getDataroomSessionByLinkIdInPagesRouter(req, linkId);
|
|
if (!session) {
|
|
return res.status(401).json({ error: "Session required" });
|
|
}
|
|
|
|
const view = await prisma.view.findUnique({
|
|
where: { id: session.viewId },
|
|
select: { viewerEmail: true },
|
|
});
|
|
if (!view?.viewerEmail) {
|
|
return res.status(403).json({ error: "Viewer email not found" });
|
|
}
|
|
|
|
const job = await downloadJobStore.getJob(jobId);
|
|
if (!job) {
|
|
return res
|
|
.status(404)
|
|
.json({ error: "Download job not found or expired" });
|
|
}
|
|
|
|
if (
|
|
job.linkId !== linkId ||
|
|
job.viewerEmail?.toLowerCase().trim() !==
|
|
view.viewerEmail?.toLowerCase().trim()
|
|
) {
|
|
return res
|
|
.status(403)
|
|
.json({ error: "Job does not belong to this viewer" });
|
|
}
|
|
|
|
if (job.status !== "COMPLETED" || !job.downloadUrls?.length) {
|
|
return res.status(400).json({ error: "Download not ready" });
|
|
}
|
|
|
|
const index = parseInt(partIndex, 10);
|
|
if (Number.isNaN(index) || index < 0 || index >= job.downloadUrls.length) {
|
|
return res.status(400).json({ error: "Invalid part index" });
|
|
}
|
|
|
|
// Generate a fresh presigned URL using long-term IAM credentials
|
|
// to avoid the Lambda STS token expiration issue
|
|
const s3Key = job.downloadS3Keys?.[index];
|
|
if (s3Key && job.teamId) {
|
|
try {
|
|
const freshUrl = await generateFreshPresignedUrl(job.teamId, s3Key);
|
|
return res.redirect(302, freshUrl);
|
|
} catch (error) {
|
|
console.error("Failed to generate fresh presigned URL:", error);
|
|
}
|
|
}
|
|
|
|
// Fallback to stored presigned URL (may fail if STS token expired)
|
|
const presignedUrl = job.downloadUrls[index];
|
|
res.redirect(302, presignedUrl);
|
|
}
|