types: clear remaining tsc errors across 41 files (76→14, behavior-preserving)
Per-file type-only fixes surfaced after the Supabase client was correctly typed. All fixes preserve runtime behavior; no any/ts-ignore/ts-expect-error. - lib/supabase/client.ts: annotate the browser client as SupabaseClient<Database> (same ssr/js drift as server.ts; fixes it centrally for all callers). - Supabase embedded-select joins whose FK metadata is missing from the generated types are bridged with `as unknown as <target>` + a TODO to remove after regenerating types/database.ts. - setState optimistic-update variance and raw <select> enum values cast to the precise element/union type; .insert payload fields (Json, enums) given the precise column type via satisfies/field casts. - Added narrowing guards where a value was legitimately nullable (comms channel, public form page) without changing the intended path. The 14 remaining errors are confined to the four files fixed in Phase B (real bugs + the tautological actions.test rewrite). 639 tests still green. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
1766780bca
commit
b1edb5c460
+24
-3
@@ -432,7 +432,26 @@ export async function listUpcomingSessions() {
|
||||
.order('starts_at', { ascending: true })
|
||||
if (error) return { error: error.message }
|
||||
|
||||
const rows = (sessions ?? []).filter(
|
||||
// TODO(types): remove after regenerating types/database.ts (missing FK relationship metadata)
|
||||
const rows = ((sessions ?? []) as unknown as Array<{
|
||||
id: string
|
||||
class_id: string
|
||||
starts_at: string
|
||||
ends_at: string | null
|
||||
location: string | null
|
||||
capacity: number | null
|
||||
status: string
|
||||
notes: string | null
|
||||
classes: {
|
||||
title: string
|
||||
description: string | null
|
||||
payment_link: string | null
|
||||
capacity: number | null
|
||||
is_active: boolean
|
||||
grants_certification_id: string | null
|
||||
required_form_id: string | null
|
||||
} | null
|
||||
}>).filter(
|
||||
(s: { classes?: { is_active?: boolean } | null }) => s.classes?.is_active !== false,
|
||||
)
|
||||
const ids = rows.map((s: { id: string }) => s.id)
|
||||
@@ -536,7 +555,8 @@ export async function signUpForClass(input: unknown) {
|
||||
.eq('space_id', member.space_id)
|
||||
.maybeSingle()
|
||||
if (!session) return { error: 'Session not found' }
|
||||
const cls = (session as {
|
||||
// TODO(types): remove after regenerating types/database.ts (missing FK relationship metadata)
|
||||
const cls = (session as unknown as {
|
||||
classes?: { title: string | null; capacity: number | null; is_active: boolean; required_form_id: string | null } | null
|
||||
}).classes
|
||||
if (cls && cls.is_active === false) return { error: 'This class is no longer available.' }
|
||||
@@ -827,7 +847,8 @@ export async function completeSession(input: unknown) {
|
||||
.eq('space_id', member.space_id)
|
||||
if (upErr) return { error: upErr.message }
|
||||
|
||||
const cls = (session as { classes?: { title: string; grants_certification_id: string | null } | null }).classes
|
||||
// TODO(types): remove after regenerating types/database.ts (missing FK relationship metadata)
|
||||
const cls = (session as unknown as { classes?: { title: string; grants_certification_id: string | null } | null }).classes
|
||||
let issued = 0
|
||||
let certSkipped = false
|
||||
if (cls?.grants_certification_id) {
|
||||
|
||||
+2
-1
@@ -619,7 +619,8 @@ export async function listDoorCards(input: unknown) {
|
||||
|
||||
return {
|
||||
data: (cards ?? []).map(c => {
|
||||
const sm = c.space_members as { display_name: string | null } | { display_name: string | null }[] | null
|
||||
// TODO(types): remove after regenerating types/database.ts (missing FK relationship metadata)
|
||||
const sm = c.space_members as unknown as { display_name: string | null } | { display_name: string | null }[] | null
|
||||
const name = Array.isArray(sm) ? sm[0]?.display_name : sm?.display_name
|
||||
return {
|
||||
cardId: c.id as string,
|
||||
|
||||
@@ -41,6 +41,7 @@ import {
|
||||
getSpaceName,
|
||||
buildManageUrl,
|
||||
} from '@/lib/notifications/enqueue'
|
||||
import type { Json } from '@/types/database'
|
||||
|
||||
// Associate prior unlinked submissions in a space with a member by email
|
||||
// (case-insensitive, ILIKE-escaped so `_`/`%` in an address are literal).
|
||||
@@ -530,7 +531,7 @@ export async function submitForm(input: unknown) {
|
||||
space_id: form.space_id,
|
||||
member_id: linkedMemberId,
|
||||
submitter_email: submitterEmail,
|
||||
answers: answers.value,
|
||||
answers: answers.value as Json,
|
||||
form_snapshot: form.schema,
|
||||
legal_text_snapshot: form.legal_text ?? null,
|
||||
form_version: form.version,
|
||||
|
||||
@@ -5,6 +5,7 @@ import { createClient } from '@/lib/supabase/server'
|
||||
import { requireMemberWithRole } from '@/lib/auth-helpers'
|
||||
import { ADMIN_ROLES } from '@/lib/permissions'
|
||||
import { importMembersSchema } from '@/lib/validations'
|
||||
import type { TablesInsert } from '@/types/database'
|
||||
|
||||
export async function importMembers(rows: unknown) {
|
||||
if (!Array.isArray(rows) || rows.length === 0) {
|
||||
@@ -19,7 +20,7 @@ export async function importMembers(rows: unknown) {
|
||||
// Validate per row so one bad row does not reject the whole file; the
|
||||
// schema lowercases email and normalizes dates via flexibleDateTime.
|
||||
const rowSchema = importMembersSchema.element
|
||||
const valid: Array<Record<string, unknown>> = []
|
||||
const valid: Array<TablesInsert<'space_members'>> = []
|
||||
let skipped = 0
|
||||
for (const raw of rows) {
|
||||
const r = rowSchema.safeParse(raw)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { revalidatePath } from 'next/cache'
|
||||
import { createClient } from '@/lib/supabase/server'
|
||||
import { createAdminClient } from '@/lib/supabase/admin'
|
||||
import type { Json } from '@/types/database'
|
||||
import { requireMember, requireMemberWithRole, parseInput } from '@/lib/auth-helpers'
|
||||
import {
|
||||
createOnboardingStepSchema,
|
||||
@@ -45,7 +46,7 @@ export async function createOnboardingStep(input: {
|
||||
step_type: v.data.step_type,
|
||||
title: v.data.title,
|
||||
body: v.data.body ?? null,
|
||||
config: v.data.config ?? {},
|
||||
config: (v.data.config ?? {}) as Json,
|
||||
is_enabled: v.data.is_enabled ?? true,
|
||||
is_required: v.data.is_required ?? false,
|
||||
is_system: false,
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
linkPaymentSchema,
|
||||
importPaymentsCsvSchema,
|
||||
} from '@/lib/validations'
|
||||
import type { Enums } from '@/types/database'
|
||||
import type { Enums, TablesInsert } from '@/types/database'
|
||||
|
||||
type PaymentPlatform = Enums<'payment_platform'>
|
||||
|
||||
@@ -131,7 +131,7 @@ export async function importPaymentsCsv(rows: unknown) {
|
||||
// transaction_date. Invalid rows are skipped and counted, not silently
|
||||
// dropped without feedback.
|
||||
const rowSchema = importPaymentsCsvSchema.element
|
||||
const inserts: Array<Record<string, unknown>> = []
|
||||
const inserts: Array<TablesInsert<'payments'>> = []
|
||||
let skipped = 0
|
||||
for (const raw of rows) {
|
||||
const r = rowSchema.safeParse(raw)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { revalidatePath } from 'next/cache'
|
||||
import { createClient } from '@/lib/supabase/server'
|
||||
import type { TablesInsert } from '@/types/database'
|
||||
import { requireMember, requireMemberWithRole, parseInput } from '@/lib/auth-helpers'
|
||||
import { ADMIN_ROLES } from '@/lib/permissions'
|
||||
import { createSecretSchema, updateSecretSchema, uuidSchema } from '@/lib/validations'
|
||||
@@ -45,7 +46,7 @@ export async function createSecret(formData: {
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('secrets')
|
||||
.insert(row)
|
||||
.insert(row as TablesInsert<'secrets'>)
|
||||
.select('id, title, label, area, description, icon, encryption_version, created_at, updated_at, space_id, created_by')
|
||||
.single()
|
||||
|
||||
|
||||
@@ -257,7 +257,8 @@ export async function listMemberBilling() {
|
||||
if (error) return { error: error.message }
|
||||
return {
|
||||
data: (data ?? []).map(r => {
|
||||
const sm = r.space_members as { display_name: string | null; email: string | null; tier: string | null } | { display_name: string | null; email: string | null; tier: string | null }[] | null
|
||||
// TODO(types): remove after regenerating types/database.ts (missing FK relationship metadata)
|
||||
const sm = r.space_members as unknown as { display_name: string | null; email: string | null; tier: string | null } | { display_name: string | null; email: string | null; tier: string | null }[] | null
|
||||
const mem = Array.isArray(sm) ? sm[0] : sm
|
||||
return {
|
||||
memberId: r.member_id as string,
|
||||
|
||||
Reference in New Issue
Block a user