@alexify/migronaut 1.0.0 → 2.1.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/CHANGELOG.md +409 -1
- package/README.md +248 -24
- package/bin/migronaut.js +11 -3
- package/bullmq.d.ts +845 -0
- package/bullmq.js +1 -0
- package/index.d.ts +757 -29
- package/migronaut.schema.json +191 -1
- package/package.json +27 -6
- package/src/bullmq/index.js +55 -0
- package/src/bullmq/jobs.js +454 -0
- package/src/bullmq/processor.js +608 -0
- package/src/bullmq/producer.js +424 -0
- package/src/bullmq/service.js +653 -0
- package/src/bullmq/wait.js +124 -0
- package/src/cli/args.js +12 -2
- package/src/cli/commands/baseline.js +45 -0
- package/src/cli/commands/converge.js +160 -0
- package/src/cli/commands/down.js +2 -0
- package/src/cli/commands/lock.js +2 -1
- package/src/cli/commands/redo.js +8 -1
- package/src/cli/commands/unlock.js +12 -2
- package/src/cli/commands/up.js +14 -1
- package/src/cli/exit-codes.js +10 -2
- package/src/cli/index.js +4 -0
- package/src/cli/shared.js +29 -7
- package/src/cli/table.js +105 -0
- package/src/core/audit.js +17 -3
- package/src/core/baseline.js +80 -0
- package/src/core/changelog.js +140 -24
- package/src/core/collections.js +372 -0
- package/src/core/config.js +125 -27
- package/src/core/converge-log.js +47 -0
- package/src/core/converge-plan.js +483 -0
- package/src/core/converge.js +867 -0
- package/src/core/import-runner.js +34 -6
- package/src/core/import.js +14 -7
- package/src/core/index-spec.js +496 -0
- package/src/core/lock-wait.js +260 -0
- package/src/core/lock.js +71 -20
- package/src/core/migrator.js +805 -304
- package/src/core/options.js +251 -0
- package/src/core/run-recorder.js +157 -0
- package/src/core/run.js +71 -71
- package/src/core/runner.js +70 -20
- package/src/core/sequence.js +134 -0
- package/src/errors/index.js +71 -1
- package/src/index.js +16 -0
- package/src/utils/actor.js +48 -0
- package/src/utils/canonical.js +179 -0
- package/src/utils/collection-name.js +21 -0
- package/src/utils/error.js +18 -1
- package/src/utils/id.js +77 -0
- package/src/utils/loader.js +39 -21
- package/src/utils/logger.js +30 -12
- package/src/utils/migration-name.js +32 -0
- package/src/utils/redact.js +57 -4
- package/src/utils/sanitize.js +8 -3
- package/src/utils/telemetry.js +393 -0
- package/src/utils/template.js +60 -12
package/migronaut.schema.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
3
|
"$id": "https://migronaut.vercel.app/migronaut.schema.json",
|
|
4
4
|
"title": "migronaut configuration",
|
|
5
|
-
"description": "Configuration for migronaut.config.json. Options that hold live instances (hooks, logger, mongoose, client) are only available in a .ts/.js config.",
|
|
5
|
+
"description": "Configuration for migronaut.config.json. Options that hold live instances or functions (hooks, logger, mongoose, client, generateId, telemetry) are only available in a .ts/.js config.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"properties": {
|
|
8
8
|
"$schema": {
|
|
@@ -39,6 +39,13 @@
|
|
|
39
39
|
"pattern": "^(?!system\\.)[^$\\u0000]+$",
|
|
40
40
|
"description": "Collection used for the concurrency lock"
|
|
41
41
|
},
|
|
42
|
+
"convergeLogCollection": {
|
|
43
|
+
"type": "string",
|
|
44
|
+
"minLength": 1,
|
|
45
|
+
"default": "_migronaut_converge",
|
|
46
|
+
"pattern": "^(?!system\\.)[^$\\u0000]+$",
|
|
47
|
+
"description": "Collection holding the converge history (written on the first converge that changes something)"
|
|
48
|
+
},
|
|
42
49
|
"lockTTLSeconds": {
|
|
43
50
|
"type": "integer",
|
|
44
51
|
"minimum": 1,
|
|
@@ -99,6 +106,15 @@
|
|
|
99
106
|
"default": "abort",
|
|
100
107
|
"description": "What to do when the lock is lost mid-run"
|
|
101
108
|
},
|
|
109
|
+
"onOutOfOrder": {
|
|
110
|
+
"enum": [
|
|
111
|
+
"warn",
|
|
112
|
+
"error",
|
|
113
|
+
"allow"
|
|
114
|
+
],
|
|
115
|
+
"default": "warn",
|
|
116
|
+
"description": "What a bulk `up` does when a pending migration sorts before the newest applied one (a file merged late from a parallel branch)"
|
|
117
|
+
},
|
|
102
118
|
"envFile": {
|
|
103
119
|
"oneOf": [
|
|
104
120
|
{
|
|
@@ -130,6 +146,180 @@
|
|
|
130
146
|
"clientOptions": {
|
|
131
147
|
"type": "object",
|
|
132
148
|
"description": "MongoDB driver options (MongoClientOptions): TLS, auth mechanisms, proxies, pool sizing. Passed to the driver as-is."
|
|
149
|
+
},
|
|
150
|
+
"collections": {
|
|
151
|
+
"type": "array",
|
|
152
|
+
"items": {
|
|
153
|
+
"$ref": "#/definitions/collection"
|
|
154
|
+
},
|
|
155
|
+
"description": "Declared collections: `migronaut converge` keeps their indexes and validator in the declared state, with no migration file per change"
|
|
156
|
+
},
|
|
157
|
+
"collectionsDir": {
|
|
158
|
+
"type": "string",
|
|
159
|
+
"minLength": 1,
|
|
160
|
+
"description": "Directory of collection definition files, one collection per file. Opt-in: nothing is read unless this is set"
|
|
161
|
+
},
|
|
162
|
+
"convergeAfterUp": {
|
|
163
|
+
"type": "boolean",
|
|
164
|
+
"default": false,
|
|
165
|
+
"description": "End every bulk `up` (no file, no --to) by converging the declared collections under the same lock"
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
"definitions": {
|
|
169
|
+
"collection": {
|
|
170
|
+
"type": "object",
|
|
171
|
+
"required": [
|
|
172
|
+
"name"
|
|
173
|
+
],
|
|
174
|
+
"additionalProperties": false,
|
|
175
|
+
"anyOf": [
|
|
176
|
+
{
|
|
177
|
+
"required": [
|
|
178
|
+
"indexes"
|
|
179
|
+
]
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"required": [
|
|
183
|
+
"validator"
|
|
184
|
+
]
|
|
185
|
+
}
|
|
186
|
+
],
|
|
187
|
+
"properties": {
|
|
188
|
+
"name": {
|
|
189
|
+
"type": "string",
|
|
190
|
+
"minLength": 1,
|
|
191
|
+
"pattern": "^(?!system\\.)[^$\\u0000]+$",
|
|
192
|
+
"description": "Collection name"
|
|
193
|
+
},
|
|
194
|
+
"indexes": {
|
|
195
|
+
"type": "array",
|
|
196
|
+
"items": {
|
|
197
|
+
"$ref": "#/definitions/index"
|
|
198
|
+
},
|
|
199
|
+
"description": "Every index besides _id. Omit to leave the collection's indexes unmanaged"
|
|
200
|
+
},
|
|
201
|
+
"validator": {
|
|
202
|
+
"oneOf": [
|
|
203
|
+
{
|
|
204
|
+
"type": "object"
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"type": "null"
|
|
208
|
+
}
|
|
209
|
+
],
|
|
210
|
+
"description": "A query or { $jsonSchema } document; null or {} for no validator. Omit to leave the validator unmanaged"
|
|
211
|
+
},
|
|
212
|
+
"validationLevel": {
|
|
213
|
+
"enum": [
|
|
214
|
+
"off",
|
|
215
|
+
"strict",
|
|
216
|
+
"moderate"
|
|
217
|
+
],
|
|
218
|
+
"description": "How the validator applies to updates. Defaults to 'strict'"
|
|
219
|
+
},
|
|
220
|
+
"validationAction": {
|
|
221
|
+
"enum": [
|
|
222
|
+
"error",
|
|
223
|
+
"warn",
|
|
224
|
+
"errorAndLog"
|
|
225
|
+
],
|
|
226
|
+
"description": "What an invalid write does. Defaults to 'error'"
|
|
227
|
+
},
|
|
228
|
+
"prune": {
|
|
229
|
+
"type": "boolean",
|
|
230
|
+
"description": "Drop indexes this definition does not declare (otherwise they are kept and reported)"
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
"index": {
|
|
235
|
+
"type": "object",
|
|
236
|
+
"required": [
|
|
237
|
+
"key"
|
|
238
|
+
],
|
|
239
|
+
"additionalProperties": false,
|
|
240
|
+
"properties": {
|
|
241
|
+
"key": {
|
|
242
|
+
"type": "object",
|
|
243
|
+
"minProperties": 1,
|
|
244
|
+
"additionalProperties": {
|
|
245
|
+
"enum": [
|
|
246
|
+
1,
|
|
247
|
+
-1,
|
|
248
|
+
"text",
|
|
249
|
+
"hashed",
|
|
250
|
+
"2d",
|
|
251
|
+
"2dsphere"
|
|
252
|
+
]
|
|
253
|
+
},
|
|
254
|
+
"description": "Field → direction, in index order"
|
|
255
|
+
},
|
|
256
|
+
"name": {
|
|
257
|
+
"type": "string",
|
|
258
|
+
"minLength": 1,
|
|
259
|
+
"description": "Defaults to the name MongoDB generates (email_1)"
|
|
260
|
+
},
|
|
261
|
+
"unique": {
|
|
262
|
+
"type": "boolean"
|
|
263
|
+
},
|
|
264
|
+
"sparse": {
|
|
265
|
+
"type": "boolean"
|
|
266
|
+
},
|
|
267
|
+
"hidden": {
|
|
268
|
+
"type": "boolean"
|
|
269
|
+
},
|
|
270
|
+
"expireAfterSeconds": {
|
|
271
|
+
"type": "integer",
|
|
272
|
+
"minimum": 0
|
|
273
|
+
},
|
|
274
|
+
"partialFilterExpression": {
|
|
275
|
+
"type": "object"
|
|
276
|
+
},
|
|
277
|
+
"collation": {
|
|
278
|
+
"type": "object",
|
|
279
|
+
"required": [
|
|
280
|
+
"locale"
|
|
281
|
+
]
|
|
282
|
+
},
|
|
283
|
+
"wildcardProjection": {
|
|
284
|
+
"type": "object"
|
|
285
|
+
},
|
|
286
|
+
"weights": {
|
|
287
|
+
"type": "object"
|
|
288
|
+
},
|
|
289
|
+
"default_language": {
|
|
290
|
+
"type": "string",
|
|
291
|
+
"minLength": 1
|
|
292
|
+
},
|
|
293
|
+
"language_override": {
|
|
294
|
+
"type": "string",
|
|
295
|
+
"minLength": 1
|
|
296
|
+
},
|
|
297
|
+
"textIndexVersion": {
|
|
298
|
+
"type": "integer",
|
|
299
|
+
"minimum": 1
|
|
300
|
+
},
|
|
301
|
+
"2dsphereIndexVersion": {
|
|
302
|
+
"type": "integer",
|
|
303
|
+
"minimum": 1
|
|
304
|
+
},
|
|
305
|
+
"bits": {
|
|
306
|
+
"type": "integer",
|
|
307
|
+
"minimum": 1
|
|
308
|
+
},
|
|
309
|
+
"min": {
|
|
310
|
+
"type": "number"
|
|
311
|
+
},
|
|
312
|
+
"max": {
|
|
313
|
+
"type": "number"
|
|
314
|
+
},
|
|
315
|
+
"storageEngine": {
|
|
316
|
+
"type": "object"
|
|
317
|
+
},
|
|
318
|
+
"background": {
|
|
319
|
+
"type": "boolean",
|
|
320
|
+
"description": "Accepted and ignored — a no-op since MongoDB 4.2"
|
|
321
|
+
}
|
|
322
|
+
}
|
|
133
323
|
}
|
|
134
324
|
}
|
|
135
325
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alexify/migronaut",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "Elegant, fast, fully-typed, zero-dependency MongoDB migrations for Node.js",
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "Elegant, fast, fully-typed, zero-dependency MongoDB migrations for Node.js — adopts an existing migrate-mongo changelog in one command",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Alex Dolid <dolid.sasha@gmail.com>",
|
|
7
7
|
"repository": {
|
|
@@ -24,6 +24,10 @@
|
|
|
24
24
|
".": {
|
|
25
25
|
"types": "./index.d.ts",
|
|
26
26
|
"default": "./index.js"
|
|
27
|
+
},
|
|
28
|
+
"./bullmq": {
|
|
29
|
+
"types": "./bullmq.d.ts",
|
|
30
|
+
"default": "./bullmq.js"
|
|
27
31
|
}
|
|
28
32
|
},
|
|
29
33
|
"directories": {
|
|
@@ -32,6 +36,8 @@
|
|
|
32
36
|
"files": [
|
|
33
37
|
"index.js",
|
|
34
38
|
"index.d.ts",
|
|
39
|
+
"bullmq.js",
|
|
40
|
+
"bullmq.d.ts",
|
|
35
41
|
"migronaut.schema.json",
|
|
36
42
|
"bin",
|
|
37
43
|
"src",
|
|
@@ -51,13 +57,19 @@
|
|
|
51
57
|
"migrations",
|
|
52
58
|
"mongodb-migration",
|
|
53
59
|
"mongodb-migrations",
|
|
60
|
+
"mongodb-migrate",
|
|
54
61
|
"database-migration",
|
|
55
62
|
"schema-migration",
|
|
56
63
|
"migrate-mongo",
|
|
64
|
+
"migrate-mongo-alternative",
|
|
57
65
|
"mongoose",
|
|
58
66
|
"mongoose-migration",
|
|
67
|
+
"bullmq",
|
|
68
|
+
"job-queue",
|
|
69
|
+
"migration-service",
|
|
59
70
|
"rollback",
|
|
60
71
|
"transactions",
|
|
72
|
+
"zero-dependency",
|
|
61
73
|
"cli",
|
|
62
74
|
"typescript",
|
|
63
75
|
"nosql"
|
|
@@ -72,9 +84,18 @@
|
|
|
72
84
|
}
|
|
73
85
|
},
|
|
74
86
|
"devDependencies": {
|
|
87
|
+
"@opentelemetry/api": "^1.9.1",
|
|
88
|
+
"@opentelemetry/instrumentation-mongodb": "^0.75.0",
|
|
89
|
+
"@opentelemetry/sdk-metrics": "^2.11.0",
|
|
90
|
+
"@opentelemetry/sdk-trace-node": "^2.11.0",
|
|
75
91
|
"@types/node": "^22.19.19",
|
|
92
|
+
"@vercel/analytics": "^2.0.1",
|
|
93
|
+
"@vercel/speed-insights": "^2.0.0",
|
|
94
|
+
"bullmq": "^6.3.11",
|
|
95
|
+
"bullmq-otel": "^2.0.1",
|
|
76
96
|
"c8": "^10.1.3",
|
|
77
97
|
"esbuild": "^0.28.1",
|
|
98
|
+
"ioredis": "^5.11.1",
|
|
78
99
|
"mongodb": "^6.12.0",
|
|
79
100
|
"mongodb-memory-server": "10.4.3",
|
|
80
101
|
"mongoose": "^8.9.2",
|
|
@@ -91,10 +112,10 @@
|
|
|
91
112
|
"test:integration": "node scripts/node-test.js --test-concurrency=1 \"tests/integration/**/*.test.js\"",
|
|
92
113
|
"test:coverage": "c8 --all --include 'src/**' --check-coverage --lines 90 --branches 90 --functions 90 --reporter text --reporter lcov node scripts/node-test.js --test-concurrency=1 \"tests/unit/**/*.test.js\" \"tests/integration/**/*.test.js\"",
|
|
93
114
|
"test:types": "tsd",
|
|
94
|
-
"check:dts": "tsc --noEmit --strict --skipLibCheck false index.d.ts",
|
|
95
|
-
"lint": "oxlint src bin scripts tests bench",
|
|
96
|
-
"format": "oxfmt src bin scripts tests bench",
|
|
97
|
-
"format:check": "oxfmt --check src bin scripts tests bench",
|
|
115
|
+
"check:dts": "tsc --noEmit --strict --skipLibCheck false index.d.ts bullmq.d.ts",
|
|
116
|
+
"lint": "oxlint src bin scripts tests bench examples",
|
|
117
|
+
"format": "oxfmt src bin scripts tests bench examples",
|
|
118
|
+
"format:check": "oxfmt --check src bin scripts tests bench examples",
|
|
98
119
|
"size": "node scripts/size.js",
|
|
99
120
|
"bench": "node bench/bench.js",
|
|
100
121
|
"docs:dev": "vitepress dev docs",
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const {
|
|
2
|
+
DEFAULT_CONVERGE_SCHEDULER_ID,
|
|
3
|
+
DEFAULT_QUEUE_NAME,
|
|
4
|
+
DEFAULT_SCHEDULER_ID,
|
|
5
|
+
JOB_DATA_VERSION,
|
|
6
|
+
JOB_NAMES,
|
|
7
|
+
MIN_JOB_DATA_VERSION,
|
|
8
|
+
dedupId,
|
|
9
|
+
parseJobData,
|
|
10
|
+
} = require('./jobs.js');
|
|
11
|
+
const { RETRYABLE_CODES, createMigrationProcessor, isRetryableError } = require('./processor.js');
|
|
12
|
+
const {
|
|
13
|
+
enqueueConverge,
|
|
14
|
+
enqueueDown,
|
|
15
|
+
enqueueUp,
|
|
16
|
+
planDownJobs,
|
|
17
|
+
planUpJobs,
|
|
18
|
+
} = require('./producer.js');
|
|
19
|
+
const { MigrationQueue, createMigrationQueue } = require('./service.js');
|
|
20
|
+
const { waitForGroup } = require('./wait.js');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* `@alexify/migronaut/bullmq` — migrations as a queue, one migration per job.
|
|
24
|
+
*
|
|
25
|
+
* BullMQ is never required from here: the classes are injected by the caller
|
|
26
|
+
* (`createMigrationQueue({ bullmq: { Queue, Worker } })`), so this entry point
|
|
27
|
+
* costs nothing to anyone who does not use it and pins no BullMQ version.
|
|
28
|
+
*/
|
|
29
|
+
module.exports = {
|
|
30
|
+
// The service facade — queue, worker, scheduling and status in one object
|
|
31
|
+
createMigrationQueue,
|
|
32
|
+
MigrationQueue,
|
|
33
|
+
|
|
34
|
+
// Building blocks, for a Queue/Worker the application already owns
|
|
35
|
+
// (NestJS processors, BullMQ Pro, a shared worker process)
|
|
36
|
+
createMigrationProcessor,
|
|
37
|
+
enqueueUp,
|
|
38
|
+
enqueueDown,
|
|
39
|
+
enqueueConverge,
|
|
40
|
+
planUpJobs,
|
|
41
|
+
planDownJobs,
|
|
42
|
+
waitForGroup,
|
|
43
|
+
|
|
44
|
+
// The job contract
|
|
45
|
+
JOB_NAMES,
|
|
46
|
+
JOB_DATA_VERSION,
|
|
47
|
+
MIN_JOB_DATA_VERSION,
|
|
48
|
+
DEFAULT_QUEUE_NAME,
|
|
49
|
+
DEFAULT_SCHEDULER_ID,
|
|
50
|
+
DEFAULT_CONVERGE_SCHEDULER_ID,
|
|
51
|
+
RETRYABLE_CODES,
|
|
52
|
+
dedupId,
|
|
53
|
+
isRetryableError,
|
|
54
|
+
parseJobData,
|
|
55
|
+
};
|