diff --git a/biome.json b/biome.json index 927d7d8..1292631 100644 --- a/biome.json +++ b/biome.json @@ -24,6 +24,13 @@ }, "correctness": { "noReactPropAssignments": "error" + }, + "style": { + "noNonNullAssertion": "error" + }, + "suspicious": { + "noExplicitAny": "error", + "noTsIgnore": "error" } } }, diff --git a/compile.ts b/compile.ts index 301bf65..7a9471b 100644 --- a/compile.ts +++ b/compile.ts @@ -12,8 +12,9 @@ const SUPPORTED_TARGETS: readonly Bun.Build.CompileTarget[] = [ 'bun-linux-arm64', ] -const isSupportedTarget = (value: string): value is Bun.Build.CompileTarget => - (SUPPORTED_TARGETS as readonly string[]).includes(value) +const SUPPORTED_TARGET_SET: ReadonlySet = new Set(SUPPORTED_TARGETS) + +const isSupportedTarget = (value: string): value is Bun.Build.CompileTarget => SUPPORTED_TARGET_SET.has(value) const { values } = parseArgs({ options: { target: { type: 'string' } }, diff --git a/embed-migrations.ts b/embed-migrations.ts index 8285ba2..cda7516 100644 --- a/embed-migrations.ts +++ b/embed-migrations.ts @@ -1,17 +1,31 @@ import { existsSync } from 'node:fs' import { readFile, writeFile } from 'node:fs/promises' +import { z } from 'zod' const JOURNAL = './drizzle/meta/_journal.json' const OUTPUT = './src/server/db/migrations.gen.ts' const SQL_RELATIVE_FROM_OUTPUT = '../../../drizzle' -type JournalEntry = { idx: number; tag: string; when: number; breakpoints: boolean } -type Journal = { entries: JournalEntry[] } +const journalEntrySchema = z.object({ + idx: z.number(), + tag: z.string(), + when: z.number(), + breakpoints: z.boolean(), +}) +const journalSchema = z.object({ entries: z.array(journalEntrySchema).default([]) }) + +type JournalEntry = z.infer + +const readJournalEntries = async (): Promise => { + if (!existsSync(JOURNAL)) { + return [] + } + const raw: unknown = JSON.parse(await readFile(JOURNAL, 'utf-8')) + return journalSchema.parse(raw).entries.sort((a, b) => a.idx - b.idx) +} const main = async () => { - const entries: JournalEntry[] = existsSync(JOURNAL) - ? ((JSON.parse(await readFile(JOURNAL, 'utf-8')) as Journal).entries ?? []).sort((a, b) => a.idx - b.idx) - : [] + const entries = await readJournalEntries() const imports = entries .map((e) => `import sql_${e.idx} from '${SQL_RELATIVE_FROM_OUTPUT}/${e.tag}.sql' with { type: 'text' }`) diff --git a/src/server/api/interceptors.ts b/src/server/api/interceptors.ts index 1b0fbb7..8ba6f18 100644 --- a/src/server/api/interceptors.ts +++ b/src/server/api/interceptors.ts @@ -8,7 +8,8 @@ export const logError = (error: unknown) => { export const handleValidationError = (error: unknown) => { if (error instanceof ORPCError && error.code === 'BAD_REQUEST' && error.cause instanceof ValidationError) { - // ORPC ValidationError.issues are Zod issues in this app. + // ORPC widens issues to the Standard Schema shape; every contract here is built from Zod/drizzle-zod, + // so the runtime objects are Zod issues. Rehydrate to reuse z.prettifyError / z.flattenError. const zodError = new z.ZodError(error.cause.issues as z.core.$ZodIssue[]) throw new ORPCError('INPUT_VALIDATION_FAILED', { diff --git a/src/server/db/fields.ts b/src/server/db/fields.ts index f7868d9..e02b497 100644 --- a/src/server/db/fields.ts +++ b/src/server/db/fields.ts @@ -12,4 +12,10 @@ export const generatedFields = { .$onUpdateFn(() => new Date()), } -export const generatedFieldKeys = { id: true, createdAt: true, updatedAt: true } as const +type GeneratedFieldKey = keyof typeof generatedFields + +export const generatedFieldKeys = { + id: true, + createdAt: true, + updatedAt: true, +} satisfies Record