UNPKG

everything-dev

Version:

A consolidated product package for building Module Federation apps with oRPC APIs.

131 lines (129 loc) 4.73 kB
const require_runtime = require('../_virtual/_rolldown/runtime.cjs'); const require_db = require('../db.cjs'); let node_fs = require("node:fs"); let node_path = require("node:path"); let node_crypto = require("node:crypto"); //#region src/cli/db-doctor.ts function hashFile(raw) { return (0, node_crypto.createHash)("sha256").update(raw).digest("hex"); } function readLocalMigrations(workspaceDir) { const migrationsDir = (0, node_path.resolve)(workspaceDir, "src/db/migrations"); const journalPath = (0, node_path.join)((0, node_path.join)(migrationsDir, "meta"), "_journal.json"); if (!(0, node_fs.existsSync)(journalPath)) return []; return JSON.parse((0, node_fs.readFileSync)(journalPath, "utf8")).entries.map((entry) => { const sqlPath = (0, node_path.join)(migrationsDir, `${entry.tag}.sql`); if (!(0, node_fs.existsSync)(sqlPath)) return { tag: entry.tag, hash: "", sql: [] }; const raw = (0, node_fs.readFileSync)(sqlPath, "utf8"); const sql = raw.split("--> statement-breakpoint").map((s) => s.trim()); return { tag: entry.tag, hash: hashFile(raw), sql }; }); } async function diagnosePlugin(info) { const { Pool } = await Promise.resolve().then(() => require("../node_modules/pg/esm/index.cjs")); const slug = require_db.pluginMigrationSlug(info.key); const journalTable = `__drizzle_migrations_${slug}`; const journalSchema = "drizzle"; const journalRef = `"${journalSchema}"."${journalTable}"`; const localMigrations = info.workspaceDir ? readLocalMigrations(info.workspaceDir) : []; const expectedTables = require_db.extractExpectedTables(localMigrations); const localHashes = localMigrations.map((m) => m.hash).filter(Boolean); const migrationHashes = localHashes; const pool = new Pool({ connectionString: info.databaseUrl, ssl: info.databaseUrl.includes("localhost") || info.databaseUrl.includes("127.0.0.1") ? false : { rejectUnauthorized: false }, max: 1, connectionTimeoutMillis: 1e4 }); try { const journalExists = await pool.query(` SELECT EXISTS ( SELECT 1 FROM information_schema.tables WHERE table_schema = '${journalSchema}' AND table_name = '${journalTable}' ) AS exists `); let appliedHashCount = 0; if (journalExists.rows[0]?.exists) appliedHashCount = (await pool.query(`SELECT hash FROM ${journalRef}`)).rows.length; let missingTables = []; if (expectedTables.length > 0) { const tableResult = await pool.query(` SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name = ANY($1) `, [expectedTables]); const existing = new Set(tableResult.rows.map((r) => r.table_name)); missingTables = expectedTables.filter((t) => !existing.has(t)); } const legacyCount = await countLegacyHashes(pool, localHashes); let diagnosis; if (localMigrations.length === 0) diagnosis = "no-local-migrations"; else if (appliedHashCount === 0 && localHashes.length > 0) diagnosis = legacyCount > 0 ? "legacy-importable" : "unapplied"; else if (missingTables.length === 0) diagnosis = "healthy"; else if (missingTables.length === expectedTables.length) diagnosis = "drift-safe-repair"; else diagnosis = "drift-manual"; const masked = info.databaseUrl.replace(/\/\/[^:]+:[^@]+@/, "//***:***@"); return { plugin: info.key, slug, journalTable, journalSchema, dbSecret: info.databaseSecret, dbUrl: masked, workspaceDir: info.workspaceDir, localMigrationCount: localMigrations.length, appliedHashCount, expectedTables, missingTables, migrationHashes, diagnosis, legacyCount }; } catch (error) { return { plugin: info.key, slug, journalTable, journalSchema, dbSecret: info.databaseSecret, dbUrl: info.databaseUrl.replace(/\/\/[^:]+:[^@]+@/, "//***:***@"), workspaceDir: info.workspaceDir, localMigrationCount: localMigrations.length, appliedHashCount: 0, expectedTables, missingTables: [], migrationHashes: [], diagnosis: "error", legacyCount: 0, error: error instanceof Error ? error.message : String(error) }; } finally { await pool.end().catch(() => {}); } } async function countLegacyHashes(pool, localHashes) { if (localHashes.length === 0) return 0; const candidates = [{ schema: "drizzle", table: "__drizzle_migrations" }, { schema: "public", table: "drizzle_migrations" }]; let total = 0; for (const c of candidates) try { const result = await pool.query(`SELECT count(*)::int AS cnt FROM "${c.schema}"."${c.table}" WHERE hash = ANY($1)`, [localHashes]); total += result.rows[0]?.cnt ?? 0; } catch {} return total; } //#endregion exports.diagnosePlugin = diagnosePlugin; //# sourceMappingURL=db-doctor.cjs.map