refactor: remove dead code and unused exports
Delete proxy-auth.ts, types/index.ts, staff-user.ts+test, local-imports.ts+test (only used by their own tests). Remove unused foundation exports: sanitizeFilename, canonicalizeFormValue, canonicalizeFormData, ConflictError, getRequestStore, getClientIp, elapsed. Remove stale TODO comments from rank-authority.ts and notice.ts. Fix biome lint warnings in catalog-repair.ts.
This commit is contained in:
1 parent
510d070dc5
commit
24bf8eabb9
12 files changed
+2
-265
No files matched your search
@@ -1,4 +1,3 @@
|
||||
// TODO: Check of dit bestand weg kan — uitsluitend gebruikt door eigen test
|
||||
export interface AdminMutationNotice {
|
||||
tone: "ok" | "danger";
|
||||
label: "Saved" | "Error";
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// TODO: Check of dit bestand weg kan — uitsluitend gebruikt door eigen test
|
||||
import type { AuthorizationActor } from "@/lib/admin/authorization-policy";
|
||||
|
||||
export interface RankAuthorityDb {
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { resolveStaffUser } from "@/lib/admin/staff-user";
|
||||
|
||||
describe("resolveStaffUser", () => {
|
||||
it("rejects a session whose database rank has been revoked", async () => {
|
||||
const findUser = async () => ({ id: 7, rank: 1, username: "Alice" });
|
||||
|
||||
await expect(resolveStaffUser("7", 7, findUser)).resolves.toBeNull();
|
||||
});
|
||||
|
||||
it("returns the current database identity instead of stale JWT values", async () => {
|
||||
const findUser = async () => ({ id: 7, rank: 8, username: "CurrentName" });
|
||||
|
||||
await expect(resolveStaffUser("7", 7, findUser)).resolves.toEqual({
|
||||
id: 7,
|
||||
rank: 8,
|
||||
username: "CurrentName",
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,22 +0,0 @@
|
||||
// TODO: Check of dit bestand weg kan — uitsluitend gebruikt door eigen test
|
||||
import { isStaff } from "@/lib/admin/is-staff";
|
||||
|
||||
export interface StaffUserRecord {
|
||||
id: number;
|
||||
rank: number;
|
||||
username: string;
|
||||
}
|
||||
|
||||
export type FindStaffUser = (id: number) => Promise<StaffUserRecord | null>;
|
||||
|
||||
export async function resolveStaffUser(
|
||||
sessionUserId: string,
|
||||
minStaffRank: number,
|
||||
findUser: FindStaffUser,
|
||||
): Promise<StaffUserRecord | null> {
|
||||
const id = Number(sessionUserId);
|
||||
if (!Number.isSafeInteger(id) || id <= 0) return null;
|
||||
|
||||
const user = await findUser(id);
|
||||
return user && isStaff(user.rank, minStaffRank) ? user : null;
|
||||
}
|
||||
@@ -49,14 +49,6 @@ export class RateLimitError extends DomainError {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export class ConflictError extends DomainError {
|
||||
constructor(message: string) {
|
||||
super(message, 409);
|
||||
this.name = "ConflictError";
|
||||
}
|
||||
}
|
||||
|
||||
export class DatabaseError extends DomainError {
|
||||
public readonly cause: unknown;
|
||||
|
||||
|
||||
@@ -30,27 +30,11 @@ export function runWithStore<T>(store: RequestStore, fn: () => T): T {
|
||||
return als.run(store, fn);
|
||||
}
|
||||
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export function getRequestStore(): RequestStore | null {
|
||||
return als.getStore() ?? null;
|
||||
}
|
||||
|
||||
export function getRequestId(): RequestId {
|
||||
return als.getStore()?.requestId ?? generateRequestId();
|
||||
}
|
||||
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export function getClientIp(): IpAddress {
|
||||
return als.getStore()?.ip ?? ("0.0.0.0" as IpAddress);
|
||||
}
|
||||
|
||||
export function setContextUserId(userId: UserId): void {
|
||||
const store = als.getStore();
|
||||
if (store) store.userId = userId;
|
||||
}
|
||||
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export function elapsed(): number {
|
||||
const store = als.getStore();
|
||||
return store ? Date.now() - store.startedAt : 0;
|
||||
}
|
||||
@@ -208,50 +208,6 @@ export function sanitizeField(
|
||||
return s.slice(0, maxLen);
|
||||
}
|
||||
|
||||
const INVALID_FILENAME_CHARS = /[<>:"/\\|?*]/;
|
||||
|
||||
function removeControlChars(s: string): string {
|
||||
let result = "";
|
||||
for (let i = 0; i < s.length; i++) {
|
||||
const code = s.charCodeAt(i);
|
||||
if (code >= 32) result += s.charAt(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export function sanitizeFilename(name: string): string {
|
||||
return removeControlChars(
|
||||
name
|
||||
.normalize("NFC")
|
||||
.replace(INVALID_FILENAME_CHARS, "")
|
||||
.replace(/\.\.(?:\/|$)/g, ""),
|
||||
)
|
||||
.trim()
|
||||
.slice(0, 255);
|
||||
}
|
||||
|
||||
export function canonicalizeFormValue(
|
||||
value: FormDataEntryValue | null,
|
||||
maxLen?: number,
|
||||
): string {
|
||||
const s = canonicalize(String(value ?? ""));
|
||||
return maxLen ? s.slice(0, maxLen) : s;
|
||||
}
|
||||
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export function canonicalizeFormData(
|
||||
formData: FormData,
|
||||
fields: Record<string, number | undefined>,
|
||||
): Record<string, string> {
|
||||
return Object.fromEntries(
|
||||
Object.entries(fields).map(([key, maxLen]) => [
|
||||
key,
|
||||
canonicalizeFormValue(formData.get(key), maxLen),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
export async function extractClientIpAsync(): Promise<IpAddress> {
|
||||
try {
|
||||
const h = await headers();
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { findMissingLocalImports } from "./local-imports";
|
||||
|
||||
const roots: string[] = [];
|
||||
|
||||
afterEach(async () => {
|
||||
await Promise.all(
|
||||
roots.splice(0).map((root) => rm(root, { recursive: true, force: true })),
|
||||
);
|
||||
});
|
||||
|
||||
describe("findMissingLocalImports", () => {
|
||||
it("reports unresolved alias imports and ignores modules that exist", async () => {
|
||||
const root = await mkdtemp(join(tmpdir(), "epicnext-imports-"));
|
||||
roots.push(root);
|
||||
await mkdir(join(root, "src", "features"), { recursive: true });
|
||||
await mkdir(join(root, "src", "components", "ui"), { recursive: true });
|
||||
await writeFile(
|
||||
join(root, "src", "components", "ui", "card.tsx"),
|
||||
"export const Card = {};\n",
|
||||
);
|
||||
await writeFile(
|
||||
join(root, "src", "features", "page.tsx"),
|
||||
[
|
||||
'import { Card } from "@/components/ui/card";',
|
||||
'import { Button } from "@/components/ui/button";',
|
||||
"export default Card;",
|
||||
].join("\n"),
|
||||
);
|
||||
|
||||
await expect(findMissingLocalImports(root)).resolves.toEqual([
|
||||
{
|
||||
importer: "src/features/page.tsx",
|
||||
specifier: "@/components/ui/button",
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -1,98 +0,0 @@
|
||||
// TODO: Check of dit bestand weg kan — uitsluitend gebruikt door eigen test
|
||||
import { access, readdir, readFile } from "node:fs/promises";
|
||||
import { dirname, extname, join, relative, resolve, sep } from "node:path";
|
||||
|
||||
export interface MissingLocalImport {
|
||||
importer: string;
|
||||
specifier: string;
|
||||
}
|
||||
|
||||
const sourceExtensions = new Set([
|
||||
".ts",
|
||||
".tsx",
|
||||
".js",
|
||||
".jsx",
|
||||
".mjs",
|
||||
".cjs",
|
||||
]);
|
||||
const resolutionSuffixes = [
|
||||
".ts",
|
||||
".tsx",
|
||||
".js",
|
||||
".jsx",
|
||||
".mjs",
|
||||
".cjs",
|
||||
".css",
|
||||
"/index.ts",
|
||||
"/index.tsx",
|
||||
"/index.js",
|
||||
"/index.jsx",
|
||||
];
|
||||
const importPattern =
|
||||
/(?:import|export)\s+(?:[^"']*?\s+from\s+)?["']([^"']+)["']|import\(\s*["']([^"']+)["']\s*\)|require\(\s*["']([^"']+)["']\s*\)/g;
|
||||
|
||||
async function collectSourceFiles(directory: string): Promise<string[]> {
|
||||
const entries = await readdir(directory, { withFileTypes: true });
|
||||
const files = await Promise.all(
|
||||
entries.map(async (entry) => {
|
||||
const path = join(directory, entry.name);
|
||||
if (entry.isDirectory()) return collectSourceFiles(path);
|
||||
if (/\.(?:test|spec)\.[cm]?[jt]sx?$/.test(entry.name)) return [];
|
||||
return sourceExtensions.has(extname(entry.name)) ? [path] : [];
|
||||
}),
|
||||
);
|
||||
return files.flat();
|
||||
}
|
||||
|
||||
async function exists(path: string): Promise<boolean> {
|
||||
try {
|
||||
await access(path);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function resolvesToLocalFile(base: string): Promise<boolean> {
|
||||
if (extname(base) && (await exists(base))) return true;
|
||||
for (const suffix of resolutionSuffixes) {
|
||||
if (await exists(`${base}${suffix}`)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export async function findMissingLocalImports(
|
||||
root: string,
|
||||
): Promise<MissingLocalImport[]> {
|
||||
const src = resolve(root, "src");
|
||||
const files = await collectSourceFiles(src);
|
||||
const missing: MissingLocalImport[] = [];
|
||||
|
||||
for (const importer of files) {
|
||||
const source = await readFile(importer, "utf8");
|
||||
for (const match of source.matchAll(importPattern)) {
|
||||
const specifier = match[1] ?? match[2] ?? match[3];
|
||||
if (
|
||||
!specifier?.startsWith("@/") &&
|
||||
!specifier?.startsWith("./") &&
|
||||
!specifier?.startsWith("../")
|
||||
)
|
||||
continue;
|
||||
const base = specifier.startsWith("@/")
|
||||
? resolve(src, specifier.slice(2))
|
||||
: resolve(dirname(importer), specifier);
|
||||
if (!(await resolvesToLocalFile(base))) {
|
||||
missing.push({
|
||||
importer: relative(root, importer).split(sep).join("/"),
|
||||
specifier,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return missing.sort(
|
||||
(a, b) =>
|
||||
a.importer.localeCompare(b.importer) ||
|
||||
a.specifier.localeCompare(b.specifier),
|
||||
);
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
import NextAuth from "next-auth";
|
||||
import { env } from "@/env";
|
||||
|
||||
// Proxy authentication must only decode the Auth.js session. Importing the
|
||||
// full CMS auth configuration here would also run DB/settings callbacks.
|
||||
export const { auth: proxyAuth } = NextAuth({
|
||||
trustHost: true,
|
||||
secret: env.AUTH_SECRET,
|
||||
session: { strategy: "jwt" },
|
||||
providers: [],
|
||||
});
|
||||
@@ -261,7 +261,7 @@ function derivePageCaption(classname: string, fallback: string): string {
|
||||
const re = new RegExp(`^${prefix.replace(/_/g, "[_]?")}(?:_)?(\\d*)`, "i");
|
||||
const m = lower.match(re);
|
||||
if (m) {
|
||||
const matchEnd = m.index! + m[0].length;
|
||||
const matchEnd = (m.index ?? 0) + m[0].length;
|
||||
const nextChar = lower[matchEnd];
|
||||
if (
|
||||
!nextChar ||
|
||||
@@ -278,7 +278,7 @@ function derivePageCaption(classname: string, fallback: string): string {
|
||||
// Also try matching suffix patterns (e.g., "something_xmas2025").
|
||||
for (const prefix of sortedPrefixes) {
|
||||
const re = new RegExp(
|
||||
`${prefix.replace(/_/g, "[_]?")}(?:_)?(\\d{4})` + "(_|$)",
|
||||
`${prefix.replace(/_/g, "[_]?")}(?:_)?(\\d{4})(_|$)`,
|
||||
"i",
|
||||
);
|
||||
const m = lower.match(re);
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export type { DataTableColumn, ListParams, PaginatedResult } from "./common";
|
||||
Reference in new issue
Block a user