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
+9 -4
View File
@@ -5,6 +5,7 @@ import { getAdminUser } from "@/lib/admin-permissions";
import { getActiveBrandId } from "@/lib/brand-scope";
import { withBrand, withPlatformAdmin } from "@/db/client";
import { campaigns, emailTemplates } from "@/db/schema";
import { getSession } from "@/lib/auth";
export type CampaignType = "marketing" | "operational" | "transactional";
export type CampaignStatus = "draft" | "scheduled" | "sending" | "sent" | "canceled";
@@ -101,7 +102,8 @@ function rowToCampaign(c: CampaignRow, t?: TemplateRow | null): Campaign {
}
export async function getCommunicationCampaigns(brandId?: string): Promise<ListCampaignsResult> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return { success: false, error: "Not authenticated" };
const activeBrandId = await getActiveBrandId(adminUser, brandId);
@@ -165,7 +167,8 @@ export async function upsertCampaign(params: {
audience_rules?: AudienceRules;
scheduled_at?: string;
}): Promise<UpsertCampaignResult> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return { success: false, error: "Not authenticated" };
if (adminUser.role === "brand_admin" && adminUser.brand_id !== params.brand_id) {
@@ -263,7 +266,8 @@ export async function upsertCampaign(params: {
}
export async function deleteCampaign(campaignId: string, brandId?: string): Promise<{ success: boolean; error?: string }> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return { success: false, error: "Not authenticated" };
const activeBrandId = await getActiveBrandId(adminUser, brandId);
@@ -290,7 +294,8 @@ export async function deleteCampaign(campaignId: string, brandId?: string): Prom
}
export async function getCampaignById(campaignId: string, brandId?: string): Promise<Campaign | null> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return null;
const activeBrandId = await getActiveBrandId(adminUser, brandId);
+15 -7
View File
@@ -6,6 +6,7 @@ import { parseCSVWithLimits } from "@/lib/csv-parser";
import { buildImportPreview } from "@/lib/column-detector";
import { withBrand, withPlatformAdmin } from "@/db/client";
import { customers } from "@/db/schema";
import { getSession } from "@/lib/auth";
export type ContactSource = "order" | "import" | "manual" | "admin";
@@ -134,7 +135,8 @@ export async function getContacts(params: {
limit?: number;
offset?: number;
}): Promise<GetContactsResult> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return { success: false, error: "Not authenticated" };
if (
adminUser.role === "brand_admin" &&
@@ -210,7 +212,8 @@ export async function upsertContact(contact: {
tags?: string[];
metadata?: Record<string, unknown>;
}): Promise<UpsertContactResult> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return { success: false, error: "Not authenticated" };
if (
adminUser.role === "brand_admin" &&
@@ -327,7 +330,8 @@ export async function importContactsBatch(params: {
contacts: ContactImportEntry[];
allowOptInOverride?: boolean;
}): Promise<ImportContactsResult> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return { success: false, error: "Not authenticated" };
if (
adminUser.role === "brand_admin" &&
@@ -385,7 +389,8 @@ export async function optOutContact(params: {
brandId: string;
method: "email" | "sms";
}): Promise<OptOutResult> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return { success: false, error: "Not authenticated" };
if (
adminUser.role === "brand_admin" &&
@@ -414,7 +419,8 @@ export async function optOutContact(params: {
}
export async function deleteContact(id: string, brandId?: string): Promise<{ success: boolean; error?: string }> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return { success: false, error: "Not authenticated" };
if (
adminUser.role === "brand_admin" &&
@@ -470,7 +476,8 @@ export async function exportContacts(params: {
search?: string;
source?: string;
}): Promise<ExportContactsResult> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return { success: false, error: "Not authenticated" };
const effectiveBrandId =
@@ -551,7 +558,8 @@ export async function exportContacts(params: {
export async function previewContactImport(
csvText: string
): Promise<{ success: true; preview: ImportPreviewResult } | { success: false; error: string }> {
try {
await getSession(); try {
const { csv, totalRows, warnings } = parseCSVWithLimits(csvText);
if (warnings.length > 0 && totalRows === 0) {
@@ -4,6 +4,7 @@ import { and, desc, eq } from "drizzle-orm";
import { getAdminUser } from "@/lib/admin-permissions";
import { withBrand, withPlatformAdmin } from "@/db/client";
import { files } from "@/db/schema";
import { getSession } from "@/lib/auth";
import {
importContactsBatch,
previewContactImport,
@@ -26,7 +27,8 @@ export async function uploadContactsToBucket(
brandId: string,
file: File
): Promise<UploadContactsResult> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return { success: false, error: "Not authenticated" };
// Validate file type
@@ -98,7 +100,8 @@ export async function processBucketImport(
allowOptInOverride: boolean = false,
rows?: ContactImportEntry[]
): Promise<ProcessImportResult> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return { success: false, error: "Not authenticated" };
if (!rows || rows.length === 0) {
@@ -126,7 +129,8 @@ export async function listImportHistory(
brandId: string,
limit: number = 10
): Promise<{ success: true; imports: ImportHistoryItem[] } | { success: false; error: string }> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return { success: false, error: "Not authenticated" };
try {
+7 -3
View File
@@ -5,6 +5,7 @@ import { getAdminUser } from "@/lib/admin-permissions";
import { withBrand } from "@/db/client";
import { brandSettings } from "@/db/schema";
import type { AudienceRules } from "./campaigns";
import { getSession } from "@/lib/auth";
/**
* The new schema does not have a `communication_segments` table.
@@ -88,7 +89,8 @@ async function saveSegments(brandId: string, segments: Segment[]): Promise<void>
export async function getCommunicationSegments(
brandId: string
): Promise<ListSegmentsResult> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return { success: false, error: "Not authenticated" };
if (adminUser.role === "brand_admin" && adminUser.brand_id !== brandId) {
@@ -113,7 +115,8 @@ export async function upsertSegment(params: {
description?: string;
rules: AudienceRules;
}): Promise<UpsertSegmentResult> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return { success: false, error: "Not authenticated" };
if (adminUser.role === "brand_admin" && adminUser.brand_id !== params.brand_id) {
@@ -164,7 +167,8 @@ export async function deleteSegment(
segmentId: string,
brandId: string
): Promise<{ success: boolean; error?: string }> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return { success: false, error: "Not authenticated" };
if (adminUser.role === "brand_admin" && adminUser.brand_id !== brandId) {
+7 -3
View File
@@ -6,6 +6,7 @@ import { getActiveBrandId } from "@/lib/brand-scope";
import { withBrand, withPlatformAdmin } from "@/db/client";
import { campaigns, customers } from "@/db/schema";
import type { AudienceRules } from "./campaigns";
import { getSession } from "@/lib/auth";
export type AudiencePreviewResult = {
count: number;
@@ -24,7 +25,8 @@ export async function previewCampaignAudience(
brandId: string,
audienceRules: AudienceRules
): Promise<AudiencePreviewResult | null> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return null;
if (adminUser.role === "brand_admin" && adminUser.brand_id !== brandId) {
@@ -112,7 +114,8 @@ export async function getMessageLogs(params: {
status?: string;
limit?: number;
}): Promise<GetMessageLogsResult> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return { success: false, error: "Not authenticated" };
if (adminUser.role === "brand_admin" && adminUser.brand_id !== params.brandId) {
@@ -140,7 +143,8 @@ export type SendCampaignResult = {
* status-transition that unblocks the UI.
*/
export async function sendCampaign(campaignId: string, brandId?: string): Promise<SendCampaignResult> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return { success: false, error: "Not authenticated" };
const activeBrandId = await getActiveBrandId(adminUser, brandId);
+5 -2
View File
@@ -4,6 +4,7 @@ import { getAdminUser } from "@/lib/admin-permissions";
import { withBrand } from "@/db/client";
import { brandSettings } from "@/db/schema";
import { eq } from "drizzle-orm";
import { getSession } from "@/lib/auth";
/**
* The new schema does not have a `communication_settings` table. The
@@ -46,7 +47,8 @@ function readFlag(
}
export async function getCommunicationSettings(brandId: string): Promise<CommunicationSettings | null> {
try {
await getSession(); try {
const rows = await withBrand(brandId, (db) =>
db
.select({
@@ -88,7 +90,8 @@ export async function upsertCommunicationSettings(params: {
provider?: string;
footer_html?: string;
}): Promise<UpsertSettingsResult> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return { success: false, error: "Not authenticated" };
if (adminUser.role === "brand_admin" && adminUser.brand_id !== params.brand_id) {
+3 -1
View File
@@ -4,6 +4,7 @@ import { and, eq, sql, SQL } from "drizzle-orm";
import { getAdminUser } from "@/lib/admin-permissions";
import { withBrand } from "@/db/client";
import { customers, orders, campaigns, emailTemplates } from "@/db/schema";
import { getSession } from "@/lib/auth";
export type StopBlastResult =
| { success: true; campaign_id: string; messages_logged: number }
@@ -29,7 +30,8 @@ export async function sendStopBlast(params: {
body: string;
audience: "all" | "pending" | "picked_up";
}): Promise<StopBlastResult> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return { success: false, error: "Not authenticated" };
if (adminUser.role === "brand_admin" && adminUser.brand_id !== params.brandId) {
+3 -1
View File
@@ -4,6 +4,7 @@ import { and, desc, eq, isNotNull } from "drizzle-orm";
import { getAdminUser } from "@/lib/admin-permissions";
import { withBrand } from "@/db/client";
import { customers, orders, campaigns } from "@/db/schema";
import { getSession } from "@/lib/auth";
/**
* Server-side data loader for the per-stop "Message customers" panel.
@@ -45,7 +46,8 @@ export async function getStopMessagingData(params: {
stopId: string;
brandId?: string;
}): Promise<GetStopMessagingDataResult> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return { success: false, error: "Not authenticated" };
// We don't filter by `stopId` because the new `orders` table has no
+7 -3
View File
@@ -5,6 +5,7 @@ import { getAdminUser } from "@/lib/admin-permissions";
import { getActiveBrandId } from "@/lib/brand-scope";
import { withBrand, withPlatformAdmin } from "@/db/client";
import { emailTemplates } from "@/db/schema";
import { getSession } from "@/lib/auth";
export type TemplateType = "email_template" | "sms_template" | "internal_note";
export type CampaignType = "marketing" | "operational" | "transactional";
@@ -65,7 +66,8 @@ function stripHtml(html: string): string {
}
export async function getCommunicationTemplates(brandId?: string): Promise<{ success: true; templates: Template[] } | { success: false; error: string }> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return { success: false, error: "Not authenticated" };
const activeBrandId = await getActiveBrandId(adminUser, brandId);
@@ -111,7 +113,8 @@ export async function upsertTemplate(params: {
template_type: TemplateType;
campaign_type?: CampaignType;
}): Promise<UpsertTemplateResult> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return { success: false, error: "Not authenticated" };
const bodyHtml =
@@ -163,7 +166,8 @@ export async function upsertTemplate(params: {
}
export async function getTemplateById(templateId: string): Promise<Template | null> {
const adminUser = await getAdminUser();
await getSession(); const adminUser = await getAdminUser();
if (!adminUser) return null;
const activeBrandId = await getActiveBrandId(adminUser);