everything-dev 1.47.2 → 1.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/_rolldown/runtime.cjs +2 -0
- package/dist/_virtual/_rolldown/runtime.mjs +32 -0
- package/dist/cli/db-doctor.cjs +131 -0
- package/dist/cli/db-doctor.cjs.map +1 -0
- package/dist/cli/db-doctor.mjs +130 -0
- package/dist/cli/db-doctor.mjs.map +1 -0
- package/dist/cli/db-repair.cjs +115 -0
- package/dist/cli/db-repair.cjs.map +1 -0
- package/dist/cli/db-repair.mjs +114 -0
- package/dist/cli/db-repair.mjs.map +1 -0
- package/dist/cli/db-studio.cjs +6 -0
- package/dist/cli/db-studio.cjs.map +1 -1
- package/dist/cli/db-studio.mjs +6 -0
- package/dist/cli/db-studio.mjs.map +1 -1
- package/dist/cli/init.cjs +4 -0
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.d.cts.map +1 -1
- package/dist/cli/init.d.mts.map +1 -1
- package/dist/cli/init.mjs +4 -0
- package/dist/cli/init.mjs.map +1 -1
- package/dist/cli/sync.cjs +18 -2
- package/dist/cli/sync.cjs.map +1 -1
- package/dist/cli/sync.mjs +18 -2
- package/dist/cli/sync.mjs.map +1 -1
- package/dist/cli.cjs +46 -0
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +46 -0
- package/dist/cli.mjs.map +1 -1
- package/dist/contract.cjs +46 -1
- package/dist/contract.cjs.map +1 -1
- package/dist/contract.d.cts +101 -17
- package/dist/contract.d.cts.map +1 -1
- package/dist/contract.d.mts +101 -17
- package/dist/contract.d.mts.map +1 -1
- package/dist/contract.meta.cjs +20 -0
- package/dist/contract.meta.cjs.map +1 -1
- package/dist/contract.meta.d.cts +26 -0
- package/dist/contract.meta.d.mts +26 -0
- package/dist/contract.meta.mjs +20 -0
- package/dist/contract.meta.mjs.map +1 -1
- package/dist/contract.mjs +43 -2
- package/dist/contract.mjs.map +1 -1
- package/dist/db.cjs +74 -0
- package/dist/db.cjs.map +1 -0
- package/dist/db.d.cts +23 -0
- package/dist/db.d.cts.map +1 -0
- package/dist/db.d.mts +23 -0
- package/dist/db.d.mts.map +1 -0
- package/dist/db.mjs +66 -0
- package/dist/db.mjs.map +1 -0
- package/dist/index.cjs +4 -0
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/plugin.cjs +93 -0
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.d.cts +46 -7
- package/dist/plugin.d.mts +46 -7
- package/dist/plugin.mjs +93 -0
- package/dist/plugin.mjs.map +1 -1
- package/dist/types.d.cts +2 -2
- package/dist/types.d.mts +2 -2
- package/package.json +8 -3
|
@@ -5,6 +5,7 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
8
9
|
var __copyProps = (to, from, except, desc) => {
|
|
9
10
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
11
|
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
@@ -26,4 +27,5 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
27
|
|
|
27
28
|
//#endregion
|
|
28
29
|
|
|
30
|
+
exports.__commonJSMin = __commonJSMin;
|
|
29
31
|
exports.__toESM = __toESM;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
|
|
3
|
+
//#region \0rolldown/runtime.js
|
|
4
|
+
var __create = Object.create;
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
9
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
10
|
+
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
14
|
+
key = keys[i];
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
16
|
+
__defProp(to, key, {
|
|
17
|
+
get: ((k) => from[k]).bind(null, key),
|
|
18
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return to;
|
|
24
|
+
};
|
|
25
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
26
|
+
value: mod,
|
|
27
|
+
enumerable: true
|
|
28
|
+
}) : target, mod));
|
|
29
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
30
|
+
|
|
31
|
+
//#endregion
|
|
32
|
+
export { __commonJSMin, __require, __toESM };
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
|
|
2
|
+
const require_db = require('../db.cjs');
|
|
3
|
+
let node_fs = require("node:fs");
|
|
4
|
+
let node_path = require("node:path");
|
|
5
|
+
let node_crypto = require("node:crypto");
|
|
6
|
+
|
|
7
|
+
//#region src/cli/db-doctor.ts
|
|
8
|
+
function hashFile(raw) {
|
|
9
|
+
return (0, node_crypto.createHash)("sha256").update(raw).digest("hex");
|
|
10
|
+
}
|
|
11
|
+
function readLocalMigrations(workspaceDir) {
|
|
12
|
+
const migrationsDir = (0, node_path.resolve)(workspaceDir, "src/db/migrations");
|
|
13
|
+
const journalPath = (0, node_path.join)((0, node_path.join)(migrationsDir, "meta"), "_journal.json");
|
|
14
|
+
if (!(0, node_fs.existsSync)(journalPath)) return [];
|
|
15
|
+
return JSON.parse((0, node_fs.readFileSync)(journalPath, "utf8")).entries.map((entry) => {
|
|
16
|
+
const sqlPath = (0, node_path.join)(migrationsDir, `${entry.tag}.sql`);
|
|
17
|
+
if (!(0, node_fs.existsSync)(sqlPath)) return {
|
|
18
|
+
tag: entry.tag,
|
|
19
|
+
hash: "",
|
|
20
|
+
sql: []
|
|
21
|
+
};
|
|
22
|
+
const raw = (0, node_fs.readFileSync)(sqlPath, "utf8");
|
|
23
|
+
const sql = raw.split("--> statement-breakpoint").map((s) => s.trim());
|
|
24
|
+
return {
|
|
25
|
+
tag: entry.tag,
|
|
26
|
+
hash: hashFile(raw),
|
|
27
|
+
sql
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
async function diagnosePlugin(info) {
|
|
32
|
+
const { Pool } = await Promise.resolve().then(() => require("../node_modules/pg/esm/index.cjs"));
|
|
33
|
+
const slug = require_db.pluginMigrationSlug(info.key);
|
|
34
|
+
const journalTable = `__drizzle_migrations_${slug}`;
|
|
35
|
+
const journalSchema = "drizzle";
|
|
36
|
+
const journalRef = `"${journalSchema}"."${journalTable}"`;
|
|
37
|
+
const localMigrations = info.workspaceDir ? readLocalMigrations(info.workspaceDir) : [];
|
|
38
|
+
const expectedTables = require_db.extractExpectedTables(localMigrations);
|
|
39
|
+
const localHashes = localMigrations.map((m) => m.hash).filter(Boolean);
|
|
40
|
+
const migrationHashes = localHashes;
|
|
41
|
+
const pool = new Pool({
|
|
42
|
+
connectionString: info.databaseUrl,
|
|
43
|
+
ssl: info.databaseUrl.includes("localhost") || info.databaseUrl.includes("127.0.0.1") ? false : { rejectUnauthorized: false },
|
|
44
|
+
max: 1,
|
|
45
|
+
connectionTimeoutMillis: 1e4
|
|
46
|
+
});
|
|
47
|
+
try {
|
|
48
|
+
const journalExists = await pool.query(`
|
|
49
|
+
SELECT EXISTS (
|
|
50
|
+
SELECT 1 FROM information_schema.tables
|
|
51
|
+
WHERE table_schema = '${journalSchema}' AND table_name = '${journalTable}'
|
|
52
|
+
) AS exists
|
|
53
|
+
`);
|
|
54
|
+
let appliedHashCount = 0;
|
|
55
|
+
if (journalExists.rows[0]?.exists) appliedHashCount = (await pool.query(`SELECT hash FROM ${journalRef}`)).rows.length;
|
|
56
|
+
let missingTables = [];
|
|
57
|
+
if (expectedTables.length > 0) {
|
|
58
|
+
const tableResult = await pool.query(`
|
|
59
|
+
SELECT table_name FROM information_schema.tables
|
|
60
|
+
WHERE table_schema = 'public'
|
|
61
|
+
AND table_name = ANY($1)
|
|
62
|
+
`, [expectedTables]);
|
|
63
|
+
const existing = new Set(tableResult.rows.map((r) => r.table_name));
|
|
64
|
+
missingTables = expectedTables.filter((t) => !existing.has(t));
|
|
65
|
+
}
|
|
66
|
+
const legacyCount = await countLegacyHashes(pool, localHashes);
|
|
67
|
+
let diagnosis;
|
|
68
|
+
if (localMigrations.length === 0) diagnosis = "no-local-migrations";
|
|
69
|
+
else if (appliedHashCount === 0 && localHashes.length > 0) diagnosis = legacyCount > 0 ? "legacy-importable" : "unapplied";
|
|
70
|
+
else if (missingTables.length === 0) diagnosis = "healthy";
|
|
71
|
+
else if (missingTables.length === expectedTables.length) diagnosis = "drift-safe-repair";
|
|
72
|
+
else diagnosis = "drift-manual";
|
|
73
|
+
const masked = info.databaseUrl.replace(/\/\/[^:]+:[^@]+@/, "//***:***@");
|
|
74
|
+
return {
|
|
75
|
+
plugin: info.key,
|
|
76
|
+
slug,
|
|
77
|
+
journalTable,
|
|
78
|
+
journalSchema,
|
|
79
|
+
dbSecret: info.databaseSecret,
|
|
80
|
+
dbUrl: masked,
|
|
81
|
+
workspaceDir: info.workspaceDir,
|
|
82
|
+
localMigrationCount: localMigrations.length,
|
|
83
|
+
appliedHashCount,
|
|
84
|
+
expectedTables,
|
|
85
|
+
missingTables,
|
|
86
|
+
migrationHashes,
|
|
87
|
+
diagnosis,
|
|
88
|
+
legacyCount
|
|
89
|
+
};
|
|
90
|
+
} catch (error) {
|
|
91
|
+
return {
|
|
92
|
+
plugin: info.key,
|
|
93
|
+
slug,
|
|
94
|
+
journalTable,
|
|
95
|
+
journalSchema,
|
|
96
|
+
dbSecret: info.databaseSecret,
|
|
97
|
+
dbUrl: info.databaseUrl.replace(/\/\/[^:]+:[^@]+@/, "//***:***@"),
|
|
98
|
+
workspaceDir: info.workspaceDir,
|
|
99
|
+
localMigrationCount: localMigrations.length,
|
|
100
|
+
appliedHashCount: 0,
|
|
101
|
+
expectedTables,
|
|
102
|
+
missingTables: [],
|
|
103
|
+
migrationHashes: [],
|
|
104
|
+
diagnosis: "error",
|
|
105
|
+
legacyCount: 0,
|
|
106
|
+
error: error instanceof Error ? error.message : String(error)
|
|
107
|
+
};
|
|
108
|
+
} finally {
|
|
109
|
+
await pool.end().catch(() => {});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
async function countLegacyHashes(pool, localHashes) {
|
|
113
|
+
if (localHashes.length === 0) return 0;
|
|
114
|
+
const candidates = [{
|
|
115
|
+
schema: "drizzle",
|
|
116
|
+
table: "__drizzle_migrations"
|
|
117
|
+
}, {
|
|
118
|
+
schema: "public",
|
|
119
|
+
table: "drizzle_migrations"
|
|
120
|
+
}];
|
|
121
|
+
let total = 0;
|
|
122
|
+
for (const c of candidates) try {
|
|
123
|
+
const result = await pool.query(`SELECT count(*)::int AS cnt FROM "${c.schema}"."${c.table}" WHERE hash = ANY($1)`, [localHashes]);
|
|
124
|
+
total += result.rows[0]?.cnt ?? 0;
|
|
125
|
+
} catch {}
|
|
126
|
+
return total;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
//#endregion
|
|
130
|
+
exports.diagnosePlugin = diagnosePlugin;
|
|
131
|
+
//# sourceMappingURL=db-doctor.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-doctor.cjs","names":["pluginMigrationSlug","extractExpectedTables"],"sources":["../../src/cli/db-doctor.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport { extractExpectedTables, pluginMigrationSlug } from \"../db\";\nimport type { PluginDbInfo } from \"./db-studio\";\n\nexport interface DoctorReport {\n plugin: string;\n slug: string;\n journalTable: string;\n journalSchema: string;\n dbSecret: string;\n dbUrl: string;\n workspaceDir: string | undefined;\n localMigrationCount: number;\n appliedHashCount: number;\n expectedTables: string[];\n missingTables: string[];\n migrationHashes: string[];\n diagnosis: string;\n legacyCount: number;\n error?: string;\n}\n\nfunction hashFile(raw: string): string {\n return createHash(\"sha256\").update(raw).digest(\"hex\");\n}\n\ninterface LocalMigration {\n tag: string;\n hash: string;\n sql: string[];\n}\n\nfunction readLocalMigrations(workspaceDir: string): LocalMigration[] {\n const migrationsDir = resolve(workspaceDir, \"src/db/migrations\");\n const metaDir = join(migrationsDir, \"meta\");\n const journalPath = join(metaDir, \"_journal.json\");\n if (!existsSync(journalPath)) return [];\n\n const journal = JSON.parse(readFileSync(journalPath, \"utf8\")) as {\n entries: { idx: number; tag: string }[];\n };\n\n return journal.entries.map((entry) => {\n const sqlPath = join(migrationsDir, `${entry.tag}.sql`);\n if (!existsSync(sqlPath)) {\n return { tag: entry.tag, hash: \"\", sql: [] };\n }\n const raw = readFileSync(sqlPath, \"utf8\");\n const sql = raw.split(\"--> statement-breakpoint\").map((s) => s.trim());\n return { tag: entry.tag, hash: hashFile(raw), sql };\n });\n}\n\nexport async function diagnosePlugin(info: PluginDbInfo): Promise<DoctorReport> {\n const { Pool } = await import(\"pg\");\n\n const slug = pluginMigrationSlug(info.key);\n const journalTable = `__drizzle_migrations_${slug}`;\n const journalSchema = \"drizzle\";\n const journalRef = `\"${journalSchema}\".\"${journalTable}\"`;\n\n const localMigrations = info.workspaceDir ? readLocalMigrations(info.workspaceDir) : [];\n\n const expectedTables = extractExpectedTables(localMigrations);\n const localHashes = localMigrations.map((m) => m.hash).filter(Boolean);\n const migrationHashes = localHashes;\n\n const pool = new Pool({\n connectionString: info.databaseUrl,\n ssl:\n info.databaseUrl.includes(\"localhost\") || info.databaseUrl.includes(\"127.0.0.1\")\n ? false\n : { rejectUnauthorized: false },\n max: 1,\n connectionTimeoutMillis: 10_000,\n });\n\n try {\n const journalExists = await pool.query(`\n SELECT EXISTS (\n SELECT 1 FROM information_schema.tables\n WHERE table_schema = '${journalSchema}' AND table_name = '${journalTable}'\n ) AS exists\n `);\n\n let appliedHashCount = 0;\n if (journalExists.rows[0]?.exists) {\n const result = await pool.query(`SELECT hash FROM ${journalRef}`);\n appliedHashCount = result.rows.length;\n }\n\n let missingTables: string[] = [];\n if (expectedTables.length > 0) {\n const tableResult = await pool.query(\n `\n SELECT table_name FROM information_schema.tables\n WHERE table_schema = 'public'\n AND table_name = ANY($1)\n `,\n [expectedTables],\n );\n const existing = new Set(tableResult.rows.map((r: any) => r.table_name));\n missingTables = expectedTables.filter((t) => !existing.has(t));\n }\n\n const legacyCount = await countLegacyHashes(pool, localHashes);\n\n let diagnosis: string;\n if (localMigrations.length === 0) {\n diagnosis = \"no-local-migrations\";\n } else if (appliedHashCount === 0 && localHashes.length > 0) {\n diagnosis = legacyCount > 0 ? \"legacy-importable\" : \"unapplied\";\n } else if (missingTables.length === 0) {\n diagnosis = \"healthy\";\n } else if (missingTables.length === expectedTables.length) {\n diagnosis = \"drift-safe-repair\";\n } else {\n diagnosis = \"drift-manual\";\n }\n\n const masked = info.databaseUrl.replace(/\\/\\/[^:]+:[^@]+@/, \"//***:***@\");\n\n return {\n plugin: info.key,\n slug,\n journalTable,\n journalSchema,\n dbSecret: info.databaseSecret,\n dbUrl: masked,\n workspaceDir: info.workspaceDir,\n localMigrationCount: localMigrations.length,\n appliedHashCount,\n expectedTables,\n missingTables,\n migrationHashes,\n diagnosis,\n legacyCount,\n };\n } catch (error) {\n return {\n plugin: info.key,\n slug,\n journalTable,\n journalSchema,\n dbSecret: info.databaseSecret,\n dbUrl: info.databaseUrl.replace(/\\/\\/[^:]+:[^@]+@/, \"//***:***@\"),\n workspaceDir: info.workspaceDir,\n localMigrationCount: localMigrations.length,\n appliedHashCount: 0,\n expectedTables,\n missingTables: [],\n migrationHashes: [],\n diagnosis: \"error\",\n legacyCount: 0,\n error: error instanceof Error ? error.message : String(error),\n };\n } finally {\n await pool.end().catch(() => {});\n }\n}\n\nasync function countLegacyHashes(pool: any, localHashes: string[]): Promise<number> {\n if (localHashes.length === 0) return 0;\n const candidates = [\n { schema: \"drizzle\", table: \"__drizzle_migrations\" },\n { schema: \"public\", table: \"drizzle_migrations\" },\n ];\n let total = 0;\n for (const c of candidates) {\n try {\n const result = await pool.query(\n `SELECT count(*)::int AS cnt FROM \"${c.schema}\".\"${c.table}\" WHERE hash = ANY($1)`,\n [localHashes],\n );\n total += result.rows[0]?.cnt ?? 0;\n } catch {\n // table might not exist\n }\n }\n return total;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { extractExpectedTables, pluginMigrationSlug } from "../db.mjs";
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
|
+
import { createHash } from "node:crypto";
|
|
5
|
+
|
|
6
|
+
//#region src/cli/db-doctor.ts
|
|
7
|
+
function hashFile(raw) {
|
|
8
|
+
return createHash("sha256").update(raw).digest("hex");
|
|
9
|
+
}
|
|
10
|
+
function readLocalMigrations(workspaceDir) {
|
|
11
|
+
const migrationsDir = resolve(workspaceDir, "src/db/migrations");
|
|
12
|
+
const journalPath = join(join(migrationsDir, "meta"), "_journal.json");
|
|
13
|
+
if (!existsSync(journalPath)) return [];
|
|
14
|
+
return JSON.parse(readFileSync(journalPath, "utf8")).entries.map((entry) => {
|
|
15
|
+
const sqlPath = join(migrationsDir, `${entry.tag}.sql`);
|
|
16
|
+
if (!existsSync(sqlPath)) return {
|
|
17
|
+
tag: entry.tag,
|
|
18
|
+
hash: "",
|
|
19
|
+
sql: []
|
|
20
|
+
};
|
|
21
|
+
const raw = readFileSync(sqlPath, "utf8");
|
|
22
|
+
const sql = raw.split("--> statement-breakpoint").map((s) => s.trim());
|
|
23
|
+
return {
|
|
24
|
+
tag: entry.tag,
|
|
25
|
+
hash: hashFile(raw),
|
|
26
|
+
sql
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
async function diagnosePlugin(info) {
|
|
31
|
+
const { Pool } = await import("../node_modules/pg/esm/index.mjs");
|
|
32
|
+
const slug = pluginMigrationSlug(info.key);
|
|
33
|
+
const journalTable = `__drizzle_migrations_${slug}`;
|
|
34
|
+
const journalSchema = "drizzle";
|
|
35
|
+
const journalRef = `"${journalSchema}"."${journalTable}"`;
|
|
36
|
+
const localMigrations = info.workspaceDir ? readLocalMigrations(info.workspaceDir) : [];
|
|
37
|
+
const expectedTables = extractExpectedTables(localMigrations);
|
|
38
|
+
const localHashes = localMigrations.map((m) => m.hash).filter(Boolean);
|
|
39
|
+
const migrationHashes = localHashes;
|
|
40
|
+
const pool = new Pool({
|
|
41
|
+
connectionString: info.databaseUrl,
|
|
42
|
+
ssl: info.databaseUrl.includes("localhost") || info.databaseUrl.includes("127.0.0.1") ? false : { rejectUnauthorized: false },
|
|
43
|
+
max: 1,
|
|
44
|
+
connectionTimeoutMillis: 1e4
|
|
45
|
+
});
|
|
46
|
+
try {
|
|
47
|
+
const journalExists = await pool.query(`
|
|
48
|
+
SELECT EXISTS (
|
|
49
|
+
SELECT 1 FROM information_schema.tables
|
|
50
|
+
WHERE table_schema = '${journalSchema}' AND table_name = '${journalTable}'
|
|
51
|
+
) AS exists
|
|
52
|
+
`);
|
|
53
|
+
let appliedHashCount = 0;
|
|
54
|
+
if (journalExists.rows[0]?.exists) appliedHashCount = (await pool.query(`SELECT hash FROM ${journalRef}`)).rows.length;
|
|
55
|
+
let missingTables = [];
|
|
56
|
+
if (expectedTables.length > 0) {
|
|
57
|
+
const tableResult = await pool.query(`
|
|
58
|
+
SELECT table_name FROM information_schema.tables
|
|
59
|
+
WHERE table_schema = 'public'
|
|
60
|
+
AND table_name = ANY($1)
|
|
61
|
+
`, [expectedTables]);
|
|
62
|
+
const existing = new Set(tableResult.rows.map((r) => r.table_name));
|
|
63
|
+
missingTables = expectedTables.filter((t) => !existing.has(t));
|
|
64
|
+
}
|
|
65
|
+
const legacyCount = await countLegacyHashes(pool, localHashes);
|
|
66
|
+
let diagnosis;
|
|
67
|
+
if (localMigrations.length === 0) diagnosis = "no-local-migrations";
|
|
68
|
+
else if (appliedHashCount === 0 && localHashes.length > 0) diagnosis = legacyCount > 0 ? "legacy-importable" : "unapplied";
|
|
69
|
+
else if (missingTables.length === 0) diagnosis = "healthy";
|
|
70
|
+
else if (missingTables.length === expectedTables.length) diagnosis = "drift-safe-repair";
|
|
71
|
+
else diagnosis = "drift-manual";
|
|
72
|
+
const masked = info.databaseUrl.replace(/\/\/[^:]+:[^@]+@/, "//***:***@");
|
|
73
|
+
return {
|
|
74
|
+
plugin: info.key,
|
|
75
|
+
slug,
|
|
76
|
+
journalTable,
|
|
77
|
+
journalSchema,
|
|
78
|
+
dbSecret: info.databaseSecret,
|
|
79
|
+
dbUrl: masked,
|
|
80
|
+
workspaceDir: info.workspaceDir,
|
|
81
|
+
localMigrationCount: localMigrations.length,
|
|
82
|
+
appliedHashCount,
|
|
83
|
+
expectedTables,
|
|
84
|
+
missingTables,
|
|
85
|
+
migrationHashes,
|
|
86
|
+
diagnosis,
|
|
87
|
+
legacyCount
|
|
88
|
+
};
|
|
89
|
+
} catch (error) {
|
|
90
|
+
return {
|
|
91
|
+
plugin: info.key,
|
|
92
|
+
slug,
|
|
93
|
+
journalTable,
|
|
94
|
+
journalSchema,
|
|
95
|
+
dbSecret: info.databaseSecret,
|
|
96
|
+
dbUrl: info.databaseUrl.replace(/\/\/[^:]+:[^@]+@/, "//***:***@"),
|
|
97
|
+
workspaceDir: info.workspaceDir,
|
|
98
|
+
localMigrationCount: localMigrations.length,
|
|
99
|
+
appliedHashCount: 0,
|
|
100
|
+
expectedTables,
|
|
101
|
+
missingTables: [],
|
|
102
|
+
migrationHashes: [],
|
|
103
|
+
diagnosis: "error",
|
|
104
|
+
legacyCount: 0,
|
|
105
|
+
error: error instanceof Error ? error.message : String(error)
|
|
106
|
+
};
|
|
107
|
+
} finally {
|
|
108
|
+
await pool.end().catch(() => {});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
async function countLegacyHashes(pool, localHashes) {
|
|
112
|
+
if (localHashes.length === 0) return 0;
|
|
113
|
+
const candidates = [{
|
|
114
|
+
schema: "drizzle",
|
|
115
|
+
table: "__drizzle_migrations"
|
|
116
|
+
}, {
|
|
117
|
+
schema: "public",
|
|
118
|
+
table: "drizzle_migrations"
|
|
119
|
+
}];
|
|
120
|
+
let total = 0;
|
|
121
|
+
for (const c of candidates) try {
|
|
122
|
+
const result = await pool.query(`SELECT count(*)::int AS cnt FROM "${c.schema}"."${c.table}" WHERE hash = ANY($1)`, [localHashes]);
|
|
123
|
+
total += result.rows[0]?.cnt ?? 0;
|
|
124
|
+
} catch {}
|
|
125
|
+
return total;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
//#endregion
|
|
129
|
+
export { diagnosePlugin };
|
|
130
|
+
//# sourceMappingURL=db-doctor.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-doctor.mjs","names":[],"sources":["../../src/cli/db-doctor.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport { extractExpectedTables, pluginMigrationSlug } from \"../db\";\nimport type { PluginDbInfo } from \"./db-studio\";\n\nexport interface DoctorReport {\n plugin: string;\n slug: string;\n journalTable: string;\n journalSchema: string;\n dbSecret: string;\n dbUrl: string;\n workspaceDir: string | undefined;\n localMigrationCount: number;\n appliedHashCount: number;\n expectedTables: string[];\n missingTables: string[];\n migrationHashes: string[];\n diagnosis: string;\n legacyCount: number;\n error?: string;\n}\n\nfunction hashFile(raw: string): string {\n return createHash(\"sha256\").update(raw).digest(\"hex\");\n}\n\ninterface LocalMigration {\n tag: string;\n hash: string;\n sql: string[];\n}\n\nfunction readLocalMigrations(workspaceDir: string): LocalMigration[] {\n const migrationsDir = resolve(workspaceDir, \"src/db/migrations\");\n const metaDir = join(migrationsDir, \"meta\");\n const journalPath = join(metaDir, \"_journal.json\");\n if (!existsSync(journalPath)) return [];\n\n const journal = JSON.parse(readFileSync(journalPath, \"utf8\")) as {\n entries: { idx: number; tag: string }[];\n };\n\n return journal.entries.map((entry) => {\n const sqlPath = join(migrationsDir, `${entry.tag}.sql`);\n if (!existsSync(sqlPath)) {\n return { tag: entry.tag, hash: \"\", sql: [] };\n }\n const raw = readFileSync(sqlPath, \"utf8\");\n const sql = raw.split(\"--> statement-breakpoint\").map((s) => s.trim());\n return { tag: entry.tag, hash: hashFile(raw), sql };\n });\n}\n\nexport async function diagnosePlugin(info: PluginDbInfo): Promise<DoctorReport> {\n const { Pool } = await import(\"pg\");\n\n const slug = pluginMigrationSlug(info.key);\n const journalTable = `__drizzle_migrations_${slug}`;\n const journalSchema = \"drizzle\";\n const journalRef = `\"${journalSchema}\".\"${journalTable}\"`;\n\n const localMigrations = info.workspaceDir ? readLocalMigrations(info.workspaceDir) : [];\n\n const expectedTables = extractExpectedTables(localMigrations);\n const localHashes = localMigrations.map((m) => m.hash).filter(Boolean);\n const migrationHashes = localHashes;\n\n const pool = new Pool({\n connectionString: info.databaseUrl,\n ssl:\n info.databaseUrl.includes(\"localhost\") || info.databaseUrl.includes(\"127.0.0.1\")\n ? false\n : { rejectUnauthorized: false },\n max: 1,\n connectionTimeoutMillis: 10_000,\n });\n\n try {\n const journalExists = await pool.query(`\n SELECT EXISTS (\n SELECT 1 FROM information_schema.tables\n WHERE table_schema = '${journalSchema}' AND table_name = '${journalTable}'\n ) AS exists\n `);\n\n let appliedHashCount = 0;\n if (journalExists.rows[0]?.exists) {\n const result = await pool.query(`SELECT hash FROM ${journalRef}`);\n appliedHashCount = result.rows.length;\n }\n\n let missingTables: string[] = [];\n if (expectedTables.length > 0) {\n const tableResult = await pool.query(\n `\n SELECT table_name FROM information_schema.tables\n WHERE table_schema = 'public'\n AND table_name = ANY($1)\n `,\n [expectedTables],\n );\n const existing = new Set(tableResult.rows.map((r: any) => r.table_name));\n missingTables = expectedTables.filter((t) => !existing.has(t));\n }\n\n const legacyCount = await countLegacyHashes(pool, localHashes);\n\n let diagnosis: string;\n if (localMigrations.length === 0) {\n diagnosis = \"no-local-migrations\";\n } else if (appliedHashCount === 0 && localHashes.length > 0) {\n diagnosis = legacyCount > 0 ? \"legacy-importable\" : \"unapplied\";\n } else if (missingTables.length === 0) {\n diagnosis = \"healthy\";\n } else if (missingTables.length === expectedTables.length) {\n diagnosis = \"drift-safe-repair\";\n } else {\n diagnosis = \"drift-manual\";\n }\n\n const masked = info.databaseUrl.replace(/\\/\\/[^:]+:[^@]+@/, \"//***:***@\");\n\n return {\n plugin: info.key,\n slug,\n journalTable,\n journalSchema,\n dbSecret: info.databaseSecret,\n dbUrl: masked,\n workspaceDir: info.workspaceDir,\n localMigrationCount: localMigrations.length,\n appliedHashCount,\n expectedTables,\n missingTables,\n migrationHashes,\n diagnosis,\n legacyCount,\n };\n } catch (error) {\n return {\n plugin: info.key,\n slug,\n journalTable,\n journalSchema,\n dbSecret: info.databaseSecret,\n dbUrl: info.databaseUrl.replace(/\\/\\/[^:]+:[^@]+@/, \"//***:***@\"),\n workspaceDir: info.workspaceDir,\n localMigrationCount: localMigrations.length,\n appliedHashCount: 0,\n expectedTables,\n missingTables: [],\n migrationHashes: [],\n diagnosis: \"error\",\n legacyCount: 0,\n error: error instanceof Error ? error.message : String(error),\n };\n } finally {\n await pool.end().catch(() => {});\n }\n}\n\nasync function countLegacyHashes(pool: any, localHashes: string[]): Promise<number> {\n if (localHashes.length === 0) return 0;\n const candidates = [\n { schema: \"drizzle\", table: \"__drizzle_migrations\" },\n { schema: \"public\", table: \"drizzle_migrations\" },\n ];\n let total = 0;\n for (const c of candidates) {\n try {\n const result = await pool.query(\n `SELECT count(*)::int AS cnt FROM \"${c.schema}\".\"${c.table}\" WHERE hash = ANY($1)`,\n [localHashes],\n );\n total += result.rows[0]?.cnt ?? 0;\n } catch {\n // table might not exist\n }\n }\n return total;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
|
|
2
|
+
const require_db_doctor = require('./db-doctor.cjs');
|
|
3
|
+
let node_fs = require("node:fs");
|
|
4
|
+
let node_path = require("node:path");
|
|
5
|
+
let node_child_process = require("node:child_process");
|
|
6
|
+
|
|
7
|
+
//#region src/cli/db-repair.ts
|
|
8
|
+
async function repairPlugin(info, mode) {
|
|
9
|
+
const diagnosis = await require_db_doctor.diagnosePlugin(info);
|
|
10
|
+
if (diagnosis.diagnosis === "error") return {
|
|
11
|
+
status: "refused",
|
|
12
|
+
diagnosis,
|
|
13
|
+
message: `Cannot repair — diagnosis failed: ${diagnosis.error}`
|
|
14
|
+
};
|
|
15
|
+
if (mode === "recreate") return {
|
|
16
|
+
status: "refused",
|
|
17
|
+
diagnosis,
|
|
18
|
+
message: "Recreate mode is not supported without per-plugin schemas. Use --mode history-reset instead."
|
|
19
|
+
};
|
|
20
|
+
if (diagnosis.diagnosis !== "drift-safe-repair" && diagnosis.diagnosis !== "legacy-importable") {
|
|
21
|
+
if (diagnosis.diagnosis === "healthy") return {
|
|
22
|
+
status: "refused",
|
|
23
|
+
diagnosis,
|
|
24
|
+
message: "Database is healthy — no repair needed."
|
|
25
|
+
};
|
|
26
|
+
if (diagnosis.diagnosis === "no-local-migrations") return {
|
|
27
|
+
status: "refused",
|
|
28
|
+
diagnosis,
|
|
29
|
+
message: "No local migrations found for this plugin."
|
|
30
|
+
};
|
|
31
|
+
if (diagnosis.diagnosis === "drift-manual") return {
|
|
32
|
+
status: "refused",
|
|
33
|
+
diagnosis,
|
|
34
|
+
message: `Partial drift detected (${diagnosis.missingTables.length}/${diagnosis.expectedTables.length} tables missing). Manual intervention required — some tables exist but schema is incomplete.`
|
|
35
|
+
};
|
|
36
|
+
if (diagnosis.diagnosis === "unapplied") return {
|
|
37
|
+
status: "refused",
|
|
38
|
+
diagnosis,
|
|
39
|
+
message: "Migrations have not been applied yet. Start the dev server to apply them."
|
|
40
|
+
};
|
|
41
|
+
return {
|
|
42
|
+
status: "refused",
|
|
43
|
+
diagnosis,
|
|
44
|
+
message: `Cannot repair — diagnosis: ${diagnosis.diagnosis}`
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const { Pool } = await Promise.resolve().then(() => require("../node_modules/pg/esm/index.cjs"));
|
|
48
|
+
const journalRef = `"${diagnosis.journalSchema}"."${diagnosis.journalTable}"`;
|
|
49
|
+
const pool = new Pool({
|
|
50
|
+
connectionString: info.databaseUrl,
|
|
51
|
+
ssl: info.databaseUrl.includes("localhost") || info.databaseUrl.includes("127.0.0.1") ? false : { rejectUnauthorized: false },
|
|
52
|
+
max: 1,
|
|
53
|
+
connectionTimeoutMillis: 1e4
|
|
54
|
+
});
|
|
55
|
+
try {
|
|
56
|
+
await pool.query(`DROP TABLE IF EXISTS ${journalRef}`);
|
|
57
|
+
} catch (error) {
|
|
58
|
+
return {
|
|
59
|
+
status: "error",
|
|
60
|
+
diagnosis,
|
|
61
|
+
message: `Failed to reset journal: ${error instanceof Error ? error.message : String(error)}`
|
|
62
|
+
};
|
|
63
|
+
} finally {
|
|
64
|
+
await pool.end().catch(() => {});
|
|
65
|
+
}
|
|
66
|
+
if (info.workspaceDir) {
|
|
67
|
+
const configPath = (0, node_path.join)(info.workspaceDir, "drizzle.config.ts");
|
|
68
|
+
if ((0, node_fs.existsSync)(configPath)) try {
|
|
69
|
+
await spawnDrizzleMigrate(info.workspaceDir, configPath);
|
|
70
|
+
return {
|
|
71
|
+
status: "repaired",
|
|
72
|
+
diagnosis,
|
|
73
|
+
message: `Migration history reset for ${diagnosis.plugin}. Migrations reapplied via drizzle-kit. Restart the dev server to confirm.`
|
|
74
|
+
};
|
|
75
|
+
} catch (error) {
|
|
76
|
+
return {
|
|
77
|
+
status: "repaired",
|
|
78
|
+
diagnosis,
|
|
79
|
+
message: `Migration history reset for ${diagnosis.plugin}. Automatic reapply failed: ${error instanceof Error ? error.message : String(error)}. Run \`bun run --cwd ${info.workspaceDir} db:migrate\` manually.`
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
status: "repaired",
|
|
85
|
+
diagnosis,
|
|
86
|
+
message: `Migration history reset for ${diagnosis.plugin}. No local drizzle.config.ts found — start the dev server to reapply migrations.`
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function spawnDrizzleMigrate(cwd, configPath) {
|
|
90
|
+
return new Promise((resolvePromise, reject) => {
|
|
91
|
+
const child = (0, node_child_process.spawn)("npx", [
|
|
92
|
+
"drizzle-kit",
|
|
93
|
+
"migrate",
|
|
94
|
+
"--config",
|
|
95
|
+
configPath
|
|
96
|
+
], {
|
|
97
|
+
cwd,
|
|
98
|
+
stdio: "pipe",
|
|
99
|
+
shell: true
|
|
100
|
+
});
|
|
101
|
+
let stderr = "";
|
|
102
|
+
child.stderr?.on("data", (data) => {
|
|
103
|
+
stderr += data.toString();
|
|
104
|
+
});
|
|
105
|
+
child.on("error", (err) => reject(err));
|
|
106
|
+
child.on("exit", (code) => {
|
|
107
|
+
if (code === 0) resolvePromise();
|
|
108
|
+
else reject(/* @__PURE__ */ new Error(`drizzle-kit migrate exited with code ${code}: ${stderr}`));
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
//#endregion
|
|
114
|
+
exports.repairPlugin = repairPlugin;
|
|
115
|
+
//# sourceMappingURL=db-repair.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-repair.cjs","names":["diagnosePlugin"],"sources":["../../src/cli/db-repair.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { type DoctorReport, diagnosePlugin } from \"./db-doctor\";\nimport type { PluginDbInfo } from \"./db-studio\";\n\nexport interface RepairResult {\n status: \"repaired\" | \"refused\" | \"error\";\n diagnosis: DoctorReport;\n message: string;\n}\n\nexport async function repairPlugin(\n info: PluginDbInfo,\n mode: \"history-reset\" | \"recreate\",\n): Promise<RepairResult> {\n const diagnosis = await diagnosePlugin(info);\n\n if (diagnosis.diagnosis === \"error\") {\n return {\n status: \"refused\",\n diagnosis,\n message: `Cannot repair — diagnosis failed: ${diagnosis.error}`,\n };\n }\n\n if (mode === \"recreate\") {\n return {\n status: \"refused\",\n diagnosis,\n message:\n \"Recreate mode is not supported without per-plugin schemas. Use --mode history-reset instead.\",\n };\n }\n\n if (diagnosis.diagnosis !== \"drift-safe-repair\" && diagnosis.diagnosis !== \"legacy-importable\") {\n if (diagnosis.diagnosis === \"healthy\") {\n return { status: \"refused\", diagnosis, message: \"Database is healthy — no repair needed.\" };\n }\n if (diagnosis.diagnosis === \"no-local-migrations\") {\n return {\n status: \"refused\",\n diagnosis,\n message: \"No local migrations found for this plugin.\",\n };\n }\n if (diagnosis.diagnosis === \"drift-manual\") {\n return {\n status: \"refused\",\n diagnosis,\n message:\n `Partial drift detected (${diagnosis.missingTables.length}/${diagnosis.expectedTables.length} tables missing). ` +\n \"Manual intervention required — some tables exist but schema is incomplete.\",\n };\n }\n if (diagnosis.diagnosis === \"unapplied\") {\n return {\n status: \"refused\",\n diagnosis,\n message: \"Migrations have not been applied yet. Start the dev server to apply them.\",\n };\n }\n return {\n status: \"refused\",\n diagnosis,\n message: `Cannot repair — diagnosis: ${diagnosis.diagnosis}`,\n };\n }\n\n const { Pool } = await import(\"pg\");\n const journalRef = `\"${diagnosis.journalSchema}\".\"${diagnosis.journalTable}\"`;\n const pool = new Pool({\n connectionString: info.databaseUrl,\n ssl:\n info.databaseUrl.includes(\"localhost\") || info.databaseUrl.includes(\"127.0.0.1\")\n ? false\n : { rejectUnauthorized: false },\n max: 1,\n connectionTimeoutMillis: 10_000,\n });\n\n try {\n await pool.query(`DROP TABLE IF EXISTS ${journalRef}`);\n } catch (error) {\n return {\n status: \"error\",\n diagnosis,\n message: `Failed to reset journal: ${error instanceof Error ? error.message : String(error)}`,\n };\n } finally {\n await pool.end().catch(() => {});\n }\n\n if (info.workspaceDir) {\n const configPath = join(info.workspaceDir, \"drizzle.config.ts\");\n if (existsSync(configPath)) {\n try {\n await spawnDrizzleMigrate(info.workspaceDir, configPath);\n return {\n status: \"repaired\",\n diagnosis,\n message:\n `Migration history reset for ${diagnosis.plugin}. ` +\n `Migrations reapplied via drizzle-kit. Restart the dev server to confirm.`,\n };\n } catch (error) {\n return {\n status: \"repaired\",\n diagnosis,\n message:\n `Migration history reset for ${diagnosis.plugin}. ` +\n `Automatic reapply failed: ${error instanceof Error ? error.message : String(error)}. ` +\n `Run \\`bun run --cwd ${info.workspaceDir} db:migrate\\` manually.`,\n };\n }\n }\n }\n\n return {\n status: \"repaired\",\n diagnosis,\n message:\n `Migration history reset for ${diagnosis.plugin}. ` +\n \"No local drizzle.config.ts found — start the dev server to reapply migrations.\",\n };\n}\n\nfunction spawnDrizzleMigrate(cwd: string, configPath: string): Promise<void> {\n return new Promise((resolvePromise, reject) => {\n const child = spawn(\"npx\", [\"drizzle-kit\", \"migrate\", \"--config\", configPath], {\n cwd,\n stdio: \"pipe\",\n shell: true,\n });\n\n let stderr = \"\";\n child.stderr?.on(\"data\", (data: Buffer) => {\n stderr += data.toString();\n });\n\n child.on(\"error\", (err) => reject(err));\n\n child.on(\"exit\", (code) => {\n if (code === 0) {\n resolvePromise();\n } else {\n reject(new Error(`drizzle-kit migrate exited with code ${code}: ${stderr}`));\n }\n });\n });\n}\n"],"mappings":";;;;;;;AAYA,eAAsB,aACpB,MACA,MACuB;CACvB,MAAM,YAAY,MAAMA,iCAAe,KAAK;AAE5C,KAAI,UAAU,cAAc,QAC1B,QAAO;EACL,QAAQ;EACR;EACA,SAAS,qCAAqC,UAAU;EACzD;AAGH,KAAI,SAAS,WACX,QAAO;EACL,QAAQ;EACR;EACA,SACE;EACH;AAGH,KAAI,UAAU,cAAc,uBAAuB,UAAU,cAAc,qBAAqB;AAC9F,MAAI,UAAU,cAAc,UAC1B,QAAO;GAAE,QAAQ;GAAW;GAAW,SAAS;GAA2C;AAE7F,MAAI,UAAU,cAAc,sBAC1B,QAAO;GACL,QAAQ;GACR;GACA,SAAS;GACV;AAEH,MAAI,UAAU,cAAc,eAC1B,QAAO;GACL,QAAQ;GACR;GACA,SACE,2BAA2B,UAAU,cAAc,OAAO,GAAG,UAAU,eAAe,OAAO;GAEhG;AAEH,MAAI,UAAU,cAAc,YAC1B,QAAO;GACL,QAAQ;GACR;GACA,SAAS;GACV;AAEH,SAAO;GACL,QAAQ;GACR;GACA,SAAS,8BAA8B,UAAU;GAClD;;CAGH,MAAM,EAAE,SAAS,2CAAM;CACvB,MAAM,aAAa,IAAI,UAAU,cAAc,KAAK,UAAU,aAAa;CAC3E,MAAM,OAAO,IAAI,KAAK;EACpB,kBAAkB,KAAK;EACvB,KACE,KAAK,YAAY,SAAS,YAAY,IAAI,KAAK,YAAY,SAAS,YAAY,GAC5E,QACA,EAAE,oBAAoB,OAAO;EACnC,KAAK;EACL,yBAAyB;EAC1B,CAAC;AAEF,KAAI;AACF,QAAM,KAAK,MAAM,wBAAwB,aAAa;UAC/C,OAAO;AACd,SAAO;GACL,QAAQ;GACR;GACA,SAAS,4BAA4B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;GAC5F;WACO;AACR,QAAM,KAAK,KAAK,CAAC,YAAY,GAAG;;AAGlC,KAAI,KAAK,cAAc;EACrB,MAAM,iCAAkB,KAAK,cAAc,oBAAoB;AAC/D,8BAAe,WAAW,CACxB,KAAI;AACF,SAAM,oBAAoB,KAAK,cAAc,WAAW;AACxD,UAAO;IACL,QAAQ;IACR;IACA,SACE,+BAA+B,UAAU,OAAO;IAEnD;WACM,OAAO;AACd,UAAO;IACL,QAAQ;IACR;IACA,SACE,+BAA+B,UAAU,OAAO,8BACnB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,CAAC,wBAC7D,KAAK,aAAa;IAC5C;;;AAKP,QAAO;EACL,QAAQ;EACR;EACA,SACE,+BAA+B,UAAU,OAAO;EAEnD;;AAGH,SAAS,oBAAoB,KAAa,YAAmC;AAC3E,QAAO,IAAI,SAAS,gBAAgB,WAAW;EAC7C,MAAM,sCAAc,OAAO;GAAC;GAAe;GAAW;GAAY;GAAW,EAAE;GAC7E;GACA,OAAO;GACP,OAAO;GACR,CAAC;EAEF,IAAI,SAAS;AACb,QAAM,QAAQ,GAAG,SAAS,SAAiB;AACzC,aAAU,KAAK,UAAU;IACzB;AAEF,QAAM,GAAG,UAAU,QAAQ,OAAO,IAAI,CAAC;AAEvC,QAAM,GAAG,SAAS,SAAS;AACzB,OAAI,SAAS,EACX,iBAAgB;OAEhB,wBAAO,IAAI,MAAM,wCAAwC,KAAK,IAAI,SAAS,CAAC;IAE9E;GACF"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { diagnosePlugin } from "./db-doctor.mjs";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { spawn } from "node:child_process";
|
|
5
|
+
|
|
6
|
+
//#region src/cli/db-repair.ts
|
|
7
|
+
async function repairPlugin(info, mode) {
|
|
8
|
+
const diagnosis = await diagnosePlugin(info);
|
|
9
|
+
if (diagnosis.diagnosis === "error") return {
|
|
10
|
+
status: "refused",
|
|
11
|
+
diagnosis,
|
|
12
|
+
message: `Cannot repair — diagnosis failed: ${diagnosis.error}`
|
|
13
|
+
};
|
|
14
|
+
if (mode === "recreate") return {
|
|
15
|
+
status: "refused",
|
|
16
|
+
diagnosis,
|
|
17
|
+
message: "Recreate mode is not supported without per-plugin schemas. Use --mode history-reset instead."
|
|
18
|
+
};
|
|
19
|
+
if (diagnosis.diagnosis !== "drift-safe-repair" && diagnosis.diagnosis !== "legacy-importable") {
|
|
20
|
+
if (diagnosis.diagnosis === "healthy") return {
|
|
21
|
+
status: "refused",
|
|
22
|
+
diagnosis,
|
|
23
|
+
message: "Database is healthy — no repair needed."
|
|
24
|
+
};
|
|
25
|
+
if (diagnosis.diagnosis === "no-local-migrations") return {
|
|
26
|
+
status: "refused",
|
|
27
|
+
diagnosis,
|
|
28
|
+
message: "No local migrations found for this plugin."
|
|
29
|
+
};
|
|
30
|
+
if (diagnosis.diagnosis === "drift-manual") return {
|
|
31
|
+
status: "refused",
|
|
32
|
+
diagnosis,
|
|
33
|
+
message: `Partial drift detected (${diagnosis.missingTables.length}/${diagnosis.expectedTables.length} tables missing). Manual intervention required — some tables exist but schema is incomplete.`
|
|
34
|
+
};
|
|
35
|
+
if (diagnosis.diagnosis === "unapplied") return {
|
|
36
|
+
status: "refused",
|
|
37
|
+
diagnosis,
|
|
38
|
+
message: "Migrations have not been applied yet. Start the dev server to apply them."
|
|
39
|
+
};
|
|
40
|
+
return {
|
|
41
|
+
status: "refused",
|
|
42
|
+
diagnosis,
|
|
43
|
+
message: `Cannot repair — diagnosis: ${diagnosis.diagnosis}`
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const { Pool } = await import("../node_modules/pg/esm/index.mjs");
|
|
47
|
+
const journalRef = `"${diagnosis.journalSchema}"."${diagnosis.journalTable}"`;
|
|
48
|
+
const pool = new Pool({
|
|
49
|
+
connectionString: info.databaseUrl,
|
|
50
|
+
ssl: info.databaseUrl.includes("localhost") || info.databaseUrl.includes("127.0.0.1") ? false : { rejectUnauthorized: false },
|
|
51
|
+
max: 1,
|
|
52
|
+
connectionTimeoutMillis: 1e4
|
|
53
|
+
});
|
|
54
|
+
try {
|
|
55
|
+
await pool.query(`DROP TABLE IF EXISTS ${journalRef}`);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
return {
|
|
58
|
+
status: "error",
|
|
59
|
+
diagnosis,
|
|
60
|
+
message: `Failed to reset journal: ${error instanceof Error ? error.message : String(error)}`
|
|
61
|
+
};
|
|
62
|
+
} finally {
|
|
63
|
+
await pool.end().catch(() => {});
|
|
64
|
+
}
|
|
65
|
+
if (info.workspaceDir) {
|
|
66
|
+
const configPath = join(info.workspaceDir, "drizzle.config.ts");
|
|
67
|
+
if (existsSync(configPath)) try {
|
|
68
|
+
await spawnDrizzleMigrate(info.workspaceDir, configPath);
|
|
69
|
+
return {
|
|
70
|
+
status: "repaired",
|
|
71
|
+
diagnosis,
|
|
72
|
+
message: `Migration history reset for ${diagnosis.plugin}. Migrations reapplied via drizzle-kit. Restart the dev server to confirm.`
|
|
73
|
+
};
|
|
74
|
+
} catch (error) {
|
|
75
|
+
return {
|
|
76
|
+
status: "repaired",
|
|
77
|
+
diagnosis,
|
|
78
|
+
message: `Migration history reset for ${diagnosis.plugin}. Automatic reapply failed: ${error instanceof Error ? error.message : String(error)}. Run \`bun run --cwd ${info.workspaceDir} db:migrate\` manually.`
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
status: "repaired",
|
|
84
|
+
diagnosis,
|
|
85
|
+
message: `Migration history reset for ${diagnosis.plugin}. No local drizzle.config.ts found — start the dev server to reapply migrations.`
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function spawnDrizzleMigrate(cwd, configPath) {
|
|
89
|
+
return new Promise((resolvePromise, reject) => {
|
|
90
|
+
const child = spawn("npx", [
|
|
91
|
+
"drizzle-kit",
|
|
92
|
+
"migrate",
|
|
93
|
+
"--config",
|
|
94
|
+
configPath
|
|
95
|
+
], {
|
|
96
|
+
cwd,
|
|
97
|
+
stdio: "pipe",
|
|
98
|
+
shell: true
|
|
99
|
+
});
|
|
100
|
+
let stderr = "";
|
|
101
|
+
child.stderr?.on("data", (data) => {
|
|
102
|
+
stderr += data.toString();
|
|
103
|
+
});
|
|
104
|
+
child.on("error", (err) => reject(err));
|
|
105
|
+
child.on("exit", (code) => {
|
|
106
|
+
if (code === 0) resolvePromise();
|
|
107
|
+
else reject(/* @__PURE__ */ new Error(`drizzle-kit migrate exited with code ${code}: ${stderr}`));
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
//#endregion
|
|
113
|
+
export { repairPlugin };
|
|
114
|
+
//# sourceMappingURL=db-repair.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-repair.mjs","names":[],"sources":["../../src/cli/db-repair.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { type DoctorReport, diagnosePlugin } from \"./db-doctor\";\nimport type { PluginDbInfo } from \"./db-studio\";\n\nexport interface RepairResult {\n status: \"repaired\" | \"refused\" | \"error\";\n diagnosis: DoctorReport;\n message: string;\n}\n\nexport async function repairPlugin(\n info: PluginDbInfo,\n mode: \"history-reset\" | \"recreate\",\n): Promise<RepairResult> {\n const diagnosis = await diagnosePlugin(info);\n\n if (diagnosis.diagnosis === \"error\") {\n return {\n status: \"refused\",\n diagnosis,\n message: `Cannot repair — diagnosis failed: ${diagnosis.error}`,\n };\n }\n\n if (mode === \"recreate\") {\n return {\n status: \"refused\",\n diagnosis,\n message:\n \"Recreate mode is not supported without per-plugin schemas. Use --mode history-reset instead.\",\n };\n }\n\n if (diagnosis.diagnosis !== \"drift-safe-repair\" && diagnosis.diagnosis !== \"legacy-importable\") {\n if (diagnosis.diagnosis === \"healthy\") {\n return { status: \"refused\", diagnosis, message: \"Database is healthy — no repair needed.\" };\n }\n if (diagnosis.diagnosis === \"no-local-migrations\") {\n return {\n status: \"refused\",\n diagnosis,\n message: \"No local migrations found for this plugin.\",\n };\n }\n if (diagnosis.diagnosis === \"drift-manual\") {\n return {\n status: \"refused\",\n diagnosis,\n message:\n `Partial drift detected (${diagnosis.missingTables.length}/${diagnosis.expectedTables.length} tables missing). ` +\n \"Manual intervention required — some tables exist but schema is incomplete.\",\n };\n }\n if (diagnosis.diagnosis === \"unapplied\") {\n return {\n status: \"refused\",\n diagnosis,\n message: \"Migrations have not been applied yet. Start the dev server to apply them.\",\n };\n }\n return {\n status: \"refused\",\n diagnosis,\n message: `Cannot repair — diagnosis: ${diagnosis.diagnosis}`,\n };\n }\n\n const { Pool } = await import(\"pg\");\n const journalRef = `\"${diagnosis.journalSchema}\".\"${diagnosis.journalTable}\"`;\n const pool = new Pool({\n connectionString: info.databaseUrl,\n ssl:\n info.databaseUrl.includes(\"localhost\") || info.databaseUrl.includes(\"127.0.0.1\")\n ? false\n : { rejectUnauthorized: false },\n max: 1,\n connectionTimeoutMillis: 10_000,\n });\n\n try {\n await pool.query(`DROP TABLE IF EXISTS ${journalRef}`);\n } catch (error) {\n return {\n status: \"error\",\n diagnosis,\n message: `Failed to reset journal: ${error instanceof Error ? error.message : String(error)}`,\n };\n } finally {\n await pool.end().catch(() => {});\n }\n\n if (info.workspaceDir) {\n const configPath = join(info.workspaceDir, \"drizzle.config.ts\");\n if (existsSync(configPath)) {\n try {\n await spawnDrizzleMigrate(info.workspaceDir, configPath);\n return {\n status: \"repaired\",\n diagnosis,\n message:\n `Migration history reset for ${diagnosis.plugin}. ` +\n `Migrations reapplied via drizzle-kit. Restart the dev server to confirm.`,\n };\n } catch (error) {\n return {\n status: \"repaired\",\n diagnosis,\n message:\n `Migration history reset for ${diagnosis.plugin}. ` +\n `Automatic reapply failed: ${error instanceof Error ? error.message : String(error)}. ` +\n `Run \\`bun run --cwd ${info.workspaceDir} db:migrate\\` manually.`,\n };\n }\n }\n }\n\n return {\n status: \"repaired\",\n diagnosis,\n message:\n `Migration history reset for ${diagnosis.plugin}. ` +\n \"No local drizzle.config.ts found — start the dev server to reapply migrations.\",\n };\n}\n\nfunction spawnDrizzleMigrate(cwd: string, configPath: string): Promise<void> {\n return new Promise((resolvePromise, reject) => {\n const child = spawn(\"npx\", [\"drizzle-kit\", \"migrate\", \"--config\", configPath], {\n cwd,\n stdio: \"pipe\",\n shell: true,\n });\n\n let stderr = \"\";\n child.stderr?.on(\"data\", (data: Buffer) => {\n stderr += data.toString();\n });\n\n child.on(\"error\", (err) => reject(err));\n\n child.on(\"exit\", (code) => {\n if (code === 0) {\n resolvePromise();\n } else {\n reject(new Error(`drizzle-kit migrate exited with code ${code}: ${stderr}`));\n }\n });\n });\n}\n"],"mappings":";;;;;;AAYA,eAAsB,aACpB,MACA,MACuB;CACvB,MAAM,YAAY,MAAM,eAAe,KAAK;AAE5C,KAAI,UAAU,cAAc,QAC1B,QAAO;EACL,QAAQ;EACR;EACA,SAAS,qCAAqC,UAAU;EACzD;AAGH,KAAI,SAAS,WACX,QAAO;EACL,QAAQ;EACR;EACA,SACE;EACH;AAGH,KAAI,UAAU,cAAc,uBAAuB,UAAU,cAAc,qBAAqB;AAC9F,MAAI,UAAU,cAAc,UAC1B,QAAO;GAAE,QAAQ;GAAW;GAAW,SAAS;GAA2C;AAE7F,MAAI,UAAU,cAAc,sBAC1B,QAAO;GACL,QAAQ;GACR;GACA,SAAS;GACV;AAEH,MAAI,UAAU,cAAc,eAC1B,QAAO;GACL,QAAQ;GACR;GACA,SACE,2BAA2B,UAAU,cAAc,OAAO,GAAG,UAAU,eAAe,OAAO;GAEhG;AAEH,MAAI,UAAU,cAAc,YAC1B,QAAO;GACL,QAAQ;GACR;GACA,SAAS;GACV;AAEH,SAAO;GACL,QAAQ;GACR;GACA,SAAS,8BAA8B,UAAU;GAClD;;CAGH,MAAM,EAAE,SAAS,MAAM,OAAO;CAC9B,MAAM,aAAa,IAAI,UAAU,cAAc,KAAK,UAAU,aAAa;CAC3E,MAAM,OAAO,IAAI,KAAK;EACpB,kBAAkB,KAAK;EACvB,KACE,KAAK,YAAY,SAAS,YAAY,IAAI,KAAK,YAAY,SAAS,YAAY,GAC5E,QACA,EAAE,oBAAoB,OAAO;EACnC,KAAK;EACL,yBAAyB;EAC1B,CAAC;AAEF,KAAI;AACF,QAAM,KAAK,MAAM,wBAAwB,aAAa;UAC/C,OAAO;AACd,SAAO;GACL,QAAQ;GACR;GACA,SAAS,4BAA4B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;GAC5F;WACO;AACR,QAAM,KAAK,KAAK,CAAC,YAAY,GAAG;;AAGlC,KAAI,KAAK,cAAc;EACrB,MAAM,aAAa,KAAK,KAAK,cAAc,oBAAoB;AAC/D,MAAI,WAAW,WAAW,CACxB,KAAI;AACF,SAAM,oBAAoB,KAAK,cAAc,WAAW;AACxD,UAAO;IACL,QAAQ;IACR;IACA,SACE,+BAA+B,UAAU,OAAO;IAEnD;WACM,OAAO;AACd,UAAO;IACL,QAAQ;IACR;IACA,SACE,+BAA+B,UAAU,OAAO,8BACnB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,CAAC,wBAC7D,KAAK,aAAa;IAC5C;;;AAKP,QAAO;EACL,QAAQ;EACR;EACA,SACE,+BAA+B,UAAU,OAAO;EAEnD;;AAGH,SAAS,oBAAoB,KAAa,YAAmC;AAC3E,QAAO,IAAI,SAAS,gBAAgB,WAAW;EAC7C,MAAM,QAAQ,MAAM,OAAO;GAAC;GAAe;GAAW;GAAY;GAAW,EAAE;GAC7E;GACA,OAAO;GACP,OAAO;GACR,CAAC;EAEF,IAAI,SAAS;AACb,QAAM,QAAQ,GAAG,SAAS,SAAiB;AACzC,aAAU,KAAK,UAAU;IACzB;AAEF,QAAM,GAAG,UAAU,QAAQ,OAAO,IAAI,CAAC;AAEvC,QAAM,GAAG,SAAS,SAAS;AACzB,OAAI,SAAS,EACX,iBAAgB;OAEhB,wBAAO,IAAI,MAAM,wCAAwC,KAAK,IAAI,SAAS,CAAC;IAE9E;GACF"}
|
package/dist/cli/db-studio.cjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
|
|
2
|
+
const require_db = require('../db.cjs');
|
|
2
3
|
let node_fs = require("node:fs");
|
|
3
4
|
let node_path = require("node:path");
|
|
4
5
|
let _clack_prompts = require("@clack/prompts");
|
|
@@ -65,6 +66,7 @@ async function runStudioLocal(info) {
|
|
|
65
66
|
async function runStudioRemote(info) {
|
|
66
67
|
const dbDir = (0, node_path.resolve)(info.projectDir, ".bos", "db", info.key);
|
|
67
68
|
(0, node_fs.mkdirSync)(dbDir, { recursive: true });
|
|
69
|
+
const journalTable = `__drizzle_migrations_${require_db.pluginMigrationSlug(info.key)}`;
|
|
68
70
|
const configPath = (0, node_path.join)(dbDir, "drizzle.config.ts");
|
|
69
71
|
(0, node_fs.writeFileSync)(configPath, `import { defineConfig } from "drizzle-kit";
|
|
70
72
|
|
|
@@ -75,6 +77,10 @@ export default defineConfig({
|
|
|
75
77
|
dbCredentials: {
|
|
76
78
|
url: "${info.databaseUrl}",
|
|
77
79
|
},
|
|
80
|
+
migrations: {
|
|
81
|
+
schema: "drizzle",
|
|
82
|
+
table: "${journalTable}",
|
|
83
|
+
},
|
|
78
84
|
verbose: true,
|
|
79
85
|
strict: true,
|
|
80
86
|
});
|