@alexify/migronaut 1.0.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 +128 -0
- package/LICENSE +22 -0
- package/README.md +773 -0
- package/bin/migronaut.js +36 -0
- package/index.d.ts +903 -0
- package/index.js +1 -0
- package/migronaut.schema.json +135 -0
- package/package.json +105 -0
- package/src/cli/args.js +314 -0
- package/src/cli/commands/audit.js +40 -0
- package/src/cli/commands/create.js +29 -0
- package/src/cli/commands/down.js +30 -0
- package/src/cli/commands/dry-run.js +36 -0
- package/src/cli/commands/import.js +33 -0
- package/src/cli/commands/init.js +64 -0
- package/src/cli/commands/list.js +19 -0
- package/src/cli/commands/lock.js +35 -0
- package/src/cli/commands/redo.js +16 -0
- package/src/cli/commands/status.js +52 -0
- package/src/cli/commands/unlock.js +43 -0
- package/src/cli/commands/up.js +53 -0
- package/src/cli/exit-codes.js +38 -0
- package/src/cli/index.js +91 -0
- package/src/cli/shared.js +343 -0
- package/src/cli/spinner.js +59 -0
- package/src/cli/table.js +259 -0
- package/src/core/audit.js +152 -0
- package/src/core/changelog.js +231 -0
- package/src/core/config.js +479 -0
- package/src/core/context.js +16 -0
- package/src/core/import-runner.js +164 -0
- package/src/core/import.js +60 -0
- package/src/core/lock.js +348 -0
- package/src/core/migrator.js +1475 -0
- package/src/core/run.js +144 -0
- package/src/core/runner.js +150 -0
- package/src/errors/index.js +215 -0
- package/src/index.js +59 -0
- package/src/utils/checksum.js +23 -0
- package/src/utils/colors.js +68 -0
- package/src/utils/concurrency.js +32 -0
- package/src/utils/date.js +28 -0
- package/src/utils/env.js +51 -0
- package/src/utils/error.js +11 -0
- package/src/utils/loader.js +131 -0
- package/src/utils/logger.js +109 -0
- package/src/utils/redact.js +39 -0
- package/src/utils/sanitize.js +43 -0
- package/src/utils/template.js +615 -0
- package/src/utils/user.js +25 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## v1.0.0
|
|
6
|
+
|
|
7
|
+
Initial release. Requires **Node.js ≥ 22.18**.
|
|
8
|
+
|
|
9
|
+
### Core
|
|
10
|
+
|
|
11
|
+
- `MigratorKit` orchestration: `up`, `down`, `redo`, `dryRun`, `status`, `list`, `audit`,
|
|
12
|
+
`create`, `init`, `import`, `lockInfo`, `forceUnlock`
|
|
13
|
+
- `migronaut` CLI with `init`, `up`, `down`, `redo`, `status`, `list`, `dry-run`, `audit`,
|
|
14
|
+
`create`, `import`, `lock`, and `unlock` commands
|
|
15
|
+
- Config loader with priority: CLI flags → `MIGRONAUT_*` env vars → config file → defaults,
|
|
16
|
+
checked by a built-in zero-dependency validator (`ConfigInvalidError` with per-issue
|
|
17
|
+
`{ path, message }`)
|
|
18
|
+
- **Every scalar option is settable from the environment** — a table-driven `MIGRONAUT_*` layer
|
|
19
|
+
pinned against the config-key spec by a test, so a config file is genuinely optional rather than
|
|
20
|
+
merely discouraged. Values fail closed: `MIGRONAUT_STRICT=on`, `MIGRONAUT_LOCK_TTL=abc` and
|
|
21
|
+
`MIGRONAUT_CREATE_EXTENSION=tsx` are rejected with an error naming the variable, never coerced
|
|
22
|
+
- `MIGRONAUT_NO_COLOR` / `MIGRONAUT_FORCE_COLOR` pin migronaut's own color output above the
|
|
23
|
+
ecosystem-wide `NO_COLOR`/`FORCE_COLOR`, which stay honored underneath; `MIGRONAUT_USER`
|
|
24
|
+
overrides the OS user recorded in `executedBy`, for CI where that user is a meaningless `runner`
|
|
25
|
+
- Function / async config files — `export default` a (sync or async) factory returning the config,
|
|
26
|
+
for loading the connection from a secret manager at runtime with no bundled cloud SDKs
|
|
27
|
+
- **Client injection** (`config.client`) — reuse an already-connected `MongoClient` (its pool,
|
|
28
|
+
auth, TLS); ownership stays with the caller and `disconnect()` never closes it
|
|
29
|
+
- **Lifecycle events** — `MigratorKit` is an EventEmitter: `run:start`/`run:end` (with duration
|
|
30
|
+
and result counts), `migration:start`/`success`/`skipped`/`error`,
|
|
31
|
+
`lock:acquired`/`released`/`lost` — feed metrics or alerting without parsing log lines
|
|
32
|
+
- First-class `.ts` and `.js` (ESM + CJS) migration loading
|
|
33
|
+
- MongoDB-native concurrency lock with TTL-based stale reclaim and heartbeat renewal for long
|
|
34
|
+
migrations
|
|
35
|
+
- SHA-256 checksum tamper detection, surfaced in `status`
|
|
36
|
+
- Opt-in transactions (per-file or global) with automatic commit/abort
|
|
37
|
+
- Lifecycle hooks: `beforeAll`, `afterAll`, `beforeEach`, `afterEach`, `onError`
|
|
38
|
+
- Append-only audit trail in `_migronaut_migrations` — reverts are never deleted
|
|
39
|
+
|
|
40
|
+
### Step controls & automation
|
|
41
|
+
|
|
42
|
+
- **`migronaut up --step`** — apply each pending file as its own sequential batch, so a later
|
|
43
|
+
`down` can peel migrations off one at a time
|
|
44
|
+
- **`migronaut down --steps <n>`** — revert the last N applied migrations, newest first, regardless
|
|
45
|
+
of batch
|
|
46
|
+
- **`migronaut up --to <file>` / `migronaut down --to <file>`** — migrate to a named point in the
|
|
47
|
+
sequence: `up --to` applies pending files up to and including it, `down --to` reverts everything
|
|
48
|
+
applied after it (exclusive), so the pair is a round trip
|
|
49
|
+
- **`migronaut dry-run`** previews the same selections — `--steps`, `--batch`, and `--to` — without
|
|
50
|
+
touching the database
|
|
51
|
+
- **`migronaut audit`** — read-only health check (config, connectivity, transaction support,
|
|
52
|
+
indexes, lock state, checksum drift, runtime) with pass/warn/fail per check
|
|
53
|
+
- **`migronaut lock`** — inspect the current migration lock holder without modifying it
|
|
54
|
+
- **`--json` machine-readable output** as a global flag (`migronaut --json status` and
|
|
55
|
+
`migronaut status --json` both work) on every command — `up`, `down`, `redo`, `status`, `list`,
|
|
56
|
+
`dry-run`, `import`, `create`, `audit`, `lock`, `unlock` — a single JSON document on stdout;
|
|
57
|
+
human logs and the spinner go to stderr, so stdout stays pipe-safe. The one exception is
|
|
58
|
+
`init`, whose deliverable is the config file itself: `init --format <js|ts|json>` selects the
|
|
59
|
+
file format, and a stray `init --json` is rejected with a pointer to `--format`
|
|
60
|
+
- **`migronaut status --check`** — exits with code 2 (`PENDING_MIGRATIONS`) when any migration is
|
|
61
|
+
pending, for CI deploy gates; `--pending` and `--limit <n>` filter the table
|
|
62
|
+
- **Typed exit codes for every error** — each `MigronautError` code maps to a dedicated exit code
|
|
63
|
+
(idempotency cases included: `CONFIG_FILE_EXISTS` = 16, `IMPORT_TARGET_NOT_EMPTY` = 17), audit
|
|
64
|
+
failures exit 22, and the full map is exported from the package root as `EXIT_CODES`
|
|
65
|
+
- **`migronaut unlock`** — force-release a stuck lock left behind by a crashed run, with holder
|
|
66
|
+
info (pid / host / user / since) and a confirmation prompt (`--yes` to skip)
|
|
67
|
+
- **`migronaut up <file> --force --yes`** — confirm a forced re-run non-interactively
|
|
68
|
+
|
|
69
|
+
### Zero dependencies
|
|
70
|
+
|
|
71
|
+
- **No runtime dependencies at all** — `package.json` has no `dependencies` key; only `mongodb`
|
|
72
|
+
(required) and `mongoose` (optional) as peers
|
|
73
|
+
- `.env` loading via native `util.parseEnv` (quotes, `export ` prefix, comments, multiline
|
|
74
|
+
values) — real env vars always win over `.env`
|
|
75
|
+
- Hand-rolled ANSI colors (detection: `MIGRONAUT_FORCE_COLOR` > `MIGRONAUT_NO_COLOR` >
|
|
76
|
+
`FORCE_COLOR` > `NO_COLOR` > `TERM=dumb` > TTY), a TTY-only
|
|
77
|
+
spinner (complete no-op when piped), box-drawing tables with ANSI-aware column widths, and a
|
|
78
|
+
commander-compatible argument parser (combined short flags like `-fy` are not supported)
|
|
79
|
+
- `MigronautLogger` is pino-compatible (`{ debug, info, warn, error, child? }`) — pass a pino
|
|
80
|
+
instance directly as `logger`; a `component: 'migronaut'` child binding is applied once and a
|
|
81
|
+
throwing logger can never break a migration run
|
|
82
|
+
|
|
83
|
+
### Import from `migrate-mongo`
|
|
84
|
+
|
|
85
|
+
- **`migronaut import`** — read an existing `migrate-mongo` `changelog` and record that history in
|
|
86
|
+
the migronaut changelog, so `migronaut up` runs only what is new. One-time and forward-only; the
|
|
87
|
+
source collection is never modified
|
|
88
|
+
- `--from <collection>` / `--to <collection>`, `--dry-run`, `--trust-hash`, `--force`, `--no-lock`
|
|
89
|
+
- **Forward-only safety** — imported records are tagged `origin: 'migrate-mongo'`; `migronaut
|
|
90
|
+
down`/`redo` refuse them up front with a clear reason, so the changelog is never corrupted
|
|
91
|
+
|
|
92
|
+
### Hardening
|
|
93
|
+
|
|
94
|
+
- **Path-traversal protection** — migration names are validated as bare filenames confined to the
|
|
95
|
+
migrations directory, so a crafted name can't load or read a file outside it
|
|
96
|
+
(`MigrationInvalidNameError`)
|
|
97
|
+
- **Lock safety for long migrations** — heartbeat renewal at half the TTL, owner-scoped
|
|
98
|
+
acquire/release/renew, server-time (`$$NOW`) staleness judgments immune to host clock skew, and
|
|
99
|
+
a hard renewal deadline that stops the run strictly before a peer could reclaim the lock
|
|
100
|
+
- **Credential redaction** — connection-string passwords are masked (`user:****@`) in every error
|
|
101
|
+
message, `--json` payload, and `--verbose` stack the CLI emits
|
|
102
|
+
- **Terminal-injection safety** — control characters in DB-sourced values (descriptions,
|
|
103
|
+
filenames, lock-holder fields) are stripped in the default logger's write path, the spinner and
|
|
104
|
+
table rendering; migronaut's own SGR colors survive, cursor movement and screen clearing do not.
|
|
105
|
+
Raw `Error` objects never reach event subscribers either — `migration:error` and `run:end`
|
|
106
|
+
carry a pre-redacted message string
|
|
107
|
+
- **Unbounded-wait protection** — `runMigrations` validates `lockWaitTimeoutMs` /
|
|
108
|
+
`lockPollIntervalMs` up front (`ConfigInvalidError`), so a `NaN` can no longer turn the
|
|
109
|
+
lock-wait loop into an infinite retry storm; the summary reports `waitedMs` and `attempts`
|
|
110
|
+
- **Preview parity** — `dry-run down` uses the exact selection the real `down` executes,
|
|
111
|
+
including the refusal of forward-only migrate-mongo imports, and lists rows in revert order
|
|
112
|
+
- **`redo` correctness** — the target is resolved *inside* the lock (no race with a peer), and a
|
|
113
|
+
failed re-apply carries the already-reverted rows in `error.context.results`
|
|
114
|
+
- **CLI logger fallback** — a `logger` from the config file (pino, or `null` for silence) is
|
|
115
|
+
respected by the CLI instead of being clobbered by its console logger
|
|
116
|
+
- **Clear `.ts` runtime errors** — actionable messages when type stripping is disabled or a
|
|
117
|
+
migration uses non-erasable TypeScript syntax (`enum`, `namespace`)
|
|
118
|
+
- **`TransactionsUnsupportedError`** — `useTransaction` on a standalone server names the topology
|
|
119
|
+
as the problem instead of blaming the migration
|
|
120
|
+
- `prepublishOnly` runs `lint` + `format:check` + coverage-gated tests + `tsd` type tests +
|
|
121
|
+
a strict `tsc` pass over `index.d.ts` (`check:dts`), so a broken release can't be published
|
|
122
|
+
|
|
123
|
+
### Documentation
|
|
124
|
+
|
|
125
|
+
- Full documentation site at <https://migronaut.vercel.app/> — guides, a full command reference, a
|
|
126
|
+
programmatic API overview, an FAQ, and a migrate-mongo migration guide
|
|
127
|
+
- Requires **Node.js ≥ 22.18** — `.ts` migrations run natively (built-in type stripping) with no
|
|
128
|
+
loader or build step; `.js` migrations likewise
|
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Santosh Gupta
|
|
4
|
+
Copyright (c) 2026 Alexis Technologies
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|