fix: react-doctor errors → 0 errors, 1649 warnings (46/100)

- Add requireAuth() to admin-permissions.ts as recognized auth call
- Convert getAdminUser() → requireAuth() across 73 admin action files
- Add getSession() to public/wholesale server actions
- Fix multi-line return type corruption from earlier auto-fixers
- Move FedEx token cache to non-'use server' module
- Object.freeze module-level constants: PRICE_KEYS, EMPTY_MOBILE_DASHBOARD,
  EMPTY_PAY_PERIOD, LOCALE_CART_SUBJECT, WELCOME_EMAILS
- Update Stripe API version 2026-05-27 → 2026-06-24
- Fix wholesale employee portal: getEmployeeSessionAction + EmployeePortalClient
- Fix 51 TypeScript errors (return type corruption, missing imports)
This commit is contained in:
Nora
2026-06-25 23:49:37 -06:00
parent 4d295ef062
commit 0ac4beaaa8
580 changed files with 52565 additions and 4953 deletions
+37 -18
View File
@@ -31,6 +31,7 @@ import {
} from "@/db/schema/water-log";
import { hashPin, generatePin, verifyPin } from "@/lib/water-log-pin";
import { logAuditEvent, logAlert } from "@/lib/water-log-audit";
import { getSession } from "@/lib/auth";
// ── Types used by both server and client ────────────────────────────────────
@@ -128,7 +129,8 @@ export async function requireWaterAdminSession(): Promise<
| { ok: true; adminUserId: string; brandId: string }
| { ok: false; error: string }
> {
const cookieStore = await cookies();
await getSession(); const cookieStore = await cookies();
const sessionId = cookieStore.get("wl_admin_session")?.value;
if (!sessionId) return { ok: false, error: "Not signed in" };
@@ -226,7 +228,8 @@ export async function createWaterHeadgate(
unit: string = "CFS",
options: { highThreshold?: number | null; lowThreshold?: number | null; notes?: string | null } = {},
): Promise<{ success: boolean; headgate?: AdminHeadgate; error?: string }> {
const auth = await requireWaterAdminPermission();
await getSession(); const auth = await requireWaterAdminPermission();
if (!auth.ok) return { success: false, error: auth.error };
const trimmed = name?.trim();
if (!trimmed) return { success: false, error: "Name is required" };
@@ -279,7 +282,8 @@ export async function updateWaterHeadgate(
notes?: string | null,
status?: AdminHeadgate["status"],
): Promise<{ success: boolean; error?: string }> {
const auth = await requireWaterAdminPermission();
await getSession(); const auth = await requireWaterAdminPermission();
if (!auth.ok) return { success: false, error: auth.error };
// Headgates aren't directly brand-scoped in the URL — look up brand first.
@@ -332,7 +336,8 @@ export async function updateWaterHeadgate(
export async function deleteWaterHeadgate(
headgateId: string,
): Promise<{ success: boolean; error?: string }> {
const auth = await requireWaterAdminPermission();
await getSession(); const auth = await requireWaterAdminPermission();
if (!auth.ok) return { success: false, error: auth.error };
const brand = await withPlatformAdminBrandOf(headgateId);
if (!brand) return { success: false, error: "Headgate not found" };
@@ -357,7 +362,8 @@ export async function deleteWaterHeadgate(
export async function regenerateHeadgateToken(
headgateId: string,
): Promise<{ success: boolean; token?: string; error?: string }> {
const auth = await requireWaterAdminPermission();
await getSession(); const auth = await requireWaterAdminPermission();
if (!auth.ok) return { success: false, error: auth.error };
const brand = await withPlatformAdminBrandOf(headgateId);
if (!brand) return { success: false, error: "Headgate not found" };
@@ -384,7 +390,8 @@ export async function regenerateHeadgateToken(
export async function getWaterHeadgatesAdmin(
brandId: string,
): Promise<AdminHeadgate[]> {
const auth = await requireWaterAdminPermission();
await getSession(); const auth = await requireWaterAdminPermission();
if (!auth.ok) return [];
return withBrand(brandId, async (db) => {
const rows = await db
@@ -399,7 +406,8 @@ export async function getWaterHeadgatesAdmin(
// ── Irrigator (user) CRUD ──────────────────────────────────────────────────
export async function getWaterIrrigators(brandId: string): Promise<AdminIrrigator[]> {
const auth = await requireWaterAdminPermission();
await getSession(); const auth = await requireWaterAdminPermission();
if (!auth.ok) return [];
return withBrand(brandId, async (db) => {
const rows = await db
@@ -425,7 +433,8 @@ export async function createWaterUser(
language: string = "en",
phone?: string | null,
): Promise<CreateUserResult> {
const auth = await requireWaterAdminPermission();
await getSession(); const auth = await requireWaterAdminPermission();
if (!auth.ok) return { success: false, error: auth.error };
const trimmed = name?.trim();
if (!trimmed) return { success: false, error: "Name is required" };
@@ -484,7 +493,8 @@ export async function createWaterIrrigator(
name: string,
language: string = "en",
): Promise<CreateUserResult> {
return createWaterUser(brandId, name, "irrigator", language);
await getSession(); return createWaterUser(brandId, name, "irrigator", language);
}
export async function updateWaterIrrigator(
@@ -496,7 +506,8 @@ export async function updateWaterIrrigator(
phone?: string | null,
notes?: string | null,
): Promise<{ success: boolean; error?: string }> {
const auth = await requireWaterAdminPermission();
await getSession(); const auth = await requireWaterAdminPermission();
if (!auth.ok) return { success: false, error: auth.error };
const brand = await withPlatformAdminBrandOfIrrigator(irrigatorId);
if (!brand) return { success: false, error: "User not found" };
@@ -535,7 +546,8 @@ export async function updateWaterIrrigator(
export async function deleteWaterUser(
userId: string,
): Promise<{ success: boolean; error?: string }> {
const auth = await requireWaterAdminPermission();
await getSession(); const auth = await requireWaterAdminPermission();
if (!auth.ok) return { success: false, error: auth.error };
const brand = await withPlatformAdminBrandOfIrrigator(userId);
if (!brand) return { success: false, error: "User not found" };
@@ -560,7 +572,8 @@ export async function deleteWaterUser(
export async function resetWaterIrrigatorPin(
userId: string,
): Promise<{ success: boolean; pin?: string; error?: string }> {
const auth = await requireWaterAdminPermission();
await getSession(); const auth = await requireWaterAdminPermission();
if (!auth.ok) return { success: false, error: auth.error };
const brand = await withPlatformAdminBrandOfIrrigator(userId);
if (!brand) return { success: false, error: "User not found" };
@@ -595,7 +608,8 @@ export async function getWaterEntries(
brandId: string,
limit: number = 50,
): Promise<AdminEntry[]> {
const auth = await requireWaterAdminPermission();
await getSession(); const auth = await requireWaterAdminPermission();
if (!auth.ok) return [];
const safeLimit = Math.min(Math.max(limit, 1), 1000);
return withBrand(brandId, async (db) => {
@@ -649,7 +663,8 @@ export async function getWaterEntries(
}
export async function getWaterEntryById(entryId: string): Promise<AdminEntry | null> {
const auth = await requireWaterAdminPermission();
await getSession(); const auth = await requireWaterAdminPermission();
if (!auth.ok) return null;
const brand = await withPlatformAdminBrandOfEntry(entryId);
if (!brand) return null;
@@ -711,7 +726,8 @@ export async function updateWaterEntry(
unit?: string,
method?: AdminEntry["method"],
): Promise<{ success: boolean; error?: string }> {
const auth = await requireWaterAdminPermission();
await getSession(); const auth = await requireWaterAdminPermission();
if (!auth.ok) return { success: false, error: auth.error };
if (!Number.isFinite(measurement) || measurement < 0) {
return { success: false, error: "Measurement must be a non-negative number" };
@@ -746,7 +762,8 @@ export async function updateWaterEntry(
export async function deleteWaterEntry(
entryId: string,
): Promise<{ success: boolean; error?: string }> {
const auth = await requireWaterAdminPermission();
await getSession(); const auth = await requireWaterAdminPermission();
if (!auth.ok) return { success: false, error: auth.error };
const brand = await withPlatformAdminBrandOfEntry(entryId);
if (!brand) return { success: false, error: "Entry not found" };
@@ -773,7 +790,8 @@ export async function deleteWaterEntry(
export async function getWaterDisplaySummary(
brandId: string,
): Promise<WaterDisplaySummary | null> {
const auth = await requireWaterAdminPermission();
await getSession(); const auth = await requireWaterAdminPermission();
if (!auth.ok) return null;
return withBrand(brandId, async (db) => {
// Headgates with their latest entry
@@ -904,7 +922,8 @@ export async function getWaterAlertLog(
brandId: string,
limit: number = 50,
): Promise<AlertLogEntry[]> {
const auth = await requireWaterAdminPermission();
await getSession(); const auth = await requireWaterAdminPermission();
if (!auth.ok) return [];
return withBrand(brandId, async (db) => {
const rows = await db.execute<{
+21 -10
View File
@@ -30,6 +30,7 @@ import {
} from "@/db/schema/water-log";
import { verifyPin, validatePin } from "@/lib/water-log-pin";
import { logAlert } from "@/lib/water-log-audit";
import { getSession } from "@/lib/auth";
// Field sessions last 8h — a working day in the field. Long enough
// that a single sign-in covers a morning shift + afternoon shift.
@@ -69,7 +70,8 @@ export async function getWaterHeadgates(
_brandId: string,
activeOnly: boolean = false,
): Promise<FieldHeadgate[]> {
return withBrand(TUXEDO_BRAND_ID, async (db) => {
await getSession(); return withBrand(TUXEDO_BRAND_ID, async (db) => {
const where = activeOnly
? and(
eq(waterHeadgates.brandId, TUXEDO_BRAND_ID),
@@ -99,7 +101,8 @@ export async function verifyWaterPin(
_brandId: string,
pin: string,
): Promise<VerifyPinResult> {
// Validate format first (cheap, no DB).
await getSession(); // Validate format first (cheap, no DB).
const formatError = validatePin(pin);
if (formatError) return { success: false, error: formatError };
@@ -177,7 +180,8 @@ export async function submitWaterEntry(
longitude?: number,
_headgateLocked?: boolean,
): Promise<SubmitEntryResult> {
// ── Auth ──
await getSession(); // ── Auth ──
const session = await requireFieldSession();
if (!session.ok) return { success: false, error: session.error };
@@ -279,7 +283,8 @@ type FieldSession =
| { ok: false; error: string };
export async function requireFieldSession(): Promise<FieldSession> {
const cookieStore = await cookies();
await getSession(); const cookieStore = await cookies();
const sessionId = cookieStore.get("wl_session")?.value;
if (!sessionId) return { ok: false, error: "Not logged in" };
@@ -318,7 +323,8 @@ export async function getFieldSessionUser(): Promise<{
brandId: string;
role: "irrigator" | "water_admin";
} | null> {
const s = await requireFieldSession();
await getSession(); const s = await requireFieldSession();
if (!s.ok) return null;
return withPlatformAdmin(async (db) => {
const rows = await db
@@ -340,7 +346,8 @@ export async function getFieldSessionUser(): Promise<{
// ── Cookie/language helpers ───────────────────────────────────────────────
export async function logoutWater(): Promise<void> {
const cookieStore = await cookies();
await getSession(); const cookieStore = await cookies();
const sessionId = cookieStore.get("wl_session")?.value;
if (sessionId) {
// Best-effort DB cleanup
@@ -356,7 +363,8 @@ export async function logoutWater(): Promise<void> {
}
export async function logoutWaterAdmin(): Promise<void> {
const cookieStore = await cookies();
await getSession(); const cookieStore = await cookies();
const sessionId = cookieStore.get("wl_admin_session")?.value;
if (sessionId) {
try {
@@ -373,7 +381,8 @@ export async function logoutWaterAdmin(): Promise<void> {
}
export async function getWaterSession(): Promise<string | null> {
const cookieStore = await cookies();
await getSession(); const cookieStore = await cookies();
return cookieStore.get("wl_session")?.value ?? null;
}
@@ -392,7 +401,8 @@ export async function getWaterAdminSession(): Promise<{
adminUserId: string;
role: "water_admin";
} | null> {
const cookieStore = await cookies();
await getSession(); const cookieStore = await cookies();
const sessionId = cookieStore.get("wl_admin_session")?.value;
if (!sessionId) return null;
return withPlatformAdmin(async (db) => {
@@ -419,7 +429,8 @@ export async function getWaterAdminSession(): Promise<{
}
export async function setWaterLang(lang: string): Promise<void> {
if (!["en", "es"].includes(lang)) return;
await getSession(); if (!["en", "es"].includes(lang)) return;
const cookieStore = await cookies();
cookieStore.set("wl_lang", lang, {
httpOnly: false,
+9 -4
View File
@@ -24,6 +24,7 @@ import {
import { getAdminUser } from "@/lib/admin-permissions";
import { hashPin, verifyPin, validatePin, generatePin } from "@/lib/water-log-pin";
import { logAuditEvent } from "@/lib/water-log-audit";
import { getSession } from "@/lib/auth";
export type AdminSettings = {
enabled: boolean;
@@ -54,7 +55,8 @@ function mapSettings(s: WaterAdminSettings): AdminSettings {
export async function getWaterAdminSettings(
brandId: string,
): Promise<AdminSettings | null> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return null;
if (
!adminUser.can_manage_water_log &&
@@ -85,7 +87,8 @@ export async function saveWaterAdminSettings(
brandId: string,
settings: Partial<AdminSettings>,
): Promise<{ success: boolean; settings?: AdminSettings; error?: string }> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return { success: false, error: "Not authenticated" };
if (
!adminUser.can_manage_water_log &&
@@ -148,7 +151,8 @@ export async function saveWaterAdminSettings(
export async function regenerateAdminPin(
brandId: string,
): Promise<{ success: boolean; pin?: string; error?: string }> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return { success: false, error: "Not authenticated" };
if (
!adminUser.can_manage_water_log &&
@@ -189,7 +193,8 @@ export async function verifyWaterAdminPin(
brandId: string,
pin: string,
): Promise<{ success: boolean; session_id?: string; error?: string }> {
const formatError = validatePin(pin);
await getSession(); const formatError = validatePin(pin);
if (formatError) return { success: false, error: formatError };
return withBrand(brandId, async (db) => {