@friggframework/core 2.0.0-next.49 → 2.0.0-next.50
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/database/encryption/README.md +3 -2
- package/database/repositories/health-check-repository-factory.js +16 -11
- package/database/repositories/health-check-repository-interface.js +3 -2
- package/database/repositories/health-check-repository-mongodb.js +46 -30
- package/database/repositories/health-check-repository-postgres.js +35 -28
- package/database/use-cases/check-database-health-use-case.js +3 -8
- package/handlers/routers/health.js +2 -1
- package/package.json +5 -5
|
@@ -501,8 +501,9 @@ database: {
|
|
|
501
501
|
# Run encryption tests
|
|
502
502
|
npm test -- database/encryption/
|
|
503
503
|
|
|
504
|
-
# Tests use explicit
|
|
505
|
-
#
|
|
504
|
+
# Tests use explicit prismaClient injection:
|
|
505
|
+
# const { prisma } = require('../prisma');
|
|
506
|
+
# const repository = createHealthCheckRepository({ prismaClient: prisma });
|
|
506
507
|
```
|
|
507
508
|
|
|
508
509
|
## Error Handling & Logging
|
|
@@ -3,25 +3,31 @@ const { HealthCheckRepositoryPostgreSQL } = require('./health-check-repository-p
|
|
|
3
3
|
const config = require('../config');
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* Factory function to create a health check repository for the configured database type.
|
|
7
|
+
* Requires explicit prismaClient injection to support IoC container patterns.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* @param {Object} options
|
|
10
|
+
* @param {Object} options.prismaClient - Prisma client instance (required for dependency injection)
|
|
11
|
+
* @returns {HealthCheckRepositoryInterface} Database-specific health check repository
|
|
12
|
+
* @throws {Error} If prismaClient is not provided
|
|
13
13
|
*
|
|
14
|
-
* @
|
|
14
|
+
* @example
|
|
15
|
+
* const { prisma } = require('../prisma');
|
|
16
|
+
* const repository = createHealthCheckRepository({ prismaClient: prisma });
|
|
15
17
|
*/
|
|
16
|
-
function createHealthCheckRepository() {
|
|
18
|
+
function createHealthCheckRepository({ prismaClient } = {}) {
|
|
19
|
+
if (!prismaClient) {
|
|
20
|
+
throw new Error('prismaClient is required');
|
|
21
|
+
}
|
|
22
|
+
|
|
17
23
|
const dbType = config.DB_TYPE;
|
|
18
24
|
|
|
19
25
|
switch (dbType) {
|
|
20
26
|
case 'mongodb':
|
|
21
|
-
return new HealthCheckRepositoryMongoDB();
|
|
27
|
+
return new HealthCheckRepositoryMongoDB({ prismaClient });
|
|
22
28
|
|
|
23
29
|
case 'postgresql':
|
|
24
|
-
return new HealthCheckRepositoryPostgreSQL();
|
|
30
|
+
return new HealthCheckRepositoryPostgreSQL({ prismaClient });
|
|
25
31
|
|
|
26
32
|
default:
|
|
27
33
|
throw new Error(
|
|
@@ -32,7 +38,6 @@ function createHealthCheckRepository() {
|
|
|
32
38
|
|
|
33
39
|
module.exports = {
|
|
34
40
|
createHealthCheckRepository,
|
|
35
|
-
// Export adapters for direct testing
|
|
36
41
|
HealthCheckRepositoryMongoDB,
|
|
37
42
|
HealthCheckRepositoryPostgreSQL,
|
|
38
43
|
};
|
|
@@ -76,9 +76,10 @@ class HealthCheckRepositoryInterface {
|
|
|
76
76
|
/**
|
|
77
77
|
* Get database connection state
|
|
78
78
|
*
|
|
79
|
-
* @returns {Object} Connection state info
|
|
79
|
+
* @returns {Promise<Object>} Connection state info
|
|
80
|
+
* @abstract
|
|
80
81
|
*/
|
|
81
|
-
getDatabaseConnectionState() {
|
|
82
|
+
async getDatabaseConnectionState() {
|
|
82
83
|
throw new Error('Method getDatabaseConnectionState must be implemented by subclass');
|
|
83
84
|
}
|
|
84
85
|
}
|
|
@@ -1,62 +1,78 @@
|
|
|
1
|
-
const { prisma } = require('../prisma');
|
|
2
1
|
const { mongoose } = require('../mongoose');
|
|
3
2
|
const {
|
|
4
3
|
HealthCheckRepositoryInterface,
|
|
5
4
|
} = require('./health-check-repository-interface');
|
|
6
5
|
|
|
7
|
-
/**
|
|
8
|
-
* MongoDB-specific Health Check Repository
|
|
9
|
-
*
|
|
10
|
-
* Provides MongoDB-specific database operations for health testing.
|
|
11
|
-
* Uses Mongoose for MongoDB-specific operations (raw access, ping).
|
|
12
|
-
*/
|
|
13
6
|
class HealthCheckRepositoryMongoDB extends HealthCheckRepositoryInterface {
|
|
14
|
-
|
|
7
|
+
/**
|
|
8
|
+
* @param {Object} params
|
|
9
|
+
* @param {Object} params.prismaClient - Prisma client instance
|
|
10
|
+
*/
|
|
11
|
+
constructor({ prismaClient }) {
|
|
15
12
|
super();
|
|
13
|
+
this.prisma = prismaClient;
|
|
16
14
|
}
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
16
|
+
/**
|
|
17
|
+
* @returns {Promise<{readyState: number, stateName: string, isConnected: boolean}>}
|
|
18
|
+
*/
|
|
19
|
+
async getDatabaseConnectionState() {
|
|
20
|
+
let isConnected = false;
|
|
21
|
+
let stateName = 'unknown';
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
await this.prisma.$runCommandRaw({ ping: 1 });
|
|
25
|
+
isConnected = true;
|
|
26
|
+
stateName = 'connected';
|
|
27
|
+
} catch (error) {
|
|
28
|
+
stateName = 'disconnected';
|
|
29
|
+
}
|
|
26
30
|
|
|
27
31
|
return {
|
|
28
|
-
readyState,
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
readyState: isConnected ? 1 : 0,
|
|
33
|
+
readyState: isConnected ? 1 : 0,
|
|
34
|
+
stateName,
|
|
35
|
+
isConnected,
|
|
31
36
|
};
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
async pingDatabase(maxTimeMS = 2000) {
|
|
35
40
|
const pingStart = Date.now();
|
|
36
|
-
|
|
41
|
+
|
|
42
|
+
// Create a timeout promise that rejects after maxTimeMS
|
|
43
|
+
const timeoutPromise = new Promise((_, reject) =>
|
|
44
|
+
setTimeout(() => reject(new Error('Database ping timeout')), maxTimeMS)
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
// Race between the database ping and the timeout
|
|
48
|
+
await Promise.race([
|
|
49
|
+
prisma.$queryRaw`SELECT 1`.catch(() => {
|
|
50
|
+
// For MongoDB, use runCommandRaw instead
|
|
51
|
+
return prisma.$runCommandRaw({ ping: 1 });
|
|
52
|
+
}),
|
|
53
|
+
timeoutPromise
|
|
54
|
+
]);
|
|
55
|
+
|
|
56
|
+
return Date.now() - pingStart;
|
|
57
|
+
}
|
|
37
58
|
return Date.now() - pingStart;
|
|
38
59
|
}
|
|
39
60
|
|
|
40
61
|
async createCredential(credentialData) {
|
|
41
|
-
|
|
42
|
-
// initializeMongoDBSchema() in database/utils/mongodb-schema-init.js
|
|
43
|
-
// This prevents "Cannot create namespace in multi-document transaction" errors
|
|
44
|
-
return await prisma.credential.create({
|
|
62
|
+
return await this.prisma.credential.create({
|
|
45
63
|
data: credentialData,
|
|
46
64
|
});
|
|
47
65
|
}
|
|
48
66
|
|
|
49
67
|
async findCredentialById(id) {
|
|
50
|
-
return await prisma.credential.findUnique({
|
|
68
|
+
return await this.prisma.credential.findUnique({
|
|
51
69
|
where: { id },
|
|
52
70
|
});
|
|
53
71
|
}
|
|
54
72
|
|
|
55
73
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* @param {string} id - Credential ID
|
|
59
|
-
* @returns {Promise<Object|null>} Raw credential from database
|
|
74
|
+
* @param {string} id
|
|
75
|
+
* @returns {Promise<Object|null>}
|
|
60
76
|
*/
|
|
61
77
|
async getRawCredentialById(id) {
|
|
62
78
|
const { ObjectId } = require('mongodb');
|
|
@@ -66,7 +82,7 @@ class HealthCheckRepositoryMongoDB extends HealthCheckRepositoryInterface {
|
|
|
66
82
|
}
|
|
67
83
|
|
|
68
84
|
async deleteCredential(id) {
|
|
69
|
-
await prisma.credential.delete({
|
|
85
|
+
await this.prisma.credential.delete({
|
|
70
86
|
where: { id },
|
|
71
87
|
});
|
|
72
88
|
}
|
|
@@ -1,59 +1,67 @@
|
|
|
1
|
-
const { prisma } = require('../prisma');
|
|
2
1
|
const {
|
|
3
2
|
HealthCheckRepositoryInterface,
|
|
4
3
|
} = require('./health-check-repository-interface');
|
|
5
4
|
|
|
6
|
-
/**
|
|
7
|
-
* PostgreSQL-specific Health Check Repository
|
|
8
|
-
*
|
|
9
|
-
* Provides PostgreSQL-specific database operations for health testing.
|
|
10
|
-
* Uses Prisma raw queries for PostgreSQL-specific operations.
|
|
11
|
-
*/
|
|
12
5
|
class HealthCheckRepositoryPostgreSQL extends HealthCheckRepositoryInterface {
|
|
13
|
-
|
|
6
|
+
/**
|
|
7
|
+
* @param {Object} params
|
|
8
|
+
* @param {Object} params.prismaClient - Prisma client instance
|
|
9
|
+
*/
|
|
10
|
+
constructor({ prismaClient }) {
|
|
14
11
|
super();
|
|
12
|
+
this.prisma = prismaClient;
|
|
15
13
|
}
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
/**
|
|
16
|
+
* @returns {Promise<{readyState: number, stateName: string, isConnected: boolean}>}
|
|
17
|
+
*/
|
|
18
|
+
async getDatabaseConnectionState() {
|
|
19
|
+
let isConnected = false;
|
|
20
|
+
let stateName = 'unknown';
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
await this.prisma.$queryRaw`SELECT 1`;
|
|
24
|
+
isConnected = true;
|
|
25
|
+
stateName = 'connected';
|
|
26
|
+
} catch (error) {
|
|
27
|
+
stateName = 'disconnected';
|
|
28
|
+
}
|
|
29
|
+
|
|
21
30
|
return {
|
|
22
|
-
readyState:
|
|
23
|
-
stateName
|
|
24
|
-
isConnected
|
|
31
|
+
readyState: isConnected ? 1 : 0,
|
|
32
|
+
stateName,
|
|
33
|
+
isConnected,
|
|
25
34
|
};
|
|
26
35
|
}
|
|
27
36
|
|
|
37
|
+
/**
|
|
38
|
+
* @param {number} maxTimeMS
|
|
39
|
+
* @returns {Promise<number>} Response time in milliseconds
|
|
40
|
+
*/
|
|
28
41
|
async pingDatabase(maxTimeMS = 2000) {
|
|
29
42
|
const pingStart = Date.now();
|
|
30
|
-
|
|
31
|
-
// PostgreSQL ping using SELECT 1
|
|
32
|
-
await prisma.$queryRaw`SELECT 1`;
|
|
33
|
-
|
|
43
|
+
await this.prisma.$queryRaw`SELECT 1`;
|
|
34
44
|
return Date.now() - pingStart;
|
|
35
45
|
}
|
|
36
46
|
|
|
37
47
|
async createCredential(credentialData) {
|
|
38
|
-
return await prisma.credential.create({
|
|
48
|
+
return await this.prisma.credential.create({
|
|
39
49
|
data: credentialData,
|
|
40
50
|
});
|
|
41
51
|
}
|
|
42
52
|
|
|
43
53
|
async findCredentialById(id) {
|
|
44
|
-
return await prisma.credential.findUnique({
|
|
54
|
+
return await this.prisma.credential.findUnique({
|
|
45
55
|
where: { id },
|
|
46
56
|
});
|
|
47
57
|
}
|
|
48
58
|
|
|
49
59
|
/**
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* @param {string} id - Credential ID
|
|
53
|
-
* @returns {Promise<Object|null>} Raw credential from database
|
|
60
|
+
* @param {string} id
|
|
61
|
+
* @returns {Promise<Object|null>}
|
|
54
62
|
*/
|
|
55
63
|
async getRawCredentialById(id) {
|
|
56
|
-
const results = await prisma.$queryRaw`
|
|
64
|
+
const results = await this.prisma.$queryRaw`
|
|
57
65
|
SELECT * FROM "Credential" WHERE id = ${id}
|
|
58
66
|
`;
|
|
59
67
|
|
|
@@ -61,12 +69,11 @@ class HealthCheckRepositoryPostgreSQL extends HealthCheckRepositoryInterface {
|
|
|
61
69
|
return null;
|
|
62
70
|
}
|
|
63
71
|
|
|
64
|
-
// Return first result
|
|
65
72
|
return results[0];
|
|
66
73
|
}
|
|
67
74
|
|
|
68
75
|
async deleteCredential(id) {
|
|
69
|
-
await prisma.credential.delete({
|
|
76
|
+
await this.prisma.credential.delete({
|
|
70
77
|
where: { id },
|
|
71
78
|
});
|
|
72
79
|
}
|
|
@@ -1,22 +1,17 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Use Case for checking database health.
|
|
3
|
-
* Contains business logic for determining database connectivity and health status.
|
|
4
|
-
*/
|
|
5
1
|
class CheckDatabaseHealthUseCase {
|
|
6
2
|
/**
|
|
7
3
|
* @param {Object} params
|
|
8
|
-
* @param {import('../health-check-repository-interface').HealthCheckRepositoryInterface} params.healthCheckRepository
|
|
4
|
+
* @param {import('../repositories/health-check-repository-interface').HealthCheckRepositoryInterface} params.healthCheckRepository
|
|
9
5
|
*/
|
|
10
6
|
constructor({ healthCheckRepository }) {
|
|
11
7
|
this.repository = healthCheckRepository;
|
|
12
8
|
}
|
|
13
9
|
|
|
14
10
|
/**
|
|
15
|
-
*
|
|
16
|
-
* @returns {Promise<Object>} Health check result with status, state, and response time
|
|
11
|
+
* @returns {Promise<{status: string, state: string, responseTime?: number}>}
|
|
17
12
|
*/
|
|
18
13
|
async execute() {
|
|
19
|
-
const { stateName, isConnected } = this.repository.getDatabaseConnectionState();
|
|
14
|
+
const { stateName, isConnected } = await this.repository.getDatabaseConnectionState();
|
|
20
15
|
|
|
21
16
|
const result = {
|
|
22
17
|
status: isConnected ? 'healthy' : 'unhealthy',
|
|
@@ -14,6 +14,7 @@ const {
|
|
|
14
14
|
const {
|
|
15
15
|
createHealthCheckRepository,
|
|
16
16
|
} = require('../../database/repositories/health-check-repository-factory');
|
|
17
|
+
const { prisma } = require('../../database/prisma');
|
|
17
18
|
const {
|
|
18
19
|
TestEncryptionUseCase,
|
|
19
20
|
} = require('../../database/use-cases/test-encryption-use-case');
|
|
@@ -31,7 +32,7 @@ const {
|
|
|
31
32
|
} = require('../use-cases/check-integrations-health-use-case');
|
|
32
33
|
|
|
33
34
|
const router = Router();
|
|
34
|
-
const healthCheckRepository = createHealthCheckRepository();
|
|
35
|
+
const healthCheckRepository = createHealthCheckRepository({ prismaClient: prisma });
|
|
35
36
|
|
|
36
37
|
// Load integrations and create factories just like auth router does
|
|
37
38
|
// This verifies the system can properly load integrations
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@friggframework/core",
|
|
3
3
|
"prettier": "@friggframework/prettier-config",
|
|
4
|
-
"version": "2.0.0-next.
|
|
4
|
+
"version": "2.0.0-next.50",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@aws-sdk/client-apigatewaymanagementapi": "^3.588.0",
|
|
7
7
|
"@aws-sdk/client-kms": "^3.588.0",
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
}
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@friggframework/eslint-config": "2.0.0-next.
|
|
42
|
-
"@friggframework/prettier-config": "2.0.0-next.
|
|
43
|
-
"@friggframework/test": "2.0.0-next.
|
|
41
|
+
"@friggframework/eslint-config": "2.0.0-next.50",
|
|
42
|
+
"@friggframework/prettier-config": "2.0.0-next.50",
|
|
43
|
+
"@friggframework/test": "2.0.0-next.50",
|
|
44
44
|
"@prisma/client": "^6.17.0",
|
|
45
45
|
"@types/lodash": "4.17.15",
|
|
46
46
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
@@ -80,5 +80,5 @@
|
|
|
80
80
|
"publishConfig": {
|
|
81
81
|
"access": "public"
|
|
82
82
|
},
|
|
83
|
-
"gitHead": "
|
|
83
|
+
"gitHead": "8a6cfd1c1b42d5c9ec77cb6a2d30a8789fe686a5"
|
|
84
84
|
}
|