@friggframework/core 2.0.0--canary.454.e2a280d.0 → 2.0.0--canary.458.c150d9a.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/README.md CHANGED
@@ -62,34 +62,6 @@ npm install @friggframework/core
62
62
  yarn add @friggframework/core
63
63
  ```
64
64
 
65
- ### Prisma Support (Optional)
66
-
67
- `@friggframework/core` supports both MongoDB and PostgreSQL via Prisma ORM. **Prisma is an optional peer dependency** - you only need to install it if you're using database features that require migrations or schema generation.
68
-
69
- **When you need Prisma:**
70
- - Running database migrations (`prisma migrate`, `prisma db push`)
71
- - Generating Prisma clients for your application
72
- - Using the migration Lambda function (`dbMigrate`)
73
-
74
- **Installation:**
75
- ```bash
76
- # Install Prisma CLI and Client as dev dependencies
77
- npm install --save-dev prisma @prisma/client
78
-
79
- # Or with yarn
80
- yarn add -D prisma @prisma/client
81
- ```
82
-
83
- **Generate Prisma Clients:**
84
- ```bash
85
- # From @friggframework/core directory
86
- npm run prisma:generate:mongo # MongoDB only
87
- npm run prisma:generate:postgres # PostgreSQL only
88
- npm run prisma:generate # Both databases
89
- ```
90
-
91
- **Note:** The published npm package includes pre-generated Prisma clients, so you don't need to install Prisma just to use `@friggframework/core` in production. Prisma is only required if you're actively developing migrations or running the migration Lambda function.
92
-
93
65
  ### Prerequisites
94
66
 
95
67
  - Node.js 16+
@@ -37,35 +37,7 @@ function getDatabaseType() {
37
37
  );
38
38
  }
39
39
 
40
- let backendModule;
41
- try {
42
- backendModule = require(backendIndexPath);
43
- } catch (requireError) {
44
- // Extract the actual file with the error from the stack trace
45
- // Skip internal Node.js files (node:internal/*) and find first user file
46
- let errorFile = 'unknown file';
47
- const stackLines = requireError.stack?.split('\n') || [];
48
-
49
- for (const line of stackLines) {
50
- // Match file paths in stack trace, excluding node:internal
51
- const match = line.match(/\(([^)]+\.js):\d+:\d+\)/) || line.match(/at ([^(]+\.js):\d+:\d+/);
52
- if (match && match[1] && !match[1].includes('node:internal')) {
53
- errorFile = match[1];
54
- break;
55
- }
56
- }
57
-
58
- // Provide better error context for syntax/runtime errors
59
- throw new Error(
60
- `[Frigg] Failed to load app definition from ${backendIndexPath}\n` +
61
- `Error: ${requireError.message}\n` +
62
- `File with error: ${errorFile}\n` +
63
- `\nFull stack trace:\n${requireError.stack}\n\n` +
64
- 'This error occurred while loading your app definition or its dependencies. ' +
65
- 'Check the file listed above for syntax errors (trailing commas, missing brackets, etc.)'
66
- );
67
- }
68
-
40
+ const backendModule = require(backendIndexPath);
69
41
  database = backendModule?.Definition?.database;
70
42
 
71
43
  if (!database) {
@@ -77,9 +77,9 @@ const prismaClientSingleton = () => {
77
77
  let PrismaClient;
78
78
 
79
79
  if (config.DB_TYPE === 'mongodb') {
80
- PrismaClient = require('../generated/prisma-mongodb').PrismaClient;
80
+ PrismaClient = require('@prisma-mongodb/client').PrismaClient;
81
81
  } else if (config.DB_TYPE === 'postgresql') {
82
- PrismaClient = require('../generated/prisma-postgresql').PrismaClient;
82
+ PrismaClient = require('@prisma-postgresql/client').PrismaClient;
83
83
  } else {
84
84
  throw new Error(
85
85
  `Unsupported database type: ${config.DB_TYPE}. Supported values: 'mongodb', 'postgresql'`
@@ -83,14 +83,13 @@ class TestEncryptionUseCase {
83
83
  * @private
84
84
  */
85
85
  _mapTestDataToCredential(testData) {
86
- // Note: Using camelCase for Prisma compatibility (both MongoDB and PostgreSQL)
87
- // Changed from snake_case (user_id, entity_id) to camelCase (userId, externalId)
88
86
  return {
89
- externalId: 'test-encryption-entity',
87
+ user_id: 'test-encryption-user',
88
+ entity_id: 'test-encryption-entity',
90
89
  data: {
91
- access_token: testData.testSecret, // Encrypted field
92
- refresh_token: testData.nestedSecret?.value, // Encrypted field
93
- domain: testData.normalField, // Not encrypted
90
+ access_token: testData.testSecret,
91
+ refresh_token: testData.nestedSecret?.value,
92
+ domain: testData.normalField,
94
93
  },
95
94
  };
96
95
  }
@@ -1,7 +1,9 @@
1
1
  const express = require('express');
2
2
  const { createAppHandler } = require('../app-handler-helpers');
3
3
  const { checkRequiredParams } = require('@friggframework/core');
4
- const { createUserRepository } = require('../../user/user-repository-factory');
4
+ const {
5
+ createUserRepository,
6
+ } = require('../../user/repositories/user-repository-factory');
5
7
  const {
6
8
  CreateIndividualUser,
7
9
  } = require('../../user/use-cases/create-individual-user');
package/modules/module.js CHANGED
@@ -42,7 +42,7 @@ class Module extends Delegate {
42
42
  const apiParams = {
43
43
  ...this.definition.env,
44
44
  delegate: this,
45
- ...this.apiParamsFromCredential(this.credential.data), // todo: check if this works for mongo as well
45
+ ...(this.credential?.data ? this.apiParamsFromCredential(this.credential.data) : {}), // Handle case when credential is undefined
46
46
  ...this.apiParamsFromEntity(this.entity),
47
47
  };
48
48
  this.api = new this.apiClass(apiParams);
@@ -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.458.c150d9a.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.458.c150d9a.0",
27
+ "@friggframework/prettier-config": "2.0.0--canary.458.c150d9a.0",
28
+ "@friggframework/test": "2.0.0--canary.458.c150d9a.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": "c150d9a112596c02f6e29eae2944f7dcb1ed1489"
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())
@@ -88,12 +86,12 @@ model Token {
88
86
  /// OAuth credentials and API tokens
89
87
  /// All sensitive data encrypted with KMS at rest
90
88
  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?
89
+ id String @id @default(auto()) @map("_id") @db.ObjectId
90
+ userId String? @db.ObjectId
91
+ user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
92
+ subType String?
95
93
  authIsValid Boolean?
96
- externalId String?
94
+ externalId String?
97
95
 
98
96
  // Dynamic OAuth fields stored as JSON (encrypted via Prisma middleware)
99
97
  // Contains: access_token, refresh_token, domain, expires_in, token_type, etc.
@@ -126,11 +124,11 @@ model Entity {
126
124
  updatedAt DateTime @updatedAt
127
125
 
128
126
  // Relations - many-to-many with scalar lists
129
- integrations Integration[] @relation("IntegrationEntities", fields: [integrationIds], references: [id])
130
- integrationIds String[] @db.ObjectId
127
+ integrations Integration[] @relation("IntegrationEntities", fields: [integrationIds], references: [id])
128
+ integrationIds String[] @db.ObjectId
131
129
 
132
- syncs Sync[] @relation("SyncEntities", fields: [syncIds], references: [id])
133
- syncIds String[] @db.ObjectId
130
+ syncs Sync[] @relation("SyncEntities", fields: [syncIds], references: [id])
131
+ syncIds String[] @db.ObjectId
134
132
 
135
133
  dataIdentifiers DataIdentifier[]
136
134
  associationObjects AssociationObject[]
@@ -154,16 +152,13 @@ model Integration {
154
152
  status IntegrationStatus @default(ENABLED)
155
153
 
156
154
  // Configuration and version
157
- config Json? // Integration configuration object
155
+ config Json? // Integration configuration object
158
156
  version String?
159
157
 
160
158
  // Entity references (many-to-many via explicit scalar list)
161
159
  entities Entity[] @relation("IntegrationEntities", fields: [entityIds], references: [id])
162
160
  entityIds String[] @db.ObjectId
163
161
 
164
- // Entity reference map (Map<String, String> stored as JSON)
165
- entityReferenceMap Json? @default("{}")
166
-
167
162
  // Message arrays (stored as JSON)
168
163
  errors Json @default("[]")
169
164
  warnings Json @default("[]")
@@ -281,11 +276,11 @@ model Association {
281
276
  /// Association object entry
282
277
  /// Replaces nested array structure in Mongoose
283
278
  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)
279
+ id String @id @default(auto()) @map("_id") @db.ObjectId
280
+ associationId String @db.ObjectId
281
+ association Association @relation(fields: [associationId], references: [id], onDelete: Cascade)
282
+ entityId String @db.ObjectId
283
+ entity Entity @relation(fields: [entityId], references: [id], onDelete: Cascade)
289
284
  objectType String
290
285
  objId String
291
286
  metadata Json? // Optional metadata
@@ -320,4 +315,4 @@ model WebsocketConnection {
320
315
 
321
316
  @@index([connectionId])
322
317
  @@map("WebsocketConnection")
323
- }
318
+ }
@@ -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
- };