refactor(scripts): delete 20 one-off/legacy scripts
The scripts/ directory had accumulated 29 entries, half of which were one-off fixes that had already done their job and several of which were Supabase-era artifacts that don't apply now that the project uses direct Postgres via `pg`. Deleted (none referenced from package.json, CLAUDE.md, MEMORY.md, .gitea/workflows/deploy.yml, db/seeds/, or src/): Supabase-era one-offs (the project moved off Supabase JS/REST): - apply-admin-create-stop.js (RPC installer against supabase.co) - fix-archived-rls.js (RLS repair against supabase.co) - seed.sh (pure supabase REST seeding) - seed_tuxedo_tour.py (Python equivalent of the JS seed) Codemods / lint fixers that ran once: - fix-server-auth.js, fix-server-auth-ast.js - fix-button-has-type.js, fix-control-has-associated-label.js Versioned iteration history of one-off checks: - check-stop-fns.js, check-stop-fns2.js, check-stop-fns3.js - verify-stop-fns.js (only referenced by apply-admin-create-stop.js) Other one-offs: - cleanup-duplicate-stops.ts - create-admin-user.ts, seed-admin.ts (superseded by provision-admin.ts) - seed-tuxedo.ts (superseded by seed-tuxedo-2026.js) - import-woo-to-route.ts (WooCommerce import, no longer used) - upload-tuxedo-video.mjs, verify-email.ts, e2e-test.sh Also updated one stale comment in src/actions/admin/users.ts that referenced scripts/seed-admin.ts. Kept (9 scripts, all live-referenced): - migrate.js (package.json + deploy.yml + MEMORY.md) - db-reset.js (package.json: db:reset) - seed-tuxedo-2026.js (package.json: db:seed:tour) - import-tuxedo-stops.ts (db/seeds preferred path) - provision-admin.ts (CLAUDE.md production bootstrap) - preflight-check.js, postflight-check.js (.gitea/workflows/deploy.yml) - generate-pwa-icons.js, generate-pwa-screenshots.js (reproducible PWA build assets, referenced in design docs) Verified: tsc clean, 174/175 tests pass (same baseline), package.json scripts and deploy.yml all still resolve to kept scripts.
This commit is contained in:
@@ -1,150 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Add an auth check to every exported async function in a "use server"
|
||||
* file using the TypeScript compiler API. Idempotent.
|
||||
*
|
||||
* The check inserted as the first statement in the function body is:
|
||||
*
|
||||
* const adminUser = await getAdminUser();
|
||||
* if (!adminUser) return { success: false, error: "Unauthorized" };
|
||||
*
|
||||
* If the function body already calls getAdminUser() or getSession() within
|
||||
* its first few statements, it is left alone.
|
||||
*
|
||||
* Usage: node scripts/fix-server-auth-ast.js <file>...
|
||||
*/
|
||||
const fs = require("node:fs");
|
||||
const path = require("node:path");
|
||||
const ts = require("typescript");
|
||||
|
||||
function ensureGetAdminUserImport(sourceFile) {
|
||||
let src = sourceFile.text;
|
||||
const hasImport = sourceFile.statements.some(
|
||||
(s) =>
|
||||
ts.isImportDeclaration(s) &&
|
||||
s.moduleSpecifier &&
|
||||
s.moduleSpecifier.text === "@/lib/admin-permissions",
|
||||
);
|
||||
if (hasImport) return src;
|
||||
|
||||
const importLine = `import { getAdminUser } from "@/lib/admin-permissions";\n`;
|
||||
// Insert after "use server" directive.
|
||||
for (const stmt of sourceFile.statements) {
|
||||
if (
|
||||
ts.isExpressionStatement(stmt) &&
|
||||
ts.isStringLiteral(stmt.expression) &&
|
||||
(stmt.expression.text === "use server" ||
|
||||
stmt.expression.text === "use client")
|
||||
) {
|
||||
const pos = stmt.getEnd();
|
||||
return src.slice(0, pos) + "\n" + importLine + src.slice(pos);
|
||||
}
|
||||
}
|
||||
// Otherwise after the first import.
|
||||
for (const stmt of sourceFile.statements) {
|
||||
if (ts.isImportDeclaration(stmt)) {
|
||||
const pos = stmt.getEnd();
|
||||
return src.slice(0, pos) + "\n" + importLine + src.slice(pos);
|
||||
}
|
||||
}
|
||||
return importLine + src;
|
||||
}
|
||||
|
||||
function alreadyGated(body) {
|
||||
// Walk the function body and detect either:
|
||||
// 1. A getAdminUser() / getSession() call (auth gate already in place)
|
||||
// 2. An existing `const adminUser = ...` declaration (would collide)
|
||||
let hasAuthCall = false;
|
||||
let hasAdminUserVar = false;
|
||||
function walk(node) {
|
||||
if (
|
||||
ts.isCallExpression(node) &&
|
||||
ts.isIdentifier(node.expression) &&
|
||||
(node.expression.text === "getAdminUser" ||
|
||||
node.expression.text === "getSession")
|
||||
) {
|
||||
hasAuthCall = true;
|
||||
}
|
||||
if (
|
||||
ts.isVariableDeclaration(node) &&
|
||||
ts.isIdentifier(node.name) &&
|
||||
node.name.text === "adminUser"
|
||||
) {
|
||||
hasAdminUserVar = true;
|
||||
}
|
||||
ts.forEachChild(node, walk);
|
||||
}
|
||||
walk(body);
|
||||
return hasAuthCall || hasAdminUserVar;
|
||||
}
|
||||
|
||||
function processFile(filePath) {
|
||||
const abs = path.resolve(filePath);
|
||||
if (!fs.existsSync(abs)) {
|
||||
console.error(`skip (not found): ${abs}`);
|
||||
return 0;
|
||||
}
|
||||
const original = fs.readFileSync(abs, "utf8");
|
||||
if (!original.includes('"use server"') && !original.includes("'use server'")) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const sourceFile = ts.createSourceFile(
|
||||
abs,
|
||||
original,
|
||||
ts.ScriptTarget.Latest,
|
||||
true,
|
||||
);
|
||||
|
||||
let src = ensureGetAdminUserImport(sourceFile);
|
||||
// Re-parse after import insertion.
|
||||
const sf = ts.createSourceFile(abs, src, ts.ScriptTarget.Latest, true);
|
||||
|
||||
const edits = [];
|
||||
function visit(node) {
|
||||
if (
|
||||
ts.isFunctionDeclaration(node) &&
|
||||
node.modifiers &&
|
||||
node.modifiers.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) &&
|
||||
node.modifiers.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) &&
|
||||
node.body
|
||||
) {
|
||||
if (!alreadyGated(node.body)) {
|
||||
// Throwing is universal — it works regardless of the function's
|
||||
// return type annotation (Promise<void>, {success, error}, etc.)
|
||||
// and matches how the rest of the app signals "auth gate" errors.
|
||||
const insert = `\n const adminUser = await getAdminUser();\n if (!adminUser) throw new Error("Unauthorized");\n`;
|
||||
const pos = node.body.getStart(sf) + 1; // after `{`
|
||||
edits.push({ pos, insert });
|
||||
}
|
||||
}
|
||||
ts.forEachChild(node, visit);
|
||||
}
|
||||
visit(sf);
|
||||
|
||||
// Apply edits in reverse order so positions don't shift.
|
||||
edits.sort((a, b) => b.pos - a.pos);
|
||||
let out = src;
|
||||
for (const e of edits) {
|
||||
out = out.slice(0, e.pos) + e.insert + out.slice(e.pos);
|
||||
}
|
||||
|
||||
if (edits.length > 0) {
|
||||
fs.writeFileSync(abs, out, "utf8");
|
||||
console.log(`patched (${edits.length} functions): ${abs}`);
|
||||
}
|
||||
return edits.length;
|
||||
}
|
||||
|
||||
const files = process.argv.slice(2);
|
||||
if (files.length === 0) {
|
||||
console.error("usage: node scripts/fix-server-auth-ast.js <file>...");
|
||||
process.exit(2);
|
||||
}
|
||||
let patched = 0, total = 0;
|
||||
for (const f of files) {
|
||||
const n = processFile(f);
|
||||
if (n > 0) patched++;
|
||||
total += n;
|
||||
}
|
||||
console.log(`done — ${patched} files, ${total} functions`);
|
||||
Reference in New Issue
Block a user