@syncular/migrations 0.0.6-95 → 0.1.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/README.md +51 -8
- package/dist/checksum.d.ts +7 -0
- package/dist/checksum.d.ts.map +1 -0
- package/dist/checksum.js +29 -0
- package/dist/checksum.js.map +1 -0
- package/dist/define.d.ts +22 -14
- package/dist/define.d.ts.map +1 -1
- package/dist/define.js +39 -145
- package/dist/define.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/naming.d.ts +38 -0
- package/dist/naming.d.ts.map +1 -0
- package/dist/naming.js +60 -0
- package/dist/naming.js.map +1 -0
- package/dist/runner.d.ts +8 -2
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +50 -17
- package/dist/runner.js.map +1 -1
- package/dist/tracking.d.ts.map +1 -1
- package/dist/tracking.js +11 -3
- package/dist/tracking.js.map +1 -1
- package/dist/types.d.ts +15 -8
- package/dist/types.d.ts.map +1 -1
- package/package.json +12 -4
- package/src/checksum.ts +54 -0
- package/src/define.ts +50 -171
- package/src/index.ts +3 -1
- package/src/naming.ts +106 -0
- package/src/runner.ts +94 -19
- package/src/tracking.ts +11 -3
- package/src/types.ts +18 -9
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @syncular/migrations
|
|
2
2
|
|
|
3
|
-
Versioned migration utilities for Syncular apps. Provides `defineMigrations()` and `runMigrations()` with migration tracking and checksum validation (plus an optional reset strategy for client DBs).
|
|
3
|
+
Versioned migration utilities for Syncular apps. Provides `defineMigrations()` and `runMigrations()` with migration tracking and optional generated checksum validation (plus an optional reset strategy for client DBs).
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -11,20 +11,63 @@ npm install @syncular/migrations
|
|
|
11
11
|
## Usage
|
|
12
12
|
|
|
13
13
|
```ts
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
createMigrationTrackingTableName,
|
|
16
|
+
runMigrations,
|
|
17
|
+
} from '@syncular/migrations';
|
|
18
|
+
import { migrations } from './migrations';
|
|
19
|
+
import { migrationChecksums } from './migrations.checksums.generated';
|
|
20
|
+
|
|
21
|
+
await runMigrations({
|
|
22
|
+
db,
|
|
23
|
+
migrations,
|
|
24
|
+
checksums: migrationChecksums,
|
|
25
|
+
trackingTable: createMigrationTrackingTableName(['my_app', 'client']),
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Define the migrations in a separate source module, for example:
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
// migrations.ts
|
|
33
|
+
import { defineMigrations } from '@syncular/migrations';
|
|
15
34
|
|
|
16
35
|
export const migrations = defineMigrations({
|
|
17
|
-
v1:
|
|
18
|
-
|
|
36
|
+
v1: {
|
|
37
|
+
up: async (db) => {
|
|
38
|
+
await db.schema.createTable('tasks').addColumn('id', 'text').execute();
|
|
39
|
+
},
|
|
40
|
+
down: async (db) => {
|
|
41
|
+
await db.schema.dropTable('tasks').ifExists().execute();
|
|
42
|
+
},
|
|
19
43
|
},
|
|
20
|
-
v2:
|
|
21
|
-
|
|
44
|
+
v2: {
|
|
45
|
+
up: async (db) => {
|
|
46
|
+
await db.schema
|
|
47
|
+
.alterTable('tasks')
|
|
48
|
+
.addColumn('done', 'integer')
|
|
49
|
+
.execute();
|
|
50
|
+
},
|
|
51
|
+
down: async (db) => {
|
|
52
|
+
await db.schema.alterTable('tasks').dropColumn('done').execute();
|
|
53
|
+
},
|
|
22
54
|
},
|
|
23
55
|
});
|
|
24
|
-
|
|
25
|
-
await runMigrations({ db, migrations });
|
|
26
56
|
```
|
|
27
57
|
|
|
58
|
+
Use `createMigrationTrackingTableName(...)` whenever you want a custom table.
|
|
59
|
+
It keeps names lowercase, predictable, and consistently suffixed with
|
|
60
|
+
`migration_state`.
|
|
61
|
+
|
|
62
|
+
Use `checksum: 'deterministic'` for migrations that have a generated checksum
|
|
63
|
+
manifest. Generate that manifest with `@syncular/typegen`; `runMigrations`
|
|
64
|
+
compares the stored checksum against the generated SQL-trace checksum at
|
|
65
|
+
runtime.
|
|
66
|
+
|
|
67
|
+
Use `checksum: 'disabled'` for migrations that cannot be replayed safely during
|
|
68
|
+
build-time checksum generation. Disabled migrations still track
|
|
69
|
+
version/application state, but they skip checksum creation and mismatch checks.
|
|
70
|
+
|
|
28
71
|
## Documentation
|
|
29
72
|
|
|
30
73
|
- Schema migrations: https://syncular.dev/docs/build/migrations
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { MigrationChecksumAlgorithm, MigrationChecksums, ParsedMigration } from './types';
|
|
2
|
+
export declare const DISABLED_MIGRATION_CHECKSUM = "__syncular_checksum_disabled__";
|
|
3
|
+
export declare const SQL_TRACE_MIGRATION_CHECKSUM_ALGORITHM = "sql_trace_v1";
|
|
4
|
+
export declare const DISABLED_MIGRATION_CHECKSUM_ALGORITHM = "disabled";
|
|
5
|
+
export declare function getStoredDeterministicChecksum<DB>(migration: ParsedMigration<DB>, checksums: MigrationChecksums | undefined): string;
|
|
6
|
+
export declare function getMigrationChecksumAlgorithm<DB>(migration: ParsedMigration<DB>, checksums: MigrationChecksums | undefined): MigrationChecksumAlgorithm;
|
|
7
|
+
//# sourceMappingURL=checksum.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checksum.d.ts","sourceRoot":"","sources":["../src/checksum.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAC1B,kBAAkB,EAClB,eAAe,EAChB,MAAM,SAAS,CAAC;AAEjB,eAAO,MAAM,2BAA2B,mCAAmC,CAAC;AAC5E,eAAO,MAAM,sCAAsC,iBAAiB,CAAC;AACrE,eAAO,MAAM,qCAAqC,aAAa,CAAC;AAEhE,wBAAgB,8BAA8B,CAAC,EAAE,EAC/C,SAAS,EAAE,eAAe,CAAC,EAAE,CAAC,EAC9B,SAAS,EAAE,kBAAkB,GAAG,SAAS,GACxC,MAAM,CAsBR;AAED,wBAAgB,6BAA6B,CAAC,EAAE,EAC9C,SAAS,EAAE,eAAe,CAAC,EAAE,CAAC,EAC9B,SAAS,EAAE,kBAAkB,GAAG,SAAS,GACxC,0BAA0B,CAa5B"}
|
package/dist/checksum.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export const DISABLED_MIGRATION_CHECKSUM = '__syncular_checksum_disabled__';
|
|
2
|
+
export const SQL_TRACE_MIGRATION_CHECKSUM_ALGORITHM = 'sql_trace_v1';
|
|
3
|
+
export const DISABLED_MIGRATION_CHECKSUM_ALGORITHM = 'disabled';
|
|
4
|
+
export function getStoredDeterministicChecksum(migration, checksums) {
|
|
5
|
+
if (migration.checksum === 'disabled') {
|
|
6
|
+
return DISABLED_MIGRATION_CHECKSUM;
|
|
7
|
+
}
|
|
8
|
+
if (!checksums) {
|
|
9
|
+
throw new Error(`Migration v${migration.version} (${migration.name}) requires generated checksums. ` +
|
|
10
|
+
'Generate a checksum manifest with @syncular/typegen and pass it to runMigrations({ checksums }).');
|
|
11
|
+
}
|
|
12
|
+
const checksum = checksums[String(migration.version)];
|
|
13
|
+
if (!checksum) {
|
|
14
|
+
throw new Error(`Missing generated checksum for migration v${migration.version} (${migration.name}). ` +
|
|
15
|
+
'Regenerate the checksum manifest before running migrations.');
|
|
16
|
+
}
|
|
17
|
+
return checksum;
|
|
18
|
+
}
|
|
19
|
+
export function getMigrationChecksumAlgorithm(migration, checksums) {
|
|
20
|
+
if (migration.checksum === 'disabled') {
|
|
21
|
+
return DISABLED_MIGRATION_CHECKSUM_ALGORITHM;
|
|
22
|
+
}
|
|
23
|
+
if (!checksums) {
|
|
24
|
+
throw new Error(`Migration v${migration.version} (${migration.name}) requires generated checksums. ` +
|
|
25
|
+
'Generate a checksum manifest with @syncular/typegen and pass it to runMigrations({ checksums }).');
|
|
26
|
+
}
|
|
27
|
+
return SQL_TRACE_MIGRATION_CHECKSUM_ALGORITHM;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=checksum.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checksum.js","sourceRoot":"","sources":["../src/checksum.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,2BAA2B,GAAG,gCAAgC,CAAC;AAC5E,MAAM,CAAC,MAAM,sCAAsC,GAAG,cAAc,CAAC;AACrE,MAAM,CAAC,MAAM,qCAAqC,GAAG,UAAU,CAAC;AAEhE,MAAM,UAAU,8BAA8B,CAC5C,SAA8B,EAC9B,SAAyC;IAEzC,IAAI,SAAS,CAAC,QAAQ,KAAK,UAAU,EAAE,CAAC;QACtC,OAAO,2BAA2B,CAAC;IACrC,CAAC;IAED,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,cAAc,SAAS,CAAC,OAAO,KAAK,SAAS,CAAC,IAAI,kCAAkC;YAClF,kGAAkG,CACrG,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;IAEtD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CACb,6CAA6C,SAAS,CAAC,OAAO,KAAK,SAAS,CAAC,IAAI,KAAK;YACpF,6DAA6D,CAChE,CAAC;IACJ,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,6BAA6B,CAC3C,SAA8B,EAC9B,SAAyC;IAEzC,IAAI,SAAS,CAAC,QAAQ,KAAK,UAAU,EAAE,CAAC;QACtC,OAAO,qCAAqC,CAAC;IAC/C,CAAC;IAED,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,cAAc,SAAS,CAAC,OAAO,KAAK,SAAS,CAAC,IAAI,kCAAkC;YAClF,kGAAkG,CACrG,CAAC;IACJ,CAAC;IAED,OAAO,sCAAsC,CAAC;AAChD,CAAC"}
|
package/dist/define.d.ts
CHANGED
|
@@ -1,30 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @syncular/migrations - Migration definition
|
|
3
3
|
*/
|
|
4
|
-
import type { DefinedMigrations, MigrationRecord
|
|
4
|
+
import type { DefinedMigrations, MigrationRecord } from './types';
|
|
5
5
|
/**
|
|
6
6
|
* Define versioned migrations with automatic version parsing and sorting.
|
|
7
7
|
*
|
|
8
8
|
* @example
|
|
9
9
|
* ```typescript
|
|
10
10
|
* export const migrations = defineMigrations({
|
|
11
|
-
* v1:
|
|
12
|
-
*
|
|
13
|
-
* .
|
|
14
|
-
*
|
|
15
|
-
*
|
|
11
|
+
* v1: {
|
|
12
|
+
* up: async (db) => {
|
|
13
|
+
* await db.schema.createTable('tasks')
|
|
14
|
+
* .addColumn('id', 'text', col => col.primaryKey())
|
|
15
|
+
* .addColumn('title', 'text', col => col.notNull())
|
|
16
|
+
* .execute();
|
|
17
|
+
* },
|
|
18
|
+
* down: async (db) => {
|
|
19
|
+
* await db.schema.dropTable('tasks').ifExists().execute();
|
|
20
|
+
* },
|
|
16
21
|
* },
|
|
17
|
-
* v2:
|
|
18
|
-
*
|
|
19
|
-
* .
|
|
20
|
-
*
|
|
22
|
+
* v2: {
|
|
23
|
+
* up: async (db) => {
|
|
24
|
+
* await db.schema.alterTable('tasks')
|
|
25
|
+
* .addColumn('priority', 'integer', col => col.defaultTo(0))
|
|
26
|
+
* .execute();
|
|
27
|
+
* },
|
|
28
|
+
* down: async (db) => {
|
|
29
|
+
* await db.schema.alterTable('tasks')
|
|
30
|
+
* .dropColumn('priority')
|
|
31
|
+
* .execute();
|
|
32
|
+
* },
|
|
21
33
|
* },
|
|
22
34
|
* });
|
|
23
35
|
* ```
|
|
24
36
|
*/
|
|
25
37
|
export declare function defineMigrations<DB = unknown, T extends MigrationRecord<DB> = MigrationRecord<DB>>(versionedMigrations: T): DefinedMigrations<DB>;
|
|
26
|
-
/**
|
|
27
|
-
* Get the checksum for a migration.
|
|
28
|
-
*/
|
|
29
|
-
export declare function getMigrationChecksum<DB>(migration: ParsedMigration<DB>): string;
|
|
30
38
|
//# sourceMappingURL=define.d.ts.map
|
package/dist/define.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,iBAAiB,EAGjB,eAAe,
|
|
1
|
+
{"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,iBAAiB,EAGjB,eAAe,EAEhB,MAAM,SAAS,CAAC;AAmCjB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,gBAAgB,CAC9B,EAAE,GAAG,OAAO,EACZ,CAAC,SAAS,eAAe,CAAC,EAAE,CAAC,GAAG,eAAe,CAAC,EAAE,CAAC,EACnD,mBAAmB,EAAE,CAAC,GAAG,iBAAiB,CAAC,EAAE,CAAC,CA4D/C"}
|
package/dist/define.js
CHANGED
|
@@ -12,146 +12,46 @@ function parseVersionKey(key) {
|
|
|
12
12
|
const version = Number.parseInt(match[1], 10);
|
|
13
13
|
return Number.isNaN(version) ? null : version;
|
|
14
14
|
}
|
|
15
|
-
/**
|
|
16
|
-
* Normalize a function source string for checksum comparison.
|
|
17
|
-
* Strips comments and collapses whitespace so that formatting-only
|
|
18
|
-
* changes don't break checksums.
|
|
19
|
-
*/
|
|
20
|
-
function stripCommentsPreservingStrings(source) {
|
|
21
|
-
let out = '';
|
|
22
|
-
let i = 0;
|
|
23
|
-
let mode = 'code';
|
|
24
|
-
while (i < source.length) {
|
|
25
|
-
const char = source[i];
|
|
26
|
-
const next = source[i + 1];
|
|
27
|
-
if (mode === 'lineComment') {
|
|
28
|
-
if (char === '\n') {
|
|
29
|
-
out += '\n';
|
|
30
|
-
mode = 'code';
|
|
31
|
-
}
|
|
32
|
-
i += 1;
|
|
33
|
-
continue;
|
|
34
|
-
}
|
|
35
|
-
if (mode === 'blockComment') {
|
|
36
|
-
if (char === '*' && next === '/') {
|
|
37
|
-
i += 2;
|
|
38
|
-
mode = 'code';
|
|
39
|
-
continue;
|
|
40
|
-
}
|
|
41
|
-
if (char === '\n') {
|
|
42
|
-
out += '\n';
|
|
43
|
-
}
|
|
44
|
-
i += 1;
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
if (mode === 'singleQuote') {
|
|
48
|
-
out += char;
|
|
49
|
-
if (char === '\\' && next !== undefined) {
|
|
50
|
-
out += next;
|
|
51
|
-
i += 2;
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
if (char === "'") {
|
|
55
|
-
mode = 'code';
|
|
56
|
-
}
|
|
57
|
-
i += 1;
|
|
58
|
-
continue;
|
|
59
|
-
}
|
|
60
|
-
if (mode === 'doubleQuote') {
|
|
61
|
-
out += char;
|
|
62
|
-
if (char === '\\' && next !== undefined) {
|
|
63
|
-
out += next;
|
|
64
|
-
i += 2;
|
|
65
|
-
continue;
|
|
66
|
-
}
|
|
67
|
-
if (char === '"') {
|
|
68
|
-
mode = 'code';
|
|
69
|
-
}
|
|
70
|
-
i += 1;
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
73
|
-
if (mode === 'template') {
|
|
74
|
-
out += char;
|
|
75
|
-
if (char === '\\' && next !== undefined) {
|
|
76
|
-
out += next;
|
|
77
|
-
i += 2;
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
if (char === '`') {
|
|
81
|
-
mode = 'code';
|
|
82
|
-
}
|
|
83
|
-
i += 1;
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
if (char === '/' && next === '/') {
|
|
87
|
-
mode = 'lineComment';
|
|
88
|
-
i += 2;
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
if (char === '/' && next === '*') {
|
|
92
|
-
mode = 'blockComment';
|
|
93
|
-
i += 2;
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
if (char === "'") {
|
|
97
|
-
mode = 'singleQuote';
|
|
98
|
-
out += char;
|
|
99
|
-
i += 1;
|
|
100
|
-
continue;
|
|
101
|
-
}
|
|
102
|
-
if (char === '"') {
|
|
103
|
-
mode = 'doubleQuote';
|
|
104
|
-
out += char;
|
|
105
|
-
i += 1;
|
|
106
|
-
continue;
|
|
107
|
-
}
|
|
108
|
-
if (char === '`') {
|
|
109
|
-
mode = 'template';
|
|
110
|
-
out += char;
|
|
111
|
-
i += 1;
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
out += char;
|
|
115
|
-
i += 1;
|
|
116
|
-
}
|
|
117
|
-
return out;
|
|
118
|
-
}
|
|
119
|
-
function normalizeSource(source) {
|
|
120
|
-
return stripCommentsPreservingStrings(source)
|
|
121
|
-
.replace(/\s+/g, ' ') // collapse whitespace
|
|
122
|
-
.trim();
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Compute a simple checksum for a migration function.
|
|
126
|
-
* Used to detect if a migration has changed after being applied.
|
|
127
|
-
*/
|
|
128
|
-
function computeChecksum(fn) {
|
|
129
|
-
const fnStr = normalizeSource(fn.toString());
|
|
130
|
-
let hash = 0;
|
|
131
|
-
for (let i = 0; i < fnStr.length; i++) {
|
|
132
|
-
hash = (hash * 31 + fnStr.charCodeAt(i)) >>> 0;
|
|
133
|
-
}
|
|
134
|
-
return hash.toString(16).padStart(8, '0');
|
|
135
|
-
}
|
|
136
15
|
function isMigrationDefinitionObject(value) {
|
|
137
16
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
138
17
|
}
|
|
18
|
+
function normalizeChecksumMode(key, checksum) {
|
|
19
|
+
if (checksum === undefined) {
|
|
20
|
+
return 'deterministic';
|
|
21
|
+
}
|
|
22
|
+
if (checksum === 'deterministic' || checksum === 'disabled') {
|
|
23
|
+
return checksum;
|
|
24
|
+
}
|
|
25
|
+
throw new Error(`Invalid migration "${key}": "checksum" must be "deterministic" or "disabled" when provided.`);
|
|
26
|
+
}
|
|
139
27
|
/**
|
|
140
28
|
* Define versioned migrations with automatic version parsing and sorting.
|
|
141
29
|
*
|
|
142
30
|
* @example
|
|
143
31
|
* ```typescript
|
|
144
32
|
* export const migrations = defineMigrations({
|
|
145
|
-
* v1:
|
|
146
|
-
*
|
|
147
|
-
* .
|
|
148
|
-
*
|
|
149
|
-
*
|
|
33
|
+
* v1: {
|
|
34
|
+
* up: async (db) => {
|
|
35
|
+
* await db.schema.createTable('tasks')
|
|
36
|
+
* .addColumn('id', 'text', col => col.primaryKey())
|
|
37
|
+
* .addColumn('title', 'text', col => col.notNull())
|
|
38
|
+
* .execute();
|
|
39
|
+
* },
|
|
40
|
+
* down: async (db) => {
|
|
41
|
+
* await db.schema.dropTable('tasks').ifExists().execute();
|
|
42
|
+
* },
|
|
150
43
|
* },
|
|
151
|
-
* v2:
|
|
152
|
-
*
|
|
153
|
-
* .
|
|
154
|
-
*
|
|
44
|
+
* v2: {
|
|
45
|
+
* up: async (db) => {
|
|
46
|
+
* await db.schema.alterTable('tasks')
|
|
47
|
+
* .addColumn('priority', 'integer', col => col.defaultTo(0))
|
|
48
|
+
* .execute();
|
|
49
|
+
* },
|
|
50
|
+
* down: async (db) => {
|
|
51
|
+
* await db.schema.alterTable('tasks')
|
|
52
|
+
* .dropColumn('priority')
|
|
53
|
+
* .execute();
|
|
54
|
+
* },
|
|
155
55
|
* },
|
|
156
56
|
* });
|
|
157
57
|
* ```
|
|
@@ -166,23 +66,23 @@ export function defineMigrations(versionedMigrations) {
|
|
|
166
66
|
if (version < 1) {
|
|
167
67
|
throw new Error(`Invalid migration version ${version}: versions must be >= 1`);
|
|
168
68
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
const down =
|
|
173
|
-
|
|
174
|
-
: undefined;
|
|
69
|
+
if (!isMigrationDefinitionObject(definition)) {
|
|
70
|
+
throw new Error(`Invalid migration "${key}": expected a { up, down } object. Shorthand migration functions are not supported.`);
|
|
71
|
+
}
|
|
72
|
+
const { up, down } = definition;
|
|
73
|
+
const checksum = normalizeChecksumMode(key, definition.checksum);
|
|
175
74
|
if (typeof up !== 'function') {
|
|
176
|
-
throw new Error(`Invalid migration "${key}":
|
|
75
|
+
throw new Error(`Invalid migration "${key}": "up" must be a function.`);
|
|
177
76
|
}
|
|
178
|
-
if (
|
|
179
|
-
throw new Error(`Invalid migration "${key}": "down" must be a function
|
|
77
|
+
if (typeof down !== 'function') {
|
|
78
|
+
throw new Error(`Invalid migration "${key}": "down" must be a function.`);
|
|
180
79
|
}
|
|
181
80
|
migrations.push({
|
|
182
81
|
version,
|
|
183
82
|
name: key,
|
|
184
83
|
up,
|
|
185
84
|
down,
|
|
85
|
+
checksum,
|
|
186
86
|
});
|
|
187
87
|
}
|
|
188
88
|
// Sort by version number
|
|
@@ -202,10 +102,4 @@ export function defineMigrations(versionedMigrations) {
|
|
|
202
102
|
},
|
|
203
103
|
};
|
|
204
104
|
}
|
|
205
|
-
/**
|
|
206
|
-
* Get the checksum for a migration.
|
|
207
|
-
*/
|
|
208
|
-
export function getMigrationChecksum(migration) {
|
|
209
|
-
return computeChecksum(migration.up);
|
|
210
|
-
}
|
|
211
105
|
//# sourceMappingURL=define.js.map
|
package/dist/define.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define.js","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"AAAA;;GAEG;AAUH;;GAEG;AACH,SAAS,eAAe,CAAC,GAAW
|
|
1
|
+
{"version":3,"file":"define.js","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @syncular/migrations - Versioned migration system
|
|
3
3
|
*
|
|
4
|
-
* Provides migration definition, tracking, and execution.
|
|
4
|
+
* Provides migration definition, tracking, naming, and execution.
|
|
5
5
|
*/
|
|
6
|
+
export * from './checksum';
|
|
6
7
|
export * from './define';
|
|
8
|
+
export * from './naming';
|
|
7
9
|
export * from './runner';
|
|
8
10
|
export * from './tracking';
|
|
9
11
|
export * from './types';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @syncular/migrations - Versioned migration system
|
|
3
3
|
*
|
|
4
|
-
* Provides migration definition, tracking, and execution.
|
|
4
|
+
* Provides migration definition, tracking, naming, and execution.
|
|
5
5
|
*/
|
|
6
|
+
export * from './checksum.js';
|
|
6
7
|
export * from './define.js';
|
|
8
|
+
export * from './naming.js';
|
|
7
9
|
export * from './runner.js';
|
|
8
10
|
export * from './tracking.js';
|
|
9
11
|
export * from './types.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC"}
|
package/dist/naming.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @syncular/migrations - Migration tracking table naming helpers
|
|
3
|
+
*/
|
|
4
|
+
export type MigrationTrackingTableNamePart = string | number | null | undefined | false;
|
|
5
|
+
export interface CreateMigrationTrackingTableNameOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Optional namespace prefix placed before the scope segments.
|
|
8
|
+
* Defaults to `sync`.
|
|
9
|
+
*/
|
|
10
|
+
namespace?: MigrationTrackingTableNamePart | readonly MigrationTrackingTableNamePart[];
|
|
11
|
+
/**
|
|
12
|
+
* Optional suffix segments appended after `migration_state`.
|
|
13
|
+
*/
|
|
14
|
+
suffix?: MigrationTrackingTableNamePart | readonly MigrationTrackingTableNamePart[];
|
|
15
|
+
}
|
|
16
|
+
export declare const DEFAULT_MIGRATION_TRACKING_TABLE = "sync_migration_state";
|
|
17
|
+
/**
|
|
18
|
+
* Create a stable migration tracking table name.
|
|
19
|
+
*
|
|
20
|
+
* The generated name always includes the `migration_state` suffix and
|
|
21
|
+
* normalizes segments to lowercase snake_case.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* createMigrationTrackingTableName()
|
|
25
|
+
* // => 'sync_migration_state'
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* createMigrationTrackingTableName('server')
|
|
29
|
+
* // => 'sync_server_migration_state'
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* createMigrationTrackingTableName(['spaces', 'billing'], {
|
|
33
|
+
* suffix: ['prod', 'v2'],
|
|
34
|
+
* })
|
|
35
|
+
* // => 'sync_spaces_billing_migration_state_prod_v2'
|
|
36
|
+
*/
|
|
37
|
+
export declare function createMigrationTrackingTableName(scope?: MigrationTrackingTableNamePart | readonly MigrationTrackingTableNamePart[], options?: CreateMigrationTrackingTableNameOptions): string;
|
|
38
|
+
//# sourceMappingURL=naming.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"naming.d.ts","sourceRoot":"","sources":["../src/naming.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,8BAA8B,GACtC,MAAM,GACN,MAAM,GACN,IAAI,GACJ,SAAS,GACT,KAAK,CAAC;AAEV,MAAM,WAAW,uCAAuC;IACtD;;;OAGG;IACH,SAAS,CAAC,EACN,8BAA8B,GAC9B,SAAS,8BAA8B,EAAE,CAAC;IAC9C;;OAEG;IACH,MAAM,CAAC,EACH,8BAA8B,GAC9B,SAAS,8BAA8B,EAAE,CAAC;CAC/C;AAED,eAAO,MAAM,gCAAgC,yBAAyB,CAAC;AAqCvE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gCAAgC,CAC9C,KAAK,CAAC,EACF,8BAA8B,GAC9B,SAAS,8BAA8B,EAAE,EAC7C,OAAO,GAAE,uCAA4C,GACpD,MAAM,CAgBR"}
|
package/dist/naming.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @syncular/migrations - Migration tracking table naming helpers
|
|
3
|
+
*/
|
|
4
|
+
export const DEFAULT_MIGRATION_TRACKING_TABLE = 'sync_migration_state';
|
|
5
|
+
function normalizeTrackingTableNamePart(part) {
|
|
6
|
+
if (part === null || part === undefined || part === false) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
const normalized = String(part)
|
|
10
|
+
.trim()
|
|
11
|
+
.toLowerCase()
|
|
12
|
+
.replace(/[^a-z0-9]+/g, '_')
|
|
13
|
+
.replace(/^_+|_+$/g, '')
|
|
14
|
+
.replace(/_+/g, '_');
|
|
15
|
+
return normalized.length > 0 ? normalized : null;
|
|
16
|
+
}
|
|
17
|
+
function normalizeTrackingTableNameParts(input) {
|
|
18
|
+
if (Array.isArray(input)) {
|
|
19
|
+
return input
|
|
20
|
+
.map((part) => normalizeTrackingTableNamePart(part))
|
|
21
|
+
.filter((part) => part !== null);
|
|
22
|
+
}
|
|
23
|
+
const normalized = normalizeTrackingTableNamePart(input);
|
|
24
|
+
return normalized ? [normalized] : [];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Create a stable migration tracking table name.
|
|
28
|
+
*
|
|
29
|
+
* The generated name always includes the `migration_state` suffix and
|
|
30
|
+
* normalizes segments to lowercase snake_case.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* createMigrationTrackingTableName()
|
|
34
|
+
* // => 'sync_migration_state'
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* createMigrationTrackingTableName('server')
|
|
38
|
+
* // => 'sync_server_migration_state'
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* createMigrationTrackingTableName(['spaces', 'billing'], {
|
|
42
|
+
* suffix: ['prod', 'v2'],
|
|
43
|
+
* })
|
|
44
|
+
* // => 'sync_spaces_billing_migration_state_prod_v2'
|
|
45
|
+
*/
|
|
46
|
+
export function createMigrationTrackingTableName(scope, options = {}) {
|
|
47
|
+
const namespace = options.namespace === undefined ? ['sync'] : options.namespace;
|
|
48
|
+
const segments = [
|
|
49
|
+
...normalizeTrackingTableNameParts(namespace),
|
|
50
|
+
...normalizeTrackingTableNameParts(scope),
|
|
51
|
+
'migration',
|
|
52
|
+
'state',
|
|
53
|
+
...normalizeTrackingTableNameParts(options.suffix),
|
|
54
|
+
];
|
|
55
|
+
if (segments.length === 0) {
|
|
56
|
+
return DEFAULT_MIGRATION_TRACKING_TABLE;
|
|
57
|
+
}
|
|
58
|
+
return segments.join('_');
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=naming.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"naming.js","sourceRoot":"","sources":["../src/naming.ts"],"names":[],"mappings":"AAAA;;GAEG;AAyBH,MAAM,CAAC,MAAM,gCAAgC,GAAG,sBAAsB,CAAC;AAEvE,SAAS,8BAA8B,CACrC,IAAoC;IAEpC,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QAC1D,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC;SAC5B,IAAI,EAAE;SACN,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAEvB,OAAO,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AACnD,CAAC;AAED,SAAS,+BAA+B,CACtC,KAGa;IAEb,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK;aACT,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,8BAA8B,CAAC,IAAI,CAAC,CAAC;aACnD,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,UAAU,GAAG,8BAA8B,CAC/C,KAAuC,CACxC,CAAC;IACF,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACxC,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,gCAAgC,CAC9C,KAE6C,EAC7C,OAAO,GAA4C,EAAE;IAErD,MAAM,SAAS,GACb,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;IACjE,MAAM,QAAQ,GAAG;QACf,GAAG,+BAA+B,CAAC,SAAS,CAAC;QAC7C,GAAG,+BAA+B,CAAC,KAAK,CAAC;QACzC,WAAW;QACX,OAAO;QACP,GAAG,+BAA+B,CAAC,OAAO,CAAC,MAAM,CAAC;KACnD,CAAC;IAEF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,gCAAgC,CAAC;IAC1C,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC"}
|
package/dist/runner.d.ts
CHANGED
|
@@ -10,8 +10,14 @@ import type { RunMigrationsOptions, RunMigrationsResult, RunMigrationsToVersionO
|
|
|
10
10
|
* import { defineMigrations, runMigrations } from '@syncular/migrations';
|
|
11
11
|
*
|
|
12
12
|
* const migrations = defineMigrations({
|
|
13
|
-
* v1:
|
|
14
|
-
*
|
|
13
|
+
* v1: {
|
|
14
|
+
* up: async (db) => { ... },
|
|
15
|
+
* down: async (db) => { ... },
|
|
16
|
+
* },
|
|
17
|
+
* v2: {
|
|
18
|
+
* up: async (db) => { ... },
|
|
19
|
+
* down: async (db) => { ... },
|
|
20
|
+
* },
|
|
15
21
|
* });
|
|
16
22
|
*
|
|
17
23
|
* const result = await runMigrations({
|
package/dist/runner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA;;GAEG;AAgBH,OAAO,KAAK,EAIV,oBAAoB,EACpB,mBAAmB,EACnB,6BAA6B,EAC7B,4BAA4B,EAC7B,MAAM,SAAS,CAAC;AAwEjB;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,aAAa,CAAC,EAAE,EACpC,OAAO,EAAE,oBAAoB,CAAC,EAAE,CAAC,GAChC,OAAO,CAAC,mBAAmB,CAAC,CAU9B;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAAC,EAAE,EAC7C,OAAO,EAAE,6BAA6B,CAAC,EAAE,CAAC,GACzC,OAAO,CAAC,4BAA4B,CAAC,CA4KvC;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,EAAE,EACvC,EAAE,EAAE,OAAO,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,EAC/B,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,MAAM,CAAC,CAKjB"}
|