@lenne.tech/nest-server 11.2.0 → 11.4.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.
Files changed (73) hide show
  1. package/bin/migrate.js +40 -0
  2. package/dist/core/common/decorators/unified-field.decorator.d.ts +2 -0
  3. package/dist/core/common/decorators/unified-field.decorator.js +26 -9
  4. package/dist/core/common/decorators/unified-field.decorator.js.map +1 -1
  5. package/dist/core/common/models/core-persistence.model.js +2 -2
  6. package/dist/core/common/models/core-persistence.model.js.map +1 -1
  7. package/dist/core/modules/file/core-file-info.model.js +41 -23
  8. package/dist/core/modules/file/core-file-info.model.js.map +1 -1
  9. package/dist/core/modules/migrate/cli/migrate-cli.d.ts +3 -0
  10. package/dist/core/modules/migrate/cli/migrate-cli.js +221 -0
  11. package/dist/core/modules/migrate/cli/migrate-cli.js.map +1 -0
  12. package/dist/core/modules/migrate/helpers/migration.helper.d.ts +12 -0
  13. package/dist/core/modules/migrate/helpers/migration.helper.js +57 -0
  14. package/dist/core/modules/migrate/helpers/migration.helper.js.map +1 -0
  15. package/dist/core/modules/migrate/helpers/ts-compiler.d.ts +2 -0
  16. package/dist/core/modules/migrate/helpers/ts-compiler.js +3 -0
  17. package/dist/core/modules/migrate/helpers/ts-compiler.js.map +1 -0
  18. package/dist/core/modules/migrate/index.d.ts +4 -0
  19. package/dist/core/modules/migrate/index.js +21 -0
  20. package/dist/core/modules/migrate/index.js.map +1 -0
  21. package/dist/core/modules/migrate/migration-runner.d.ts +26 -0
  22. package/dist/core/modules/migrate/migration-runner.js +124 -0
  23. package/dist/core/modules/migrate/migration-runner.js.map +1 -0
  24. package/dist/core/modules/migrate/mongo-state-store.d.ts +30 -0
  25. package/dist/core/modules/migrate/mongo-state-store.js +105 -0
  26. package/dist/core/modules/migrate/mongo-state-store.js.map +1 -0
  27. package/dist/core/modules/migrate/templates/migration-with-helper.template.d.ts +2 -0
  28. package/dist/core/modules/migrate/templates/migration-with-helper.template.js +10 -0
  29. package/dist/core/modules/migrate/templates/migration-with-helper.template.js.map +1 -0
  30. package/dist/core/modules/migrate/templates/migration.template.d.ts +2 -0
  31. package/dist/core/modules/migrate/templates/migration.template.js +15 -0
  32. package/dist/core/modules/migrate/templates/migration.template.js.map +1 -0
  33. package/dist/core/modules/user/core-user.model.js +95 -54
  34. package/dist/core/modules/user/core-user.model.js.map +1 -1
  35. package/dist/index.d.ts +1 -0
  36. package/dist/index.js +1 -0
  37. package/dist/index.js.map +1 -1
  38. package/dist/main.js +22 -0
  39. package/dist/main.js.map +1 -1
  40. package/dist/server/common/models/persistence.model.js +13 -11
  41. package/dist/server/common/models/persistence.model.js.map +1 -1
  42. package/dist/server/modules/auth/auth.model.js +6 -2
  43. package/dist/server/modules/auth/auth.model.js.map +1 -1
  44. package/dist/server/modules/user/user.controller.d.ts +19 -0
  45. package/dist/server/modules/user/user.controller.js +256 -0
  46. package/dist/server/modules/user/user.controller.js.map +1 -0
  47. package/dist/server/modules/user/user.model.js +37 -24
  48. package/dist/server/modules/user/user.model.js.map +1 -1
  49. package/dist/server/modules/user/user.module.js +2 -1
  50. package/dist/server/modules/user/user.module.js.map +1 -1
  51. package/dist/tsconfig.build.tsbuildinfo +1 -1
  52. package/package.json +33 -29
  53. package/src/core/common/decorators/unified-field.decorator.ts +49 -10
  54. package/src/core/common/models/core-persistence.model.ts +3 -3
  55. package/src/core/modules/file/core-file-info.model.ts +40 -22
  56. package/src/core/modules/migrate/MIGRATION_FROM_NODEPIT.md +219 -0
  57. package/src/core/modules/migrate/README.md +452 -0
  58. package/src/core/modules/migrate/cli/migrate-cli.ts +319 -0
  59. package/src/core/modules/migrate/helpers/migration.helper.ts +117 -0
  60. package/src/core/modules/migrate/helpers/ts-compiler.js +14 -0
  61. package/src/core/modules/migrate/index.ts +41 -0
  62. package/src/core/modules/migrate/migration-runner.ts +230 -0
  63. package/src/core/modules/migrate/mongo-state-store.ts +283 -0
  64. package/src/core/modules/migrate/templates/migration-with-helper.template.ts +72 -0
  65. package/src/core/modules/migrate/templates/migration.template.ts +59 -0
  66. package/src/core/modules/user/core-user.model.ts +120 -78
  67. package/src/index.ts +9 -3
  68. package/src/main.ts +25 -0
  69. package/src/server/common/models/persistence.model.ts +15 -13
  70. package/src/server/modules/auth/auth.model.ts +7 -3
  71. package/src/server/modules/user/user.controller.ts +242 -0
  72. package/src/server/modules/user/user.model.ts +39 -26
  73. package/src/server/modules/user/user.module.ts +2 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lenne.tech/nest-server",
3
- "version": "11.2.0",
3
+ "version": "11.4.0",
4
4
  "description": "Modern, fast, powerful Node.js web framework in TypeScript based on Nest with a GraphQL API and a connection to MongoDB (or other databases).",
5
5
  "keywords": [
6
6
  "node",
@@ -67,18 +67,18 @@
67
67
  "node": ">= 20"
68
68
  },
69
69
  "dependencies": {
70
- "@apollo/gateway": "2.11.3",
70
+ "@apollo/gateway": "2.12.0",
71
71
  "@getbrevo/brevo": "3.0.1",
72
72
  "@nestjs/apollo": "13.1.0",
73
- "@nestjs/common": "11.1.6",
74
- "@nestjs/core": "11.1.6",
73
+ "@nestjs/common": "11.1.8",
74
+ "@nestjs/core": "11.1.8",
75
75
  "@nestjs/graphql": "13.1.0",
76
76
  "@nestjs/jwt": "11.0.1",
77
77
  "@nestjs/mongoose": "11.0.3",
78
78
  "@nestjs/passport": "11.0.5",
79
- "@nestjs/platform-express": "11.1.6",
79
+ "@nestjs/platform-express": "11.1.8",
80
80
  "@nestjs/schedule": "6.0.1",
81
- "@nestjs/swagger": "11.2.0",
81
+ "@nestjs/swagger": "11.2.1",
82
82
  "@nestjs/terminus": "11.0.0",
83
83
  "apollo-server-core": "3.13.0",
84
84
  "apollo-server-express": "3.13.0",
@@ -89,55 +89,52 @@
89
89
  "cookie-parser": "1.4.7",
90
90
  "dotenv": "17.2.3",
91
91
  "ejs": "3.1.10",
92
- "graphql": "16.11.0",
92
+ "graphql": "16.12.0",
93
93
  "graphql-query-complexity": "1.1.0",
94
94
  "graphql-subscriptions": "3.0.0",
95
95
  "graphql-upload": "15.0.2",
96
96
  "js-sha256": "0.11.1",
97
97
  "json-to-graphql-query": "2.3.0",
98
- "light-my-request": "6.6.0",
99
98
  "lodash": "4.17.21",
100
- "mongodb": "6.20.0",
101
- "mongoose": "8.19.1",
99
+ "mongodb": "7.0.0",
100
+ "mongoose": "8.19.3",
102
101
  "multer": "2.0.2",
103
- "node-mailjet": "6.0.9",
104
- "nodemailer": "7.0.9",
105
- "nodemon": "3.1.10",
102
+ "node-mailjet": "6.0.11",
103
+ "nodemailer": "7.0.10",
106
104
  "passport": "0.7.0",
107
105
  "passport-jwt": "4.0.1",
108
106
  "reflect-metadata": "0.2.2",
109
107
  "rfdc": "1.4.1",
110
- "rimraf": "6.0.1",
111
108
  "rxjs": "7.8.2",
112
109
  "yuml-diagram": "1.2.0"
113
110
  },
114
111
  "devDependencies": {
115
112
  "@babel/plugin-proposal-private-methods": "7.18.6",
116
- "@compodoc/compodoc": "1.1.31",
117
- "@lenne.tech/eslint-config-ts": "2.1.3",
113
+ "@compodoc/compodoc": "1.1.32",
114
+ "@lenne.tech/eslint-config-ts": "2.1.4",
118
115
  "@nestjs/cli": "11.0.10",
119
116
  "@nestjs/schematics": "11.0.9",
120
- "@nestjs/testing": "11.1.6",
121
- "@swc/cli": "0.7.8",
122
- "@swc/core": "1.13.5",
117
+ "@nestjs/testing": "11.1.8",
118
+ "@swc/cli": "0.7.9",
119
+ "@swc/core": "1.15.0",
123
120
  "@swc/jest": "0.2.39",
124
121
  "@types/compression": "1.8.1",
125
- "@types/cookie-parser": "1.4.9",
122
+ "@types/cookie-parser": "1.4.10",
126
123
  "@types/ejs": "3.1.5",
127
124
  "@types/express": "4.17.21",
128
125
  "@types/jest": "30.0.0",
129
126
  "@types/lodash": "4.17.20",
130
127
  "@types/multer": "2.0.0",
131
- "@types/node": "24.7.1",
132
- "@types/nodemailer": "7.0.2",
128
+ "@types/node": "24.10.0",
129
+ "@types/nodemailer": "7.0.3",
133
130
  "@types/passport": "1.0.17",
134
131
  "@types/supertest": "6.0.3",
135
- "@typescript-eslint/eslint-plugin": "8.46.0",
136
- "@typescript-eslint/parser": "8.46.0",
132
+ "@typescript-eslint/eslint-plugin": "8.46.3",
133
+ "@typescript-eslint/parser": "8.46.3",
137
134
  "coffeescript": "2.7.0",
138
- "eslint": "9.37.0",
135
+ "eslint": "9.39.1",
139
136
  "eslint-config-prettier": "10.1.8",
140
- "eslint-plugin-unused-imports": "4.2.0",
137
+ "eslint-plugin-unused-imports": "4.3.0",
141
138
  "find-file-up": "2.0.1",
142
139
  "grunt": "1.6.1",
143
140
  "grunt-bg-shell": "2.3.3",
@@ -146,14 +143,16 @@
146
143
  "grunt-sync": "0.8.2",
147
144
  "husky": "9.1.7",
148
145
  "jest": "30.2.0",
146
+ "nodemon": "3.1.10",
149
147
  "npm-watch": "0.13.0",
150
148
  "pm2": "6.0.13",
151
149
  "prettier": "3.6.2",
152
150
  "pretty-quick": "4.2.2",
151
+ "rimraf": "6.1.0",
153
152
  "supertest": "7.1.4",
154
153
  "ts-jest": "29.4.5",
155
154
  "ts-loader": "9.5.4",
156
- "ts-morph": "27.0.0",
155
+ "ts-morph": "27.0.2",
157
156
  "ts-node": "10.9.2",
158
157
  "tsconfig-paths": "4.2.0",
159
158
  "typescript": "5.9.3",
@@ -164,7 +163,7 @@
164
163
  "flat": "5.0.2",
165
164
  "mime": "2.6.0"
166
165
  },
167
- "ts-morph": "27.0.0"
166
+ "ts-morph": "27.0.2"
168
167
  },
169
168
  "jest": {
170
169
  "collectCoverage": true,
@@ -183,9 +182,14 @@
183
182
  },
184
183
  "main": "dist/index.js",
185
184
  "types": "dist/index.d.ts",
185
+ "bin": {
186
+ "nest-migrate": "./bin/migrate.js",
187
+ "migrate": "./bin/migrate.js"
188
+ },
186
189
  "files": [
187
190
  "dist/**/*",
188
- "src/**/*"
191
+ "src/**/*",
192
+ "bin/**/*"
189
193
  ],
190
194
  "watch": {
191
195
  "build:dev": "src"
@@ -1,4 +1,5 @@
1
1
  import { Field, FieldOptions } from '@nestjs/graphql';
2
+ import { Prop, PropOptions } from '@nestjs/mongoose';
2
3
  import { ApiProperty, ApiPropertyOptions } from '@nestjs/swagger';
3
4
  import { EnumAllowedTypes } from '@nestjs/swagger/dist/interfaces/schema-object-metadata.interface';
4
5
  import { Type } from 'class-transformer';
@@ -38,6 +39,8 @@ export interface UnifiedFieldOptions {
38
39
  isArray?: boolean;
39
40
  /** Default: false */
40
41
  isOptional?: boolean;
42
+ /** Whether to apply Mongoose @Prop decorator. Optional, used for database models. Default: false */
43
+ mongoose?: boolean | PropOptions;
41
44
  /** Restricted roles */
42
45
  roles?: RestrictedType | RoleEnum | RoleEnum[];
43
46
  /** Options for swagger api documentation */
@@ -48,8 +51,12 @@ export interface UnifiedFieldOptions {
48
51
  *
49
52
  * Enums should be defined via the enum option.
50
53
  *
54
+ * For array fields, you can use either:
55
+ * - `type: () => ItemType` (recommended, decorator adds array wrapping automatically)
56
+ * - `type: () => [ItemType]` (also supported, decorator extracts ItemType to avoid double-nesting)
57
+ *
51
58
  * Supports:
52
- * - A factory function that returns the type: `() => MyType`
59
+ * - A factory function that returns the type: `() => MyType` or `() => [MyType]`
53
60
  * - A GraphQL scalar: `GraphQLScalarType`
54
61
  * - A class constructor: `MyClass`
55
62
  * */
@@ -96,7 +103,16 @@ export function UnifiedField(opts: UnifiedFieldOptions = {}): PropertyDecorator
96
103
  return metadataType;
97
104
  };
98
105
 
99
- const baseType = resolvedTypeFn();
106
+ // Resolve the type and extract item type if user provided array syntax
107
+ const resolvedType = resolvedTypeFn();
108
+
109
+ // If this is an array field and the user provided type: () => [ItemType],
110
+ // extract the ItemType to avoid double-nesting (e.g., [[ItemType]])
111
+ // We check: isArrayField (should be array) && Array.isArray (is actually an array) && length === 1 (GraphQL array syntax)
112
+ const baseType =
113
+ isArrayField && Array.isArray(resolvedType) && resolvedType.length === 1
114
+ ? resolvedType[0] // Extract item type from [ItemType]
115
+ : resolvedType; // Use as-is
100
116
 
101
117
  // Prepare merged options
102
118
  const gqlOpts: FieldOptions = { ...opts.gqlOptions };
@@ -161,8 +177,14 @@ export function UnifiedField(opts: UnifiedFieldOptions = {}): PropertyDecorator
161
177
  }
162
178
 
163
179
  // Type function for gql
180
+ // We need to keep the factory pattern (calling resolvedTypeFn inside the arrow function)
181
+ // to support circular references. But we also need to extract array item types to avoid double-nesting.
164
182
  const gqlTypeFn = isArrayField
165
- ? () => [opts.enum?.enum || opts.gqlType || resolvedTypeFn()]
183
+ ? () => {
184
+ const resolved = opts.enum?.enum || opts.gqlType || resolvedTypeFn();
185
+ // Extract item type if user provided [ItemType] syntax to avoid [[ItemType]]
186
+ return [Array.isArray(resolved) && resolved.length === 1 ? resolved[0] : resolved];
187
+ }
166
188
  : () => opts.enum?.enum || opts.gqlType || resolvedTypeFn();
167
189
 
168
190
  // Gql decorator
@@ -178,7 +200,7 @@ export function UnifiedField(opts: UnifiedFieldOptions = {}): PropertyDecorator
178
200
 
179
201
  // Completely skip validation if its any
180
202
  if (opts.validator) {
181
- opts.validator(valOpts).forEach(d => d(target, propertyKey));
203
+ opts.validator(valOpts).forEach((d) => d(target, propertyKey));
182
204
  } else if (!opts.isAny) {
183
205
  const validator = getBuiltInValidator(baseType, valOpts, isArrayField, target);
184
206
  if (validator) {
@@ -199,6 +221,23 @@ export function UnifiedField(opts: UnifiedFieldOptions = {}): PropertyDecorator
199
221
  const rolesArr = Array.isArray(opts.roles) ? opts.roles : [opts.roles];
200
222
  Restricted(...rolesArr)(target, propertyKey);
201
223
  }
224
+
225
+ // Mongoose @Prop decorator (optional)
226
+ if (opts.mongoose) {
227
+ const propOptions: any = typeof opts.mongoose === 'object' ? opts.mongoose : {};
228
+
229
+ // Set type for Prop if not already defined in propOptions
230
+ if (typeof propOptions === 'object' && !Array.isArray(propOptions) && !propOptions.type && baseType) {
231
+ propOptions.type = baseType;
232
+ }
233
+
234
+ // Apply array type if needed
235
+ if (typeof propOptions === 'object' && !Array.isArray(propOptions) && isArrayField && !propOptions.type) {
236
+ propOptions.type = [baseType];
237
+ }
238
+
239
+ Prop(propOptions)(target, propertyKey);
240
+ }
202
241
  };
203
242
  }
204
243
 
@@ -228,12 +267,12 @@ function getBuiltInValidator(
228
267
  function isGraphQLScalar(type: any): boolean {
229
268
  // CustomScalar check (The CustomScalar interface implements these functions below)
230
269
  return (
231
- (type
232
- && typeof type === 'function'
233
- && typeof type.prototype?.serialize === 'function'
234
- && typeof type.prototype?.parseValue === 'function'
235
- && typeof type.prototype?.parseLiteral === 'function')
236
- || type instanceof GraphQLScalarType
270
+ (type &&
271
+ typeof type === 'function' &&
272
+ typeof type.prototype?.serialize === 'function' &&
273
+ typeof type.prototype?.parseValue === 'function' &&
274
+ typeof type.prototype?.parseLiteral === 'function') ||
275
+ type instanceof GraphQLScalarType
237
276
  );
238
277
  }
239
278
 
@@ -1,5 +1,5 @@
1
1
  import { ObjectType } from '@nestjs/graphql';
2
- import { Prop, Schema } from '@nestjs/mongoose';
2
+ import { Schema } from '@nestjs/mongoose';
3
3
  import { Types } from 'mongoose';
4
4
 
5
5
  import { Restricted } from '../decorators/restricted.decorator';
@@ -85,10 +85,10 @@ export abstract class CorePersistenceModel extends CoreModel {
85
85
  /**
86
86
  * Created date, is set automatically by mongoose
87
87
  */
88
- @Prop()
89
88
  @UnifiedField({
90
89
  description: 'Created date',
91
90
  isOptional: true,
91
+ mongoose: true,
92
92
  roles: RoleEnum.S_EVERYONE,
93
93
  swaggerApiOptions: { example: 1740037703939, format: 'int64', type: Date },
94
94
  type: Date,
@@ -98,10 +98,10 @@ export abstract class CorePersistenceModel extends CoreModel {
98
98
  /**
99
99
  * Updated date is set automatically by mongoose
100
100
  */
101
- @Prop()
102
101
  @UnifiedField({
103
102
  description: 'Updated date',
104
103
  isOptional: true,
104
+ mongoose: true,
105
105
  roles: RoleEnum.S_EVERYONE,
106
106
  swaggerApiOptions: { example: 1740037703939, format: 'int64', type: Date },
107
107
  type: Date,
@@ -1,8 +1,8 @@
1
- import { Field, ObjectType } from '@nestjs/graphql';
2
- import { Prop } from '@nestjs/mongoose';
1
+ import { ObjectType } from '@nestjs/graphql';
3
2
  import { Types } from 'mongoose';
4
3
 
5
4
  import { Restricted } from '../../common/decorators/restricted.decorator';
5
+ import { UnifiedField } from '../../common/decorators/unified-field.decorator';
6
6
  import { RoleEnum } from '../../common/enums/role.enum';
7
7
  import { CoreModel } from '../../common/models/core-model.model';
8
8
 
@@ -25,37 +25,55 @@ export class CoreFileInfo extends CoreModel {
25
25
  // Properties
26
26
  // ===========================================================================
27
27
 
28
- @Field(() => String, { description: 'ID of the file' })
29
- @Restricted(RoleEnum.S_EVERYONE)
28
+ @UnifiedField({
29
+ description: 'ID of the file',
30
+ roles: RoleEnum.S_EVERYONE,
31
+ type: () => String,
32
+ })
30
33
  id: string = undefined;
31
34
 
32
- @Field(() => Number, {
35
+ @UnifiedField({
33
36
  description:
34
- 'The size of each chunk in bytes. GridFS divides the document into chunks of size chunkSize, '
35
- + 'except for the last, which is only as large as needed. The default size is 255 kilobytes (kB)',
36
- nullable: true,
37
+ 'The size of each chunk in bytes. GridFS divides the document into chunks of size chunkSize, ' +
38
+ 'except for the last, which is only as large as needed. The default size is 255 kilobytes (kB)',
39
+ isOptional: true,
40
+ mongoose: { required: false, type: Number },
41
+ roles: RoleEnum.S_EVERYONE,
42
+ type: () => Number,
37
43
  })
38
- @Prop({ required: false, type: Number })
39
- @Restricted(RoleEnum.S_EVERYONE)
40
44
  chunkSize: number = undefined;
41
45
 
42
- @Field(() => String, { description: 'Content type', nullable: true })
43
- @Prop({ required: false, type: String })
44
- @Restricted(RoleEnum.S_EVERYONE)
46
+ @UnifiedField({
47
+ description: 'Content type',
48
+ isOptional: true,
49
+ mongoose: { required: false, type: String },
50
+ roles: RoleEnum.S_EVERYONE,
51
+ })
45
52
  contentType?: string = undefined;
46
53
 
47
- @Field(() => String, { description: 'Name of the file', nullable: true })
48
- @Prop({ required: false, type: String })
49
- @Restricted(RoleEnum.S_EVERYONE)
54
+ @UnifiedField({
55
+ description: 'Name of the file',
56
+ isOptional: true,
57
+ mongoose: { required: false, type: String },
58
+ roles: RoleEnum.S_EVERYONE,
59
+ })
50
60
  filename?: string = undefined;
51
61
 
52
- @Field(() => Number, { description: 'The size of the document in bytes', nullable: true })
53
- @Prop({ required: false, type: Number })
54
- @Restricted(RoleEnum.S_EVERYONE)
62
+ @UnifiedField({
63
+ description: 'The size of the document in bytes',
64
+ isOptional: true,
65
+ mongoose: { required: false, type: Number },
66
+ roles: RoleEnum.S_EVERYONE,
67
+ type: () => Number,
68
+ })
55
69
  length: number = undefined;
56
70
 
57
- @Field(() => Date, { description: 'The date the file was first stored', nullable: true })
58
- @Prop({ required: false, type: Date })
59
- @Restricted(RoleEnum.S_EVERYONE)
71
+ @UnifiedField({
72
+ description: 'The date the file was first stored',
73
+ isOptional: true,
74
+ mongoose: { required: false, type: Date },
75
+ roles: RoleEnum.S_EVERYONE,
76
+ type: () => Date,
77
+ })
60
78
  uploadDate: Date = undefined;
61
79
  }
@@ -0,0 +1,219 @@
1
+ # Migration from @nodepit/migrate-state-store-mongodb
2
+
3
+ This guide provides step-by-step instructions to migrate from `@nodepit/migrate-state-store-mongodb` to the built-in nest-server migration system.
4
+
5
+ ## Prerequisites
6
+
7
+ Current state of nest-server-starter projects:
8
+ - Using `@nodepit/migrate-state-store-mongodb` for state storage
9
+ - Using external `migrate` package for CLI
10
+ - Custom migration utilities in `migrations-utils/`
11
+
12
+ ## Migration Steps
13
+
14
+ ### Step 1: Update Dependencies
15
+
16
+ **File:** `package.json`
17
+
18
+ Remove old migration packages:
19
+ ```bash
20
+ npm uninstall migrate @nodepit/migrate-state-store-mongodb ts-migrate-mongoose
21
+ ```
22
+
23
+ Ensure latest nest-server is installed:
24
+ ```bash
25
+ npm install @lenne.tech/nest-server@latest
26
+ ```
27
+
28
+ ### Step 2: Update Migration State Store
29
+
30
+ **File:** `migrations-utils/migrate.js`
31
+
32
+ **Before:**
33
+ ```javascript
34
+ import config from '../src/config.env';
35
+ const migrate = require('migrate');
36
+ const { MongoStateStore } = require('@nodepit/migrate-state-store-mongodb');
37
+
38
+ const MONGO_URL = config.mongoose.uri;
39
+ const COLLECTION_NAME = 'migrations';
40
+
41
+ module.exports = class MyMongoStateStore extends MongoStateStore {
42
+ constructor() {
43
+ super({ uri: MONGO_URL, collectionName: COLLECTION_NAME });
44
+ }
45
+ };
46
+ ```
47
+
48
+ **After:**
49
+ ```javascript
50
+ const { createMigrationStore } = require('@lenne.tech/nest-server');
51
+ const config = require('../src/config.env');
52
+
53
+ module.exports = createMigrationStore(
54
+ config.default.mongoose.uri,
55
+ 'migrations' // optional, default is 'migrations'
56
+ );
57
+ ```
58
+
59
+ ### Step 3: Update Database Helper
60
+
61
+ **File:** `migrations-utils/db.ts`
62
+
63
+ **Before:**
64
+ ```typescript
65
+ import * as fs from 'fs';
66
+ import { GridFSBucket, MongoClient, ObjectId } from 'mongodb';
67
+ import * as path from 'path';
68
+ import config from '../src/config.env';
69
+
70
+ const MONGO_URL = config.mongoose.uri;
71
+
72
+ export const getDb = async () => {
73
+ const client: MongoClient = await MongoClient.connect(MONGO_URL);
74
+ return client.db();
75
+ };
76
+
77
+ export const uploadFile = async (
78
+ relativePath,
79
+ options?: { bucketName?: string; filename?: string },
80
+ ): Promise<ObjectId> => {
81
+ // ... implementation
82
+ };
83
+ ```
84
+
85
+ **After:**
86
+ ```typescript
87
+ import config from '../src/config.env';
88
+ import { getDb as getDbHelper, uploadFileToGridFS } from '@lenne.tech/nest-server';
89
+ import { Db, ObjectId } from 'mongodb';
90
+
91
+ const MONGO_URL = config.mongoose.uri;
92
+
93
+ /**
94
+ * Get database connection
95
+ */
96
+ export const getDb = async (): Promise<Db> => {
97
+ return getDbHelper(MONGO_URL);
98
+ };
99
+
100
+ /**
101
+ * Upload file to GridFS
102
+ */
103
+ export const uploadFile = async (
104
+ relativePath: string,
105
+ options?: { bucketName?: string; filename?: string }
106
+ ): Promise<ObjectId> => {
107
+ return uploadFileToGridFS(MONGO_URL, relativePath, options);
108
+ };
109
+ ```
110
+
111
+ ### Step 4: Verify package.json Scripts
112
+
113
+ **File:** `package.json`
114
+
115
+ Scripts should remain unchanged - they will work with the built-in CLI:
116
+
117
+ ```json
118
+ {
119
+ "scripts": {
120
+ "migrate:create": "migrate create --template-file ./migrations-utils/template.ts --migrations-dir=\"./migrations\" --compiler=\"ts:./migrations-utils/ts-compiler.js\"",
121
+ "migrate:up": "migrate --store=./migrations-utils/migrate.js --migrations-dir=\"./migrations\" --compiler=\"ts:./migrations-utils/ts-compiler.js\" up",
122
+ "migrate:develop:up": "NODE_ENV=develop migrate --store=./migrations-utils/migrate.js --migrations-dir=\"./migrations\" --compiler=\"ts:./migrations-utils/ts-compiler.js\" up",
123
+ "migrate:test:up": "NODE_ENV=test migrate --store=./migrations-utils/migrate.js --migrations-dir=\"./migrations\" --compiler=\"ts:./migrations-utils/ts-compiler.js\" up",
124
+ "migrate:preview:up": "NODE_ENV=preview migrate --store=./migrations-utils/migrate.js --migrations-dir=\"./migrations\" --compiler=\"ts:./migrations-utils/ts-compiler.js\" up",
125
+ "migrate:prod:up": "NODE_ENV=production migrate --store=./migrations-utils/migrate.js --migrations-dir=\"./migrations\" --compiler=\"ts:./migrations-utils/ts-compiler.js\" up"
126
+ }
127
+ }
128
+ ```
129
+
130
+ Note: The `migrate` command now comes from `@lenne.tech/nest-server` - no external package needed.
131
+
132
+ ### Step 5: Test Migration
133
+
134
+ ```bash
135
+ # Install dependencies
136
+ npm install
137
+
138
+ # Test migration creation
139
+ npm run migrate:create -- test-migration
140
+
141
+ # Test migration execution (if safe in current environment)
142
+ npm run migrate:up
143
+ ```
144
+
145
+ ## Verification Checklist
146
+
147
+ - [ ] `migrate` package removed from package.json
148
+ - [ ] `@nodepit/migrate-state-store-mongodb` removed from package.json
149
+ - [ ] `ts-migrate-mongoose` removed from package.json
150
+ - [ ] `migrations-utils/migrate.js` updated to use `createMigrationStore`
151
+ - [ ] `migrations-utils/db.ts` updated to use nest-server helpers
152
+ - [ ] `npm install` completed successfully
153
+ - [ ] `npm run migrate:create -- test` works
154
+ - [ ] Existing migrations still in database (no data loss)
155
+
156
+ ## What Stays the Same
157
+
158
+ - ✅ All migration files in `migrations/` folder
159
+ - ✅ All migration data in MongoDB
160
+ - ✅ All npm scripts in package.json
161
+ - ✅ Migration file format (up/down functions)
162
+ - ✅ Template files (if using custom templates)
163
+
164
+ ## What Changes
165
+
166
+ - ✅ `migrations-utils/migrate.js` - simplified (3 lines)
167
+ - ✅ `migrations-utils/db.ts` - uses nest-server helpers
168
+ - ✅ package.json dependencies - 2-3 packages removed
169
+ - ✅ CLI comes from nest-server instead of external package
170
+
171
+ ## Rollback (if needed)
172
+
173
+ If you need to rollback:
174
+
175
+ ```bash
176
+ # Reinstall old packages
177
+ npm install --save-dev migrate @nodepit/migrate-state-store-mongodb
178
+
179
+ # Revert migrations-utils/migrate.js to old version from git
180
+ git checkout migrations-utils/migrate.js
181
+
182
+ # Revert migrations-utils/db.ts to old version from git
183
+ git checkout migrations-utils/db.ts
184
+ ```
185
+
186
+ ## Benefits After Migration
187
+
188
+ 1. **One less dependency** - No external `migrate` package needed
189
+ 2. **Simplified code** - ~90% less boilerplate in migrations-utils
190
+ 3. **Better TypeScript** - Native TypeScript implementation
191
+ 4. **MongoDB 7.x support** - Works with latest MongoDB versions
192
+ 5. **Central maintenance** - Updates come with nest-server
193
+
194
+ ## Support
195
+
196
+ If issues occur during migration:
197
+ - Check that `@lenne.tech/nest-server` is at version 11.3.0 or higher
198
+ - Verify `ts-node` is installed as devDependency
199
+ - Ensure `migrations-utils/migrate.js` exports the state store correctly
200
+ - Test with `migrate --help` to verify CLI is available
201
+
202
+ ## File Structure After Migration
203
+
204
+ ```
205
+ project-root/
206
+ ├── migrations/ # Unchanged
207
+ │ └── TIMESTAMP-*.ts # Your migrations
208
+ ├── migrations-utils/
209
+ │ ├── migrate.js # Updated (3 lines)
210
+ │ ├── db.ts # Updated (uses nest-server helpers)
211
+ │ ├── template.ts # Unchanged (optional)
212
+ │ └── ts-compiler.js # Unchanged (optional, can be removed)
213
+ └── package.json # Dependencies removed
214
+ ```
215
+
216
+ Note: `ts-compiler.js` can optionally be removed and replaced with:
217
+ ```
218
+ --compiler="ts:./node_modules/@lenne.tech/nest-server/dist/core/modules/migrate/helpers/ts-compiler.js"
219
+ ```