From 21db4d0e64cb41893b284ee9526afd43fcbd250a Mon Sep 17 00:00:00 2001 From: sjcoetzeesj-coder Date: Sun, 18 Oct 2026 15:48:50 +0200 Subject: [PATCH] fix: resolve all 7 type errors that broke the production build next build runs 'Linting and checking validity of types' and fails on the first type error, so the Coolify image build died at app/api/cipc/search/route.ts:640. These errors were pre-existing but only surface on next build (npm run dev does not type check). - cipc/search/route.ts: coerce spawnSync stdout/stderr with toString(); result is typed as the un-overloaded return, so they are string|Buffer - group-report pdf+email: use fetchCollection instead of an invalid cast; normalise description null -> undefined for ReportData - CipcExplorer (cipc + cipc-2): split the state ternary into two returns; the RowState union correlates state with differs, so 'diff' | 'match' matched neither variant - ComplianceTreeGrid: ar_non_compliance_date is optional; the API omits it and this component never reads it Verified: tsc --noEmit 0 errors, next build exit 0, standalone output ok. --- Workflow/app/api/cipc/search/route.ts | 7 +++++-- Workflow/app/api/group-report/[id]/email/route.ts | 8 ++++---- Workflow/app/api/group-report/[id]/pdf/route.ts | 8 ++++---- Workflow/app/cipc-2/CipcExplorer.tsx | 14 +++++++------- Workflow/app/cipc/CipcExplorer.tsx | 14 +++++++------- Workflow/components/ComplianceTreeGrid.tsx | 4 +++- 6 files changed, 30 insertions(+), 25 deletions(-) diff --git a/Workflow/app/api/cipc/search/route.ts b/Workflow/app/api/cipc/search/route.ts index 6165ffa..1de7633 100644 --- a/Workflow/app/api/cipc/search/route.ts +++ b/Workflow/app/api/cipc/search/route.ts @@ -637,8 +637,11 @@ export async function POST(req: NextRequest) { ); } duration = Date.now() - start; - stdout = result.stdout || ""; - stderr = result.stderr || ""; + // `result` is typed as the un-overloaded spawnSync return, so stdout/stderr + // are `string | Buffer`. encoding: "utf-8" is set above, but toString() + // is a no-op on a string and the correct decode if that ever changes. + stdout = result.stdout?.toString() ?? ""; + stderr = result.stderr?.toString() ?? ""; exitCode = result.status; wrapperUsed = false; } else { diff --git a/Workflow/app/api/group-report/[id]/email/route.ts b/Workflow/app/api/group-report/[id]/email/route.ts index 6b47ca9..d7d6561 100644 --- a/Workflow/app/api/group-report/[id]/email/route.ts +++ b/Workflow/app/api/group-report/[id]/email/route.ts @@ -14,7 +14,7 @@ import { HIMALAYA_BIN, himalayaSendArgs } from "@/lib/himalaya"; import { fetchCollection, fetchJunctionEntriesForCompany } from "@/lib/pb"; import { buildGroupReportBlocks, groupReportFilename, groupReportTitle } from "@/lib/report"; import { renderPdf } from "@/lib/pdf-render"; -import type { YsterbaardCompany, YsterbaardDirector } from "@/lib/types"; +import type { YsterbaardCompany, YsterbaardDirector, YsterbaardGroup } from "@/lib/types"; export const dynamic = "force-dynamic"; @@ -41,11 +41,11 @@ export async function POST( } // ── Fetch group ───────────────────────────────────────────────────────── - const gResult = await fetchCollection("groups", { filter: `id="${id}"` }); + const gResult = await fetchCollection("groups", { filter: `id="${id}"` }); if (!gResult.items.length) { return NextResponse.json({ error: "Group not found" }, { status: 404 }); } - const group = gResult.items[0] as { id: string; name: string; description?: string }; + const group = gResult.items[0]; // ── Fetch all companies in this group ───────────────────────────────── const companiesResult = await fetchCollection("ysterbaard_companies", { @@ -82,7 +82,7 @@ export async function POST( // ── Build report blocks ──────────────────────────────────────────────── const reportData = { - group: { id: group.id, name: group.name, description: group.description }, + group: { id: group.id, name: group.name, description: group.description ?? undefined }, companies, directors, companyDirectors, diff --git a/Workflow/app/api/group-report/[id]/pdf/route.ts b/Workflow/app/api/group-report/[id]/pdf/route.ts index 6b10417..977b8dd 100644 --- a/Workflow/app/api/group-report/[id]/pdf/route.ts +++ b/Workflow/app/api/group-report/[id]/pdf/route.ts @@ -7,7 +7,7 @@ import { NextRequest, NextResponse } from "next/server"; import { fetchCollection, fetchJunctionEntriesForCompany } from "@/lib/pb"; import { buildGroupReportBlocks, groupReportFilename, groupReportTitle } from "@/lib/report"; import { renderPdf } from "@/lib/pdf-render"; -import type { YsterbaardCompany, YsterbaardDirector } from "@/lib/types"; +import type { YsterbaardCompany, YsterbaardDirector, YsterbaardGroup } from "@/lib/types"; import { promises as fs } from "fs"; import os from "os"; import path from "path"; @@ -23,11 +23,11 @@ export async function GET( const { id } = await params; // ── Fetch group ───────────────────────────────────────────────────────── - const gResult = await fetchCollection("groups", { filter: `id="${id}"` }); + const gResult = await fetchCollection("groups", { filter: `id="${id}"` }); if (!gResult.items.length) { return NextResponse.json({ error: "Group not found" }, { status: 404 }); } - const group = gResult.items[0] as { id: string; name: string; description?: string }; + const group = gResult.items[0]; // ── Fetch all companies in this group ───────────────────────────────── // Companies are linked to groups via a `groups` multi-relation field @@ -68,7 +68,7 @@ export async function GET( // ── Build report ─────────────────────────────────────────────────────── const reportData = { - group: { id: group.id, name: group.name, description: group.description }, + group: { id: group.id, name: group.name, description: group.description ?? undefined }, companies, directors, companyDirectors, diff --git a/Workflow/app/cipc-2/CipcExplorer.tsx b/Workflow/app/cipc-2/CipcExplorer.tsx index 298dd29..80d886f 100644 --- a/Workflow/app/cipc-2/CipcExplorer.tsx +++ b/Workflow/app/cipc-2/CipcExplorer.tsx @@ -1794,13 +1794,13 @@ function KvSectionWithDiff({ if (!m.updatable) { return { state: "readonly", cipcValue, pbValue, differs }; } - return { - state: differs ? "diff" : "match", - cipcValue, - pbValue, - field: m.field, - differs, - }; + // Split into two returns: the RowState union correlates `state` with + // `differs`, so a single `state: differs ? "diff" : "match"` infers a + // "diff" | "match" union that matches neither variant. + if (differs) { + return { state: "diff", cipcValue, pbValue, field: m.field, differs: true }; + } + return { state: "match", cipcValue, pbValue, field: m.field, differs: false }; }); const selectableRowStates = rowStates.filter((r) => r.state === "diff"); diff --git a/Workflow/app/cipc/CipcExplorer.tsx b/Workflow/app/cipc/CipcExplorer.tsx index 7f3baaf..b734e72 100644 --- a/Workflow/app/cipc/CipcExplorer.tsx +++ b/Workflow/app/cipc/CipcExplorer.tsx @@ -1034,13 +1034,13 @@ function KvSectionWithDiff({ if (!m.updatable) { return { state: "readonly", cipcValue, pbValue, differs }; } - return { - state: differs ? "diff" : "match", - cipcValue, - pbValue, - field: m.field, - differs, - }; + // Split into two returns: the RowState union correlates `state` with + // `differs`, so a single `state: differs ? "diff" : "match"` infers a + // "diff" | "match" union that matches neither variant. + if (differs) { + return { state: "diff", cipcValue, pbValue, field: m.field, differs: true }; + } + return { state: "match", cipcValue, pbValue, field: m.field, differs: false }; }); const selectableRowStates = rowStates.filter((r) => r.state === "diff"); diff --git a/Workflow/components/ComplianceTreeGrid.tsx b/Workflow/components/ComplianceTreeGrid.tsx index c5498f1..7bf5571 100644 --- a/Workflow/components/ComplianceTreeGrid.tsx +++ b/Workflow/components/ComplianceTreeGrid.tsx @@ -66,7 +66,9 @@ type AnnualReturn = { is_filed: boolean; date_filed: string; amount_paid: number; - ar_non_compliance_date: string; + // Optional: the /api/compliance payload only includes it when the + // PocketBase collection has the field. Unused in this component. + ar_non_compliance_date?: string; }; type IRP6Record = {