@nextlyhq/adapter-drizzle 0.0.1
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/LICENSE +22 -0
- package/README.md +9 -0
- package/dist/adapter-BxJVtttb.d.ts +592 -0
- package/dist/adapter-nvlxFkF-.d.cts +592 -0
- package/dist/core-CVO7WYDj.d.cts +74 -0
- package/dist/core-CVO7WYDj.d.ts +74 -0
- package/dist/error-um1d_3Uo.d.cts +105 -0
- package/dist/error-um1d_3Uo.d.ts +105 -0
- package/dist/index.cjs +1137 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +57 -0
- package/dist/index.d.ts +57 -0
- package/dist/index.mjs +1134 -0
- package/dist/index.mjs.map +1 -0
- package/dist/migration-BbO5meEV.d.cts +622 -0
- package/dist/migration-Qe70wDOC.d.ts +622 -0
- package/dist/migrations.cjs +195 -0
- package/dist/migrations.cjs.map +1 -0
- package/dist/migrations.d.cts +351 -0
- package/dist/migrations.d.ts +351 -0
- package/dist/migrations.mjs +185 -0
- package/dist/migrations.mjs.map +1 -0
- package/dist/schema/index.cjs +10 -0
- package/dist/schema/index.cjs.map +1 -0
- package/dist/schema/index.d.cts +133 -0
- package/dist/schema/index.d.ts +133 -0
- package/dist/schema/index.mjs +7 -0
- package/dist/schema/index.mjs.map +1 -0
- package/dist/schema-BDn8WfSL.d.cts +200 -0
- package/dist/schema-BIQ0YQZ_.d.ts +200 -0
- package/dist/types/index.cjs +24 -0
- package/dist/types/index.cjs.map +1 -0
- package/dist/types/index.d.cts +210 -0
- package/dist/types/index.d.ts +210 -0
- package/dist/types/index.mjs +21 -0
- package/dist/types/index.mjs.map +1 -0
- package/dist/version-check.cjs +154 -0
- package/dist/version-check.cjs.map +1 -0
- package/dist/version-check.d.cts +43 -0
- package/dist/version-check.d.ts +43 -0
- package/dist/version-check.mjs +150 -0
- package/dist/version-check.mjs.map +1 -0
- package/package.json +94 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var crypto = require('crypto');
|
|
4
|
+
|
|
5
|
+
// src/migrations.ts
|
|
6
|
+
function calculateChecksum(migration) {
|
|
7
|
+
const content = JSON.stringify({
|
|
8
|
+
id: migration.id,
|
|
9
|
+
name: migration.name,
|
|
10
|
+
timestamp: migration.timestamp,
|
|
11
|
+
up: typeof migration.up === "string" ? migration.up : migration.up.toString(),
|
|
12
|
+
down: typeof migration.down === "string" ? migration.down : migration.down?.toString() || null
|
|
13
|
+
});
|
|
14
|
+
return crypto.createHash("sha256").update(content, "utf8").digest("hex");
|
|
15
|
+
}
|
|
16
|
+
function sortMigrations(migrations) {
|
|
17
|
+
return [...migrations].sort((a, b) => {
|
|
18
|
+
if (a.timestamp !== b.timestamp) {
|
|
19
|
+
return a.timestamp - b.timestamp;
|
|
20
|
+
}
|
|
21
|
+
return a.id.localeCompare(b.id);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function filterPending(migrations, applied) {
|
|
25
|
+
const appliedIds = new Set(applied.map((record) => record.id));
|
|
26
|
+
return migrations.filter((migration) => !appliedIds.has(migration.id));
|
|
27
|
+
}
|
|
28
|
+
function filterApplied(migrations, applied) {
|
|
29
|
+
const migrationIds = new Set(migrations.map((migration) => migration.id));
|
|
30
|
+
return applied.filter((record) => migrationIds.has(record.id));
|
|
31
|
+
}
|
|
32
|
+
function validateChecksum(migration, record) {
|
|
33
|
+
if (!record.checksum) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
const currentChecksum = calculateChecksum(migration);
|
|
37
|
+
return currentChecksum === record.checksum;
|
|
38
|
+
}
|
|
39
|
+
function detectModified(migrations, applied) {
|
|
40
|
+
const migrationMap = new Map(migrations.map((m) => [m.id, m]));
|
|
41
|
+
const modified = [];
|
|
42
|
+
for (const record of applied) {
|
|
43
|
+
const migration = migrationMap.get(record.id);
|
|
44
|
+
if (migration && !validateChecksum(migration, record)) {
|
|
45
|
+
modified.push(record);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return modified;
|
|
49
|
+
}
|
|
50
|
+
function getMigrationStatus(migrations, applied) {
|
|
51
|
+
const sortedMigrations = sortMigrations(migrations);
|
|
52
|
+
const sortedApplied = [...applied].sort(
|
|
53
|
+
(a, b) => b.appliedAt.getTime() - a.appliedAt.getTime()
|
|
54
|
+
);
|
|
55
|
+
const pending = filterPending(sortedMigrations, applied);
|
|
56
|
+
const current = sortedApplied.length > 0 ? sortedApplied[0].id : null;
|
|
57
|
+
return {
|
|
58
|
+
current,
|
|
59
|
+
appliedCount: applied.length,
|
|
60
|
+
pendingCount: pending.length,
|
|
61
|
+
applied,
|
|
62
|
+
pending
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function validateMigrations(migrations, applied, options) {
|
|
66
|
+
const errors = [];
|
|
67
|
+
const warnings = [];
|
|
68
|
+
const duplicates = [];
|
|
69
|
+
const idCounts = /* @__PURE__ */ new Map();
|
|
70
|
+
for (const migration of migrations) {
|
|
71
|
+
const count = (idCounts.get(migration.id) || 0) + 1;
|
|
72
|
+
idCounts.set(migration.id, count);
|
|
73
|
+
if (count > 1) {
|
|
74
|
+
duplicates.push(migration.id);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (duplicates.length > 0) {
|
|
78
|
+
errors.push(`Duplicate migration IDs found: ${duplicates.join(", ")}`);
|
|
79
|
+
}
|
|
80
|
+
for (const migration of migrations) {
|
|
81
|
+
if (!migration.id) {
|
|
82
|
+
errors.push("Migration missing required field: id");
|
|
83
|
+
}
|
|
84
|
+
if (!migration.name) {
|
|
85
|
+
errors.push(`Migration ${migration.id} missing required field: name`);
|
|
86
|
+
}
|
|
87
|
+
if (!migration.timestamp || typeof migration.timestamp !== "number") {
|
|
88
|
+
errors.push(`Migration ${migration.id} missing or invalid timestamp`);
|
|
89
|
+
}
|
|
90
|
+
if (!migration.up) {
|
|
91
|
+
errors.push(`Migration ${migration.id} missing required field: up`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const modified = detectModified(migrations, applied);
|
|
95
|
+
if (modified.length > 0) {
|
|
96
|
+
const modifiedIds = modified.map((r) => r.id).join(", ");
|
|
97
|
+
const message = `Applied migrations have been modified: ${modifiedIds}`;
|
|
98
|
+
const strictChecksums = options?.strictChecksums ?? true;
|
|
99
|
+
if (strictChecksums) {
|
|
100
|
+
errors.push(message);
|
|
101
|
+
} else {
|
|
102
|
+
warnings.push(message);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
valid: errors.length === 0,
|
|
107
|
+
errors,
|
|
108
|
+
warnings,
|
|
109
|
+
modified,
|
|
110
|
+
duplicates
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
var migrationHelpers = {
|
|
114
|
+
async createMigrationsTable(adapter) {
|
|
115
|
+
const caps = adapter.getCapabilities();
|
|
116
|
+
const dialect = caps.dialect;
|
|
117
|
+
let sql = "";
|
|
118
|
+
if (dialect === "postgresql") {
|
|
119
|
+
sql = `
|
|
120
|
+
CREATE TABLE IF NOT EXISTS nextly_migrations (
|
|
121
|
+
id VARCHAR(255) PRIMARY KEY,
|
|
122
|
+
name VARCHAR(255) NOT NULL,
|
|
123
|
+
applied_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
124
|
+
checksum VARCHAR(64)
|
|
125
|
+
)
|
|
126
|
+
`;
|
|
127
|
+
} else if (dialect === "mysql") {
|
|
128
|
+
sql = `
|
|
129
|
+
CREATE TABLE IF NOT EXISTS nextly_migrations (
|
|
130
|
+
id VARCHAR(255) PRIMARY KEY,
|
|
131
|
+
name VARCHAR(255) NOT NULL,
|
|
132
|
+
applied_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
133
|
+
checksum VARCHAR(64)
|
|
134
|
+
)
|
|
135
|
+
`;
|
|
136
|
+
} else if (dialect === "sqlite") {
|
|
137
|
+
sql = `
|
|
138
|
+
CREATE TABLE IF NOT EXISTS nextly_migrations (
|
|
139
|
+
id TEXT PRIMARY KEY,
|
|
140
|
+
name TEXT NOT NULL,
|
|
141
|
+
applied_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
142
|
+
checksum TEXT
|
|
143
|
+
)
|
|
144
|
+
`;
|
|
145
|
+
} else {
|
|
146
|
+
throw new Error(`Unsupported dialect: ${String(dialect)}`);
|
|
147
|
+
}
|
|
148
|
+
await adapter.executeQuery(sql);
|
|
149
|
+
},
|
|
150
|
+
async getAppliedMigrations(adapter) {
|
|
151
|
+
const results = await adapter.select("nextly_migrations", {
|
|
152
|
+
orderBy: [{ column: "applied_at", direction: "desc" }]
|
|
153
|
+
});
|
|
154
|
+
return results.map((row) => ({
|
|
155
|
+
id: row.id,
|
|
156
|
+
name: row.name,
|
|
157
|
+
appliedAt: new Date(row.applied_at),
|
|
158
|
+
checksum: row.checksum
|
|
159
|
+
}));
|
|
160
|
+
},
|
|
161
|
+
async recordMigration(adapter, migration) {
|
|
162
|
+
const checksum = calculateChecksum(migration);
|
|
163
|
+
await adapter.insert("nextly_migrations", {
|
|
164
|
+
id: migration.id,
|
|
165
|
+
name: migration.name,
|
|
166
|
+
applied_at: /* @__PURE__ */ new Date(),
|
|
167
|
+
checksum
|
|
168
|
+
});
|
|
169
|
+
},
|
|
170
|
+
async removeMigrationRecord(adapter, migrationId) {
|
|
171
|
+
await adapter.delete("nextly_migrations", {
|
|
172
|
+
and: [{ column: "id", op: "=", value: migrationId }]
|
|
173
|
+
});
|
|
174
|
+
},
|
|
175
|
+
async migrationsTableExists(adapter) {
|
|
176
|
+
try {
|
|
177
|
+
await adapter.select("nextly_migrations", { limit: 1 });
|
|
178
|
+
return true;
|
|
179
|
+
} catch {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
exports.calculateChecksum = calculateChecksum;
|
|
186
|
+
exports.detectModified = detectModified;
|
|
187
|
+
exports.filterApplied = filterApplied;
|
|
188
|
+
exports.filterPending = filterPending;
|
|
189
|
+
exports.getMigrationStatus = getMigrationStatus;
|
|
190
|
+
exports.migrationHelpers = migrationHelpers;
|
|
191
|
+
exports.sortMigrations = sortMigrations;
|
|
192
|
+
exports.validateChecksum = validateChecksum;
|
|
193
|
+
exports.validateMigrations = validateMigrations;
|
|
194
|
+
//# sourceMappingURL=migrations.cjs.map
|
|
195
|
+
//# sourceMappingURL=migrations.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/migrations.ts"],"names":["createHash"],"mappings":"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","file":"migrations.cjs","sourcesContent":["/**\n * Database migration utilities.\n *\n * @remarks\n * Provides core utilities for migration management including checksum calculation,\n * sorting, filtering, and validation. Also includes optional helpers for adapters\n * to use for common migration operations.\n *\n * @packageDocumentation\n */\n\nimport { createHash } from \"crypto\";\n\nimport type { DrizzleAdapter } from \"./adapter\";\nimport type {\n Migration,\n MigrationRecord,\n MigrationStatus,\n MigrationOptions,\n} from \"./types/migration\";\n\n// ============================================================\n// Core Utilities\n// ============================================================\n\n/**\n * Calculate SHA-256 checksum for a migration.\n *\n * @remarks\n * Creates a checksum of the entire migration object including id, name, timestamp,\n * and the string representation of up/down functions. This allows detection of\n * any changes to the migration after it has been applied.\n *\n * @param migration - Migration to calculate checksum for\n * @returns Hexadecimal SHA-256 hash\n *\n * @example\n * ```typescript\n * const migration: Migration = {\n * id: \"20250104_001_create_users\",\n * name: \"Create users table\",\n * timestamp: 1704326400000,\n * up: \"CREATE TABLE users (id UUID PRIMARY KEY);\",\n * };\n *\n * const checksum = calculateChecksum(migration);\n * // Returns: \"a3f5b8c9d2e1f0...\"\n * ```\n *\n * @public\n */\nexport function calculateChecksum(migration: Migration): string {\n // Serialize migration to a consistent string format\n const content = JSON.stringify({\n id: migration.id,\n name: migration.name,\n timestamp: migration.timestamp,\n up:\n typeof migration.up === \"string\" ? migration.up : migration.up.toString(),\n down:\n typeof migration.down === \"string\"\n ? migration.down\n : migration.down?.toString() || null,\n });\n\n // Create SHA-256 hash\n return createHash(\"sha256\").update(content, \"utf8\").digest(\"hex\");\n}\n\n/**\n * Sort migrations by timestamp in ascending order.\n *\n * @remarks\n * Provides deterministic ordering of migrations. If timestamps are equal,\n * falls back to sorting by migration ID alphabetically.\n *\n * @param migrations - Array of migrations to sort\n * @returns New sorted array (original array is not modified)\n *\n * @example\n * ```typescript\n * const migrations = [\n * { id: \"003\", timestamp: 1704412800000, ... },\n * { id: \"001\", timestamp: 1704326400000, ... },\n * { id: \"002\", timestamp: 1704326400000, ... },\n * ];\n *\n * const sorted = sortMigrations(migrations);\n * // Returns: [001, 002, 003] (001 and 002 same timestamp, sorted by id)\n * ```\n *\n * @public\n */\nexport function sortMigrations(migrations: Migration[]): Migration[] {\n return [...migrations].sort((a, b) => {\n // Primary sort: timestamp ascending\n if (a.timestamp !== b.timestamp) {\n return a.timestamp - b.timestamp;\n }\n // Secondary sort: id alphabetically (for deterministic ordering)\n return a.id.localeCompare(b.id);\n });\n}\n\n/**\n * Filter migrations to get only pending (unapplied) migrations.\n *\n * @remarks\n * Returns migrations that have not been applied to the database yet.\n * A migration is considered pending if its ID is not present in the\n * applied migration records.\n *\n * @param migrations - All available migrations\n * @param applied - Records of applied migrations from database\n * @returns Array of pending migrations\n *\n * @example\n * ```typescript\n * const allMigrations = [\n * { id: \"001_create_users\", ... },\n * { id: \"002_create_posts\", ... },\n * { id: \"003_create_comments\", ... },\n * ];\n *\n * const appliedRecords = [\n * { id: \"001_create_users\", appliedAt: new Date(), ... },\n * ];\n *\n * const pending = filterPending(allMigrations, appliedRecords);\n * // Returns: [002_create_posts, 003_create_comments]\n * ```\n *\n * @public\n */\nexport function filterPending(\n migrations: Migration[],\n applied: MigrationRecord[]\n): Migration[] {\n const appliedIds = new Set(applied.map(record => record.id));\n return migrations.filter(migration => !appliedIds.has(migration.id));\n}\n\n/**\n * Filter migration records to get only those that match given migrations.\n *\n * @remarks\n * Returns applied migration records that correspond to the given migrations.\n * Useful for getting the subset of applied records relevant to a specific\n * set of migrations.\n *\n * @param migrations - Migrations to match\n * @param applied - All applied migration records from database\n * @returns Array of matching applied records\n *\n * @example\n * ```typescript\n * const migrations = [\n * { id: \"001_create_users\", ... },\n * { id: \"002_create_posts\", ... },\n * ];\n *\n * const allApplied = [\n * { id: \"001_create_users\", appliedAt: new Date(), ... },\n * { id: \"002_create_posts\", appliedAt: new Date(), ... },\n * { id: \"003_create_comments\", appliedAt: new Date(), ... },\n * ];\n *\n * const relevant = filterApplied(migrations, allApplied);\n * // Returns: [001_create_users, 002_create_posts]\n * ```\n *\n * @public\n */\nexport function filterApplied(\n migrations: Migration[],\n applied: MigrationRecord[]\n): MigrationRecord[] {\n const migrationIds = new Set(migrations.map(migration => migration.id));\n return applied.filter(record => migrationIds.has(record.id));\n}\n\n/**\n * Validate that a migration's checksum matches its applied record.\n *\n * @remarks\n * Compares the calculated checksum of a migration against the stored checksum\n * in its migration record. Returns false if checksums don't match or if the\n * record has no checksum.\n *\n * @param migration - Migration to validate\n * @param record - Applied migration record with stored checksum\n * @returns true if checksums match, false otherwise\n *\n * @example\n * ```typescript\n * const migration: Migration = { id: \"001\", ... };\n * const record: MigrationRecord = {\n * id: \"001\",\n * checksum: \"a3f5b8c9...\",\n * ...\n * };\n *\n * const isValid = validateChecksum(migration, record);\n * // Returns: true if checksums match, false if modified\n * ```\n *\n * @public\n */\nexport function validateChecksum(\n migration: Migration,\n record: MigrationRecord\n): boolean {\n if (!record.checksum) {\n // No checksum stored, cannot validate\n return false;\n }\n\n const currentChecksum = calculateChecksum(migration);\n return currentChecksum === record.checksum;\n}\n\n/**\n * Detect migrations that have been modified after being applied.\n *\n * @remarks\n * Compares checksums of migrations against their applied records to detect\n * any modifications. Returns records for migrations that have been changed\n * since they were applied to the database.\n *\n * This is critical for detecting potentially dangerous situations where a\n * migration that has already run has been modified.\n *\n * @param migrations - Current migrations\n * @param applied - Applied migration records with checksums\n * @returns Array of records for modified migrations\n *\n * @example\n * ```typescript\n * const migrations = [{ id: \"001\", up: \"CREATE TABLE users_v2 ...\" }];\n * const applied = [{ id: \"001\", checksum: \"original_hash\", ... }];\n *\n * const modified = detectModified(migrations, applied);\n * // Returns: [{ id: \"001\", ... }] if migration was changed\n * ```\n *\n * @public\n */\nexport function detectModified(\n migrations: Migration[],\n applied: MigrationRecord[]\n): MigrationRecord[] {\n const migrationMap = new Map(migrations.map(m => [m.id, m]));\n const modified: MigrationRecord[] = [];\n\n for (const record of applied) {\n const migration = migrationMap.get(record.id);\n if (migration && !validateChecksum(migration, record)) {\n modified.push(record);\n }\n }\n\n return modified;\n}\n\n/**\n * Get comprehensive migration status.\n *\n * @remarks\n * Analyzes migrations and applied records to produce a complete status report\n * including current migration, applied/pending counts, and full lists.\n *\n * @param migrations - All available migrations\n * @param applied - Applied migration records from database\n * @returns Complete migration status information\n *\n * @example\n * ```typescript\n * const status = getMigrationStatus(allMigrations, appliedRecords);\n * console.log(`Current: ${status.current}`);\n * console.log(`Applied: ${status.appliedCount}, Pending: ${status.pendingCount}`);\n * ```\n *\n * @public\n */\nexport function getMigrationStatus(\n migrations: Migration[],\n applied: MigrationRecord[]\n): MigrationStatus {\n const sortedMigrations = sortMigrations(migrations);\n const sortedApplied = [...applied].sort(\n (a, b) => b.appliedAt.getTime() - a.appliedAt.getTime()\n );\n\n const pending = filterPending(sortedMigrations, applied);\n const current = sortedApplied.length > 0 ? sortedApplied[0].id : null;\n\n return {\n current,\n appliedCount: applied.length,\n pendingCount: pending.length,\n applied,\n pending,\n };\n}\n\n// ============================================================\n// Migration Validation\n// ============================================================\n\n/**\n * Validation result for migrations.\n *\n * @public\n */\nexport interface MigrationValidationResult {\n /** Whether all validations passed */\n valid: boolean;\n\n /** List of validation errors */\n errors: string[];\n\n /** List of validation warnings */\n warnings: string[];\n\n /** Migrations that have been modified */\n modified: MigrationRecord[];\n\n /** Duplicate migration IDs found */\n duplicates: string[];\n}\n\n/**\n * Validate migrations for common issues.\n *\n * @remarks\n * Performs comprehensive validation including:\n * - Duplicate migration IDs\n * - Modified applied migrations (checksum mismatch)\n * - Missing required fields\n * - Invalid timestamps\n *\n * @param migrations - Migrations to validate\n * @param applied - Applied migration records (for checksum validation)\n * @param options - Migration options (for strictness configuration)\n * @returns Validation result with errors and warnings\n *\n * @example\n * ```typescript\n * const result = validateMigrations(migrations, applied, {\n * strictChecksums: true\n * });\n *\n * if (!result.valid) {\n * console.error(\"Validation errors:\", result.errors);\n * throw new Error(\"Migration validation failed\");\n * }\n * ```\n *\n * @public\n */\nexport function validateMigrations(\n migrations: Migration[],\n applied: MigrationRecord[],\n options?: MigrationOptions\n): MigrationValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n const duplicates: string[] = [];\n\n // Check for duplicate IDs\n const idCounts = new Map<string, number>();\n for (const migration of migrations) {\n const count = (idCounts.get(migration.id) || 0) + 1;\n idCounts.set(migration.id, count);\n if (count > 1) {\n duplicates.push(migration.id);\n }\n }\n\n if (duplicates.length > 0) {\n errors.push(`Duplicate migration IDs found: ${duplicates.join(\", \")}`);\n }\n\n // Validate required fields\n for (const migration of migrations) {\n if (!migration.id) {\n errors.push(\"Migration missing required field: id\");\n }\n if (!migration.name) {\n errors.push(`Migration ${migration.id} missing required field: name`);\n }\n if (!migration.timestamp || typeof migration.timestamp !== \"number\") {\n errors.push(`Migration ${migration.id} missing or invalid timestamp`);\n }\n if (!migration.up) {\n errors.push(`Migration ${migration.id} missing required field: up`);\n }\n }\n\n // Check for modified migrations\n const modified = detectModified(migrations, applied);\n\n if (modified.length > 0) {\n const modifiedIds = modified.map(r => r.id).join(\", \");\n const message = `Applied migrations have been modified: ${modifiedIds}`;\n\n // Use strictChecksums option if available, default to true (strict)\n const strictChecksums = options?.strictChecksums ?? true;\n\n if (strictChecksums) {\n errors.push(message);\n } else {\n warnings.push(message);\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n modified,\n duplicates,\n };\n}\n\n// ============================================================\n// Migration Helpers (for adapters)\n// ============================================================\n\n/**\n * Helper functions for managing migrations in database adapters.\n *\n * @remarks\n * These helpers reduce boilerplate code in dialect-specific adapters by\n * providing common operations like creating migration tables, recording\n * migrations, and querying migration status.\n *\n * Adapters can use these helpers or implement their own logic.\n *\n * @public\n */\nexport interface MigrationHelpers {\n /**\n * Create the migrations tracking table if it doesn't exist.\n *\n * @remarks\n * Creates a table named `nextly_migrations` with columns:\n * - id (string, primary key)\n * - name (string)\n * - applied_at (timestamp)\n * - checksum (string, optional)\n *\n * Uses CREATE TABLE IF NOT EXISTS for safety.\n *\n * @param adapter - Database adapter to use\n * @returns Promise that resolves when table is created\n */\n createMigrationsTable(adapter: DrizzleAdapter): Promise<void>;\n\n /**\n * Get all applied migration records from the database.\n *\n * @remarks\n * Queries the `nextly_migrations` table and returns all records\n * sorted by applied_at descending (most recent first).\n *\n * @param adapter - Database adapter to use\n * @returns Promise with array of applied migration records\n */\n getAppliedMigrations(adapter: DrizzleAdapter): Promise<MigrationRecord[]>;\n\n /**\n * Record a migration as applied in the database.\n *\n * @remarks\n * Inserts a new record into the `nextly_migrations` table with:\n * - Migration ID, name\n * - Current timestamp for applied_at\n * - Calculated checksum\n *\n * Should be called within a transaction during migration execution.\n *\n * @param adapter - Database adapter to use\n * @param migration - Migration that was applied\n * @returns Promise that resolves when record is inserted\n */\n recordMigration(adapter: DrizzleAdapter, migration: Migration): Promise<void>;\n\n /**\n * Remove a migration record from the database.\n *\n * @remarks\n * Deletes a record from the `nextly_migrations` table.\n * Used during migration rollback operations.\n *\n * Should be called within a transaction during rollback.\n *\n * @param adapter - Database adapter to use\n * @param migrationId - ID of the migration to remove\n * @returns Promise that resolves when record is deleted\n */\n removeMigrationRecord(\n adapter: DrizzleAdapter,\n migrationId: string\n ): Promise<void>;\n\n /**\n * Check if migrations table exists.\n *\n * @remarks\n * Queries database metadata to check if the `nextly_migrations` table exists.\n * Useful for determining if initialization is needed.\n *\n * @param adapter - Database adapter to use\n * @returns Promise with boolean indicating if table exists\n */\n migrationsTableExists(adapter: DrizzleAdapter): Promise<boolean>;\n}\n\n/**\n * Implementation of migration helpers.\n *\n * @remarks\n * Provides default implementations using the adapter's query methods.\n * These work across all dialects but adapters can optimize for their\n * specific database if needed.\n *\n * @public\n */\nexport const migrationHelpers: MigrationHelpers = {\n async createMigrationsTable(adapter: DrizzleAdapter): Promise<void> {\n const caps = adapter.getCapabilities();\n const dialect = caps.dialect;\n\n // Build CREATE TABLE statement with dialect-specific syntax\n let sql = \"\";\n\n if (dialect === \"postgresql\") {\n sql = `\n CREATE TABLE IF NOT EXISTS nextly_migrations (\n id VARCHAR(255) PRIMARY KEY,\n name VARCHAR(255) NOT NULL,\n applied_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n checksum VARCHAR(64)\n )\n `;\n } else if (dialect === \"mysql\") {\n sql = `\n CREATE TABLE IF NOT EXISTS nextly_migrations (\n id VARCHAR(255) PRIMARY KEY,\n name VARCHAR(255) NOT NULL,\n applied_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n checksum VARCHAR(64)\n )\n `;\n } else if (dialect === \"sqlite\") {\n sql = `\n CREATE TABLE IF NOT EXISTS nextly_migrations (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n applied_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,\n checksum TEXT\n )\n `;\n } else {\n throw new Error(`Unsupported dialect: ${String(dialect)}`);\n }\n\n await adapter.executeQuery(sql);\n },\n\n async getAppliedMigrations(\n adapter: DrizzleAdapter\n ): Promise<MigrationRecord[]> {\n const results = await adapter.select<{\n id: string;\n name: string;\n applied_at: Date;\n checksum?: string;\n }>(\"nextly_migrations\", {\n orderBy: [{ column: \"applied_at\", direction: \"desc\" }],\n });\n\n return results.map(row => ({\n id: row.id,\n name: row.name,\n appliedAt: new Date(row.applied_at),\n checksum: row.checksum,\n }));\n },\n\n async recordMigration(\n adapter: DrizzleAdapter,\n migration: Migration\n ): Promise<void> {\n const checksum = calculateChecksum(migration);\n\n await adapter.insert(\"nextly_migrations\", {\n id: migration.id,\n name: migration.name,\n applied_at: new Date(),\n checksum,\n });\n },\n\n async removeMigrationRecord(\n adapter: DrizzleAdapter,\n migrationId: string\n ): Promise<void> {\n await adapter.delete(\"nextly_migrations\", {\n and: [{ column: \"id\", op: \"=\", value: migrationId }],\n });\n },\n\n async migrationsTableExists(adapter: DrizzleAdapter): Promise<boolean> {\n try {\n // Try to query the table - if it doesn't exist, this will throw\n await adapter.select(\"nextly_migrations\", { limit: 1 });\n return true;\n } catch {\n return false;\n }\n },\n};\n\n// ============================================================\n// Type Exports\n// ============================================================\n\n// Re-export migration types for convenience\nexport type {\n Migration,\n MigrationRecord,\n MigrationResult,\n MigrationStatus,\n MigrationOptions,\n} from \"./types/migration\";\n"]}
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import { D as DrizzleAdapter } from './adapter-nvlxFkF-.cjs';
|
|
2
|
+
import { M as MigrationRecord, a as Migration, b as MigrationStatus, c as MigrationOptions } from './migration-BbO5meEV.cjs';
|
|
3
|
+
export { d as MigrationResult } from './migration-BbO5meEV.cjs';
|
|
4
|
+
import './core-CVO7WYDj.cjs';
|
|
5
|
+
import './schema-BDn8WfSL.cjs';
|
|
6
|
+
import './error-um1d_3Uo.cjs';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Database migration utilities.
|
|
10
|
+
*
|
|
11
|
+
* @remarks
|
|
12
|
+
* Provides core utilities for migration management including checksum calculation,
|
|
13
|
+
* sorting, filtering, and validation. Also includes optional helpers for adapters
|
|
14
|
+
* to use for common migration operations.
|
|
15
|
+
*
|
|
16
|
+
* @packageDocumentation
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Calculate SHA-256 checksum for a migration.
|
|
21
|
+
*
|
|
22
|
+
* @remarks
|
|
23
|
+
* Creates a checksum of the entire migration object including id, name, timestamp,
|
|
24
|
+
* and the string representation of up/down functions. This allows detection of
|
|
25
|
+
* any changes to the migration after it has been applied.
|
|
26
|
+
*
|
|
27
|
+
* @param migration - Migration to calculate checksum for
|
|
28
|
+
* @returns Hexadecimal SHA-256 hash
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* const migration: Migration = {
|
|
33
|
+
* id: "20250104_001_create_users",
|
|
34
|
+
* name: "Create users table",
|
|
35
|
+
* timestamp: 1704326400000,
|
|
36
|
+
* up: "CREATE TABLE users (id UUID PRIMARY KEY);",
|
|
37
|
+
* };
|
|
38
|
+
*
|
|
39
|
+
* const checksum = calculateChecksum(migration);
|
|
40
|
+
* // Returns: "a3f5b8c9d2e1f0..."
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* @public
|
|
44
|
+
*/
|
|
45
|
+
declare function calculateChecksum(migration: Migration): string;
|
|
46
|
+
/**
|
|
47
|
+
* Sort migrations by timestamp in ascending order.
|
|
48
|
+
*
|
|
49
|
+
* @remarks
|
|
50
|
+
* Provides deterministic ordering of migrations. If timestamps are equal,
|
|
51
|
+
* falls back to sorting by migration ID alphabetically.
|
|
52
|
+
*
|
|
53
|
+
* @param migrations - Array of migrations to sort
|
|
54
|
+
* @returns New sorted array (original array is not modified)
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* const migrations = [
|
|
59
|
+
* { id: "003", timestamp: 1704412800000, ... },
|
|
60
|
+
* { id: "001", timestamp: 1704326400000, ... },
|
|
61
|
+
* { id: "002", timestamp: 1704326400000, ... },
|
|
62
|
+
* ];
|
|
63
|
+
*
|
|
64
|
+
* const sorted = sortMigrations(migrations);
|
|
65
|
+
* // Returns: [001, 002, 003] (001 and 002 same timestamp, sorted by id)
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* @public
|
|
69
|
+
*/
|
|
70
|
+
declare function sortMigrations(migrations: Migration[]): Migration[];
|
|
71
|
+
/**
|
|
72
|
+
* Filter migrations to get only pending (unapplied) migrations.
|
|
73
|
+
*
|
|
74
|
+
* @remarks
|
|
75
|
+
* Returns migrations that have not been applied to the database yet.
|
|
76
|
+
* A migration is considered pending if its ID is not present in the
|
|
77
|
+
* applied migration records.
|
|
78
|
+
*
|
|
79
|
+
* @param migrations - All available migrations
|
|
80
|
+
* @param applied - Records of applied migrations from database
|
|
81
|
+
* @returns Array of pending migrations
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```typescript
|
|
85
|
+
* const allMigrations = [
|
|
86
|
+
* { id: "001_create_users", ... },
|
|
87
|
+
* { id: "002_create_posts", ... },
|
|
88
|
+
* { id: "003_create_comments", ... },
|
|
89
|
+
* ];
|
|
90
|
+
*
|
|
91
|
+
* const appliedRecords = [
|
|
92
|
+
* { id: "001_create_users", appliedAt: new Date(), ... },
|
|
93
|
+
* ];
|
|
94
|
+
*
|
|
95
|
+
* const pending = filterPending(allMigrations, appliedRecords);
|
|
96
|
+
* // Returns: [002_create_posts, 003_create_comments]
|
|
97
|
+
* ```
|
|
98
|
+
*
|
|
99
|
+
* @public
|
|
100
|
+
*/
|
|
101
|
+
declare function filterPending(migrations: Migration[], applied: MigrationRecord[]): Migration[];
|
|
102
|
+
/**
|
|
103
|
+
* Filter migration records to get only those that match given migrations.
|
|
104
|
+
*
|
|
105
|
+
* @remarks
|
|
106
|
+
* Returns applied migration records that correspond to the given migrations.
|
|
107
|
+
* Useful for getting the subset of applied records relevant to a specific
|
|
108
|
+
* set of migrations.
|
|
109
|
+
*
|
|
110
|
+
* @param migrations - Migrations to match
|
|
111
|
+
* @param applied - All applied migration records from database
|
|
112
|
+
* @returns Array of matching applied records
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* const migrations = [
|
|
117
|
+
* { id: "001_create_users", ... },
|
|
118
|
+
* { id: "002_create_posts", ... },
|
|
119
|
+
* ];
|
|
120
|
+
*
|
|
121
|
+
* const allApplied = [
|
|
122
|
+
* { id: "001_create_users", appliedAt: new Date(), ... },
|
|
123
|
+
* { id: "002_create_posts", appliedAt: new Date(), ... },
|
|
124
|
+
* { id: "003_create_comments", appliedAt: new Date(), ... },
|
|
125
|
+
* ];
|
|
126
|
+
*
|
|
127
|
+
* const relevant = filterApplied(migrations, allApplied);
|
|
128
|
+
* // Returns: [001_create_users, 002_create_posts]
|
|
129
|
+
* ```
|
|
130
|
+
*
|
|
131
|
+
* @public
|
|
132
|
+
*/
|
|
133
|
+
declare function filterApplied(migrations: Migration[], applied: MigrationRecord[]): MigrationRecord[];
|
|
134
|
+
/**
|
|
135
|
+
* Validate that a migration's checksum matches its applied record.
|
|
136
|
+
*
|
|
137
|
+
* @remarks
|
|
138
|
+
* Compares the calculated checksum of a migration against the stored checksum
|
|
139
|
+
* in its migration record. Returns false if checksums don't match or if the
|
|
140
|
+
* record has no checksum.
|
|
141
|
+
*
|
|
142
|
+
* @param migration - Migration to validate
|
|
143
|
+
* @param record - Applied migration record with stored checksum
|
|
144
|
+
* @returns true if checksums match, false otherwise
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```typescript
|
|
148
|
+
* const migration: Migration = { id: "001", ... };
|
|
149
|
+
* const record: MigrationRecord = {
|
|
150
|
+
* id: "001",
|
|
151
|
+
* checksum: "a3f5b8c9...",
|
|
152
|
+
* ...
|
|
153
|
+
* };
|
|
154
|
+
*
|
|
155
|
+
* const isValid = validateChecksum(migration, record);
|
|
156
|
+
* // Returns: true if checksums match, false if modified
|
|
157
|
+
* ```
|
|
158
|
+
*
|
|
159
|
+
* @public
|
|
160
|
+
*/
|
|
161
|
+
declare function validateChecksum(migration: Migration, record: MigrationRecord): boolean;
|
|
162
|
+
/**
|
|
163
|
+
* Detect migrations that have been modified after being applied.
|
|
164
|
+
*
|
|
165
|
+
* @remarks
|
|
166
|
+
* Compares checksums of migrations against their applied records to detect
|
|
167
|
+
* any modifications. Returns records for migrations that have been changed
|
|
168
|
+
* since they were applied to the database.
|
|
169
|
+
*
|
|
170
|
+
* This is critical for detecting potentially dangerous situations where a
|
|
171
|
+
* migration that has already run has been modified.
|
|
172
|
+
*
|
|
173
|
+
* @param migrations - Current migrations
|
|
174
|
+
* @param applied - Applied migration records with checksums
|
|
175
|
+
* @returns Array of records for modified migrations
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```typescript
|
|
179
|
+
* const migrations = [{ id: "001", up: "CREATE TABLE users_v2 ..." }];
|
|
180
|
+
* const applied = [{ id: "001", checksum: "original_hash", ... }];
|
|
181
|
+
*
|
|
182
|
+
* const modified = detectModified(migrations, applied);
|
|
183
|
+
* // Returns: [{ id: "001", ... }] if migration was changed
|
|
184
|
+
* ```
|
|
185
|
+
*
|
|
186
|
+
* @public
|
|
187
|
+
*/
|
|
188
|
+
declare function detectModified(migrations: Migration[], applied: MigrationRecord[]): MigrationRecord[];
|
|
189
|
+
/**
|
|
190
|
+
* Get comprehensive migration status.
|
|
191
|
+
*
|
|
192
|
+
* @remarks
|
|
193
|
+
* Analyzes migrations and applied records to produce a complete status report
|
|
194
|
+
* including current migration, applied/pending counts, and full lists.
|
|
195
|
+
*
|
|
196
|
+
* @param migrations - All available migrations
|
|
197
|
+
* @param applied - Applied migration records from database
|
|
198
|
+
* @returns Complete migration status information
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* ```typescript
|
|
202
|
+
* const status = getMigrationStatus(allMigrations, appliedRecords);
|
|
203
|
+
* console.log(`Current: ${status.current}`);
|
|
204
|
+
* console.log(`Applied: ${status.appliedCount}, Pending: ${status.pendingCount}`);
|
|
205
|
+
* ```
|
|
206
|
+
*
|
|
207
|
+
* @public
|
|
208
|
+
*/
|
|
209
|
+
declare function getMigrationStatus(migrations: Migration[], applied: MigrationRecord[]): MigrationStatus;
|
|
210
|
+
/**
|
|
211
|
+
* Validation result for migrations.
|
|
212
|
+
*
|
|
213
|
+
* @public
|
|
214
|
+
*/
|
|
215
|
+
interface MigrationValidationResult {
|
|
216
|
+
/** Whether all validations passed */
|
|
217
|
+
valid: boolean;
|
|
218
|
+
/** List of validation errors */
|
|
219
|
+
errors: string[];
|
|
220
|
+
/** List of validation warnings */
|
|
221
|
+
warnings: string[];
|
|
222
|
+
/** Migrations that have been modified */
|
|
223
|
+
modified: MigrationRecord[];
|
|
224
|
+
/** Duplicate migration IDs found */
|
|
225
|
+
duplicates: string[];
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Validate migrations for common issues.
|
|
229
|
+
*
|
|
230
|
+
* @remarks
|
|
231
|
+
* Performs comprehensive validation including:
|
|
232
|
+
* - Duplicate migration IDs
|
|
233
|
+
* - Modified applied migrations (checksum mismatch)
|
|
234
|
+
* - Missing required fields
|
|
235
|
+
* - Invalid timestamps
|
|
236
|
+
*
|
|
237
|
+
* @param migrations - Migrations to validate
|
|
238
|
+
* @param applied - Applied migration records (for checksum validation)
|
|
239
|
+
* @param options - Migration options (for strictness configuration)
|
|
240
|
+
* @returns Validation result with errors and warnings
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
* ```typescript
|
|
244
|
+
* const result = validateMigrations(migrations, applied, {
|
|
245
|
+
* strictChecksums: true
|
|
246
|
+
* });
|
|
247
|
+
*
|
|
248
|
+
* if (!result.valid) {
|
|
249
|
+
* console.error("Validation errors:", result.errors);
|
|
250
|
+
* throw new Error("Migration validation failed");
|
|
251
|
+
* }
|
|
252
|
+
* ```
|
|
253
|
+
*
|
|
254
|
+
* @public
|
|
255
|
+
*/
|
|
256
|
+
declare function validateMigrations(migrations: Migration[], applied: MigrationRecord[], options?: MigrationOptions): MigrationValidationResult;
|
|
257
|
+
/**
|
|
258
|
+
* Helper functions for managing migrations in database adapters.
|
|
259
|
+
*
|
|
260
|
+
* @remarks
|
|
261
|
+
* These helpers reduce boilerplate code in dialect-specific adapters by
|
|
262
|
+
* providing common operations like creating migration tables, recording
|
|
263
|
+
* migrations, and querying migration status.
|
|
264
|
+
*
|
|
265
|
+
* Adapters can use these helpers or implement their own logic.
|
|
266
|
+
*
|
|
267
|
+
* @public
|
|
268
|
+
*/
|
|
269
|
+
interface MigrationHelpers {
|
|
270
|
+
/**
|
|
271
|
+
* Create the migrations tracking table if it doesn't exist.
|
|
272
|
+
*
|
|
273
|
+
* @remarks
|
|
274
|
+
* Creates a table named `nextly_migrations` with columns:
|
|
275
|
+
* - id (string, primary key)
|
|
276
|
+
* - name (string)
|
|
277
|
+
* - applied_at (timestamp)
|
|
278
|
+
* - checksum (string, optional)
|
|
279
|
+
*
|
|
280
|
+
* Uses CREATE TABLE IF NOT EXISTS for safety.
|
|
281
|
+
*
|
|
282
|
+
* @param adapter - Database adapter to use
|
|
283
|
+
* @returns Promise that resolves when table is created
|
|
284
|
+
*/
|
|
285
|
+
createMigrationsTable(adapter: DrizzleAdapter): Promise<void>;
|
|
286
|
+
/**
|
|
287
|
+
* Get all applied migration records from the database.
|
|
288
|
+
*
|
|
289
|
+
* @remarks
|
|
290
|
+
* Queries the `nextly_migrations` table and returns all records
|
|
291
|
+
* sorted by applied_at descending (most recent first).
|
|
292
|
+
*
|
|
293
|
+
* @param adapter - Database adapter to use
|
|
294
|
+
* @returns Promise with array of applied migration records
|
|
295
|
+
*/
|
|
296
|
+
getAppliedMigrations(adapter: DrizzleAdapter): Promise<MigrationRecord[]>;
|
|
297
|
+
/**
|
|
298
|
+
* Record a migration as applied in the database.
|
|
299
|
+
*
|
|
300
|
+
* @remarks
|
|
301
|
+
* Inserts a new record into the `nextly_migrations` table with:
|
|
302
|
+
* - Migration ID, name
|
|
303
|
+
* - Current timestamp for applied_at
|
|
304
|
+
* - Calculated checksum
|
|
305
|
+
*
|
|
306
|
+
* Should be called within a transaction during migration execution.
|
|
307
|
+
*
|
|
308
|
+
* @param adapter - Database adapter to use
|
|
309
|
+
* @param migration - Migration that was applied
|
|
310
|
+
* @returns Promise that resolves when record is inserted
|
|
311
|
+
*/
|
|
312
|
+
recordMigration(adapter: DrizzleAdapter, migration: Migration): Promise<void>;
|
|
313
|
+
/**
|
|
314
|
+
* Remove a migration record from the database.
|
|
315
|
+
*
|
|
316
|
+
* @remarks
|
|
317
|
+
* Deletes a record from the `nextly_migrations` table.
|
|
318
|
+
* Used during migration rollback operations.
|
|
319
|
+
*
|
|
320
|
+
* Should be called within a transaction during rollback.
|
|
321
|
+
*
|
|
322
|
+
* @param adapter - Database adapter to use
|
|
323
|
+
* @param migrationId - ID of the migration to remove
|
|
324
|
+
* @returns Promise that resolves when record is deleted
|
|
325
|
+
*/
|
|
326
|
+
removeMigrationRecord(adapter: DrizzleAdapter, migrationId: string): Promise<void>;
|
|
327
|
+
/**
|
|
328
|
+
* Check if migrations table exists.
|
|
329
|
+
*
|
|
330
|
+
* @remarks
|
|
331
|
+
* Queries database metadata to check if the `nextly_migrations` table exists.
|
|
332
|
+
* Useful for determining if initialization is needed.
|
|
333
|
+
*
|
|
334
|
+
* @param adapter - Database adapter to use
|
|
335
|
+
* @returns Promise with boolean indicating if table exists
|
|
336
|
+
*/
|
|
337
|
+
migrationsTableExists(adapter: DrizzleAdapter): Promise<boolean>;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Implementation of migration helpers.
|
|
341
|
+
*
|
|
342
|
+
* @remarks
|
|
343
|
+
* Provides default implementations using the adapter's query methods.
|
|
344
|
+
* These work across all dialects but adapters can optimize for their
|
|
345
|
+
* specific database if needed.
|
|
346
|
+
*
|
|
347
|
+
* @public
|
|
348
|
+
*/
|
|
349
|
+
declare const migrationHelpers: MigrationHelpers;
|
|
350
|
+
|
|
351
|
+
export { Migration, type MigrationHelpers, MigrationOptions, MigrationRecord, MigrationStatus, type MigrationValidationResult, calculateChecksum, detectModified, filterApplied, filterPending, getMigrationStatus, migrationHelpers, sortMigrations, validateChecksum, validateMigrations };
|