everything-dev 1.48.0 → 1.50.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/app.cjs +66 -86
- package/dist/app.cjs.map +1 -1
- package/dist/app.mjs +66 -87
- package/dist/app.mjs.map +1 -1
- package/dist/cli/db-doctor.cjs +6 -23
- package/dist/cli/db-doctor.cjs.map +1 -1
- package/dist/cli/db-doctor.mjs +7 -24
- package/dist/cli/db-doctor.mjs.map +1 -1
- package/dist/cli/db-repair.cjs +25 -20
- package/dist/cli/db-repair.cjs.map +1 -1
- package/dist/cli/db-repair.mjs +25 -20
- package/dist/cli/db-repair.mjs.map +1 -1
- package/dist/cli/db-studio.cjs +4 -2
- package/dist/cli/db-studio.cjs.map +1 -1
- package/dist/cli/db-studio.mjs +5 -3
- package/dist/cli/db-studio.mjs.map +1 -1
- package/dist/cli/framework-version.cjs +45 -9
- package/dist/cli/framework-version.cjs.map +1 -1
- package/dist/cli/framework-version.mjs +45 -10
- package/dist/cli/framework-version.mjs.map +1 -1
- package/dist/cli/infra.cjs +89 -3
- package/dist/cli/infra.cjs.map +1 -1
- package/dist/cli/infra.mjs +83 -4
- package/dist/cli/infra.mjs.map +1 -1
- package/dist/cli/init.cjs +39 -15
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.d.cts +8 -3
- package/dist/cli/init.d.cts.map +1 -1
- package/dist/cli/init.d.mts +8 -3
- package/dist/cli/init.d.mts.map +1 -1
- package/dist/cli/init.mjs +39 -16
- package/dist/cli/init.mjs.map +1 -1
- package/dist/cli/status.cjs +6 -2
- package/dist/cli/status.cjs.map +1 -1
- package/dist/cli/status.mjs +7 -3
- package/dist/cli/status.mjs.map +1 -1
- package/dist/cli/sync.cjs +1 -3
- package/dist/cli/sync.cjs.map +1 -1
- package/dist/cli/sync.mjs +1 -3
- package/dist/cli/sync.mjs.map +1 -1
- package/dist/cli/upgrade.cjs +8 -4
- package/dist/cli/upgrade.cjs.map +1 -1
- package/dist/cli/upgrade.mjs +8 -4
- package/dist/cli/upgrade.mjs.map +1 -1
- package/dist/cli.cjs +73 -9
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +74 -10
- package/dist/cli.mjs.map +1 -1
- package/dist/config.cjs +7 -3
- package/dist/config.cjs.map +1 -1
- package/dist/config.d.cts.map +1 -1
- package/dist/config.d.mts.map +1 -1
- package/dist/config.mjs +7 -3
- package/dist/config.mjs.map +1 -1
- package/dist/contract.cjs +76 -4
- package/dist/contract.cjs.map +1 -1
- package/dist/contract.d.cts +164 -19
- package/dist/contract.d.cts.map +1 -1
- package/dist/contract.d.mts +164 -19
- package/dist/contract.d.mts.map +1 -1
- package/dist/contract.meta.cjs +17 -2
- package/dist/contract.meta.cjs.map +1 -1
- package/dist/contract.meta.d.cts +23 -2
- package/dist/contract.meta.d.mts +23 -2
- package/dist/contract.meta.mjs +17 -2
- package/dist/contract.meta.mjs.map +1 -1
- package/dist/contract.mjs +72 -5
- package/dist/contract.mjs.map +1 -1
- package/dist/db.cjs +33 -25
- package/dist/db.cjs.map +1 -1
- package/dist/db.d.cts +16 -9
- package/dist/db.d.cts.map +1 -1
- package/dist/db.d.mts +16 -9
- package/dist/db.d.mts.map +1 -1
- package/dist/db.mjs +33 -24
- package/dist/db.mjs.map +1 -1
- package/dist/dev-session.cjs +28 -0
- package/dist/dev-session.cjs.map +1 -1
- package/dist/dev-session.mjs +29 -1
- package/dist/dev-session.mjs.map +1 -1
- package/dist/index.cjs +5 -0
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/infra/planner.cjs +337 -0
- package/dist/infra/planner.cjs.map +1 -0
- package/dist/infra/planner.mjs +336 -0
- package/dist/infra/planner.mjs.map +1 -0
- package/dist/infra/preflight.cjs +131 -0
- package/dist/infra/preflight.cjs.map +1 -0
- package/dist/infra/preflight.mjs +130 -0
- package/dist/infra/preflight.mjs.map +1 -0
- package/dist/infra/types.cjs +9 -0
- package/dist/infra/types.cjs.map +1 -0
- package/dist/infra/types.mjs +8 -0
- package/dist/infra/types.mjs.map +1 -0
- package/dist/near-cli.cjs +37 -0
- package/dist/near-cli.cjs.map +1 -1
- package/dist/near-cli.mjs +36 -1
- package/dist/near-cli.mjs.map +1 -1
- package/dist/orchestrator.cjs +10 -2
- package/dist/orchestrator.cjs.map +1 -1
- package/dist/orchestrator.mjs +10 -2
- package/dist/orchestrator.mjs.map +1 -1
- package/dist/plugin.cjs +160 -43
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.d.cts +64 -8
- package/dist/plugin.d.cts.map +1 -1
- package/dist/plugin.d.mts +64 -8
- package/dist/plugin.d.mts.map +1 -1
- package/dist/plugin.mjs +164 -47
- package/dist/plugin.mjs.map +1 -1
- package/dist/process-registry.cjs +88 -0
- package/dist/process-registry.cjs.map +1 -0
- package/dist/process-registry.mjs +83 -0
- package/dist/process-registry.mjs.map +1 -0
- package/dist/publish.cjs +4 -0
- package/dist/publish.cjs.map +1 -1
- package/dist/publish.mjs +4 -0
- package/dist/publish.mjs.map +1 -1
- package/dist/service-descriptor.cjs +4 -0
- package/dist/service-descriptor.cjs.map +1 -1
- package/dist/service-descriptor.mjs +4 -1
- package/dist/service-descriptor.mjs.map +1 -1
- package/dist/types.d.cts +2 -2
- package/dist/types.d.mts +2 -2
- package/dist/ui/index.cjs +2 -1
- package/dist/ui/index.d.cts +2 -2
- package/dist/ui/index.d.mts +2 -2
- package/dist/ui/index.mjs +2 -2
- package/dist/ui/router.cjs +40 -0
- package/dist/ui/router.cjs.map +1 -1
- package/dist/ui/router.d.cts +6 -1
- package/dist/ui/router.d.cts.map +1 -1
- package/dist/ui/router.d.mts +6 -1
- package/dist/ui/router.d.mts.map +1 -1
- package/dist/ui/router.mjs +40 -1
- package/dist/ui/router.mjs.map +1 -1
- package/package.json +4 -1
- package/skills/cli-reference/SKILL.md +5 -4
- package/skills/dev-workflow/SKILL.md +40 -11
- package/skills/plugin-development/SKILL.md +9 -2
package/dist/cli/db-doctor.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { extractExpectedTables, pluginMigrationSlug } from "../db.mjs";
|
|
1
|
+
import { extractExpectedTables, getMigrationStorage, pluginMigrationSlug } from "../db.mjs";
|
|
2
2
|
import { existsSync, readFileSync } from "node:fs";
|
|
3
3
|
import { join, resolve } from "node:path";
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
@@ -30,8 +30,9 @@ function readLocalMigrations(workspaceDir) {
|
|
|
30
30
|
async function diagnosePlugin(info) {
|
|
31
31
|
const { Pool } = await import("../node_modules/pg/esm/index.mjs");
|
|
32
32
|
const slug = pluginMigrationSlug(info.key);
|
|
33
|
-
const
|
|
34
|
-
const
|
|
33
|
+
const storage = getMigrationStorage(slug);
|
|
34
|
+
const journalTable = storage.table;
|
|
35
|
+
const journalSchema = storage.schema;
|
|
35
36
|
const journalRef = `"${journalSchema}"."${journalTable}"`;
|
|
36
37
|
const localMigrations = info.workspaceDir ? readLocalMigrations(info.workspaceDir) : [];
|
|
37
38
|
const expectedTables = extractExpectedTables(localMigrations);
|
|
@@ -62,10 +63,10 @@ async function diagnosePlugin(info) {
|
|
|
62
63
|
const existing = new Set(tableResult.rows.map((r) => r.table_name));
|
|
63
64
|
missingTables = expectedTables.filter((t) => !existing.has(t));
|
|
64
65
|
}
|
|
65
|
-
const legacyCount = await countLegacyHashes(pool, localHashes);
|
|
66
66
|
let diagnosis;
|
|
67
67
|
if (localMigrations.length === 0) diagnosis = "no-local-migrations";
|
|
68
|
-
else if (appliedHashCount === 0 && localHashes.length > 0) diagnosis =
|
|
68
|
+
else if (appliedHashCount === 0 && missingTables.length === 0 && localHashes.length > 0) diagnosis = "untracked-existing-schema";
|
|
69
|
+
else if (appliedHashCount === 0 && localHashes.length > 0) diagnosis = "unapplied";
|
|
69
70
|
else if (missingTables.length === 0) diagnosis = "healthy";
|
|
70
71
|
else if (missingTables.length === expectedTables.length) diagnosis = "drift-safe-repair";
|
|
71
72
|
else diagnosis = "drift-manual";
|
|
@@ -83,8 +84,7 @@ async function diagnosePlugin(info) {
|
|
|
83
84
|
expectedTables,
|
|
84
85
|
missingTables,
|
|
85
86
|
migrationHashes,
|
|
86
|
-
diagnosis
|
|
87
|
-
legacyCount
|
|
87
|
+
diagnosis
|
|
88
88
|
};
|
|
89
89
|
} catch (error) {
|
|
90
90
|
return {
|
|
@@ -101,29 +101,12 @@ async function diagnosePlugin(info) {
|
|
|
101
101
|
missingTables: [],
|
|
102
102
|
migrationHashes: [],
|
|
103
103
|
diagnosis: "error",
|
|
104
|
-
legacyCount: 0,
|
|
105
104
|
error: error instanceof Error ? error.message : String(error)
|
|
106
105
|
};
|
|
107
106
|
} finally {
|
|
108
107
|
await pool.end().catch(() => {});
|
|
109
108
|
}
|
|
110
109
|
}
|
|
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
110
|
|
|
128
111
|
//#endregion
|
|
129
112
|
export { diagnosePlugin };
|
|
@@ -1 +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
|
|
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, getMigrationStorage, 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 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 storage = getMigrationStorage(slug);\n const journalTable = storage.table;\n const journalSchema = storage.schema;\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 let diagnosis: string;\n if (localMigrations.length === 0) {\n diagnosis = \"no-local-migrations\";\n } else if (appliedHashCount === 0 && missingTables.length === 0 && localHashes.length > 0) {\n // Journal is empty but all expected public tables exist.\n diagnosis = \"untracked-existing-schema\";\n } else if (appliedHashCount === 0 && localHashes.length > 0) {\n diagnosis = \"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 };\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 error: error instanceof Error ? error.message : String(error),\n };\n } finally {\n await pool.end().catch(() => {});\n }\n}\n"],"mappings":"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"}
|
package/dist/cli/db-repair.cjs
CHANGED
|
@@ -15,9 +15,9 @@ async function repairPlugin(info, mode) {
|
|
|
15
15
|
if (mode === "recreate") return {
|
|
16
16
|
status: "refused",
|
|
17
17
|
diagnosis,
|
|
18
|
-
message: "Recreate mode is not supported without per-plugin schemas. Use --mode history-reset instead."
|
|
18
|
+
message: "Recreate mode is not supported without per-plugin database schemas. Use --mode history-reset instead."
|
|
19
19
|
};
|
|
20
|
-
if (diagnosis.diagnosis !== "drift-safe-repair"
|
|
20
|
+
if (diagnosis.diagnosis !== "drift-safe-repair") {
|
|
21
21
|
if (diagnosis.diagnosis === "healthy") return {
|
|
22
22
|
status: "refused",
|
|
23
23
|
diagnosis,
|
|
@@ -38,6 +38,11 @@ async function repairPlugin(info, mode) {
|
|
|
38
38
|
diagnosis,
|
|
39
39
|
message: "Migrations have not been applied yet. Start the dev server to apply them."
|
|
40
40
|
};
|
|
41
|
+
if (diagnosis.diagnosis === "untracked-existing-schema") return {
|
|
42
|
+
status: "refused",
|
|
43
|
+
diagnosis,
|
|
44
|
+
message: "Tables exist but no matching migration history was found. Run `drizzle-kit pull --init` in the plugin workspace to adopt the existing schema, then run migrations from that baseline."
|
|
45
|
+
};
|
|
41
46
|
return {
|
|
42
47
|
status: "refused",
|
|
43
48
|
diagnosis,
|
|
@@ -54,32 +59,32 @@ async function repairPlugin(info, mode) {
|
|
|
54
59
|
});
|
|
55
60
|
try {
|
|
56
61
|
await pool.query(`DROP TABLE IF EXISTS ${journalRef}`);
|
|
62
|
+
if (info.workspaceDir) {
|
|
63
|
+
const configPath = (0, node_path.join)(info.workspaceDir, "drizzle.config.ts");
|
|
64
|
+
if ((0, node_fs.existsSync)(configPath)) try {
|
|
65
|
+
await spawnDrizzleMigrate(info.workspaceDir, configPath);
|
|
66
|
+
return {
|
|
67
|
+
status: "repaired",
|
|
68
|
+
diagnosis,
|
|
69
|
+
message: `Migration history reset for ${diagnosis.plugin}. Migrations reapplied via drizzle-kit. Restart the dev server to confirm.`
|
|
70
|
+
};
|
|
71
|
+
} catch (error) {
|
|
72
|
+
return {
|
|
73
|
+
status: "repaired",
|
|
74
|
+
diagnosis,
|
|
75
|
+
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.`
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
57
79
|
} catch (error) {
|
|
58
80
|
return {
|
|
59
81
|
status: "error",
|
|
60
82
|
diagnosis,
|
|
61
|
-
message: `
|
|
83
|
+
message: `Repair failed: ${error instanceof Error ? error.message : String(error)}`
|
|
62
84
|
};
|
|
63
85
|
} finally {
|
|
64
86
|
await pool.end().catch(() => {});
|
|
65
87
|
}
|
|
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
88
|
return {
|
|
84
89
|
status: "repaired",
|
|
85
90
|
diagnosis,
|
|
@@ -1 +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\"
|
|
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 database schemas. Use --mode history-reset instead.\",\n };\n }\n\n if (diagnosis.diagnosis !== \"drift-safe-repair\") {\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 if (diagnosis.diagnosis === \"untracked-existing-schema\") {\n return {\n status: \"refused\",\n diagnosis,\n message:\n \"Tables exist but no matching migration history was found. \" +\n \"Run `drizzle-kit pull --init` in the plugin workspace to adopt the existing schema, \" +\n \"then run migrations from that baseline.\",\n };\n }\n return {\n status: \"refused\",\n diagnosis,\n message: `Cannot repair — diagnosis: ${diagnosis.diagnosis}`,\n };\n }\n\n // drift-safe-repair: drop the journal and replay\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\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 } catch (error) {\n return {\n status: \"error\",\n diagnosis,\n message: `Repair failed: ${error instanceof Error ? error.message : String(error)}`,\n };\n } finally {\n await pool.end().catch(() => {});\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,qBAAqB;AAC/C,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,MAAI,UAAU,cAAc,4BAC1B,QAAO;GACL,QAAQ;GACR;GACA,SACE;GAGH;AAEH,SAAO;GACL,QAAQ;GACR;GACA,SAAS,8BAA8B,UAAU;GAClD;;CAIH,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;AAEtD,MAAI,KAAK,cAAc;GACrB,MAAM,iCAAkB,KAAK,cAAc,oBAAoB;AAC/D,+BAAe,WAAW,CACxB,KAAI;AACF,UAAM,oBAAoB,KAAK,cAAc,WAAW;AACxD,WAAO;KACL,QAAQ;KACR;KACA,SACE,+BAA+B,UAAU,OAAO;KAEnD;YACM,OAAO;AACd,WAAO;KACL,QAAQ;KACR;KACA,SACE,+BAA+B,UAAU,OAAO,8BACnB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,CAAC,wBAC7D,KAAK,aAAa;KAC5C;;;UAIA,OAAO;AACd,SAAO;GACL,QAAQ;GACR;GACA,SAAS,kBAAkB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;GAClF;WACO;AACR,QAAM,KAAK,KAAK,CAAC,YAAY,GAAG;;AAGlC,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"}
|
package/dist/cli/db-repair.mjs
CHANGED
|
@@ -14,9 +14,9 @@ async function repairPlugin(info, mode) {
|
|
|
14
14
|
if (mode === "recreate") return {
|
|
15
15
|
status: "refused",
|
|
16
16
|
diagnosis,
|
|
17
|
-
message: "Recreate mode is not supported without per-plugin schemas. Use --mode history-reset instead."
|
|
17
|
+
message: "Recreate mode is not supported without per-plugin database schemas. Use --mode history-reset instead."
|
|
18
18
|
};
|
|
19
|
-
if (diagnosis.diagnosis !== "drift-safe-repair"
|
|
19
|
+
if (diagnosis.diagnosis !== "drift-safe-repair") {
|
|
20
20
|
if (diagnosis.diagnosis === "healthy") return {
|
|
21
21
|
status: "refused",
|
|
22
22
|
diagnosis,
|
|
@@ -37,6 +37,11 @@ async function repairPlugin(info, mode) {
|
|
|
37
37
|
diagnosis,
|
|
38
38
|
message: "Migrations have not been applied yet. Start the dev server to apply them."
|
|
39
39
|
};
|
|
40
|
+
if (diagnosis.diagnosis === "untracked-existing-schema") return {
|
|
41
|
+
status: "refused",
|
|
42
|
+
diagnosis,
|
|
43
|
+
message: "Tables exist but no matching migration history was found. Run `drizzle-kit pull --init` in the plugin workspace to adopt the existing schema, then run migrations from that baseline."
|
|
44
|
+
};
|
|
40
45
|
return {
|
|
41
46
|
status: "refused",
|
|
42
47
|
diagnosis,
|
|
@@ -53,32 +58,32 @@ async function repairPlugin(info, mode) {
|
|
|
53
58
|
});
|
|
54
59
|
try {
|
|
55
60
|
await pool.query(`DROP TABLE IF EXISTS ${journalRef}`);
|
|
61
|
+
if (info.workspaceDir) {
|
|
62
|
+
const configPath = join(info.workspaceDir, "drizzle.config.ts");
|
|
63
|
+
if (existsSync(configPath)) try {
|
|
64
|
+
await spawnDrizzleMigrate(info.workspaceDir, configPath);
|
|
65
|
+
return {
|
|
66
|
+
status: "repaired",
|
|
67
|
+
diagnosis,
|
|
68
|
+
message: `Migration history reset for ${diagnosis.plugin}. Migrations reapplied via drizzle-kit. Restart the dev server to confirm.`
|
|
69
|
+
};
|
|
70
|
+
} catch (error) {
|
|
71
|
+
return {
|
|
72
|
+
status: "repaired",
|
|
73
|
+
diagnosis,
|
|
74
|
+
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.`
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
56
78
|
} catch (error) {
|
|
57
79
|
return {
|
|
58
80
|
status: "error",
|
|
59
81
|
diagnosis,
|
|
60
|
-
message: `
|
|
82
|
+
message: `Repair failed: ${error instanceof Error ? error.message : String(error)}`
|
|
61
83
|
};
|
|
62
84
|
} finally {
|
|
63
85
|
await pool.end().catch(() => {});
|
|
64
86
|
}
|
|
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
87
|
return {
|
|
83
88
|
status: "repaired",
|
|
84
89
|
diagnosis,
|
|
@@ -1 +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\"
|
|
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 database schemas. Use --mode history-reset instead.\",\n };\n }\n\n if (diagnosis.diagnosis !== \"drift-safe-repair\") {\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 if (diagnosis.diagnosis === \"untracked-existing-schema\") {\n return {\n status: \"refused\",\n diagnosis,\n message:\n \"Tables exist but no matching migration history was found. \" +\n \"Run `drizzle-kit pull --init` in the plugin workspace to adopt the existing schema, \" +\n \"then run migrations from that baseline.\",\n };\n }\n return {\n status: \"refused\",\n diagnosis,\n message: `Cannot repair — diagnosis: ${diagnosis.diagnosis}`,\n };\n }\n\n // drift-safe-repair: drop the journal and replay\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\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 } catch (error) {\n return {\n status: \"error\",\n diagnosis,\n message: `Repair failed: ${error instanceof Error ? error.message : String(error)}`,\n };\n } finally {\n await pool.end().catch(() => {});\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,qBAAqB;AAC/C,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,MAAI,UAAU,cAAc,4BAC1B,QAAO;GACL,QAAQ;GACR;GACA,SACE;GAGH;AAEH,SAAO;GACL,QAAQ;GACR;GACA,SAAS,8BAA8B,UAAU;GAClD;;CAIH,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;AAEtD,MAAI,KAAK,cAAc;GACrB,MAAM,aAAa,KAAK,KAAK,cAAc,oBAAoB;AAC/D,OAAI,WAAW,WAAW,CACxB,KAAI;AACF,UAAM,oBAAoB,KAAK,cAAc,WAAW;AACxD,WAAO;KACL,QAAQ;KACR;KACA,SACE,+BAA+B,UAAU,OAAO;KAEnD;YACM,OAAO;AACd,WAAO;KACL,QAAQ;KACR;KACA,SACE,+BAA+B,UAAU,OAAO,8BACnB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,CAAC,wBAC7D,KAAK,aAAa;KAC5C;;;UAIA,OAAO;AACd,SAAO;GACL,QAAQ;GACR;GACA,SAAS,kBAAkB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;GAClF;WACO;AACR,QAAM,KAAK,KAAK,CAAC,YAAY,GAAG;;AAGlC,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
|
@@ -66,7 +66,9 @@ async function runStudioLocal(info) {
|
|
|
66
66
|
async function runStudioRemote(info) {
|
|
67
67
|
const dbDir = (0, node_path.resolve)(info.projectDir, ".bos", "db", info.key);
|
|
68
68
|
(0, node_fs.mkdirSync)(dbDir, { recursive: true });
|
|
69
|
-
const
|
|
69
|
+
const storage = require_db.getMigrationStorage(require_db.pluginMigrationSlug(info.key));
|
|
70
|
+
const journalSchema = storage.schema;
|
|
71
|
+
const journalTable = storage.table;
|
|
70
72
|
const configPath = (0, node_path.join)(dbDir, "drizzle.config.ts");
|
|
71
73
|
(0, node_fs.writeFileSync)(configPath, `import { defineConfig } from "drizzle-kit";
|
|
72
74
|
|
|
@@ -78,7 +80,7 @@ export default defineConfig({
|
|
|
78
80
|
url: "${info.databaseUrl}",
|
|
79
81
|
},
|
|
80
82
|
migrations: {
|
|
81
|
-
schema: "
|
|
83
|
+
schema: "${journalSchema}",
|
|
82
84
|
table: "${journalTable}",
|
|
83
85
|
},
|
|
84
86
|
verbose: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db-studio.cjs","names":["pluginMigrationSlug"],"sources":["../../src/cli/db-studio.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport * as p from \"@clack/prompts\";\nimport type { RuntimeConfig } from \"../types\";\n\nexport interface PluginDbInfo {\n key: string;\n source: \"local\" | \"remote\";\n section: \"app.api\" | \"app.auth\" | \"plugins\";\n databaseSecret: string;\n databaseUrl: string;\n workspaceDir?: string;\n projectDir: string;\n}\n\nexport function resolvePluginDbInfo(\n pluginKey: string,\n runtimeConfig: RuntimeConfig,\n projectDir: string,\n): PluginDbInfo {\n let source: \"local\" | \"remote\" | undefined;\n let section: PluginDbInfo[\"section\"];\n let secrets: string[] | undefined;\n let localPath: string | undefined;\n let key: string;\n\n if (pluginKey === \"api\" && runtimeConfig.api) {\n source = runtimeConfig.api.source;\n section = \"app.api\";\n secrets = runtimeConfig.api.secrets;\n localPath = runtimeConfig.api.localPath;\n key = \"api\";\n } else if (pluginKey === \"auth\" && runtimeConfig.auth) {\n source = runtimeConfig.auth.source;\n section = \"app.auth\";\n secrets = runtimeConfig.auth.secrets;\n localPath = runtimeConfig.auth.localPath;\n key = \"auth\";\n } else if (runtimeConfig.plugins?.[pluginKey]) {\n const plugin = runtimeConfig.plugins[pluginKey];\n source = plugin.source;\n section = \"plugins\";\n secrets = plugin.secrets;\n localPath = plugin.localPath;\n key = pluginKey;\n } else {\n throw new Error(\n `Plugin \"${pluginKey}\" not found in app.api, app.auth, or plugins. ` +\n `Available: ${[\n \"api\",\n ...(runtimeConfig.auth ? [\"auth\"] : []),\n ...Object.keys(runtimeConfig.plugins ?? {}),\n ].join(\", \")}`,\n );\n }\n\n const dbSecret = secrets?.find((s) => s.endsWith(\"_DATABASE_URL\"));\n if (!dbSecret) {\n throw new Error(\n `Plugin \"${pluginKey}\" has no database secret (no secret ending in _DATABASE_URL). ` +\n `Secrets: ${(secrets ?? []).join(\", \") || \"none\"}`,\n );\n }\n\n const dbUrl = process.env[dbSecret];\n if (!dbUrl) {\n throw new Error(\n `.env missing ${dbSecret} for plugin \"${pluginKey}\". ` +\n `Add it to your .env file (see .env.example).`,\n );\n }\n\n return {\n key,\n source: source ?? \"remote\",\n section,\n databaseSecret: dbSecret,\n databaseUrl: dbUrl,\n workspaceDir: localPath,\n projectDir,\n };\n}\n\nexport async function runStudioLocal(info: PluginDbInfo): Promise<void> {\n const workspaceRoot = info.workspaceDir\n ? resolve(info.projectDir, info.workspaceDir)\n : resolve(info.projectDir, info.key);\n const configPath = join(workspaceRoot, \"drizzle.config.ts\");\n\n if (!existsSync(configPath)) {\n throw new Error(\n `No drizzle.config.ts found in ${workspaceRoot}. ` +\n `Run 'drizzle-kit init' first in the plugin workspace.`,\n );\n }\n\n p.log.info(`Starting Drizzle Studio for ${info.key} (local)...`);\n\n await spawnAsync(\"npx\", [\"drizzle-kit\", \"studio\", \"--config\", configPath], {\n cwd: workspaceRoot,\n });\n}\n\
|
|
1
|
+
{"version":3,"file":"db-studio.cjs","names":["getMigrationStorage","pluginMigrationSlug"],"sources":["../../src/cli/db-studio.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport * as p from \"@clack/prompts\";\nimport { getMigrationStorage, pluginMigrationSlug } from \"../db\";\nimport type { RuntimeConfig } from \"../types\";\n\nexport interface PluginDbInfo {\n key: string;\n source: \"local\" | \"remote\";\n section: \"app.api\" | \"app.auth\" | \"plugins\";\n databaseSecret: string;\n databaseUrl: string;\n workspaceDir?: string;\n projectDir: string;\n}\n\nexport function resolvePluginDbInfo(\n pluginKey: string,\n runtimeConfig: RuntimeConfig,\n projectDir: string,\n): PluginDbInfo {\n let source: \"local\" | \"remote\" | undefined;\n let section: PluginDbInfo[\"section\"];\n let secrets: string[] | undefined;\n let localPath: string | undefined;\n let key: string;\n\n if (pluginKey === \"api\" && runtimeConfig.api) {\n source = runtimeConfig.api.source;\n section = \"app.api\";\n secrets = runtimeConfig.api.secrets;\n localPath = runtimeConfig.api.localPath;\n key = \"api\";\n } else if (pluginKey === \"auth\" && runtimeConfig.auth) {\n source = runtimeConfig.auth.source;\n section = \"app.auth\";\n secrets = runtimeConfig.auth.secrets;\n localPath = runtimeConfig.auth.localPath;\n key = \"auth\";\n } else if (runtimeConfig.plugins?.[pluginKey]) {\n const plugin = runtimeConfig.plugins[pluginKey];\n source = plugin.source;\n section = \"plugins\";\n secrets = plugin.secrets;\n localPath = plugin.localPath;\n key = pluginKey;\n } else {\n throw new Error(\n `Plugin \"${pluginKey}\" not found in app.api, app.auth, or plugins. ` +\n `Available: ${[\n \"api\",\n ...(runtimeConfig.auth ? [\"auth\"] : []),\n ...Object.keys(runtimeConfig.plugins ?? {}),\n ].join(\", \")}`,\n );\n }\n\n const dbSecret = secrets?.find((s) => s.endsWith(\"_DATABASE_URL\"));\n if (!dbSecret) {\n throw new Error(\n `Plugin \"${pluginKey}\" has no database secret (no secret ending in _DATABASE_URL). ` +\n `Secrets: ${(secrets ?? []).join(\", \") || \"none\"}`,\n );\n }\n\n const dbUrl = process.env[dbSecret];\n if (!dbUrl) {\n throw new Error(\n `.env missing ${dbSecret} for plugin \"${pluginKey}\". ` +\n `Add it to your .env file (see .env.example).`,\n );\n }\n\n return {\n key,\n source: source ?? \"remote\",\n section,\n databaseSecret: dbSecret,\n databaseUrl: dbUrl,\n workspaceDir: localPath,\n projectDir,\n };\n}\n\nexport async function runStudioLocal(info: PluginDbInfo): Promise<void> {\n const workspaceRoot = info.workspaceDir\n ? resolve(info.projectDir, info.workspaceDir)\n : resolve(info.projectDir, info.key);\n const configPath = join(workspaceRoot, \"drizzle.config.ts\");\n\n if (!existsSync(configPath)) {\n throw new Error(\n `No drizzle.config.ts found in ${workspaceRoot}. ` +\n `Run 'drizzle-kit init' first in the plugin workspace.`,\n );\n }\n\n p.log.info(`Starting Drizzle Studio for ${info.key} (local)...`);\n\n await spawnAsync(\"npx\", [\"drizzle-kit\", \"studio\", \"--config\", configPath], {\n cwd: workspaceRoot,\n });\n}\n\nexport async function runStudioRemote(info: PluginDbInfo): Promise<void> {\n const dbDir = resolve(info.projectDir, \".bos\", \"db\", info.key);\n\n mkdirSync(dbDir, { recursive: true });\n\n const storage = getMigrationStorage(pluginMigrationSlug(info.key));\n const journalSchema = storage.schema;\n const journalTable = storage.table;\n\n const configPath = join(dbDir, \"drizzle.config.ts\");\n const configContent = `import { defineConfig } from \"drizzle-kit\";\n\nexport default defineConfig({\n schema: \"./drizzle/schema.ts\",\n out: \"./drizzle\",\n dialect: \"postgresql\",\n dbCredentials: {\n url: \"${info.databaseUrl}\",\n },\n migrations: {\n schema: \"${journalSchema}\",\n table: \"${journalTable}\",\n },\n verbose: true,\n strict: true,\n});\n`;\n\n writeFileSync(configPath, configContent);\n\n p.log.info(`Introspecting database schema for ${info.key}...`);\n try {\n await spawnAsync(\"npx\", [\"drizzle-kit\", \"pull\", \"--config\", configPath], {\n cwd: dbDir,\n });\n } catch {\n throw new Error(\n `Failed to introspect database for \"${info.key}\". ` +\n `Check that ${info.databaseSecret} is correct and the database is reachable.`,\n );\n }\n\n p.log.info(`Starting Drizzle Studio for ${info.key}...`);\n await spawnAsync(\"npx\", [\"drizzle-kit\", \"studio\", \"--config\", configPath], {\n cwd: dbDir,\n });\n}\n\nfunction spawnAsync(cmd: string, args: string[], options: { cwd: string }): Promise<void> {\n return new Promise((resolvePromise, reject) => {\n const child = spawn(cmd, args, {\n cwd: options.cwd,\n stdio: \"inherit\",\n shell: true,\n });\n\n child.on(\"error\", (err) => {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n reject(\n new Error(\n `\"${cmd}\" not found. Ensure it is installed (e.g. 'npm install -g drizzle-kit').`,\n ),\n );\n } else {\n reject(new Error(`Failed to start ${cmd}: ${err.message}`));\n }\n });\n\n child.on(\"exit\", (code) => {\n if (code === 0 || code === null) {\n resolvePromise();\n } else {\n reject(new Error(`\"${cmd}\" exited with code ${code}`));\n }\n });\n });\n}\n"],"mappings":"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"}
|
package/dist/cli/db-studio.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { pluginMigrationSlug } from "../db.mjs";
|
|
1
|
+
import { getMigrationStorage, pluginMigrationSlug } from "../db.mjs";
|
|
2
2
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { join, resolve } from "node:path";
|
|
4
4
|
import * as p from "@clack/prompts";
|
|
@@ -64,7 +64,9 @@ async function runStudioLocal(info) {
|
|
|
64
64
|
async function runStudioRemote(info) {
|
|
65
65
|
const dbDir = resolve(info.projectDir, ".bos", "db", info.key);
|
|
66
66
|
mkdirSync(dbDir, { recursive: true });
|
|
67
|
-
const
|
|
67
|
+
const storage = getMigrationStorage(pluginMigrationSlug(info.key));
|
|
68
|
+
const journalSchema = storage.schema;
|
|
69
|
+
const journalTable = storage.table;
|
|
68
70
|
const configPath = join(dbDir, "drizzle.config.ts");
|
|
69
71
|
writeFileSync(configPath, `import { defineConfig } from "drizzle-kit";
|
|
70
72
|
|
|
@@ -76,7 +78,7 @@ export default defineConfig({
|
|
|
76
78
|
url: "${info.databaseUrl}",
|
|
77
79
|
},
|
|
78
80
|
migrations: {
|
|
79
|
-
schema: "
|
|
81
|
+
schema: "${journalSchema}",
|
|
80
82
|
table: "${journalTable}",
|
|
81
83
|
},
|
|
82
84
|
verbose: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db-studio.mjs","names":[],"sources":["../../src/cli/db-studio.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport * as p from \"@clack/prompts\";\nimport type { RuntimeConfig } from \"../types\";\n\nexport interface PluginDbInfo {\n key: string;\n source: \"local\" | \"remote\";\n section: \"app.api\" | \"app.auth\" | \"plugins\";\n databaseSecret: string;\n databaseUrl: string;\n workspaceDir?: string;\n projectDir: string;\n}\n\nexport function resolvePluginDbInfo(\n pluginKey: string,\n runtimeConfig: RuntimeConfig,\n projectDir: string,\n): PluginDbInfo {\n let source: \"local\" | \"remote\" | undefined;\n let section: PluginDbInfo[\"section\"];\n let secrets: string[] | undefined;\n let localPath: string | undefined;\n let key: string;\n\n if (pluginKey === \"api\" && runtimeConfig.api) {\n source = runtimeConfig.api.source;\n section = \"app.api\";\n secrets = runtimeConfig.api.secrets;\n localPath = runtimeConfig.api.localPath;\n key = \"api\";\n } else if (pluginKey === \"auth\" && runtimeConfig.auth) {\n source = runtimeConfig.auth.source;\n section = \"app.auth\";\n secrets = runtimeConfig.auth.secrets;\n localPath = runtimeConfig.auth.localPath;\n key = \"auth\";\n } else if (runtimeConfig.plugins?.[pluginKey]) {\n const plugin = runtimeConfig.plugins[pluginKey];\n source = plugin.source;\n section = \"plugins\";\n secrets = plugin.secrets;\n localPath = plugin.localPath;\n key = pluginKey;\n } else {\n throw new Error(\n `Plugin \"${pluginKey}\" not found in app.api, app.auth, or plugins. ` +\n `Available: ${[\n \"api\",\n ...(runtimeConfig.auth ? [\"auth\"] : []),\n ...Object.keys(runtimeConfig.plugins ?? {}),\n ].join(\", \")}`,\n );\n }\n\n const dbSecret = secrets?.find((s) => s.endsWith(\"_DATABASE_URL\"));\n if (!dbSecret) {\n throw new Error(\n `Plugin \"${pluginKey}\" has no database secret (no secret ending in _DATABASE_URL). ` +\n `Secrets: ${(secrets ?? []).join(\", \") || \"none\"}`,\n );\n }\n\n const dbUrl = process.env[dbSecret];\n if (!dbUrl) {\n throw new Error(\n `.env missing ${dbSecret} for plugin \"${pluginKey}\". ` +\n `Add it to your .env file (see .env.example).`,\n );\n }\n\n return {\n key,\n source: source ?? \"remote\",\n section,\n databaseSecret: dbSecret,\n databaseUrl: dbUrl,\n workspaceDir: localPath,\n projectDir,\n };\n}\n\nexport async function runStudioLocal(info: PluginDbInfo): Promise<void> {\n const workspaceRoot = info.workspaceDir\n ? resolve(info.projectDir, info.workspaceDir)\n : resolve(info.projectDir, info.key);\n const configPath = join(workspaceRoot, \"drizzle.config.ts\");\n\n if (!existsSync(configPath)) {\n throw new Error(\n `No drizzle.config.ts found in ${workspaceRoot}. ` +\n `Run 'drizzle-kit init' first in the plugin workspace.`,\n );\n }\n\n p.log.info(`Starting Drizzle Studio for ${info.key} (local)...`);\n\n await spawnAsync(\"npx\", [\"drizzle-kit\", \"studio\", \"--config\", configPath], {\n cwd: workspaceRoot,\n });\n}\n\
|
|
1
|
+
{"version":3,"file":"db-studio.mjs","names":[],"sources":["../../src/cli/db-studio.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport * as p from \"@clack/prompts\";\nimport { getMigrationStorage, pluginMigrationSlug } from \"../db\";\nimport type { RuntimeConfig } from \"../types\";\n\nexport interface PluginDbInfo {\n key: string;\n source: \"local\" | \"remote\";\n section: \"app.api\" | \"app.auth\" | \"plugins\";\n databaseSecret: string;\n databaseUrl: string;\n workspaceDir?: string;\n projectDir: string;\n}\n\nexport function resolvePluginDbInfo(\n pluginKey: string,\n runtimeConfig: RuntimeConfig,\n projectDir: string,\n): PluginDbInfo {\n let source: \"local\" | \"remote\" | undefined;\n let section: PluginDbInfo[\"section\"];\n let secrets: string[] | undefined;\n let localPath: string | undefined;\n let key: string;\n\n if (pluginKey === \"api\" && runtimeConfig.api) {\n source = runtimeConfig.api.source;\n section = \"app.api\";\n secrets = runtimeConfig.api.secrets;\n localPath = runtimeConfig.api.localPath;\n key = \"api\";\n } else if (pluginKey === \"auth\" && runtimeConfig.auth) {\n source = runtimeConfig.auth.source;\n section = \"app.auth\";\n secrets = runtimeConfig.auth.secrets;\n localPath = runtimeConfig.auth.localPath;\n key = \"auth\";\n } else if (runtimeConfig.plugins?.[pluginKey]) {\n const plugin = runtimeConfig.plugins[pluginKey];\n source = plugin.source;\n section = \"plugins\";\n secrets = plugin.secrets;\n localPath = plugin.localPath;\n key = pluginKey;\n } else {\n throw new Error(\n `Plugin \"${pluginKey}\" not found in app.api, app.auth, or plugins. ` +\n `Available: ${[\n \"api\",\n ...(runtimeConfig.auth ? [\"auth\"] : []),\n ...Object.keys(runtimeConfig.plugins ?? {}),\n ].join(\", \")}`,\n );\n }\n\n const dbSecret = secrets?.find((s) => s.endsWith(\"_DATABASE_URL\"));\n if (!dbSecret) {\n throw new Error(\n `Plugin \"${pluginKey}\" has no database secret (no secret ending in _DATABASE_URL). ` +\n `Secrets: ${(secrets ?? []).join(\", \") || \"none\"}`,\n );\n }\n\n const dbUrl = process.env[dbSecret];\n if (!dbUrl) {\n throw new Error(\n `.env missing ${dbSecret} for plugin \"${pluginKey}\". ` +\n `Add it to your .env file (see .env.example).`,\n );\n }\n\n return {\n key,\n source: source ?? \"remote\",\n section,\n databaseSecret: dbSecret,\n databaseUrl: dbUrl,\n workspaceDir: localPath,\n projectDir,\n };\n}\n\nexport async function runStudioLocal(info: PluginDbInfo): Promise<void> {\n const workspaceRoot = info.workspaceDir\n ? resolve(info.projectDir, info.workspaceDir)\n : resolve(info.projectDir, info.key);\n const configPath = join(workspaceRoot, \"drizzle.config.ts\");\n\n if (!existsSync(configPath)) {\n throw new Error(\n `No drizzle.config.ts found in ${workspaceRoot}. ` +\n `Run 'drizzle-kit init' first in the plugin workspace.`,\n );\n }\n\n p.log.info(`Starting Drizzle Studio for ${info.key} (local)...`);\n\n await spawnAsync(\"npx\", [\"drizzle-kit\", \"studio\", \"--config\", configPath], {\n cwd: workspaceRoot,\n });\n}\n\nexport async function runStudioRemote(info: PluginDbInfo): Promise<void> {\n const dbDir = resolve(info.projectDir, \".bos\", \"db\", info.key);\n\n mkdirSync(dbDir, { recursive: true });\n\n const storage = getMigrationStorage(pluginMigrationSlug(info.key));\n const journalSchema = storage.schema;\n const journalTable = storage.table;\n\n const configPath = join(dbDir, \"drizzle.config.ts\");\n const configContent = `import { defineConfig } from \"drizzle-kit\";\n\nexport default defineConfig({\n schema: \"./drizzle/schema.ts\",\n out: \"./drizzle\",\n dialect: \"postgresql\",\n dbCredentials: {\n url: \"${info.databaseUrl}\",\n },\n migrations: {\n schema: \"${journalSchema}\",\n table: \"${journalTable}\",\n },\n verbose: true,\n strict: true,\n});\n`;\n\n writeFileSync(configPath, configContent);\n\n p.log.info(`Introspecting database schema for ${info.key}...`);\n try {\n await spawnAsync(\"npx\", [\"drizzle-kit\", \"pull\", \"--config\", configPath], {\n cwd: dbDir,\n });\n } catch {\n throw new Error(\n `Failed to introspect database for \"${info.key}\". ` +\n `Check that ${info.databaseSecret} is correct and the database is reachable.`,\n );\n }\n\n p.log.info(`Starting Drizzle Studio for ${info.key}...`);\n await spawnAsync(\"npx\", [\"drizzle-kit\", \"studio\", \"--config\", configPath], {\n cwd: dbDir,\n });\n}\n\nfunction spawnAsync(cmd: string, args: string[], options: { cwd: string }): Promise<void> {\n return new Promise((resolvePromise, reject) => {\n const child = spawn(cmd, args, {\n cwd: options.cwd,\n stdio: \"inherit\",\n shell: true,\n });\n\n child.on(\"error\", (err) => {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n reject(\n new Error(\n `\"${cmd}\" not found. Ensure it is installed (e.g. 'npm install -g drizzle-kit').`,\n ),\n );\n } else {\n reject(new Error(`Failed to start ${cmd}: ${err.message}`));\n }\n });\n\n child.on(\"exit\", (code) => {\n if (code === 0 || code === null) {\n resolvePromise();\n } else {\n reject(new Error(`\"${cmd}\" exited with code ${code}`));\n }\n });\n });\n}\n"],"mappings":"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"}
|
|
@@ -17,19 +17,55 @@ function readNodeModulesVersion(projectDir, packageName) {
|
|
|
17
17
|
if (!(0, node_fs.existsSync)(pkgPath)) return void 0;
|
|
18
18
|
return JSON.parse((0, node_fs.readFileSync)(pkgPath, "utf-8")).version;
|
|
19
19
|
}
|
|
20
|
-
function
|
|
21
|
-
const pkgPath = (0, node_path.join)(projectDir, "package.json");
|
|
22
|
-
if (!(0, node_fs.existsSync)(pkgPath)) return void 0;
|
|
23
|
-
const pkg = JSON.parse((0, node_fs.readFileSync)(pkgPath, "utf-8"));
|
|
20
|
+
function readSpecifier(pkg, packageName) {
|
|
24
21
|
const deps = pkg.dependencies ?? {};
|
|
25
22
|
const devDeps = pkg.devDependencies ?? {};
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
const peerDeps = pkg.peerDependencies ?? {};
|
|
24
|
+
return deps[packageName] || devDeps[packageName] || peerDeps[packageName];
|
|
25
|
+
}
|
|
26
|
+
function resolveFrameworkPackage(projectDir, packageName) {
|
|
27
|
+
const pkgPath = (0, node_path.join)(projectDir, "package.json");
|
|
28
|
+
if (!(0, node_fs.existsSync)(pkgPath)) return {
|
|
29
|
+
isLinked: false,
|
|
30
|
+
isWorkspaceLike: false
|
|
31
|
+
};
|
|
32
|
+
const specifier = readSpecifier(JSON.parse((0, node_fs.readFileSync)(pkgPath, "utf-8")), packageName);
|
|
33
|
+
if (!specifier) return {
|
|
34
|
+
specifier,
|
|
35
|
+
installedVersion: readRootCatalogVersion(projectDir, packageName) ?? readNodeModulesVersion(projectDir, packageName),
|
|
36
|
+
isLinked: false,
|
|
37
|
+
isWorkspaceLike: false
|
|
38
|
+
};
|
|
39
|
+
if (specifier.startsWith("link:")) return {
|
|
40
|
+
specifier,
|
|
41
|
+
installedVersion: readNodeModulesVersion(projectDir, packageName),
|
|
42
|
+
isLinked: true,
|
|
43
|
+
isWorkspaceLike: false
|
|
44
|
+
};
|
|
45
|
+
if (specifier.startsWith("workspace:") || specifier.startsWith("file:")) return {
|
|
46
|
+
specifier,
|
|
47
|
+
installedVersion: readNodeModulesVersion(projectDir, packageName),
|
|
48
|
+
isLinked: false,
|
|
49
|
+
isWorkspaceLike: true
|
|
50
|
+
};
|
|
51
|
+
if (specifier === "catalog:") return {
|
|
52
|
+
specifier,
|
|
53
|
+
installedVersion: readRootCatalogVersion(projectDir, packageName) ?? readNodeModulesVersion(projectDir, packageName),
|
|
54
|
+
isLinked: false,
|
|
55
|
+
isWorkspaceLike: false
|
|
56
|
+
};
|
|
57
|
+
return {
|
|
58
|
+
specifier,
|
|
59
|
+
installedVersion: stripVersionPrefix(specifier),
|
|
60
|
+
isLinked: false,
|
|
61
|
+
isWorkspaceLike: false
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function readInstalledFrameworkVersion(projectDir, packageName) {
|
|
65
|
+
return resolveFrameworkPackage(projectDir, packageName).installedVersion;
|
|
31
66
|
}
|
|
32
67
|
|
|
33
68
|
//#endregion
|
|
34
69
|
exports.readInstalledFrameworkVersion = readInstalledFrameworkVersion;
|
|
70
|
+
exports.resolveFrameworkPackage = resolveFrameworkPackage;
|
|
35
71
|
//# sourceMappingURL=framework-version.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"framework-version.cjs","names":[],"sources":["../../src/cli/framework-version.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nfunction stripVersionPrefix(version: string): string {\n return version.replace(/^[\\^~>=]+/, \"\");\n}\n\nexport function readRootCatalogVersion(\n projectDir: string,\n packageName: string,\n): string | undefined {\n const pkgPath = join(projectDir, \"package.json\");\n if (!existsSync(pkgPath)) return undefined;\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as {\n workspaces?: { catalog?: Record<string, string> };\n };\n const version = pkg.workspaces?.catalog?.[packageName];\n return version ? stripVersionPrefix(version) : undefined;\n}\n\nexport function readNodeModulesVersion(\n projectDir: string,\n packageName: string,\n): string | undefined {\n const pkgPath = join(projectDir, \"node_modules\", packageName, \"package.json\");\n if (!existsSync(pkgPath)) return undefined;\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as { version?: string };\n return pkg.version;\n}\n\nexport function
|
|
1
|
+
{"version":3,"file":"framework-version.cjs","names":[],"sources":["../../src/cli/framework-version.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport interface FrameworkPackageResolution {\n specifier?: string;\n installedVersion?: string;\n isLinked: boolean;\n isWorkspaceLike: boolean;\n}\n\nfunction stripVersionPrefix(version: string): string {\n return version.replace(/^[\\^~>=]+/, \"\");\n}\n\nexport function readRootCatalogVersion(\n projectDir: string,\n packageName: string,\n): string | undefined {\n const pkgPath = join(projectDir, \"package.json\");\n if (!existsSync(pkgPath)) return undefined;\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as {\n workspaces?: { catalog?: Record<string, string> };\n };\n const version = pkg.workspaces?.catalog?.[packageName];\n return version ? stripVersionPrefix(version) : undefined;\n}\n\nexport function readNodeModulesVersion(\n projectDir: string,\n packageName: string,\n): string | undefined {\n const pkgPath = join(projectDir, \"node_modules\", packageName, \"package.json\");\n if (!existsSync(pkgPath)) return undefined;\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as { version?: string };\n return pkg.version;\n}\n\nfunction readSpecifier(pkg: Record<string, unknown>, packageName: string): string | undefined {\n const deps = (pkg.dependencies ?? {}) as Record<string, string>;\n const devDeps = (pkg.devDependencies ?? {}) as Record<string, string>;\n const peerDeps = (pkg.peerDependencies ?? {}) as Record<string, string>;\n return deps[packageName] || devDeps[packageName] || peerDeps[packageName];\n}\n\nexport function resolveFrameworkPackage(\n projectDir: string,\n packageName: string,\n): FrameworkPackageResolution {\n const pkgPath = join(projectDir, \"package.json\");\n if (!existsSync(pkgPath)) {\n return { isLinked: false, isWorkspaceLike: false };\n }\n\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as Record<string, unknown>;\n const specifier = readSpecifier(pkg, packageName);\n\n if (!specifier) {\n const catalog = readRootCatalogVersion(projectDir, packageName);\n const installed = catalog ?? readNodeModulesVersion(projectDir, packageName);\n return {\n specifier,\n installedVersion: installed,\n isLinked: false,\n isWorkspaceLike: false,\n };\n }\n\n if (specifier.startsWith(\"link:\")) {\n return {\n specifier,\n installedVersion: readNodeModulesVersion(projectDir, packageName),\n isLinked: true,\n isWorkspaceLike: false,\n };\n }\n\n if (specifier.startsWith(\"workspace:\") || specifier.startsWith(\"file:\")) {\n return {\n specifier,\n installedVersion: readNodeModulesVersion(projectDir, packageName),\n isLinked: false,\n isWorkspaceLike: true,\n };\n }\n\n if (specifier === \"catalog:\") {\n const catalog = readRootCatalogVersion(projectDir, packageName);\n const installed = catalog ?? readNodeModulesVersion(projectDir, packageName);\n return {\n specifier,\n installedVersion: installed,\n isLinked: false,\n isWorkspaceLike: false,\n };\n }\n\n return {\n specifier,\n installedVersion: stripVersionPrefix(specifier),\n isLinked: false,\n isWorkspaceLike: false,\n };\n}\n\nexport function readInstalledFrameworkVersion(\n projectDir: string,\n packageName: string,\n): string | undefined {\n return resolveFrameworkPackage(projectDir, packageName).installedVersion;\n}\n"],"mappings":";;;;;AAUA,SAAS,mBAAmB,SAAyB;AACnD,QAAO,QAAQ,QAAQ,aAAa,GAAG;;AAGzC,SAAgB,uBACd,YACA,aACoB;CACpB,MAAM,8BAAe,YAAY,eAAe;AAChD,KAAI,yBAAY,QAAQ,CAAE,QAAO;CAIjC,MAAM,UAHM,KAAK,gCAAmB,SAAS,QAAQ,CAGlC,CAAC,YAAY,UAAU;AAC1C,QAAO,UAAU,mBAAmB,QAAQ,GAAG;;AAGjD,SAAgB,uBACd,YACA,aACoB;CACpB,MAAM,8BAAe,YAAY,gBAAgB,aAAa,eAAe;AAC7E,KAAI,yBAAY,QAAQ,CAAE,QAAO;AAEjC,QADY,KAAK,gCAAmB,SAAS,QAAQ,CAC3C,CAAC;;AAGb,SAAS,cAAc,KAA8B,aAAyC;CAC5F,MAAM,OAAQ,IAAI,gBAAgB,EAAE;CACpC,MAAM,UAAW,IAAI,mBAAmB,EAAE;CAC1C,MAAM,WAAY,IAAI,oBAAoB,EAAE;AAC5C,QAAO,KAAK,gBAAgB,QAAQ,gBAAgB,SAAS;;AAG/D,SAAgB,wBACd,YACA,aAC4B;CAC5B,MAAM,8BAAe,YAAY,eAAe;AAChD,KAAI,yBAAY,QAAQ,CACtB,QAAO;EAAE,UAAU;EAAO,iBAAiB;EAAO;CAIpD,MAAM,YAAY,cADN,KAAK,gCAAmB,SAAS,QAAQ,CAClB,EAAE,YAAY;AAEjD,KAAI,CAAC,UAGH,QAAO;EACL;EACA,kBAJc,uBAAuB,YAAY,YAC1B,IAAI,uBAAuB,YAAY,YAAY;EAI1E,UAAU;EACV,iBAAiB;EAClB;AAGH,KAAI,UAAU,WAAW,QAAQ,CAC/B,QAAO;EACL;EACA,kBAAkB,uBAAuB,YAAY,YAAY;EACjE,UAAU;EACV,iBAAiB;EAClB;AAGH,KAAI,UAAU,WAAW,aAAa,IAAI,UAAU,WAAW,QAAQ,CACrE,QAAO;EACL;EACA,kBAAkB,uBAAuB,YAAY,YAAY;EACjE,UAAU;EACV,iBAAiB;EAClB;AAGH,KAAI,cAAc,WAGhB,QAAO;EACL;EACA,kBAJc,uBAAuB,YAAY,YAC1B,IAAI,uBAAuB,YAAY,YAAY;EAI1E,UAAU;EACV,iBAAiB;EAClB;AAGH,QAAO;EACL;EACA,kBAAkB,mBAAmB,UAAU;EAC/C,UAAU;EACV,iBAAiB;EAClB;;AAGH,SAAgB,8BACd,YACA,aACoB;AACpB,QAAO,wBAAwB,YAAY,YAAY,CAAC"}
|