fix(dashboard): normalize route id params for express 5 typings

This commit is contained in:
2026-02-12 19:10:41 +01:00
parent 2cbd11cf0d
commit 08d2165a70
5 changed files with 7696 additions and 9 deletions
+3783
View File
File diff suppressed because it is too large Load Diff
+23 -3
View File
@@ -24,7 +24,10 @@ const resolveDatabaseUrl = (rawUrl) => {
const absolutePath = path.isAbsolute(filePath) const absolutePath = path.isAbsolute(filePath)
? filePath ? filePath
: path.resolve(hasLeadingPrismaDir ? backendRoot : prismaDir, normalizedRelative); : path.resolve(
hasLeadingPrismaDir ? backendRoot : prismaDir,
normalizedRelative,
);
return `file:${absolutePath}`; return `file:${absolutePath}`;
}; };
@@ -91,7 +94,15 @@ const backupDbIfPresent = () => {
const isNonProd = nodeEnv !== "production"; const isNonProd = nodeEnv !== "production";
const isFileDb = databaseUrl.startsWith("file:"); const isFileDb = databaseUrl.startsWith("file:");
const deploy = runCapture("npx prisma migrate deploy"); let deploy = runCapture("npx prisma migrate deploy");
if (!deploy.ok) {
console.warn(
`[predev] Prisma migrate deploy failed. Attempting pnpm exec...`,
);
deploy = runCapture("pnpm exec prisma migrate deploy");
}
if (deploy.ok) { if (deploy.ok) {
if (deploy.stdout) process.stdout.write(deploy.stdout); if (deploy.stdout) process.stdout.write(deploy.stdout);
} else { } else {
@@ -111,7 +122,16 @@ if (deploy.ok) {
` If you need to preserve local data, restore the backup and baseline manually.`, ` If you need to preserve local data, restore the backup and baseline manually.`,
); );
run("npx prisma migrate reset --force --skip-seed"); // check for npx, if not present try pnpm exec
try {
console.log(
`[predev] Running: npx prisma migrate reset --force --skip-seed`,
);
run("npx prisma migrate reset --force --skip-seed");
} catch {
console.warn(`[predev] npx not found, trying pnpm exec...`);
run("pnpm exec prisma migrate reset --force --skip-seed");
}
} else { } else {
throw deploy.error; throw deploy.error;
} }
+12 -2
View File
@@ -2,6 +2,14 @@ import express from "express";
import { DashboardRouteDeps } from "./types"; import { DashboardRouteDeps } from "./types";
import { getUserTrashCollectionId, isTrashCollectionId } from "./trash"; import { getUserTrashCollectionId, isTrashCollectionId } from "./trash";
const getRouteIdParam = (value: string | string[] | undefined): string | null => {
if (typeof value === "string" && value.trim().length > 0) return value;
if (Array.isArray(value) && typeof value[0] === "string" && value[0].trim().length > 0) {
return value[0];
}
return null;
};
export const registerCollectionRoutes = ( export const registerCollectionRoutes = (
app: express.Express, app: express.Express,
deps: DashboardRouteDeps deps: DashboardRouteDeps
@@ -59,7 +67,8 @@ export const registerCollectionRoutes = (
app.put("/collections/:id", requireAuth, asyncHandler(async (req, res) => { app.put("/collections/:id", requireAuth, asyncHandler(async (req, res) => {
if (!req.user) return res.status(401).json({ error: "Unauthorized" }); if (!req.user) return res.status(401).json({ error: "Unauthorized" });
const { id } = req.params; const id = getRouteIdParam(req.params.id);
if (!id) return res.status(400).json({ error: "Validation error", message: "Invalid id parameter" });
if (isTrashCollectionId(id, req.user.id)) { if (isTrashCollectionId(id, req.user.id)) {
return res.status(400).json({ return res.status(400).json({
error: "Validation error", error: "Validation error",
@@ -99,7 +108,8 @@ export const registerCollectionRoutes = (
app.delete("/collections/:id", requireAuth, asyncHandler(async (req, res) => { app.delete("/collections/:id", requireAuth, asyncHandler(async (req, res) => {
if (!req.user) return res.status(401).json({ error: "Unauthorized" }); if (!req.user) return res.status(401).json({ error: "Unauthorized" });
const { id } = req.params; const id = getRouteIdParam(req.params.id);
if (!id) return res.status(400).json({ error: "Validation error", message: "Invalid id parameter" });
if (isTrashCollectionId(id, req.user.id)) { if (isTrashCollectionId(id, req.user.id)) {
return res.status(400).json({ return res.status(400).json({
error: "Validation error", error: "Validation error",
+16 -4
View File
@@ -8,6 +8,14 @@ import {
toPublicTrashCollectionId, toPublicTrashCollectionId,
} from "./trash"; } from "./trash";
const getRouteIdParam = (value: string | string[] | undefined): string | null => {
if (typeof value === "string" && value.trim().length > 0) return value;
if (Array.isArray(value) && typeof value[0] === "string" && value[0].trim().length > 0) {
return value[0];
}
return null;
};
export const registerDrawingRoutes = ( export const registerDrawingRoutes = (
app: express.Express, app: express.Express,
deps: DashboardRouteDeps deps: DashboardRouteDeps
@@ -172,7 +180,8 @@ export const registerDrawingRoutes = (
app.get("/drawings/:id", requireAuth, asyncHandler(async (req, res) => { app.get("/drawings/:id", requireAuth, asyncHandler(async (req, res) => {
if (!req.user) return res.status(401).json({ error: "Unauthorized" }); if (!req.user) return res.status(401).json({ error: "Unauthorized" });
const { id } = req.params; const id = getRouteIdParam(req.params.id);
if (!id) return res.status(400).json({ error: "Validation error", message: "Invalid id parameter" });
const drawing = await prisma.drawing.findFirst({ const drawing = await prisma.drawing.findFirst({
where: { where: {
id, id,
@@ -255,7 +264,8 @@ export const registerDrawingRoutes = (
app.put("/drawings/:id", requireAuth, asyncHandler(async (req, res) => { app.put("/drawings/:id", requireAuth, asyncHandler(async (req, res) => {
if (!req.user) return res.status(401).json({ error: "Unauthorized" }); if (!req.user) return res.status(401).json({ error: "Unauthorized" });
const { id } = req.params; const id = getRouteIdParam(req.params.id);
if (!id) return res.status(400).json({ error: "Validation error", message: "Invalid id parameter" });
const existingDrawing = await prisma.drawing.findFirst({ const existingDrawing = await prisma.drawing.findFirst({
where: { id, userId: req.user.id }, where: { id, userId: req.user.id },
}); });
@@ -352,7 +362,8 @@ export const registerDrawingRoutes = (
app.delete("/drawings/:id", requireAuth, asyncHandler(async (req, res) => { app.delete("/drawings/:id", requireAuth, asyncHandler(async (req, res) => {
if (!req.user) return res.status(401).json({ error: "Unauthorized" }); if (!req.user) return res.status(401).json({ error: "Unauthorized" });
const { id } = req.params; const id = getRouteIdParam(req.params.id);
if (!id) return res.status(400).json({ error: "Validation error", message: "Invalid id parameter" });
const drawing = await prisma.drawing.findFirst({ where: { id, userId: req.user.id } }); const drawing = await prisma.drawing.findFirst({ where: { id, userId: req.user.id } });
if (!drawing) return res.status(404).json({ error: "Drawing not found" }); if (!drawing) return res.status(404).json({ error: "Drawing not found" });
@@ -382,7 +393,8 @@ export const registerDrawingRoutes = (
app.post("/drawings/:id/duplicate", requireAuth, asyncHandler(async (req, res) => { app.post("/drawings/:id/duplicate", requireAuth, asyncHandler(async (req, res) => {
if (!req.user) return res.status(401).json({ error: "Unauthorized" }); if (!req.user) return res.status(401).json({ error: "Unauthorized" });
const { id } = req.params; const id = getRouteIdParam(req.params.id);
if (!id) return res.status(400).json({ error: "Validation error", message: "Invalid id parameter" });
const original = await prisma.drawing.findFirst({ where: { id, userId: req.user.id } }); const original = await prisma.drawing.findFirst({ where: { id, userId: req.user.id } });
if (!original) return res.status(404).json({ error: "Original drawing not found" }); if (!original) return res.status(404).json({ error: "Original drawing not found" });
let duplicatedCollectionId = original.collectionId; let duplicatedCollectionId = original.collectionId;
+3862
View File
File diff suppressed because it is too large Load Diff