@friggframework/core 2.0.0-next.8 → 2.0.0-next.80
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/CLAUDE.md +694 -0
- package/README.md +959 -50
- package/application/commands/README.md +451 -0
- package/application/commands/credential-commands.js +245 -0
- package/application/commands/entity-commands.js +336 -0
- package/application/commands/integration-commands.js +210 -0
- package/application/commands/scheduler-commands.js +263 -0
- package/application/commands/user-commands.js +283 -0
- package/application/index.js +73 -0
- package/assertions/index.js +0 -3
- package/core/CLAUDE.md +690 -0
- package/core/Worker.js +60 -24
- package/core/create-handler.js +79 -8
- package/credential/repositories/credential-repository-documentdb.js +304 -0
- package/credential/repositories/credential-repository-factory.js +54 -0
- package/credential/repositories/credential-repository-interface.js +98 -0
- package/credential/repositories/credential-repository-mongo.js +269 -0
- package/credential/repositories/credential-repository-postgres.js +287 -0
- package/credential/repositories/credential-repository.js +300 -0
- package/credential/use-cases/get-credential-for-user.js +25 -0
- package/credential/use-cases/update-authentication-status.js +15 -0
- package/database/MONGODB_TRANSACTION_FIX.md +198 -0
- package/database/adapters/lambda-invoker.js +97 -0
- package/database/config.js +154 -0
- package/database/documentdb-encryption-service.js +330 -0
- package/database/documentdb-utils.js +136 -0
- package/database/encryption/README.md +839 -0
- package/database/encryption/documentdb-encryption-service.md +3575 -0
- package/database/encryption/encryption-schema-registry.js +268 -0
- package/database/encryption/field-encryption-service.js +226 -0
- package/database/encryption/logger.js +79 -0
- package/database/encryption/prisma-encryption-extension.js +222 -0
- package/database/index.js +21 -21
- package/database/prisma.js +182 -0
- package/database/repositories/health-check-repository-documentdb.js +138 -0
- package/database/repositories/health-check-repository-factory.js +48 -0
- package/database/repositories/health-check-repository-interface.js +82 -0
- package/database/repositories/health-check-repository-mongodb.js +89 -0
- package/database/repositories/health-check-repository-postgres.js +82 -0
- package/database/repositories/migration-status-repository-s3.js +137 -0
- package/database/use-cases/check-database-health-use-case.js +29 -0
- package/database/use-cases/check-database-state-use-case.js +81 -0
- package/database/use-cases/check-encryption-health-use-case.js +83 -0
- package/database/use-cases/get-database-state-via-worker-use-case.js +61 -0
- package/database/use-cases/get-migration-status-use-case.js +93 -0
- package/database/use-cases/run-database-migration-use-case.js +139 -0
- package/database/use-cases/test-encryption-use-case.js +253 -0
- package/database/use-cases/trigger-database-migration-use-case.js +157 -0
- package/database/utils/mongodb-collection-utils.js +94 -0
- package/database/utils/mongodb-schema-init.js +108 -0
- package/database/utils/prisma-runner.js +477 -0
- package/database/utils/prisma-schema-parser.js +182 -0
- package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +517 -0
- package/encrypt/Cryptor.js +34 -168
- package/encrypt/index.js +1 -2
- package/errors/client-safe-error.js +26 -0
- package/errors/fetch-error.js +15 -7
- package/errors/index.js +2 -0
- package/generated/prisma-mongodb/client.d.ts +1 -0
- package/generated/prisma-mongodb/client.js +4 -0
- package/generated/prisma-mongodb/default.d.ts +1 -0
- package/generated/prisma-mongodb/default.js +4 -0
- package/generated/prisma-mongodb/edge.d.ts +1 -0
- package/generated/prisma-mongodb/edge.js +335 -0
- package/generated/prisma-mongodb/index-browser.js +317 -0
- package/generated/prisma-mongodb/index.d.ts +22955 -0
- package/generated/prisma-mongodb/index.js +360 -0
- package/generated/prisma-mongodb/package.json +183 -0
- package/generated/prisma-mongodb/query-engine-debian-openssl-3.0.x +0 -0
- package/generated/prisma-mongodb/query-engine-rhel-openssl-3.0.x +0 -0
- package/generated/prisma-mongodb/runtime/binary.d.ts +1 -0
- package/generated/prisma-mongodb/runtime/binary.js +289 -0
- package/generated/prisma-mongodb/runtime/edge-esm.js +34 -0
- package/generated/prisma-mongodb/runtime/edge.js +34 -0
- package/generated/prisma-mongodb/runtime/index-browser.d.ts +370 -0
- package/generated/prisma-mongodb/runtime/index-browser.js +16 -0
- package/generated/prisma-mongodb/runtime/library.d.ts +3977 -0
- package/generated/prisma-mongodb/runtime/react-native.js +83 -0
- package/generated/prisma-mongodb/runtime/wasm-compiler-edge.js +84 -0
- package/generated/prisma-mongodb/runtime/wasm-engine-edge.js +36 -0
- package/generated/prisma-mongodb/schema.prisma +362 -0
- package/generated/prisma-mongodb/wasm-edge-light-loader.mjs +4 -0
- package/generated/prisma-mongodb/wasm-worker-loader.mjs +4 -0
- package/generated/prisma-mongodb/wasm.d.ts +1 -0
- package/generated/prisma-mongodb/wasm.js +342 -0
- package/generated/prisma-postgresql/client.d.ts +1 -0
- package/generated/prisma-postgresql/client.js +4 -0
- package/generated/prisma-postgresql/default.d.ts +1 -0
- package/generated/prisma-postgresql/default.js +4 -0
- package/generated/prisma-postgresql/edge.d.ts +1 -0
- package/generated/prisma-postgresql/edge.js +357 -0
- package/generated/prisma-postgresql/index-browser.js +339 -0
- package/generated/prisma-postgresql/index.d.ts +25131 -0
- package/generated/prisma-postgresql/index.js +382 -0
- package/generated/prisma-postgresql/package.json +183 -0
- package/generated/prisma-postgresql/query-engine-debian-openssl-3.0.x +0 -0
- package/generated/prisma-postgresql/query-engine-rhel-openssl-3.0.x +0 -0
- package/generated/prisma-postgresql/query_engine_bg.js +2 -0
- package/generated/prisma-postgresql/query_engine_bg.wasm +0 -0
- package/generated/prisma-postgresql/runtime/binary.d.ts +1 -0
- package/generated/prisma-postgresql/runtime/binary.js +289 -0
- package/generated/prisma-postgresql/runtime/edge-esm.js +34 -0
- package/generated/prisma-postgresql/runtime/edge.js +34 -0
- package/generated/prisma-postgresql/runtime/index-browser.d.ts +370 -0
- package/generated/prisma-postgresql/runtime/index-browser.js +16 -0
- package/generated/prisma-postgresql/runtime/library.d.ts +3977 -0
- package/generated/prisma-postgresql/runtime/react-native.js +83 -0
- package/generated/prisma-postgresql/runtime/wasm-compiler-edge.js +84 -0
- package/generated/prisma-postgresql/runtime/wasm-engine-edge.js +36 -0
- package/generated/prisma-postgresql/schema.prisma +345 -0
- package/generated/prisma-postgresql/wasm-edge-light-loader.mjs +4 -0
- package/generated/prisma-postgresql/wasm-worker-loader.mjs +4 -0
- package/generated/prisma-postgresql/wasm.d.ts +1 -0
- package/generated/prisma-postgresql/wasm.js +364 -0
- package/handlers/WEBHOOKS.md +653 -0
- package/handlers/app-definition-loader.js +38 -0
- package/handlers/app-handler-helpers.js +57 -0
- package/handlers/backend-utils.js +262 -0
- package/handlers/database-migration-handler.js +227 -0
- package/handlers/integration-event-dispatcher.js +54 -0
- package/handlers/routers/HEALTHCHECK.md +342 -0
- package/handlers/routers/auth.js +15 -0
- package/handlers/routers/db-migration.handler.js +29 -0
- package/handlers/routers/db-migration.js +326 -0
- package/handlers/routers/health.js +516 -0
- package/handlers/routers/integration-defined-routers.js +45 -0
- package/handlers/routers/integration-webhook-routers.js +67 -0
- package/handlers/routers/user.js +63 -0
- package/handlers/routers/websocket.js +57 -0
- package/handlers/use-cases/check-external-apis-health-use-case.js +81 -0
- package/handlers/use-cases/check-integrations-health-use-case.js +44 -0
- package/handlers/workers/db-migration.js +352 -0
- package/handlers/workers/dlq-processor.js +63 -0
- package/handlers/workers/integration-defined-workers.js +23 -0
- package/index.js +82 -46
- package/infrastructure/scheduler/eventbridge-scheduler-adapter.js +184 -0
- package/infrastructure/scheduler/index.js +33 -0
- package/infrastructure/scheduler/mock-scheduler-adapter.js +143 -0
- package/infrastructure/scheduler/scheduler-service-factory.js +73 -0
- package/infrastructure/scheduler/scheduler-service-interface.js +47 -0
- package/integrations/WEBHOOK-QUICKSTART.md +151 -0
- package/integrations/index.js +12 -10
- package/integrations/integration-base.js +364 -55
- package/integrations/integration-router.js +375 -179
- package/integrations/options.js +1 -1
- package/integrations/repositories/integration-mapping-repository-documentdb.js +280 -0
- package/integrations/repositories/integration-mapping-repository-factory.js +57 -0
- package/integrations/repositories/integration-mapping-repository-interface.js +106 -0
- package/integrations/repositories/integration-mapping-repository-mongo.js +161 -0
- package/integrations/repositories/integration-mapping-repository-postgres.js +227 -0
- package/integrations/repositories/integration-mapping-repository.js +156 -0
- package/integrations/repositories/integration-repository-documentdb.js +219 -0
- package/integrations/repositories/integration-repository-factory.js +51 -0
- package/integrations/repositories/integration-repository-interface.js +144 -0
- package/integrations/repositories/integration-repository-mongo.js +330 -0
- package/integrations/repositories/integration-repository-postgres.js +385 -0
- package/integrations/repositories/process-repository-documentdb.js +243 -0
- package/integrations/repositories/process-repository-factory.js +53 -0
- package/integrations/repositories/process-repository-interface.js +90 -0
- package/integrations/repositories/process-repository-mongo.js +190 -0
- package/integrations/repositories/process-repository-postgres.js +217 -0
- package/integrations/tests/doubles/config-capturing-integration.js +81 -0
- package/integrations/tests/doubles/dummy-integration-class.js +105 -0
- package/integrations/tests/doubles/test-integration-repository.js +112 -0
- package/integrations/use-cases/create-integration.js +83 -0
- package/integrations/use-cases/create-process.js +128 -0
- package/integrations/use-cases/delete-integration-for-user.js +101 -0
- package/integrations/use-cases/find-integration-context-by-external-entity-id.js +72 -0
- package/integrations/use-cases/get-integration-for-user.js +78 -0
- package/integrations/use-cases/get-integration-instance-by-definition.js +67 -0
- package/integrations/use-cases/get-integration-instance.js +83 -0
- package/integrations/use-cases/get-integrations-for-user.js +88 -0
- package/integrations/use-cases/get-possible-integrations.js +27 -0
- package/integrations/use-cases/get-process.js +87 -0
- package/integrations/use-cases/index.js +19 -0
- package/integrations/use-cases/load-integration-context.js +71 -0
- package/integrations/use-cases/update-integration-messages.js +44 -0
- package/integrations/use-cases/update-integration-status.js +32 -0
- package/integrations/use-cases/update-integration.js +92 -0
- package/integrations/use-cases/update-process-metrics.js +201 -0
- package/integrations/use-cases/update-process-state.js +119 -0
- package/integrations/utils/map-integration-dto.js +37 -0
- package/jest-global-setup-noop.js +3 -0
- package/jest-global-teardown-noop.js +3 -0
- package/logs/logger.js +0 -4
- package/{module-plugin → modules}/index.js +0 -10
- package/modules/module-factory.js +56 -0
- package/modules/module.js +256 -0
- package/modules/repositories/module-repository-documentdb.js +335 -0
- package/modules/repositories/module-repository-factory.js +40 -0
- package/modules/repositories/module-repository-interface.js +129 -0
- package/modules/repositories/module-repository-mongo.js +408 -0
- package/modules/repositories/module-repository-postgres.js +453 -0
- package/modules/repositories/module-repository.js +345 -0
- package/modules/requester/api-key.js +52 -0
- package/modules/requester/oauth-2.js +396 -0
- package/{module-plugin → modules}/requester/requester.js +4 -2
- package/{module-plugin → modules}/test/mock-api/api.js +8 -3
- package/{module-plugin → modules}/test/mock-api/definition.js +14 -10
- package/modules/tests/doubles/test-module-factory.js +16 -0
- package/modules/tests/doubles/test-module-repository.js +39 -0
- package/modules/use-cases/get-entities-for-user.js +32 -0
- package/modules/use-cases/get-entity-options-by-id.js +71 -0
- package/modules/use-cases/get-entity-options-by-type.js +34 -0
- package/modules/use-cases/get-module-instance-from-type.js +31 -0
- package/modules/use-cases/get-module.js +74 -0
- package/modules/use-cases/process-authorization-callback.js +177 -0
- package/modules/use-cases/refresh-entity-options.js +72 -0
- package/modules/use-cases/test-module-auth.js +72 -0
- package/modules/utils/map-module-dto.js +18 -0
- package/package.json +82 -50
- package/prisma-mongodb/schema.prisma +362 -0
- package/prisma-postgresql/migrations/20250930193005_init/migration.sql +315 -0
- package/prisma-postgresql/migrations/20251006135218_init/migration.sql +9 -0
- package/prisma-postgresql/migrations/20251010000000_remove_unused_entity_reference_map/migration.sql +3 -0
- package/prisma-postgresql/migrations/20251112195422_update_user_unique_constraints/migration.sql +25 -0
- package/prisma-postgresql/migrations/migration_lock.toml +3 -0
- package/prisma-postgresql/schema.prisma +345 -0
- package/queues/queuer-util.js +103 -21
- package/syncs/manager.js +468 -443
- package/syncs/repositories/sync-repository-documentdb.js +240 -0
- package/syncs/repositories/sync-repository-factory.js +43 -0
- package/syncs/repositories/sync-repository-interface.js +109 -0
- package/syncs/repositories/sync-repository-mongo.js +239 -0
- package/syncs/repositories/sync-repository-postgres.js +319 -0
- package/syncs/sync.js +0 -1
- package/token/repositories/token-repository-documentdb.js +137 -0
- package/token/repositories/token-repository-factory.js +40 -0
- package/token/repositories/token-repository-interface.js +131 -0
- package/token/repositories/token-repository-mongo.js +219 -0
- package/token/repositories/token-repository-postgres.js +264 -0
- package/token/repositories/token-repository.js +219 -0
- package/types/associations/index.d.ts +0 -17
- package/types/core/index.d.ts +12 -4
- package/types/database/index.d.ts +10 -2
- package/types/encrypt/index.d.ts +5 -3
- package/types/integrations/index.d.ts +3 -8
- package/types/module-plugin/index.d.ts +17 -69
- package/types/syncs/index.d.ts +0 -17
- package/user/repositories/user-repository-documentdb.js +441 -0
- package/user/repositories/user-repository-factory.js +52 -0
- package/user/repositories/user-repository-interface.js +201 -0
- package/user/repositories/user-repository-mongo.js +308 -0
- package/user/repositories/user-repository-postgres.js +360 -0
- package/user/tests/doubles/test-user-repository.js +72 -0
- package/user/use-cases/authenticate-user.js +127 -0
- package/user/use-cases/authenticate-with-shared-secret.js +48 -0
- package/user/use-cases/create-individual-user.js +61 -0
- package/user/use-cases/create-organization-user.js +47 -0
- package/user/use-cases/create-token-for-user-id.js +30 -0
- package/user/use-cases/get-user-from-adopter-jwt.js +149 -0
- package/user/use-cases/get-user-from-bearer-token.js +77 -0
- package/user/use-cases/get-user-from-x-frigg-headers.js +132 -0
- package/user/use-cases/login-user.js +122 -0
- package/user/user.js +125 -0
- package/utils/backend-path.js +38 -0
- package/utils/index.js +6 -0
- package/websocket/repositories/websocket-connection-repository-documentdb.js +119 -0
- package/websocket/repositories/websocket-connection-repository-factory.js +44 -0
- package/websocket/repositories/websocket-connection-repository-interface.js +106 -0
- package/websocket/repositories/websocket-connection-repository-mongo.js +156 -0
- package/websocket/repositories/websocket-connection-repository-postgres.js +196 -0
- package/websocket/repositories/websocket-connection-repository.js +161 -0
- package/assertions/is-equal.js +0 -17
- package/associations/model.js +0 -54
- package/database/models/IndividualUser.js +0 -76
- package/database/models/OrganizationUser.js +0 -29
- package/database/models/State.js +0 -9
- package/database/models/Token.js +0 -70
- package/database/models/UserModel.js +0 -7
- package/database/models/WebsocketConnection.js +0 -49
- package/database/mongo.js +0 -45
- package/database/mongoose.js +0 -5
- package/encrypt/Cryptor.test.js +0 -32
- package/encrypt/encrypt.js +0 -132
- package/encrypt/encrypt.test.js +0 -1069
- package/encrypt/test-encrypt.js +0 -107
- package/errors/base-error.test.js +0 -32
- package/errors/fetch-error.test.js +0 -79
- package/errors/halt-error.test.js +0 -11
- package/errors/validation-errors.test.js +0 -120
- package/integrations/create-frigg-backend.js +0 -31
- package/integrations/integration-factory.js +0 -251
- package/integrations/integration-mapping.js +0 -43
- package/integrations/integration-model.js +0 -46
- package/integrations/integration-user.js +0 -144
- package/integrations/test/integration-base.test.js +0 -144
- package/lambda/TimeoutCatcher.test.js +0 -68
- package/logs/logger.test.js +0 -76
- package/module-plugin/auther.js +0 -393
- package/module-plugin/credential.js +0 -22
- package/module-plugin/entity-manager.js +0 -70
- package/module-plugin/entity.js +0 -46
- package/module-plugin/manager.js +0 -169
- package/module-plugin/module-factory.js +0 -61
- package/module-plugin/requester/api-key.js +0 -36
- package/module-plugin/requester/oauth-2.js +0 -219
- package/module-plugin/requester/requester.test.js +0 -28
- package/module-plugin/test/auther.test.js +0 -97
- package/syncs/model.js +0 -62
- /package/{module-plugin → modules}/ModuleConstants.js +0 -0
- /package/{module-plugin → modules}/requester/basic.js +0 -0
- /package/{module-plugin → modules}/test/mock-api/mocks/hubspot.js +0 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Health Check Repository Interface
|
|
3
|
+
* Abstract base class defining the contract for health check persistence adapters
|
|
4
|
+
*
|
|
5
|
+
* This follows the Port in Hexagonal Architecture:
|
|
6
|
+
* - Domain layer depends on this abstraction
|
|
7
|
+
* - Concrete adapters implement this interface
|
|
8
|
+
* - Use cases receive repositories via dependency injection
|
|
9
|
+
*
|
|
10
|
+
* Note: Currently, HealthCheckRepository has identical structure across MongoDB and PostgreSQL,
|
|
11
|
+
* so HealthCheckRepository serves both. This interface exists for consistency and
|
|
12
|
+
* future-proofing if database-specific implementations become needed.
|
|
13
|
+
*
|
|
14
|
+
* @abstract
|
|
15
|
+
*/
|
|
16
|
+
class HealthCheckRepositoryInterface {
|
|
17
|
+
/**
|
|
18
|
+
* @returns {Promise<{readyState: number, stateName: string, isConnected: boolean}>}
|
|
19
|
+
* @abstract
|
|
20
|
+
*/
|
|
21
|
+
async getDatabaseConnectionState() {
|
|
22
|
+
throw new Error('Method getDatabaseConnectionState must be implemented by subclass');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Ping database to verify connectivity
|
|
27
|
+
*
|
|
28
|
+
* @param {number} maxTimeMS - Maximum time in milliseconds
|
|
29
|
+
* @returns {Promise<number>} Response time in milliseconds
|
|
30
|
+
* @abstract
|
|
31
|
+
*/
|
|
32
|
+
async pingDatabase(maxTimeMS) {
|
|
33
|
+
throw new Error('Method pingDatabase must be implemented by subclass');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Persist an encrypted credential for health verification.
|
|
38
|
+
* Implementations should rely on Prisma so encryption middleware runs.
|
|
39
|
+
*
|
|
40
|
+
* @param {Object} credentialData
|
|
41
|
+
* @returns {Promise<Object>} Persisted credential
|
|
42
|
+
* @abstract
|
|
43
|
+
*/
|
|
44
|
+
async createCredential(credentialData) {
|
|
45
|
+
throw new Error('Method createCredential must be implemented by subclass');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Retrieve credential by ID using Prisma (decrypted).
|
|
50
|
+
*
|
|
51
|
+
* @param {string} id
|
|
52
|
+
* @returns {Promise<Object|null>}
|
|
53
|
+
* @abstract
|
|
54
|
+
*/
|
|
55
|
+
async findCredentialById(id) {
|
|
56
|
+
throw new Error('Method findCredentialById must be implemented by subclass');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Fetch raw credential document from the database (without decryption).
|
|
61
|
+
*
|
|
62
|
+
* @param {string} id
|
|
63
|
+
* @returns {Promise<Object|null>}
|
|
64
|
+
* @abstract
|
|
65
|
+
*/
|
|
66
|
+
async getRawCredentialById(id) {
|
|
67
|
+
throw new Error('Method getRawCredentialById must be implemented by subclass');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Delete credential by ID.
|
|
72
|
+
*
|
|
73
|
+
* @param {string} id
|
|
74
|
+
* @returns {Promise<void>}
|
|
75
|
+
* @abstract
|
|
76
|
+
*/
|
|
77
|
+
async deleteCredential(id) {
|
|
78
|
+
throw new Error('Method deleteCredential must be implemented by subclass');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
module.exports = { HealthCheckRepositoryInterface };
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
const {
|
|
2
|
+
HealthCheckRepositoryInterface,
|
|
3
|
+
} = require('./health-check-repository-interface');
|
|
4
|
+
|
|
5
|
+
class HealthCheckRepositoryMongoDB extends HealthCheckRepositoryInterface {
|
|
6
|
+
/**
|
|
7
|
+
* @param {Object} params
|
|
8
|
+
* @param {Object} params.prismaClient - Prisma client instance
|
|
9
|
+
*/
|
|
10
|
+
constructor({ prismaClient }) {
|
|
11
|
+
super();
|
|
12
|
+
this.prisma = prismaClient;
|
|
13
|
+
}
|
|
14
|
+
|
|
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.$runCommandRaw({ ping: 1 });
|
|
24
|
+
isConnected = true;
|
|
25
|
+
stateName = 'connected';
|
|
26
|
+
} catch (error) {
|
|
27
|
+
stateName = 'disconnected';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
readyState: isConnected ? 1 : 0,
|
|
32
|
+
stateName,
|
|
33
|
+
isConnected,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async pingDatabase(maxTimeMS = 2000) {
|
|
38
|
+
const pingStart = Date.now();
|
|
39
|
+
let timeoutId;
|
|
40
|
+
|
|
41
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
42
|
+
timeoutId = setTimeout(() => reject(new Error('Database ping timeout')), maxTimeMS);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
await Promise.race([
|
|
47
|
+
this.prisma.$runCommandRaw({ ping: 1 }),
|
|
48
|
+
timeoutPromise
|
|
49
|
+
]);
|
|
50
|
+
return Date.now() - pingStart;
|
|
51
|
+
} finally {
|
|
52
|
+
clearTimeout(timeoutId);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async createCredential(credentialData) {
|
|
57
|
+
return await this.prisma.credential.create({
|
|
58
|
+
data: credentialData,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async findCredentialById(id) {
|
|
63
|
+
return await this.prisma.credential.findUnique({
|
|
64
|
+
where: { id },
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Get raw credential from database bypassing Prisma encryption extension.
|
|
70
|
+
* Uses findRaw() to query MongoDB directly.
|
|
71
|
+
* @param {string} id
|
|
72
|
+
* @returns {Promise<Object|null>}
|
|
73
|
+
*/
|
|
74
|
+
async getRawCredentialById(id) {
|
|
75
|
+
if (!id) return null;
|
|
76
|
+
const results = await this.prisma.credential.findRaw({
|
|
77
|
+
filter: { _id: { $oid: id } },
|
|
78
|
+
});
|
|
79
|
+
return results[0] || null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async deleteCredential(id) {
|
|
83
|
+
await this.prisma.credential.delete({
|
|
84
|
+
where: { id },
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = { HealthCheckRepositoryMongoDB };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
const {
|
|
2
|
+
HealthCheckRepositoryInterface,
|
|
3
|
+
} = require('./health-check-repository-interface');
|
|
4
|
+
|
|
5
|
+
class HealthCheckRepositoryPostgreSQL extends HealthCheckRepositoryInterface {
|
|
6
|
+
/**
|
|
7
|
+
* @param {Object} params
|
|
8
|
+
* @param {Object} params.prismaClient - Prisma client instance
|
|
9
|
+
*/
|
|
10
|
+
constructor({ prismaClient }) {
|
|
11
|
+
super();
|
|
12
|
+
this.prisma = prismaClient;
|
|
13
|
+
}
|
|
14
|
+
|
|
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
|
+
|
|
30
|
+
return {
|
|
31
|
+
readyState: isConnected ? 1 : 0,
|
|
32
|
+
stateName,
|
|
33
|
+
isConnected,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @param {number} maxTimeMS
|
|
39
|
+
* @returns {Promise<number>} Response time in milliseconds
|
|
40
|
+
*/
|
|
41
|
+
async pingDatabase(maxTimeMS = 2000) {
|
|
42
|
+
const pingStart = Date.now();
|
|
43
|
+
await this.prisma.$queryRaw`SELECT 1`;
|
|
44
|
+
return Date.now() - pingStart;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async createCredential(credentialData) {
|
|
48
|
+
return await this.prisma.credential.create({
|
|
49
|
+
data: credentialData,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async findCredentialById(id) {
|
|
54
|
+
return await this.prisma.credential.findUnique({
|
|
55
|
+
where: { id },
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @param {string} id
|
|
61
|
+
* @returns {Promise<Object|null>}
|
|
62
|
+
*/
|
|
63
|
+
async getRawCredentialById(id) {
|
|
64
|
+
const results = await this.prisma.$queryRaw`
|
|
65
|
+
SELECT * FROM "Credential" WHERE id = ${id}
|
|
66
|
+
`;
|
|
67
|
+
|
|
68
|
+
if (!results || results.length === 0) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return results[0];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async deleteCredential(id) {
|
|
76
|
+
await this.prisma.credential.delete({
|
|
77
|
+
where: { id },
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
module.exports = { HealthCheckRepositoryPostgreSQL };
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration Status Repository - S3 Storage
|
|
3
|
+
*
|
|
4
|
+
* Infrastructure Layer - Hexagonal Architecture
|
|
5
|
+
*
|
|
6
|
+
* Stores migration status in S3 to avoid chicken-and-egg dependency on User/Process tables.
|
|
7
|
+
* Initial database migrations can't use Process table (requires User FK which doesn't exist yet).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const { S3Client, PutObjectCommand, GetObjectCommand } = require('@aws-sdk/client-s3');
|
|
11
|
+
const { randomUUID } = require('crypto');
|
|
12
|
+
|
|
13
|
+
class MigrationStatusRepositoryS3 {
|
|
14
|
+
/**
|
|
15
|
+
* @param {string} bucketName - S3 bucket name for migration status storage
|
|
16
|
+
* @param {S3Client} s3Client - Optional S3 client (for testing)
|
|
17
|
+
*/
|
|
18
|
+
constructor(bucketName, s3Client = null) {
|
|
19
|
+
this.bucketName = bucketName;
|
|
20
|
+
this.s3Client = s3Client || new S3Client({ region: process.env.AWS_REGION || 'us-east-1' });
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Build S3 key for migration status
|
|
25
|
+
* @param {string} migrationId - Migration identifier
|
|
26
|
+
* @param {string} stage - Deployment stage
|
|
27
|
+
* @returns {string} S3 key
|
|
28
|
+
*/
|
|
29
|
+
_buildS3Key(migrationId, stage) {
|
|
30
|
+
return `migrations/${stage}/${migrationId}.json`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Create new migration status record
|
|
35
|
+
* @param {Object} data - Migration data
|
|
36
|
+
* @param {string} [data.migrationId] - Migration ID (generates UUID if not provided)
|
|
37
|
+
* @param {string} data.stage - Deployment stage
|
|
38
|
+
* @param {string} [data.triggeredBy] - User or system that triggered migration
|
|
39
|
+
* @param {string} [data.triggeredAt] - ISO timestamp
|
|
40
|
+
* @returns {Promise<Object>} Created migration status
|
|
41
|
+
*/
|
|
42
|
+
async create(data) {
|
|
43
|
+
const migrationId = data.migrationId || randomUUID();
|
|
44
|
+
const timestamp = data.triggeredAt || new Date().toISOString();
|
|
45
|
+
|
|
46
|
+
const status = {
|
|
47
|
+
migrationId,
|
|
48
|
+
stage: data.stage,
|
|
49
|
+
state: 'INITIALIZING',
|
|
50
|
+
progress: 0,
|
|
51
|
+
triggeredBy: data.triggeredBy || 'system',
|
|
52
|
+
triggeredAt: timestamp,
|
|
53
|
+
createdAt: timestamp,
|
|
54
|
+
updatedAt: timestamp,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const key = this._buildS3Key(migrationId, data.stage);
|
|
58
|
+
|
|
59
|
+
await this.s3Client.send(
|
|
60
|
+
new PutObjectCommand({
|
|
61
|
+
Bucket: this.bucketName,
|
|
62
|
+
Key: key,
|
|
63
|
+
Body: JSON.stringify(status, null, 2),
|
|
64
|
+
ContentType: 'application/json',
|
|
65
|
+
})
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
return status;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Update existing migration status
|
|
73
|
+
* @param {Object} data - Update data
|
|
74
|
+
* @param {string} data.migrationId - Migration ID
|
|
75
|
+
* @param {string} data.stage - Deployment stage
|
|
76
|
+
* @param {string} [data.state] - New state
|
|
77
|
+
* @param {number} [data.progress] - Progress percentage (0-100)
|
|
78
|
+
* @param {string} [data.error] - Error message if failed
|
|
79
|
+
* @param {string} [data.completedAt] - Completion timestamp
|
|
80
|
+
* @returns {Promise<Object>} Updated migration status
|
|
81
|
+
*/
|
|
82
|
+
async update(data) {
|
|
83
|
+
const key = this._buildS3Key(data.migrationId, data.stage);
|
|
84
|
+
|
|
85
|
+
// Get existing status
|
|
86
|
+
const existing = await this.get(data.migrationId, data.stage);
|
|
87
|
+
|
|
88
|
+
// Merge updates
|
|
89
|
+
const updated = {
|
|
90
|
+
...existing,
|
|
91
|
+
...data,
|
|
92
|
+
updatedAt: new Date().toISOString(),
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
await this.s3Client.send(
|
|
96
|
+
new PutObjectCommand({
|
|
97
|
+
Bucket: this.bucketName,
|
|
98
|
+
Key: key,
|
|
99
|
+
Body: JSON.stringify(updated, null, 2),
|
|
100
|
+
ContentType: 'application/json',
|
|
101
|
+
})
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
return updated;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Get migration status by ID
|
|
109
|
+
* @param {string} migrationId - Migration ID
|
|
110
|
+
* @param {string} stage - Deployment stage
|
|
111
|
+
* @returns {Promise<Object>} Migration status
|
|
112
|
+
* @throws {Error} If migration not found
|
|
113
|
+
*/
|
|
114
|
+
async get(migrationId, stage) {
|
|
115
|
+
const key = this._buildS3Key(migrationId, stage);
|
|
116
|
+
|
|
117
|
+
try {
|
|
118
|
+
const response = await this.s3Client.send(
|
|
119
|
+
new GetObjectCommand({
|
|
120
|
+
Bucket: this.bucketName,
|
|
121
|
+
Key: key,
|
|
122
|
+
})
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const body = await response.Body.transformToString();
|
|
126
|
+
return JSON.parse(body);
|
|
127
|
+
} catch (error) {
|
|
128
|
+
if (error.name === 'NoSuchKey') {
|
|
129
|
+
throw new Error(`Migration not found: ${migrationId}`);
|
|
130
|
+
}
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
module.exports = { MigrationStatusRepositoryS3 };
|
|
137
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
class CheckDatabaseHealthUseCase {
|
|
2
|
+
/**
|
|
3
|
+
* @param {Object} params
|
|
4
|
+
* @param {import('../repositories/health-check-repository-interface').HealthCheckRepositoryInterface} params.healthCheckRepository
|
|
5
|
+
*/
|
|
6
|
+
constructor({ healthCheckRepository }) {
|
|
7
|
+
this.repository = healthCheckRepository;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @returns {Promise<{status: string, state: string, responseTime?: number}>}
|
|
12
|
+
*/
|
|
13
|
+
async execute() {
|
|
14
|
+
const { stateName, isConnected } = await this.repository.getDatabaseConnectionState();
|
|
15
|
+
|
|
16
|
+
const result = {
|
|
17
|
+
status: isConnected ? 'healthy' : 'unhealthy',
|
|
18
|
+
state: stateName,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
if (isConnected) {
|
|
22
|
+
result.responseTime = await this.repository.pingDatabase(2000);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return result;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports = { CheckDatabaseHealthUseCase };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check Database State Use Case
|
|
3
|
+
*
|
|
4
|
+
* Domain logic for checking database state (pending migrations, errors, etc).
|
|
5
|
+
* Does NOT trigger migrations, just reports current state.
|
|
6
|
+
*
|
|
7
|
+
* Architecture: Hexagonal/Clean
|
|
8
|
+
* - Use Case (Domain Layer)
|
|
9
|
+
* - Depends on prismaRunner (Infrastructure abstraction)
|
|
10
|
+
* - Called by Router or other Use Cases (Adapter Layer)
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
class ValidationError extends Error {
|
|
14
|
+
constructor(message) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = 'ValidationError';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
class CheckDatabaseStateUseCase {
|
|
21
|
+
/**
|
|
22
|
+
* @param {Object} dependencies
|
|
23
|
+
* @param {Object} dependencies.prismaRunner - Prisma runner utility
|
|
24
|
+
*/
|
|
25
|
+
constructor({ prismaRunner }) {
|
|
26
|
+
if (!prismaRunner) {
|
|
27
|
+
throw new Error('prismaRunner dependency is required');
|
|
28
|
+
}
|
|
29
|
+
this.prismaRunner = prismaRunner;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Execute check migration status
|
|
34
|
+
*
|
|
35
|
+
* @param {string} dbType - Database type (postgresql, mongodb, or documentdb)
|
|
36
|
+
* @param {string} stage - Deployment stage (default: 'production')
|
|
37
|
+
* @returns {Promise<Object>} Migration status
|
|
38
|
+
*/
|
|
39
|
+
async execute(dbType, stage = 'production') {
|
|
40
|
+
// Validate inputs
|
|
41
|
+
if (!dbType) {
|
|
42
|
+
throw new ValidationError('dbType is required');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!['postgresql', 'mongodb', 'documentdb'].includes(dbType)) {
|
|
46
|
+
throw new ValidationError('dbType must be postgresql, mongodb, or documentdb');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
console.log(`Checking migration status for ${dbType} in ${stage}`);
|
|
50
|
+
|
|
51
|
+
// Check database state using Prisma
|
|
52
|
+
const state = await this.prismaRunner.checkDatabaseState(dbType);
|
|
53
|
+
|
|
54
|
+
// Build response
|
|
55
|
+
const response = {
|
|
56
|
+
upToDate: state.upToDate,
|
|
57
|
+
pendingMigrations: state.pendingMigrations || 0,
|
|
58
|
+
dbType,
|
|
59
|
+
stage,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// Add error if present
|
|
63
|
+
if (state.error) {
|
|
64
|
+
response.error = state.error;
|
|
65
|
+
response.recommendation = 'Run POST /db-migrate to initialize database';
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Add recommendation if migrations pending
|
|
69
|
+
if (!state.upToDate && state.pendingMigrations > 0) {
|
|
70
|
+
response.recommendation = `Run POST /db-migrate to apply ${state.pendingMigrations} pending migration(s)`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return response;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
module.exports = {
|
|
78
|
+
CheckDatabaseStateUseCase,
|
|
79
|
+
ValidationError,
|
|
80
|
+
};
|
|
81
|
+
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
class CheckEncryptionHealthUseCase {
|
|
2
|
+
constructor({ testEncryptionUseCase }) {
|
|
3
|
+
this.testEncryptionUseCase = testEncryptionUseCase;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
async execute() {
|
|
7
|
+
const config = this._getEncryptionConfiguration();
|
|
8
|
+
|
|
9
|
+
if (config.isBypassed || config.mode === 'none') {
|
|
10
|
+
const testResult = config.isBypassed
|
|
11
|
+
? 'Encryption bypassed for this stage'
|
|
12
|
+
: 'No encryption keys configured';
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
status: 'disabled',
|
|
16
|
+
mode: config.mode,
|
|
17
|
+
bypassed: config.isBypassed,
|
|
18
|
+
stage: config.stage,
|
|
19
|
+
testResult,
|
|
20
|
+
encryptionWorks: false,
|
|
21
|
+
debug: {
|
|
22
|
+
hasKMS: config.hasKMS,
|
|
23
|
+
hasAES: config.hasAES,
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const testResults = await this.testEncryptionUseCase.execute();
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
...testResults,
|
|
33
|
+
mode: config.mode,
|
|
34
|
+
bypassed: config.isBypassed,
|
|
35
|
+
stage: config.stage,
|
|
36
|
+
debug: {
|
|
37
|
+
hasKMS: config.hasKMS,
|
|
38
|
+
hasAES: config.hasAES,
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
} catch (error) {
|
|
42
|
+
return {
|
|
43
|
+
status: 'unhealthy',
|
|
44
|
+
mode: config.mode,
|
|
45
|
+
bypassed: config.isBypassed,
|
|
46
|
+
stage: config.stage,
|
|
47
|
+
testResult: `Encryption test failed: ${error.message}`,
|
|
48
|
+
encryptionWorks: false,
|
|
49
|
+
debug: {
|
|
50
|
+
hasKMS: config.hasKMS,
|
|
51
|
+
hasAES: config.hasAES,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
_getEncryptionConfiguration() {
|
|
58
|
+
const { STAGE, BYPASS_ENCRYPTION_STAGE, KMS_KEY_ARN, AES_KEY_ID } =
|
|
59
|
+
process.env;
|
|
60
|
+
|
|
61
|
+
const defaultBypassStages = ['dev', 'test', 'local'];
|
|
62
|
+
const useEnv = BYPASS_ENCRYPTION_STAGE !== undefined;
|
|
63
|
+
const bypassStages = useEnv
|
|
64
|
+
? BYPASS_ENCRYPTION_STAGE.split(',').map((s) => s.trim())
|
|
65
|
+
: defaultBypassStages;
|
|
66
|
+
|
|
67
|
+
const isBypassed = bypassStages.includes(STAGE);
|
|
68
|
+
const hasAES = AES_KEY_ID && AES_KEY_ID.trim() !== '';
|
|
69
|
+
const hasKMS = KMS_KEY_ARN && KMS_KEY_ARN.trim() !== '';
|
|
70
|
+
// Prefer KMS over AES when both are configured (KMS is more secure)
|
|
71
|
+
const mode = hasKMS ? 'kms' : hasAES ? 'aes' : 'none';
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
stage: STAGE || null,
|
|
75
|
+
isBypassed,
|
|
76
|
+
hasAES,
|
|
77
|
+
hasKMS,
|
|
78
|
+
mode,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
module.exports = { CheckEncryptionHealthUseCase };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get Database State Via Worker Use Case
|
|
3
|
+
*
|
|
4
|
+
* Domain logic for getting database state by invoking the worker Lambda.
|
|
5
|
+
* This use case delegates to the worker Lambda which has Prisma CLI installed,
|
|
6
|
+
* keeping the router Lambda lightweight.
|
|
7
|
+
*
|
|
8
|
+
* Architecture: Hexagonal/Clean
|
|
9
|
+
* - Use Case (Domain Layer)
|
|
10
|
+
* - Depends on LambdaInvoker (Infrastructure abstraction)
|
|
11
|
+
* - Called by Router (Adapter Layer)
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Domain Use Case: Get database state by invoking worker Lambda
|
|
16
|
+
*
|
|
17
|
+
* This use case delegates database state checking to the worker Lambda,
|
|
18
|
+
* which has Prisma CLI installed. Keeps the router Lambda lightweight.
|
|
19
|
+
*/
|
|
20
|
+
class GetDatabaseStateViaWorkerUseCase {
|
|
21
|
+
/**
|
|
22
|
+
* @param {Object} dependencies
|
|
23
|
+
* @param {LambdaInvoker} dependencies.lambdaInvoker - Lambda invocation adapter
|
|
24
|
+
* @param {string} dependencies.workerFunctionName - Worker Lambda function name
|
|
25
|
+
*/
|
|
26
|
+
constructor({ lambdaInvoker, workerFunctionName }) {
|
|
27
|
+
if (!lambdaInvoker) {
|
|
28
|
+
throw new Error('lambdaInvoker dependency is required');
|
|
29
|
+
}
|
|
30
|
+
if (!workerFunctionName) {
|
|
31
|
+
throw new Error('workerFunctionName is required');
|
|
32
|
+
}
|
|
33
|
+
this.lambdaInvoker = lambdaInvoker;
|
|
34
|
+
this.workerFunctionName = workerFunctionName;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Execute database state check via worker Lambda
|
|
39
|
+
*
|
|
40
|
+
* @param {string} stage - Deployment stage (prod, dev, etc)
|
|
41
|
+
* @returns {Promise<Object>} Database state result
|
|
42
|
+
*/
|
|
43
|
+
async execute(stage = 'production') {
|
|
44
|
+
const dbType = process.env.DB_TYPE || 'postgresql';
|
|
45
|
+
|
|
46
|
+
console.log(`Invoking worker Lambda to check database state: ${this.workerFunctionName}`);
|
|
47
|
+
|
|
48
|
+
// Invoke worker Lambda with checkStatus action
|
|
49
|
+
const result = await this.lambdaInvoker.invoke(this.workerFunctionName, {
|
|
50
|
+
action: 'checkStatus',
|
|
51
|
+
dbType,
|
|
52
|
+
stage,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = { GetDatabaseStateViaWorkerUseCase };
|
|
60
|
+
|
|
61
|
+
|