import { CollectionConfig, Property } from "@rebasepro/types"; export type IssueSeverity = "error" | "warning" | "info"; export interface DoctorIssue { severity: IssueSeverity; category: "missing_table" | "missing_column" | "type_mismatch" | "missing_constraint" | "schema_stale" | "missing_enum" | "enum_value_mismatch" | "missing_foreign_key" | "sdk_stale" | "sdk_not_generated" | "sdk_ungeneratable"; table?: string; column?: string; expected?: string; actual?: string; message: string; fix: string; } export interface DoctorPhase { passed: boolean; issues: DoctorIssue[]; /** * Why this phase never ran, when it did not. * * A check that did not happen is a third state, not a passing one. While a * skipped phase initialised to `{ passed: true, issues: [] }` it rendered as * `✅ Collections → Database: In sync` and counted towards * `✓ All schemas are in sync!` — so a project whose connection string was * spelled `POSTGRES_URL`, or a CI job that never exported one, got two green * ticks and exit 0 against a database with no tables in it. */ skipped?: string; /** * Why this phase had nothing to compare against, when it had nothing. * * Distinct from `skipped`, which means "the check could not run, and that * is probably worth fixing". This one means "the artifact is optional and * you have not asked for it": no drift is possible, so the run is still a * clean bill of health. * * It exists because the alternative was a contradiction. The typed-SDK * phase returned `{ passed: true }` when `generated/sdk/database.types.ts` * did not exist, so a fresh project's report read * `✅ Collections → SDK Types: In sync` directly above * `ℹ Typed SDK not generated (optional).` — one line calling a file * synchronised and the next saying it is absent. "In sync" is a claim about * a comparison, and no comparison happened. */ notApplicable?: string; } export interface DoctorReport { collectionsToSchema: DoctorPhase; collectionsToSdk: DoctorPhase; schemaToDatabase: DoctorPhase; summary: { passed: number; skipped: number; notApplicable: number; warnings: number; errors: number; }; } export declare function getExpectedColumnType(prop: Property): string | null; /** * Re-exported so callers keep importing it from here, but the implementation is * now shared with the runtime and the generators — a doctor that disagreed with * the policy generator about which files are collections would compare the * wrong thing. */ export declare function loadCollections(collectionsPath: string): Promise; export declare function checkCollectionsVsSchema(collections: CollectionConfig[], schemaFilePath: string): Promise; export declare function checkCollectionsVsSdk(collections: CollectionConfig[], sdkFilePath: string): Promise; export declare function checkCollectionsVsDatabase(collections: CollectionConfig[], databaseUrl: string): Promise; export declare function renderReport(report: DoctorReport): void; export declare function runDoctor(options: { collectionsPath: string; schemaPath: string; sdkPath: string; databaseUrl?: string; }): Promise;