@schemavaults/dbh 0.10.1 → 0.11.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/.claude/skills/database-migrations/SKILL.md +244 -0
- package/README.md +15 -1
- package/dist/adapters/abstract-schemavaults-dbh-adapter.d.ts +3 -3
- package/dist/adapters/abstract-schemavaults-dbh-adapter.js +4 -4
- package/dist/adapters/schemavaults-postgres-adapter.d.ts +3 -3
- package/dist/adapters/schemavaults-postgres-adapter.js +2 -2
- package/dist/adapters/schemavaults-postgres-neon-proxy-adapter.d.ts +5 -5
- package/dist/adapters/schemavaults-postgres-neon-proxy-adapter.js +3 -3
- package/dist/create-dbh.d.ts +2 -2
- package/dist/create-dbh.js +2 -2
- package/dist/index.d.ts +5 -5
- package/dist/index.js +4 -4
- package/dist/utils/buildPostgresUrl.d.ts +1 -1
- package/dist/utils/getAppEnvironment.d.ts +1 -1
- package/dist/utils/getAppEnvironment.js +1 -1
- package/dist/utils/getPostgresNeonWsProxyUrl.d.ts +1 -1
- package/dist/utils/getPostgresNeonWsProxyUrl.js +1 -1
- package/dist/utils/isDbhInDebugMode.d.ts +1 -1
- package/dist/utils/parseDatabaseCredentials.d.ts +1 -1
- package/dist/utils/parseDatabaseCredentials.js +2 -2
- package/dist/utils/parseDatabaseCredentialsFromEnv.d.ts +1 -1
- package/dist/utils/parseDatabaseCredentialsFromEnv.js +1 -1
- package/dist/utils/validateMigrationDirectory.d.ts +35 -0
- package/dist/utils/validateMigrationDirectory.js +157 -0
- package/dist/utils/validateMigrationDirectory.js.map +1 -0
- package/dist-cli/cli.js +21 -21
- package/package.json +2 -2
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { pathToFileURL } from "url";
|
|
4
|
+
/**
|
|
5
|
+
* Extensions that are treated as migration modules. `.d.ts` declaration files
|
|
6
|
+
* are explicitly ignored (handled separately below).
|
|
7
|
+
*/
|
|
8
|
+
const MIGRATION_FILE_EXTENSIONS = [
|
|
9
|
+
".ts",
|
|
10
|
+
".mts",
|
|
11
|
+
".cts",
|
|
12
|
+
".js",
|
|
13
|
+
".mjs",
|
|
14
|
+
".cjs",
|
|
15
|
+
];
|
|
16
|
+
/** Migration file names must begin with exactly 5 digits (e.g. 00000-foo.ts). */
|
|
17
|
+
const MIGRATION_PREFIX_REGEX = /^(\d{5})(?:\D|$)/;
|
|
18
|
+
function isMigrationFile(fileName) {
|
|
19
|
+
if (fileName.startsWith(".")) {
|
|
20
|
+
// Ignore hidden/dotfiles.
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
if (fileName.endsWith(".d.ts")) {
|
|
24
|
+
// Ignore TypeScript declaration files.
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
return MIGRATION_FILE_EXTENSIONS.some((ext) => fileName.endsWith(ext));
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Validates the shape of an opinionated Kysely migrations directory.
|
|
31
|
+
*
|
|
32
|
+
* Asserts that the directory:
|
|
33
|
+
* - exists and is non-empty,
|
|
34
|
+
* - contains only files prefixed with a 5-digit migration number,
|
|
35
|
+
* - has no duplicate migration numbers (branch collisions), and
|
|
36
|
+
* - exports an `up()` and `down()` function from every migration module.
|
|
37
|
+
*/
|
|
38
|
+
export async function validateMigrationDirectory(directory, options = {}) {
|
|
39
|
+
const { duplicatesAsWarnings = false } = options;
|
|
40
|
+
const resolved = path.resolve(directory);
|
|
41
|
+
const issues = [];
|
|
42
|
+
if (!fs.existsSync(resolved)) {
|
|
43
|
+
return {
|
|
44
|
+
ok: false,
|
|
45
|
+
directory: resolved,
|
|
46
|
+
migrationFiles: [],
|
|
47
|
+
issues: [
|
|
48
|
+
{
|
|
49
|
+
level: "error",
|
|
50
|
+
message: `Migration directory does not exist: ${resolved}`,
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const stat = fs.statSync(resolved);
|
|
56
|
+
if (!stat.isDirectory()) {
|
|
57
|
+
return {
|
|
58
|
+
ok: false,
|
|
59
|
+
directory: resolved,
|
|
60
|
+
migrationFiles: [],
|
|
61
|
+
issues: [
|
|
62
|
+
{
|
|
63
|
+
level: "error",
|
|
64
|
+
message: `Migration path is not a directory: ${resolved}`,
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
const entries = fs.readdirSync(resolved, { withFileTypes: true });
|
|
70
|
+
const migrationFiles = entries
|
|
71
|
+
.filter((entry) => entry.isFile() && isMigrationFile(entry.name))
|
|
72
|
+
.map((entry) => entry.name)
|
|
73
|
+
.sort();
|
|
74
|
+
// 1) Directory must be non-empty.
|
|
75
|
+
if (migrationFiles.length === 0) {
|
|
76
|
+
issues.push({
|
|
77
|
+
level: "error",
|
|
78
|
+
message: `Migration directory is empty (no migration files found): ${resolved}`,
|
|
79
|
+
});
|
|
80
|
+
return {
|
|
81
|
+
ok: false,
|
|
82
|
+
directory: resolved,
|
|
83
|
+
migrationFiles,
|
|
84
|
+
issues,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
// 2) Every file must be prefixed with a 5-digit migration number.
|
|
88
|
+
// Track which numbers map to which files for duplicate detection.
|
|
89
|
+
const numberToFiles = new Map();
|
|
90
|
+
for (const file of migrationFiles) {
|
|
91
|
+
const match = MIGRATION_PREFIX_REGEX.exec(file);
|
|
92
|
+
if (!match) {
|
|
93
|
+
issues.push({
|
|
94
|
+
level: "error",
|
|
95
|
+
file,
|
|
96
|
+
message: `File is not prefixed with a 5-digit migration number (e.g. 00000-my-migration.ts): ${file}`,
|
|
97
|
+
});
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const number = match[1];
|
|
101
|
+
const existing = numberToFiles.get(number);
|
|
102
|
+
if (existing) {
|
|
103
|
+
existing.push(file);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
numberToFiles.set(number, [file]);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// 3) No duplicate migration numbers (collisions across branches).
|
|
110
|
+
for (const [number, files] of numberToFiles) {
|
|
111
|
+
if (files.length > 1) {
|
|
112
|
+
issues.push({
|
|
113
|
+
level: duplicatesAsWarnings ? "warning" : "error",
|
|
114
|
+
message: `Duplicate migration number '${number}' used by ${files.length} files: ${files.join(", ")}`,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// 4) Every module must export an up() and down() function.
|
|
119
|
+
for (const file of migrationFiles) {
|
|
120
|
+
const fullPath = path.join(resolved, file);
|
|
121
|
+
let mod;
|
|
122
|
+
try {
|
|
123
|
+
mod = (await import(pathToFileURL(fullPath).href));
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
issues.push({
|
|
127
|
+
level: "error",
|
|
128
|
+
file,
|
|
129
|
+
message: `Failed to import migration module '${file}': ${error instanceof Error ? error.message : String(error)}`,
|
|
130
|
+
});
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (typeof mod.up !== "function") {
|
|
134
|
+
issues.push({
|
|
135
|
+
level: "error",
|
|
136
|
+
file,
|
|
137
|
+
message: `Migration '${file}' does not export an up() function`,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
if (typeof mod.down !== "function") {
|
|
141
|
+
issues.push({
|
|
142
|
+
level: "error",
|
|
143
|
+
file,
|
|
144
|
+
message: `Migration '${file}' does not export a down() function`,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const ok = !issues.some((issue) => issue.level === "error");
|
|
149
|
+
return {
|
|
150
|
+
ok,
|
|
151
|
+
directory: resolved,
|
|
152
|
+
migrationFiles,
|
|
153
|
+
issues,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
export default validateMigrationDirectory;
|
|
157
|
+
//# sourceMappingURL=validateMigrationDirectory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validateMigrationDirectory.js","sourceRoot":"","sources":["../../src/utils/validateMigrationDirectory.ts"],"names":[],"mappings":"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"}
|