@lenne.tech/nest-server 11.3.0 → 11.4.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.
Files changed (35) hide show
  1. package/bin/migrate.js +40 -0
  2. package/dist/core/modules/migrate/cli/migrate-cli.d.ts +3 -0
  3. package/dist/core/modules/migrate/cli/migrate-cli.js +221 -0
  4. package/dist/core/modules/migrate/cli/migrate-cli.js.map +1 -0
  5. package/dist/core/modules/migrate/helpers/migration.helper.d.ts +12 -0
  6. package/dist/core/modules/migrate/helpers/migration.helper.js +57 -0
  7. package/dist/core/modules/migrate/helpers/migration.helper.js.map +1 -0
  8. package/dist/core/modules/migrate/helpers/ts-compiler.d.ts +2 -0
  9. package/dist/core/modules/migrate/helpers/ts-compiler.js +3 -0
  10. package/dist/core/modules/migrate/helpers/ts-compiler.js.map +1 -0
  11. package/dist/core/modules/migrate/index.d.ts +4 -0
  12. package/dist/core/modules/migrate/index.js +21 -0
  13. package/dist/core/modules/migrate/index.js.map +1 -0
  14. package/dist/core/modules/migrate/migration-runner.d.ts +26 -0
  15. package/dist/core/modules/migrate/migration-runner.js +124 -0
  16. package/dist/core/modules/migrate/migration-runner.js.map +1 -0
  17. package/dist/core/modules/migrate/mongo-state-store.d.ts +30 -0
  18. package/dist/core/modules/migrate/mongo-state-store.js +105 -0
  19. package/dist/core/modules/migrate/mongo-state-store.js.map +1 -0
  20. package/dist/core/modules/migrate/templates/migration-project.template.ts +53 -0
  21. package/dist/index.d.ts +1 -0
  22. package/dist/index.js +1 -0
  23. package/dist/index.js.map +1 -1
  24. package/dist/tsconfig.build.tsbuildinfo +1 -1
  25. package/package.json +9 -3
  26. package/src/core/modules/migrate/MIGRATION_FROM_NODEPIT.md +298 -0
  27. package/src/core/modules/migrate/README.md +453 -0
  28. package/src/core/modules/migrate/cli/migrate-cli.ts +319 -0
  29. package/src/core/modules/migrate/helpers/migration.helper.ts +117 -0
  30. package/src/core/modules/migrate/helpers/ts-compiler.js +14 -0
  31. package/src/core/modules/migrate/index.ts +41 -0
  32. package/src/core/modules/migrate/migration-runner.ts +230 -0
  33. package/src/core/modules/migrate/mongo-state-store.ts +283 -0
  34. package/src/core/modules/migrate/templates/migration-project.template.ts +53 -0
  35. package/src/index.ts +9 -3
@@ -0,0 +1,453 @@
1
+ # MongoDB State Store for Migrations
2
+
3
+ This module provides a MongoDB-based state storage for migration frameworks, offering a modern TypeScript implementation that is fully compatible with `@nodepit/migrate-state-store-mongodb`.
4
+
5
+ ## Features
6
+
7
+ - ✅ **Full Backward Compatibility**: Drop-in replacement for `@nodepit/migrate-state-store-mongodb`
8
+ - ✅ **MongoDB 6+ Support**: Works with MongoDB 6.x, 7.x and newer versions
9
+ - ✅ **Modern TypeScript**: Written in modern TypeScript with full type safety
10
+ - ✅ **Cluster Support**: Built-in locking mechanism for clustered environments
11
+ - ✅ **Dual API**: Supports both callback-based and Promise-based APIs
12
+ - ✅ **No External Dependencies**: Uses only MongoDB driver already included in nest-server
13
+ - ✅ **Fully Tested**: Comprehensive E2E test suite with 25+ test cases
14
+
15
+ ## Migration from @nodepit/migrate-state-store-mongodb
16
+
17
+ If you're currently using `@nodepit/migrate-state-store-mongodb`, you can migrate seamlessly:
18
+
19
+ ### 1. Remove the old package
20
+
21
+ ```bash
22
+ npm uninstall @nodepit/migrate-state-store-mongodb
23
+ ```
24
+
25
+ ### 2. Update your imports
26
+
27
+ **Before:**
28
+ ```typescript
29
+ import { MongoStateStore, synchronizedUp } from '@nodepit/migrate-state-store-mongodb';
30
+ ```
31
+
32
+ **After:**
33
+ ```typescript
34
+ import { MongoStateStore, synchronizedUp } from '@lenne.tech/nest-server';
35
+ ```
36
+
37
+ That's it! Your existing migrations will continue to work without any changes.
38
+
39
+ ## Installation
40
+
41
+ If you're using `@lenne.tech/nest-server`, the migration functionality is already included:
42
+
43
+ ```bash
44
+ npm install @lenne.tech/nest-server
45
+ ```
46
+
47
+ ## Usage
48
+
49
+ ### Basic Usage
50
+
51
+ ```typescript
52
+ import { MongoStateStore } from '@lenne.tech/nest-server';
53
+
54
+ // Simple string URI
55
+ const stateStore = new MongoStateStore('mongodb://localhost/mydb');
56
+
57
+ // Or with options
58
+ const stateStore = new MongoStateStore({
59
+ uri: 'mongodb://localhost/mydb',
60
+ collectionName: 'custom_migrations', // optional, defaults to 'migrations'
61
+ lockCollectionName: 'migration_lock' // optional, for cluster environments
62
+ });
63
+ ```
64
+
65
+ ### With Callback API
66
+
67
+ ```typescript
68
+ // Load migration state
69
+ stateStore.load((err, state) => {
70
+ if (err) {
71
+ console.error('Failed to load migration state:', err);
72
+ return;
73
+ }
74
+ console.log('Current migration state:', state);
75
+ });
76
+
77
+ // Save migration state
78
+ const migrationState = {
79
+ migrations: [
80
+ { title: '1234-my-migration.js', timestamp: Date.now() }
81
+ ],
82
+ lastRun: '1234-my-migration.js'
83
+ };
84
+
85
+ stateStore.save(migrationState, (err) => {
86
+ if (err) {
87
+ console.error('Failed to save migration state:', err);
88
+ return;
89
+ }
90
+ console.log('Migration state saved successfully');
91
+ });
92
+ ```
93
+
94
+ ### With Promise/Async API
95
+
96
+ ```typescript
97
+ // Load migration state
98
+ try {
99
+ const state = await stateStore.loadAsync();
100
+ console.log('Current migration state:', state);
101
+ } catch (err) {
102
+ console.error('Failed to load migration state:', err);
103
+ }
104
+
105
+ // Save migration state
106
+ try {
107
+ await stateStore.saveAsync(migrationState);
108
+ console.log('Migration state saved successfully');
109
+ } catch (err) {
110
+ console.error('Failed to save migration state:', err);
111
+ }
112
+ ```
113
+
114
+ ### Synchronized Migrations (Cluster Support)
115
+
116
+ For clustered environments where multiple instances might try to run migrations simultaneously:
117
+
118
+ ```typescript
119
+ import { MongoStateStore, synchronizedMigration, synchronizedUp } from '@lenne.tech/nest-server';
120
+
121
+ const migrationOptions = {
122
+ stateStore: new MongoStateStore({
123
+ uri: 'mongodb://localhost/mydb',
124
+ lockCollectionName: 'migration_lock' // Required for synchronized migrations
125
+ }),
126
+ migrationsDirectory: './migrations'
127
+ };
128
+
129
+ // Custom migration logic
130
+ await synchronizedMigration(migrationOptions, async (migrationSet) => {
131
+ // Only one instance at a time will execute this code
132
+ console.log('Running migrations...');
133
+ await promisify(migrationSet.up).call(migrationSet);
134
+ });
135
+
136
+ // Or use the convenience function to run all pending migrations
137
+ await synchronizedUp(migrationOptions);
138
+ ```
139
+
140
+ ## API Reference
141
+
142
+ ### MongoStateStore
143
+
144
+ #### Constructor
145
+
146
+ ```typescript
147
+ new MongoStateStore(options: string | MongoStateStoreOptions)
148
+ ```
149
+
150
+ **Parameters:**
151
+ - `options`: MongoDB URI string or configuration object
152
+ - `uri`: MongoDB connection URI (required)
153
+ - `collectionName`: Name of the collection to store migration state (default: 'migrations')
154
+ - `lockCollectionName`: Collection name for locking mechanism (optional)
155
+
156
+ #### Methods
157
+
158
+ ##### load(callback)
159
+
160
+ Loads the migration state from MongoDB (callback-based).
161
+
162
+ ```typescript
163
+ load(fn: (err?: Error, set?: MigrationSet) => void): void
164
+ ```
165
+
166
+ ##### loadAsync()
167
+
168
+ Loads the migration state from MongoDB (promise-based).
169
+
170
+ ```typescript
171
+ loadAsync(): Promise<MigrationSet>
172
+ ```
173
+
174
+ ##### save(set, callback)
175
+
176
+ Saves the migration state to MongoDB (callback-based).
177
+
178
+ ```typescript
179
+ save(set: MigrationSet, fn: (err?: Error) => void): void
180
+ ```
181
+
182
+ ##### saveAsync(set)
183
+
184
+ Saves the migration state to MongoDB (promise-based).
185
+
186
+ ```typescript
187
+ saveAsync(set: MigrationSet): Promise<void>
188
+ ```
189
+
190
+ ### Helper Functions
191
+
192
+ #### synchronizedMigration
193
+
194
+ Wraps migrations with a lock to prevent simultaneous execution in clustered environments.
195
+
196
+ ```typescript
197
+ async function synchronizedMigration(
198
+ opts: MigrationOptions,
199
+ callback: (set: MigrationSet) => Promise<void>
200
+ ): Promise<void>
201
+ ```
202
+
203
+ #### synchronizedUp
204
+
205
+ Convenience function that executes all pending migrations in a synchronized manner.
206
+
207
+ ```typescript
208
+ async function synchronizedUp(opts: MigrationOptions): Promise<void>
209
+ ```
210
+
211
+ ## How It Works
212
+
213
+ ### State Storage
214
+
215
+ The migration state is stored in a MongoDB collection (default: `migrations`) as a single document containing:
216
+
217
+ ```typescript
218
+ {
219
+ migrations: [
220
+ {
221
+ title: 'migration-name.js',
222
+ timestamp: 1234567890,
223
+ description: 'Migration description'
224
+ }
225
+ ],
226
+ lastRun: 'last-migration-name.js'
227
+ }
228
+ ```
229
+
230
+ ### Locking Mechanism
231
+
232
+ When using `synchronizedMigration` or `synchronizedUp`:
233
+
234
+ 1. A unique index is created on the lock collection
235
+ 2. The migration process attempts to insert a lock document
236
+ 3. Only one instance can successfully insert (others wait)
237
+ 4. After migration completes, the lock is released
238
+ 5. Waiting instances can then proceed
239
+
240
+ This ensures that in a cluster with multiple nodes, migrations run on only one machine at a time.
241
+
242
+ ## Examples
243
+
244
+ ### Example: Migration File
245
+
246
+ Create a migration file in your migrations directory:
247
+
248
+ ```javascript
249
+ // migrations/1234567890-add-user-email.js
250
+
251
+ 'use strict';
252
+
253
+ const { MongoClient } = require('mongodb');
254
+ const { promisify } = require('util');
255
+ const { callbackify } = require('util');
256
+
257
+ const mongoUrl = process.env.MONGODB_URL;
258
+
259
+ module.exports.up = function (next) {
260
+ callbackify(async () => {
261
+ const client = await MongoClient.connect(mongoUrl);
262
+ try {
263
+ await client.db().collection('users').updateMany(
264
+ { email: { $exists: false } },
265
+ { $set: { email: '' } }
266
+ );
267
+ } finally {
268
+ await client.close();
269
+ }
270
+ })(next);
271
+ };
272
+
273
+ module.exports.down = function (next) {
274
+ callbackify(async () => {
275
+ const client = await MongoClient.connect(mongoUrl);
276
+ try {
277
+ await client.db().collection('users').updateMany(
278
+ {},
279
+ { $unset: { email: '' } }
280
+ );
281
+ } finally {
282
+ await client.close();
283
+ }
284
+ })(next);
285
+ };
286
+ ```
287
+
288
+ ### Example: Running Migrations in Your Application
289
+
290
+ ```typescript
291
+ import { MongoStateStore, synchronizedUp } from '@lenne.tech/nest-server';
292
+ import path from 'path';
293
+
294
+ async function runMigrations() {
295
+ const migrationOptions = {
296
+ stateStore: new MongoStateStore({
297
+ uri: process.env.MONGODB_URL || 'mongodb://localhost/mydb',
298
+ lockCollectionName: 'migration_lock'
299
+ }),
300
+ migrationsDirectory: path.join(__dirname, 'migrations')
301
+ };
302
+
303
+ try {
304
+ await synchronizedUp(migrationOptions);
305
+ console.log('Migrations completed successfully');
306
+ } catch (err) {
307
+ console.error('Migration failed:', err);
308
+ process.exit(1);
309
+ }
310
+ }
311
+
312
+ // Run migrations on application startup
313
+ runMigrations().catch(console.error);
314
+ ```
315
+
316
+ ## Differences from @nodepit/migrate-state-store-mongodb
317
+
318
+ While maintaining full API compatibility, this implementation offers:
319
+
320
+ 1. **Better TypeScript Support**: Full type definitions and modern TypeScript syntax
321
+ 2. **MongoDB 7.x Support**: Works with latest MongoDB versions
322
+ 3. **Async/Await**: Modern async patterns instead of callback-heavy code
323
+ 4. **Better Error Handling**: More descriptive error messages
324
+ 5. **No Additional Dependencies**: Uses only what's already in nest-server
325
+
326
+ ## Testing
327
+
328
+ The module includes a comprehensive test suite with 25+ test cases covering:
329
+
330
+ - Initialization and configuration
331
+ - Error handling
332
+ - Loading and saving state
333
+ - Callback and Promise APIs
334
+ - Locking mechanism
335
+ - Parallel execution
336
+ - Backward compatibility
337
+ - MongoDB 7.x features
338
+
339
+ Run the tests:
340
+
341
+ ```bash
342
+ npm test -- tests/migrate/mongo-state-store.e2e-spec.ts
343
+ ```
344
+
345
+ ## Migration Utilities
346
+
347
+ In addition to the state store, this module provides helpful utilities for managing migrations:
348
+
349
+ ### createMigrationStore()
350
+
351
+ Factory function to create a migration store class for use with the migrate CLI:
352
+
353
+ ```javascript
354
+ // migrations-utils/migrate.js
355
+ const { createMigrationStore } = require('@lenne.tech/nest-server');
356
+ const config = require('../src/config.env');
357
+
358
+ module.exports = createMigrationStore(
359
+ config.default.mongoose.uri,
360
+ 'migrations', // optional collection name
361
+ 'migration_lock' // optional lock collection for clusters
362
+ );
363
+ ```
364
+
365
+ ### getDb()
366
+
367
+ Helper function to get a database connection in your migrations:
368
+
369
+ ```typescript
370
+ import { getDb } from '@lenne.tech/nest-server';
371
+
372
+ const db = await getDb('mongodb://localhost/mydb');
373
+ await db.collection('users').updateMany(...);
374
+ ```
375
+
376
+ ### uploadFileToGridFS()
377
+
378
+ Helper function to upload files to GridFS during migrations:
379
+
380
+ ```typescript
381
+ import { uploadFileToGridFS } from '@lenne.tech/nest-server';
382
+
383
+ const fileId = await uploadFileToGridFS(
384
+ 'mongodb://localhost/mydb',
385
+ '../assets/image.png',
386
+ { bucketName: 'images', filename: 'logo.png' }
387
+ );
388
+ ```
389
+
390
+ ### Migration Templates
391
+
392
+ Ready-to-use template for nest-server projects:
393
+
394
+ **Project Template**: `dist/core/modules/migrate/templates/migration-project.template.ts`
395
+
396
+ This template automatically imports `getDb()` and `uploadFileToGridFS()` from nest-server, along with your project's config. It's ready to use with zero configuration.
397
+
398
+ ### TypeScript Compiler
399
+
400
+ Pre-configured TypeScript compiler for migrate CLI:
401
+
402
+ ```bash
403
+ migrate --compiler="ts:./node_modules/@lenne.tech/nest-server/dist/core/modules/migrate/helpers/ts-compiler.js"
404
+ ```
405
+
406
+ ## Complete Setup Guide
407
+
408
+ For a complete step-by-step guide on migrating from @nodepit/migrate-state-store-mongodb, see [MIGRATION_FROM_NODEPIT.md](./MIGRATION_FROM_NODEPIT.md).
409
+
410
+ ### Quick Setup (No External Dependencies!) 🚀
411
+
412
+ **No need to install the `migrate` package!** nest-server now includes a built-in migration CLI.
413
+
414
+ 1. Install ts-node (dev dependency): `npm install --save-dev ts-node`
415
+ 2. Create `migrations-utils/migrate.js` using `createMigrationStore()`
416
+ 3. Add migration scripts to your `package.json`
417
+ 4. Run migrations using the built-in CLI
418
+
419
+ **Example package.json scripts:**
420
+ ```json
421
+ {
422
+ "scripts": {
423
+ "migrate:create": "migrate create --template-file ./node_modules/@lenne.tech/nest-server/dist/core/modules/migrate/templates/migration-project.template.ts --migrations-dir ./migrations --compiler ts:./node_modules/@lenne.tech/nest-server/dist/core/modules/migrate/helpers/ts-compiler.js",
424
+ "migrate:up": "migrate up --store ./migrations-utils/migrate.js --migrations-dir ./migrations --compiler ts:./node_modules/@lenne.tech/nest-server/dist/core/modules/migrate/helpers/ts-compiler.js",
425
+ "migrate:down": "migrate down --store ./migrations-utils/migrate.js --migrations-dir ./migrations --compiler ts:./node_modules/@lenne.tech/nest-server/dist/core/modules/migrate/helpers/ts-compiler.js"
426
+ }
427
+ }
428
+ ```
429
+
430
+ The `migrate` command comes from `@lenne.tech/nest-server` - no external package needed!
431
+
432
+ See the [Migration Guide](./MIGRATION_FROM_NODEPIT.md) for detailed migration instructions from @nodepit.
433
+
434
+ ## Project Integration
435
+
436
+ The migration utilities are designed to minimize boilerplate in your projects. Instead of copying multiple utility files, you can:
437
+
438
+ 1. Use `createMigrationStore()` for your store configuration
439
+ 2. Use the built-in TypeScript compiler
440
+ 3. Optionally use the provided templates
441
+ 4. Only maintain project-specific migration files
442
+
443
+ This significantly reduces the amount of migration-related code in each project.
444
+
445
+ ## License
446
+
447
+ MIT
448
+
449
+ ## Support
450
+
451
+ For issues and questions:
452
+ - GitHub: https://github.com/lenneTech/nest-server/issues
453
+ - Documentation: https://nest-server.lenne.tech