@friggframework/core 2.0.0--canary.454.e2a280d.0 → 2.0.0--canary.459.51231dd.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 (29) hide show
  1. package/README.md +0 -28
  2. package/database/prisma.js +2 -2
  3. package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +517 -0
  4. package/handlers/routers/user.js +3 -1
  5. package/integrations/repositories/process-repository-factory.js +46 -0
  6. package/integrations/repositories/process-repository-interface.js +90 -0
  7. package/integrations/repositories/process-repository-mongo.js +190 -0
  8. package/integrations/repositories/process-repository-postgres.js +190 -0
  9. package/integrations/use-cases/create-process.js +128 -0
  10. package/integrations/use-cases/create-process.test.js +178 -0
  11. package/integrations/use-cases/get-process.js +87 -0
  12. package/integrations/use-cases/get-process.test.js +190 -0
  13. package/integrations/use-cases/index.js +8 -0
  14. package/integrations/use-cases/update-process-metrics.js +165 -0
  15. package/integrations/use-cases/update-process-metrics.test.js +308 -0
  16. package/integrations/use-cases/update-process-state.js +119 -0
  17. package/integrations/use-cases/update-process-state.test.js +256 -0
  18. package/modules/module.js +1 -1
  19. package/modules/use-cases/process-authorization-callback.js +2 -1
  20. package/package.json +66 -79
  21. package/prisma-mongodb/schema.prisma +64 -25
  22. package/prisma-postgresql/migrations/20251010000000_remove_unused_entity_reference_map/migration.sql +3 -0
  23. package/prisma-postgresql/schema.prisma +14 -19
  24. package/database/use-cases/run-database-migration-use-case.js +0 -137
  25. package/database/use-cases/run-database-migration-use-case.test.js +0 -310
  26. package/database/utils/prisma-runner.js +0 -313
  27. package/database/utils/prisma-runner.test.js +0 -486
  28. package/handlers/workers/db-migration.js +0 -208
  29. package/handlers/workers/db-migration.test.js +0 -437
@@ -93,7 +93,8 @@ class ProcessAuthorizationCallback {
93
93
  );
94
94
  credentialDetails.details.authIsValid = true;
95
95
 
96
- await this.credentialRepository.upsertCredential(credentialDetails);
96
+ const persisted = await this.credentialRepository.upsertCredential(credentialDetails);
97
+ module.credential = persisted;
97
98
  }
98
99
 
99
100
  async findOrCreateEntity(entityDetails, moduleName, credentialId) {
package/package.json CHANGED
@@ -1,81 +1,68 @@
1
1
  {
2
- "name": "@friggframework/core",
3
- "prettier": "@friggframework/prettier-config",
4
- "version": "2.0.0--canary.454.e2a280d.0",
5
- "dependencies": {
6
- "@hapi/boom": "^10.0.1",
7
- "aws-sdk": "^2.1200.0",
8
- "bcryptjs": "^2.4.3",
9
- "body-parser": "^1.20.2",
10
- "chalk": "^4.1.2",
11
- "common-tags": "^1.8.2",
12
- "cors": "^2.8.5",
13
- "dotenv": "^16.4.7",
14
- "express": "^4.19.2",
15
- "express-async-handler": "^1.2.0",
16
- "form-data": "^4.0.0",
17
- "fs-extra": "^11.2.0",
18
- "lodash": "4.17.21",
19
- "lodash.get": "^4.4.2",
20
- "mongoose": "6.11.6",
21
- "node-fetch": "^2.6.7",
22
- "serverless-http": "^2.7.0",
23
- "uuid": "^9.0.1"
24
- },
25
- "peerDependencies": {
26
- "@prisma/client": "^6.16.3",
27
- "prisma": "^6.16.3"
28
- },
29
- "peerDependenciesMeta": {
30
- "@prisma/client": {
31
- "optional": true
32
- },
33
- "prisma": {
34
- "optional": true
35
- }
36
- },
37
- "devDependencies": {
38
- "@friggframework/eslint-config": "2.0.0--canary.454.e2a280d.0",
39
- "@friggframework/prettier-config": "2.0.0--canary.454.e2a280d.0",
40
- "@friggframework/test": "2.0.0--canary.454.e2a280d.0",
41
- "@prisma/client": "^6.17.0",
42
- "@types/lodash": "4.17.15",
43
- "@typescript-eslint/eslint-plugin": "^8.0.0",
44
- "chai": "^4.3.6",
45
- "eslint": "^8.22.0",
46
- "eslint-plugin-import": "^2.29.1",
47
- "eslint-plugin-n": "^17.10.2",
48
- "eslint-plugin-promise": "^7.0.0",
49
- "jest": "^29.7.0",
50
- "prettier": "^2.7.1",
51
- "prisma": "^6.17.0",
52
- "sinon": "^16.1.1",
53
- "typescript": "^5.0.2"
54
- },
55
- "scripts": {
56
- "lint:fix": "prettier --write --loglevel error . && eslint . --fix",
57
- "test": "jest --passWithNoTests # TODO",
58
- "prisma:generate:mongo": "npx prisma generate --schema ./prisma-mongodb/schema.prisma",
59
- "prisma:generate:postgres": "npx prisma generate --schema ./prisma-postgresql/schema.prisma",
60
- "prisma:generate": "npm run prisma:generate:mongo && npm run prisma:generate:postgres",
61
- "prisma:push:mongo": "npx prisma db push --schema ./prisma-mongodb/schema.prisma",
62
- "prisma:migrate:postgres": "npx prisma migrate dev --schema ./prisma-postgresql/schema.prisma",
63
- "prepublishOnly": "npm run prisma:generate"
64
- },
65
- "author": "",
66
- "license": "MIT",
67
- "main": "index.js",
68
- "repository": {
69
- "type": "git",
70
- "url": "git+https://github.com/friggframework/frigg.git"
71
- },
72
- "bugs": {
73
- "url": "https://github.com/friggframework/frigg/issues"
74
- },
75
- "homepage": "https://github.com/friggframework/frigg#readme",
76
- "description": "",
77
- "publishConfig": {
78
- "access": "public"
79
- },
80
- "gitHead": "e2a280d643ad826ce11b8267c98eba09d89d4dfd"
2
+ "name": "@friggframework/core",
3
+ "prettier": "@friggframework/prettier-config",
4
+ "version": "2.0.0--canary.459.51231dd.0",
5
+ "dependencies": {
6
+ "@hapi/boom": "^10.0.1",
7
+ "@prisma/client": "^6.16.3",
8
+ "aws-sdk": "^2.1200.0",
9
+ "bcryptjs": "^2.4.3",
10
+ "body-parser": "^1.20.2",
11
+ "common-tags": "^1.8.2",
12
+ "cors": "^2.8.5",
13
+ "dotenv": "^16.4.7",
14
+ "express": "^4.19.2",
15
+ "express-async-handler": "^1.2.0",
16
+ "form-data": "^4.0.0",
17
+ "fs-extra": "^11.2.0",
18
+ "lodash": "4.17.21",
19
+ "lodash.get": "^4.4.2",
20
+ "mongoose": "6.11.6",
21
+ "node-fetch": "^2.6.7",
22
+ "serverless-http": "^2.7.0",
23
+ "uuid": "^9.0.1"
24
+ },
25
+ "devDependencies": {
26
+ "@friggframework/eslint-config": "2.0.0--canary.459.51231dd.0",
27
+ "@friggframework/prettier-config": "2.0.0--canary.459.51231dd.0",
28
+ "@friggframework/test": "2.0.0--canary.459.51231dd.0",
29
+ "@types/lodash": "4.17.15",
30
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
31
+ "chai": "^4.3.6",
32
+ "eslint": "^8.22.0",
33
+ "eslint-plugin-import": "^2.29.1",
34
+ "eslint-plugin-n": "^17.10.2",
35
+ "eslint-plugin-promise": "^7.0.0",
36
+ "jest": "^29.7.0",
37
+ "prettier": "^2.7.1",
38
+ "prisma": "^6.16.3",
39
+ "sinon": "^16.1.1",
40
+ "typescript": "^5.0.2"
41
+ },
42
+ "scripts": {
43
+ "lint:fix": "prettier --write --loglevel error . && eslint . --fix",
44
+ "test": "jest --passWithNoTests # TODO",
45
+ "prisma:generate:mongo": "npx prisma generate --schema ./prisma-mongodb/schema.prisma",
46
+ "prisma:generate:postgres": "npx prisma generate --schema ./prisma-postgresql/schema.prisma",
47
+ "prisma:generate": "npm run prisma:generate:mongo && npm run prisma:generate:postgres",
48
+ "prisma:push:mongo": "npx prisma db push --schema ./prisma-mongodb/schema.prisma",
49
+ "prisma:migrate:postgres": "npx prisma migrate dev --schema ./prisma-postgresql/schema.prisma",
50
+ "postinstall": "npm run prisma:generate"
51
+ },
52
+ "author": "",
53
+ "license": "MIT",
54
+ "main": "index.js",
55
+ "repository": {
56
+ "type": "git",
57
+ "url": "git+https://github.com/friggframework/frigg.git"
58
+ },
59
+ "bugs": {
60
+ "url": "https://github.com/friggframework/frigg/issues"
61
+ },
62
+ "homepage": "https://github.com/friggframework/frigg#readme",
63
+ "description": "",
64
+ "publishConfig": {
65
+ "access": "public"
66
+ },
67
+ "gitHead": "51231ddd4b2d47e29b81294b303d1953f768f327"
81
68
  }
@@ -3,10 +3,8 @@
3
3
  // Migration from Mongoose ODM to Prisma ORM
4
4
 
5
5
  generator client {
6
- provider = "prisma-client-js"
7
- output = "../generated/prisma-mongodb"
8
- binaryTargets = ["native", "rhel-openssl-3.0.x"] // native for local dev, rhel for Lambda deployment
9
- engineType = "binary" // Use binary engines (smaller size)
6
+ provider = "prisma-client-js"
7
+ output = "../node_modules/@prisma-mongodb/client"
10
8
  }
11
9
 
12
10
  datasource db {
@@ -21,8 +19,8 @@ datasource db {
21
19
  /// User model with discriminator pattern support
22
20
  /// Replaces Mongoose discriminators (IndividualUser, OrganizationUser)
23
21
  model User {
24
- id String @id @default(auto()) @map("_id") @db.ObjectId
25
- type UserType
22
+ id String @id @default(auto()) @map("_id") @db.ObjectId
23
+ type UserType
26
24
 
27
25
  // Timestamps
28
26
  createdAt DateTime @default(now())
@@ -48,6 +46,7 @@ model User {
48
46
  credentials Credential[]
49
47
  entities Entity[]
50
48
  integrations Integration[]
49
+ processes Process[]
51
50
 
52
51
  @@unique([email])
53
52
  @@unique([username])
@@ -88,12 +87,12 @@ model Token {
88
87
  /// OAuth credentials and API tokens
89
88
  /// All sensitive data encrypted with KMS at rest
90
89
  model Credential {
91
- id String @id @default(auto()) @map("_id") @db.ObjectId
92
- userId String? @db.ObjectId
93
- user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
94
- subType String?
90
+ id String @id @default(auto()) @map("_id") @db.ObjectId
91
+ userId String? @db.ObjectId
92
+ user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
93
+ subType String?
95
94
  authIsValid Boolean?
96
- externalId String?
95
+ externalId String?
97
96
 
98
97
  // Dynamic OAuth fields stored as JSON (encrypted via Prisma middleware)
99
98
  // Contains: access_token, refresh_token, domain, expires_in, token_type, etc.
@@ -126,11 +125,11 @@ model Entity {
126
125
  updatedAt DateTime @updatedAt
127
126
 
128
127
  // Relations - many-to-many with scalar lists
129
- integrations Integration[] @relation("IntegrationEntities", fields: [integrationIds], references: [id])
130
- integrationIds String[] @db.ObjectId
128
+ integrations Integration[] @relation("IntegrationEntities", fields: [integrationIds], references: [id])
129
+ integrationIds String[] @db.ObjectId
131
130
 
132
- syncs Sync[] @relation("SyncEntities", fields: [syncIds], references: [id])
133
- syncIds String[] @db.ObjectId
131
+ syncs Sync[] @relation("SyncEntities", fields: [syncIds], references: [id])
132
+ syncIds String[] @db.ObjectId
134
133
 
135
134
  dataIdentifiers DataIdentifier[]
136
135
  associationObjects AssociationObject[]
@@ -154,16 +153,13 @@ model Integration {
154
153
  status IntegrationStatus @default(ENABLED)
155
154
 
156
155
  // Configuration and version
157
- config Json? // Integration configuration object
156
+ config Json? // Integration configuration object
158
157
  version String?
159
158
 
160
159
  // Entity references (many-to-many via explicit scalar list)
161
160
  entities Entity[] @relation("IntegrationEntities", fields: [entityIds], references: [id])
162
161
  entityIds String[] @db.ObjectId
163
162
 
164
- // Entity reference map (Map<String, String> stored as JSON)
165
- entityReferenceMap Json? @default("{}")
166
-
167
163
  // Message arrays (stored as JSON)
168
164
  errors Json @default("[]")
169
165
  warnings Json @default("[]")
@@ -177,6 +173,7 @@ model Integration {
177
173
  associations Association[]
178
174
  syncs Sync[]
179
175
  mappings IntegrationMapping[]
176
+ processes Process[]
180
177
 
181
178
  @@index([userId])
182
179
  @@index([status])
@@ -211,6 +208,48 @@ model IntegrationMapping {
211
208
  @@map("IntegrationMapping")
212
209
  }
213
210
 
211
+ // ============================================================================
212
+ // PROCESS MODELS
213
+ // ============================================================================
214
+
215
+ /// Generic Process Model - tracks any long-running operation
216
+ /// Used for: CRM syncs, data migrations, bulk operations, etc.
217
+ model Process {
218
+ id String @id @default(auto()) @map("_id") @db.ObjectId
219
+
220
+ // Core references
221
+ userId String @db.ObjectId
222
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
223
+ integrationId String @db.ObjectId
224
+ integration Integration @relation(fields: [integrationId], references: [id], onDelete: Cascade)
225
+
226
+ // Process identification
227
+ name String // e.g., "zoho-crm-contact-sync", "pipedrive-lead-sync"
228
+ type String // e.g., "CRM_SYNC", "DATA_MIGRATION", "BULK_OPERATION"
229
+
230
+ // State machine
231
+ state String // Current state (integration-defined states)
232
+
233
+ // Flexible storage
234
+ context Json @default("{}") // Process-specific data (pagination, metadata, etc.)
235
+ results Json @default("{}") // Process results and metrics
236
+
237
+ // Hierarchy support
238
+ childProcesses String[] @db.ObjectId
239
+ parentProcessId String? @db.ObjectId
240
+
241
+ // Timestamps
242
+ createdAt DateTime @default(now())
243
+ updatedAt DateTime @updatedAt
244
+
245
+ @@index([userId])
246
+ @@index([integrationId])
247
+ @@index([type])
248
+ @@index([state])
249
+ @@index([name])
250
+ @@map("Process")
251
+ }
252
+
214
253
  // ============================================================================
215
254
  // SYNC MODELS
216
255
  // ============================================================================
@@ -281,11 +320,11 @@ model Association {
281
320
  /// Association object entry
282
321
  /// Replaces nested array structure in Mongoose
283
322
  model AssociationObject {
284
- id String @id @default(auto()) @map("_id") @db.ObjectId
285
- associationId String @db.ObjectId
286
- association Association @relation(fields: [associationId], references: [id], onDelete: Cascade)
287
- entityId String @db.ObjectId
288
- entity Entity @relation(fields: [entityId], references: [id], onDelete: Cascade)
323
+ id String @id @default(auto()) @map("_id") @db.ObjectId
324
+ associationId String @db.ObjectId
325
+ association Association @relation(fields: [associationId], references: [id], onDelete: Cascade)
326
+ entityId String @db.ObjectId
327
+ entity Entity @relation(fields: [entityId], references: [id], onDelete: Cascade)
289
328
  objectType String
290
329
  objId String
291
330
  metadata Json? // Optional metadata
@@ -320,4 +359,4 @@ model WebsocketConnection {
320
359
 
321
360
  @@index([connectionId])
322
361
  @@map("WebsocketConnection")
323
- }
362
+ }
@@ -0,0 +1,3 @@
1
+ -- AlterTable
2
+ -- Remove unused entityReferenceMap field from Integration table
3
+ ALTER TABLE "Integration" DROP COLUMN "entityReferenceMap";
@@ -3,10 +3,8 @@
3
3
  // Converted from MongoDB schema for relational database support
4
4
 
5
5
  generator client {
6
- provider = "prisma-client-js"
7
- output = "../generated/prisma-postgresql"
8
- binaryTargets = ["native", "rhel-openssl-3.0.x"] // native for local dev, rhel for Lambda deployment
9
- engineType = "binary" // Use binary engines (smaller size)
6
+ provider = "prisma-client-js"
7
+ output = "../node_modules/@prisma-postgresql/client"
10
8
  }
11
9
 
12
10
  datasource db {
@@ -21,8 +19,8 @@ datasource db {
21
19
  /// User model with discriminator pattern support
22
20
  /// Replaces Mongoose discriminators (IndividualUser, OrganizationUser)
23
21
  model User {
24
- id Int @id @default(autoincrement())
25
- type UserType
22
+ id Int @id @default(autoincrement())
23
+ type UserType
26
24
 
27
25
  // Timestamps
28
26
  createdAt DateTime @default(now())
@@ -86,12 +84,12 @@ model Token {
86
84
  /// OAuth credentials and API tokens
87
85
  /// All sensitive data encrypted with KMS at rest
88
86
  model Credential {
89
- id Int @id @default(autoincrement())
90
- userId Int?
91
- user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
92
- subType String?
87
+ id Int @id @default(autoincrement())
88
+ userId Int?
89
+ user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
90
+ subType String?
93
91
  authIsValid Boolean?
94
- externalId String?
92
+ externalId String?
95
93
 
96
94
  // Dynamic OAuth fields stored as JSON (encrypted via Prisma middleware)
97
95
  // Contains: access_token, refresh_token, domain, expires_in, token_type, etc.
@@ -147,15 +145,12 @@ model Integration {
147
145
  status IntegrationStatus @default(ENABLED)
148
146
 
149
147
  // Configuration and version
150
- config Json? // Integration configuration object
148
+ config Json? // Integration configuration object
151
149
  version String?
152
150
 
153
151
  // Entity references (many-to-many via implicit join table)
154
152
  entities Entity[]
155
153
 
156
- // Entity reference map (Map<String, String> stored as JSON)
157
- entityReferenceMap Json? @default("{}")
158
-
159
154
  // Message arrays (stored as JSON)
160
155
  errors Json @default("[]")
161
156
  warnings Json @default("[]")
@@ -228,11 +223,11 @@ model Sync {
228
223
  /// Data identifier for sync operations
229
224
  /// Replaces nested array structure in Mongoose
230
225
  model DataIdentifier {
231
- id Int @id @default(autoincrement())
226
+ id Int @id @default(autoincrement())
232
227
  syncId Int?
233
- sync Sync? @relation(fields: [syncId], references: [id], onDelete: Cascade)
228
+ sync Sync? @relation(fields: [syncId], references: [id], onDelete: Cascade)
234
229
  entityId Int
235
- entity Entity @relation(fields: [entityId], references: [id], onDelete: Cascade)
230
+ entity Entity @relation(fields: [entityId], references: [id], onDelete: Cascade)
236
231
 
237
232
  // Identifier data (can be any structure)
238
233
  idData Json
@@ -292,7 +287,7 @@ enum AssociationType {
292
287
 
293
288
  /// Generic state storage
294
289
  model State {
295
- id Int @id @default(autoincrement())
290
+ id Int @id @default(autoincrement())
296
291
  state Json?
297
292
  }
298
293
 
@@ -1,137 +0,0 @@
1
- /**
2
- * Run Database Migration Use Case
3
- *
4
- * Business logic for running Prisma database migrations.
5
- * Orchestrates Prisma client generation and migration execution.
6
- *
7
- * This use case follows the Frigg hexagonal architecture pattern where:
8
- * - Handlers (adapters) call use cases
9
- * - Use cases contain business logic and orchestration
10
- * - Use cases call repositories/utilities for data access
11
- */
12
-
13
- class RunDatabaseMigrationUseCase {
14
- /**
15
- * @param {Object} dependencies
16
- * @param {Object} dependencies.prismaRunner - Prisma runner utilities
17
- */
18
- constructor({ prismaRunner }) {
19
- if (!prismaRunner) {
20
- throw new Error('prismaRunner dependency is required');
21
- }
22
- this.prismaRunner = prismaRunner;
23
- }
24
-
25
- /**
26
- * Execute database migration
27
- *
28
- * @param {Object} params
29
- * @param {string} params.dbType - Database type ('postgresql' or 'mongodb')
30
- * @param {string} params.stage - Deployment stage (determines migration command)
31
- * @param {boolean} [params.verbose=false] - Enable verbose output
32
- * @returns {Promise<Object>} Migration result { success, dbType, stage, command, message }
33
- * @throws {MigrationError} If migration fails
34
- * @throws {ValidationError} If parameters are invalid
35
- */
36
- async execute({ dbType, stage, verbose = false }) {
37
- // Validation
38
- this._validateParams({ dbType, stage });
39
-
40
- // Step 1: Generate Prisma client
41
- const generateResult = await this.prismaRunner.runPrismaGenerate(dbType, verbose);
42
-
43
- if (!generateResult.success) {
44
- throw new MigrationError(
45
- `Failed to generate Prisma client: ${generateResult.error || 'Unknown error'}`,
46
- { dbType, stage, step: 'generate', output: generateResult.output }
47
- );
48
- }
49
-
50
- // Step 2: Run migrations based on database type
51
- let migrationResult;
52
- let migrationCommand;
53
-
54
- if (dbType === 'postgresql') {
55
- migrationCommand = this.prismaRunner.getMigrationCommand(stage);
56
- migrationResult = await this.prismaRunner.runPrismaMigrate(migrationCommand, verbose);
57
-
58
- if (!migrationResult.success) {
59
- throw new MigrationError(
60
- `PostgreSQL migration failed: ${migrationResult.error || 'Unknown error'}`,
61
- { dbType, stage, command: migrationCommand, step: 'migrate', output: migrationResult.output }
62
- );
63
- }
64
- } else if (dbType === 'mongodb') {
65
- migrationCommand = 'db push';
66
- // Use non-interactive mode for automated/Lambda environments
67
- migrationResult = await this.prismaRunner.runPrismaDbPush(verbose, true);
68
-
69
- if (!migrationResult.success) {
70
- throw new MigrationError(
71
- `MongoDB push failed: ${migrationResult.error || 'Unknown error'}`,
72
- { dbType, stage, command: migrationCommand, step: 'push', output: migrationResult.output }
73
- );
74
- }
75
- } else {
76
- throw new ValidationError(`Unsupported database type: ${dbType}. Must be 'postgresql' or 'mongodb'.`);
77
- }
78
-
79
- // Return success result
80
- return {
81
- success: true,
82
- dbType,
83
- stage,
84
- command: migrationCommand,
85
- message: 'Database migration completed successfully',
86
- };
87
- }
88
-
89
- /**
90
- * Validate execution parameters
91
- * @private
92
- */
93
- _validateParams({ dbType, stage }) {
94
- if (!dbType) {
95
- throw new ValidationError('dbType is required');
96
- }
97
-
98
- if (typeof dbType !== 'string') {
99
- throw new ValidationError('dbType must be a string');
100
- }
101
-
102
- if (!stage) {
103
- throw new ValidationError('stage is required');
104
- }
105
-
106
- if (typeof stage !== 'string') {
107
- throw new ValidationError('stage must be a string');
108
- }
109
- }
110
- }
111
-
112
- /**
113
- * Custom error for migration failures
114
- */
115
- class MigrationError extends Error {
116
- constructor(message, context = {}) {
117
- super(message);
118
- this.name = 'MigrationError';
119
- this.context = context;
120
- }
121
- }
122
-
123
- /**
124
- * Custom error for validation failures
125
- */
126
- class ValidationError extends Error {
127
- constructor(message) {
128
- super(message);
129
- this.name = 'ValidationError';
130
- }
131
- }
132
-
133
- module.exports = {
134
- RunDatabaseMigrationUseCase,
135
- MigrationError,
136
- ValidationError,
137
- };