@friggframework/core 2.0.0--canary.548.c8ae0ca.0 → 2.0.0--canary.545.c40eca4.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/CHANGELOG.md +66 -67
- package/CLAUDE.md +148 -124
- package/README.md +165 -130
- package/admin-scripts/index.js +52 -0
- package/admin-scripts/repositories/admin-api-key-repository-documentdb.js +21 -0
- package/admin-scripts/repositories/admin-api-key-repository-factory.js +51 -0
- package/admin-scripts/repositories/admin-api-key-repository-interface.js +121 -0
- package/admin-scripts/repositories/admin-api-key-repository-mongo.js +155 -0
- package/admin-scripts/repositories/admin-api-key-repository-postgres.js +189 -0
- package/admin-scripts/repositories/admin-process-repository-documentdb.js +21 -0
- package/admin-scripts/repositories/admin-process-repository-factory.js +49 -0
- package/admin-scripts/repositories/admin-process-repository-interface.js +150 -0
- package/admin-scripts/repositories/admin-process-repository-mongo.js +213 -0
- package/admin-scripts/repositories/admin-process-repository-postgres.js +251 -0
- package/admin-scripts/repositories/script-execution-repository-documentdb.js +21 -0
- package/admin-scripts/repositories/script-execution-repository-factory.js +51 -0
- package/admin-scripts/repositories/script-execution-repository-interface.js +193 -0
- package/admin-scripts/repositories/script-execution-repository-mongo.js +278 -0
- package/admin-scripts/repositories/script-execution-repository-postgres.js +320 -0
- package/admin-scripts/repositories/script-schedule-repository-documentdb.js +21 -0
- package/admin-scripts/repositories/script-schedule-repository-factory.js +49 -0
- package/admin-scripts/repositories/script-schedule-repository-interface.js +108 -0
- package/admin-scripts/repositories/script-schedule-repository-mongo.js +179 -0
- package/admin-scripts/repositories/script-schedule-repository-postgres.js +210 -0
- package/application/commands/admin-script-commands.js +348 -0
- package/application/commands/integration-commands.js +12 -6
- package/application/index.js +5 -3
- package/assertions/get.js +17 -7
- package/associations/association.js +59 -57
- package/core/CLAUDE.md +222 -156
- package/core/Worker.js +33 -12
- package/credential/credential-router.js +262 -0
- package/credential/repositories/credential-repository-documentdb.js +71 -1
- package/credential/repositories/credential-repository-factory.js +4 -6
- package/credential/repositories/credential-repository-interface.js +8 -2
- package/credential/repositories/credential-repository-mongo.js +45 -4
- package/credential/repositories/credential-repository-postgres.js +44 -3
- package/credential/repositories/credential-repository.js +3 -1
- package/credential/use-cases/delete-credential-for-user.js +50 -0
- package/credential/use-cases/get-credential-for-user.js +21 -3
- package/credential/use-cases/list-credentials-for-user.js +31 -0
- package/credential/use-cases/reauthorize-credential.js +103 -0
- package/credential/use-cases/update-authentication-status.js +5 -2
- package/database/MONGODB_TRANSACTION_FIX.md +72 -52
- package/database/config.js +13 -59
- package/database/documentdb-encryption-service.js +29 -13
- package/database/documentdb-utils.js +21 -12
- package/database/encryption/README.md +53 -36
- package/database/encryption/encryption-schema-registry.js +29 -23
- package/database/encryption/field-encryption-service.js +15 -4
- package/database/encryption/logger.js +3 -2
- package/database/encryption/prisma-encryption-extension.js +5 -8
- package/database/prisma.js +22 -14
- package/database/repositories/health-check-repository-factory.js +7 -5
- package/database/repositories/health-check-repository-interface.js +15 -5
- package/database/repositories/health-check-repository-postgres.js +1 -1
- package/database/use-cases/check-database-health-use-case.js +3 -2
- package/database/use-cases/check-database-state-use-case.js +8 -7
- package/database/use-cases/get-database-state-via-worker-use-case.js +15 -12
- package/database/use-cases/get-migration-status-use-case.js +4 -2
- package/database/use-cases/run-database-migration-use-case.js +41 -9
- package/database/use-cases/test-encryption-use-case.js +4 -5
- package/database/use-cases/trigger-database-migration-use-case.js +9 -8
- package/database/utils/mongodb-collection-utils.js +11 -3
- package/database/utils/mongodb-schema-init.js +10 -4
- package/database/utils/prisma-runner.js +144 -74
- package/database/utils/prisma-schema-parser.js +2 -2
- package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +135 -80
- package/encrypt/Cryptor.js +54 -49
- package/encrypt/aes-encryption-key-provider.js +82 -0
- package/encrypt/encryption-key-provider-interface.js +50 -0
- package/errors/fetch-error.js +1 -1
- package/generated/prisma-mongodb/edge.js +59 -4
- package/generated/prisma-mongodb/index-browser.js +49 -1
- package/generated/prisma-mongodb/index.d.ts +4023 -61
- package/generated/prisma-mongodb/index.js +59 -4
- package/generated/prisma-mongodb/package.json +1 -1
- package/generated/prisma-mongodb/schema.prisma +87 -0
- package/generated/prisma-mongodb/wasm.js +59 -4
- package/generated/prisma-postgresql/edge.js +58 -4
- package/generated/prisma-postgresql/index-browser.js +48 -1
- package/generated/prisma-postgresql/index.d.ts +4738 -54
- package/generated/prisma-postgresql/index.js +58 -4
- package/generated/prisma-postgresql/package.json +1 -1
- package/generated/prisma-postgresql/schema.prisma +85 -0
- package/generated/prisma-postgresql/wasm.js +58 -4
- package/handlers/WEBHOOKS.md +104 -81
- package/handlers/app-definition-loader.js +53 -10
- package/handlers/app-handler-helpers.js +14 -3
- package/handlers/backend-utils.js +0 -1
- package/handlers/database-migration-handler.js +64 -45
- package/handlers/middleware/admin-auth.js +53 -0
- package/handlers/routers/HEALTHCHECK.md +170 -135
- package/handlers/routers/admin.js +474 -0
- package/handlers/routers/auth.js +51 -9
- package/handlers/routers/db-migration.handler.js +2 -3
- package/handlers/routers/db-migration.js +102 -66
- package/handlers/routers/docs.js +180 -0
- package/handlers/routers/health.js +84 -283
- package/handlers/routers/integration-defined-routers.js +44 -33
- package/handlers/routers/integration-webhook-routers.js +73 -52
- package/handlers/routers/middleware/loadUser.js +39 -0
- package/handlers/routers/middleware/requireAdmin.js +43 -0
- package/handlers/routers/middleware/requireLoggedInUser.js +19 -0
- package/handlers/routers/user.js +30 -14
- package/handlers/routers/websocket.js +18 -4
- package/handlers/use-cases/check-integrations-health-use-case.js +13 -6
- package/handlers/workers/db-migration.js +74 -35
- package/handlers/workers/integration-defined-workers.js +31 -20
- package/index.js +50 -16
- package/infrastructure/scheduler/index.js +15 -11
- package/infrastructure/scheduler/netlify-scheduler-adapter.js +185 -0
- package/infrastructure/scheduler/scheduler-service-factory.js +38 -31
- package/integrations/WEBHOOK-QUICKSTART.md +21 -14
- package/integrations/index.js +4 -0
- package/integrations/integration-base.js +9 -6
- package/integrations/integration-router.js +1828 -157
- package/integrations/options.js +47 -20
- package/integrations/repositories/integration-mapping-repository-factory.js +4 -8
- package/integrations/repositories/integration-repository-documentdb.js +53 -24
- package/integrations/repositories/integration-repository-factory.js +6 -6
- package/integrations/repositories/integration-repository-interface.js +27 -9
- package/integrations/repositories/integration-repository-postgres.js +3 -3
- package/integrations/repositories/process-repository-factory.js +4 -7
- package/integrations/repositories/process-repository-interface.js +9 -5
- package/integrations/repositories/process-repository-mongo.js +7 -3
- package/integrations/repositories/process-repository-postgres.js +2 -2
- package/integrations/tests/doubles/config-capturing-integration.js +9 -8
- package/integrations/tests/doubles/dummy-integration-class.js +81 -8
- package/integrations/tests/doubles/test-integration-repository.js +51 -11
- package/integrations/use-cases/create-integration.js +36 -32
- package/integrations/use-cases/create-process.js +20 -9
- package/integrations/use-cases/delete-integration-for-user.js +5 -4
- package/integrations/use-cases/execute-proxy-request.js +564 -0
- package/integrations/use-cases/get-integration-for-user.js +25 -10
- package/integrations/use-cases/get-integration-instance-by-definition.js +13 -7
- package/integrations/use-cases/get-integrations-for-user.js +4 -1
- package/integrations/use-cases/get-possible-integrations.js +1 -1
- package/integrations/use-cases/get-process.js +5 -6
- package/integrations/use-cases/index.js +3 -1
- package/integrations/use-cases/load-integration-context.js +1 -5
- package/integrations/use-cases/update-process-state.js +10 -8
- package/integrations/utils/map-integration-dto.js +9 -3
- package/jest-setup.js +1 -1
- package/jest-teardown.js +1 -1
- package/lambda/TimeoutCatcher.js +32 -30
- package/lambda/index.js +1 -1
- package/logs/index.js +3 -3
- package/modules/domain/entities/AuthorizationSession.js +131 -0
- package/modules/domain/entities/index.js +10 -0
- package/modules/module.js +4 -9
- package/modules/repositories/authorization-session-repository-factory.js +53 -0
- package/modules/repositories/authorization-session-repository-interface.js +75 -0
- package/modules/repositories/authorization-session-repository-mongo.js +169 -0
- package/modules/repositories/authorization-session-repository-postgres.js +170 -0
- package/modules/repositories/module-repository-documentdb.js +89 -41
- package/modules/repositories/module-repository-factory.js +4 -6
- package/modules/repositories/module-repository-interface.js +13 -0
- package/modules/repositories/module-repository-mongo.js +40 -5
- package/modules/repositories/module-repository-postgres.js +42 -5
- package/modules/repositories/module-repository.js +28 -0
- package/modules/requester/api-key.js +0 -2
- package/modules/requester/basic.js +0 -1
- package/modules/requester/oauth-2.js +3 -14
- package/modules/test/mock-api/definition.js +15 -10
- package/modules/test/mock-api/mocks/hubspot.js +36 -36
- package/modules/tests/doubles/test-module-factory.js +10 -4
- package/modules/tests/doubles/test-module-repository.js +1 -1
- package/modules/use-cases/delete-module-entity.js +23 -0
- package/modules/use-cases/get-authorization-requirements.js +110 -0
- package/modules/use-cases/get-entities-for-user.js +1 -1
- package/modules/use-cases/get-entity-options-by-id.js +8 -6
- package/modules/use-cases/get-module-entity-by-id.js +16 -0
- package/modules/use-cases/get-module.js +12 -9
- package/modules/use-cases/process-authorization-callback.js +12 -6
- package/modules/use-cases/process-authorization-step.js +160 -0
- package/modules/use-cases/refresh-entity-options.js +8 -6
- package/modules/use-cases/start-authorization-session.js +86 -0
- package/modules/use-cases/test-module-auth.js +8 -6
- package/modules/use-cases/update-module-entity.js +27 -0
- package/modules/utils/map-module-dto.js +2 -2
- package/openapi/openapi-spec-generator.js +370 -0
- package/openapi/openapi-v1.yaml +1360 -0
- package/openapi/openapi-v2.yaml +1535 -0
- package/package.json +7 -9
- package/prisma-mongodb/schema.prisma +87 -0
- package/prisma-postgresql/migrations/20260222000000_add_admin_process_and_script_schedule/migration.sql +55 -0
- package/prisma-postgresql/schema.prisma +85 -0
- package/providers/index.js +13 -0
- package/providers/resolve-provider.js +93 -0
- package/queues/index.js +19 -0
- package/queues/providers/index.js +7 -0
- package/queues/providers/netlify-background-provider.js +76 -0
- package/queues/providers/qstash-queue-provider.js +122 -0
- package/queues/queue-client-interface.js +55 -0
- package/queues/queue-provider-factory.js +93 -0
- package/queues/queue-provider.js +46 -0
- package/queues/queuer-util.js +33 -25
- package/syncs/repositories/sync-repository-documentdb.js +39 -19
- package/syncs/repositories/sync-repository-factory.js +4 -4
- package/syncs/repositories/sync-repository-interface.js +6 -2
- package/syncs/repositories/sync-repository-postgres.js +19 -13
- package/syncs/sync.js +104 -100
- package/token/repositories/token-repository-factory.js +4 -6
- package/types/assertions/index.d.ts +72 -72
- package/types/core/index.d.ts +98 -53
- package/types/errors/index.d.ts +61 -54
- package/types/eslint-config/index.d.ts +40 -40
- package/types/lambda/index.d.ts +26 -26
- package/types/logs/index.d.ts +4 -4
- package/types/prettier-config/index.d.ts +5 -5
- package/types/test-environment/index.d.ts +14 -14
- package/types/tsconfig.json +95 -93
- package/user/repositories/user-repository-factory.js +4 -4
- package/user/tests/doubles/test-user-repository.js +5 -2
- package/user/use-cases/authenticate-user.js +2 -4
- package/user/use-cases/authenticate-with-shared-secret.js +1 -1
- package/user/use-cases/create-individual-user.js +8 -7
- package/user/use-cases/create-organization-user.js +1 -1
- package/user/use-cases/create-token-for-user-id.js +1 -1
- package/user/use-cases/delete-user.js +47 -0
- package/user/use-cases/get-user-from-adopter-jwt.js +0 -2
- package/user/use-cases/get-user-from-bearer-token.js +7 -3
- package/user/use-cases/get-user-from-x-frigg-headers.js +14 -11
- package/user/use-cases/login-user.js +8 -8
- package/user/user.js +18 -4
- package/utils/backend-path.js +2 -2
- package/utils/index.js +4 -1
- package/websocket/repositories/websocket-connection-repository-documentdb.js +46 -21
- package/websocket/repositories/websocket-connection-repository-factory.js +4 -8
- package/websocket/repositories/websocket-connection-repository-mongo.js +26 -16
- package/websocket/repositories/websocket-connection-repository-postgres.js +26 -15
- package/websocket/repositories/websocket-connection-repository.js +26 -20
- package/websocket/websocket-message-sender-interface.js +38 -0
- package/database/adapters/lambda-invoker.js +0 -97
- package/database/repositories/migration-status-repository-s3.js +0 -137
- package/infrastructure/scheduler/eventbridge-scheduler-adapter.js +0 -184
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const catchAsyncError = require('express-async-handler');
|
|
2
|
+
const {
|
|
3
|
+
GetUserFromBearerToken,
|
|
4
|
+
} = require('../../../user/use-cases/get-user-from-bearer-token');
|
|
5
|
+
const {
|
|
6
|
+
createUserRepository,
|
|
7
|
+
} = require('../../../user/repositories/user-repository-factory');
|
|
8
|
+
const { loadAppDefinition } = require('../../app-definition-loader');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Load user from bearer token middleware
|
|
12
|
+
* Uses DDD pattern: Handler → Use Case → Repository
|
|
13
|
+
*/
|
|
14
|
+
module.exports = catchAsyncError(async (req, res, next) => {
|
|
15
|
+
const authorizationHeader = req.headers.authorization;
|
|
16
|
+
|
|
17
|
+
if (authorizationHeader) {
|
|
18
|
+
// Initialize dependencies following DDD pattern
|
|
19
|
+
const { userConfig } = loadAppDefinition();
|
|
20
|
+
const userRepository = createUserRepository({ userConfig });
|
|
21
|
+
const getUserFromBearerToken = new GetUserFromBearerToken({
|
|
22
|
+
userRepository,
|
|
23
|
+
userConfig,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
// Execute use case to load user
|
|
28
|
+
req.user = await getUserFromBearerToken.execute(
|
|
29
|
+
authorizationHeader
|
|
30
|
+
);
|
|
31
|
+
} catch (error) {
|
|
32
|
+
// Don't fail - just leave req.user undefined
|
|
33
|
+
// Let requireLoggedInUser middleware handle auth failures
|
|
34
|
+
console.debug('Failed to load user from token:', error.message);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return next();
|
|
39
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Middleware to require admin API key authentication.
|
|
3
|
+
* Checks for x-frigg-admin-api-key header matching ADMIN_API_KEY environment variable.
|
|
4
|
+
* In non-production environments, allows all requests through for easier development.
|
|
5
|
+
*
|
|
6
|
+
* Uses the same header convention as validateAdminApiKey (handlers/middleware/admin-auth.js).
|
|
7
|
+
*
|
|
8
|
+
* @param {import('express').Request} req - Express request object
|
|
9
|
+
* @param {import('express').Response} res - Express response object
|
|
10
|
+
* @param {import('express').NextFunction} next - Express next middleware function
|
|
11
|
+
*/
|
|
12
|
+
const requireAdmin = (req, res, next) => {
|
|
13
|
+
// Allow access in local development (when NODE_ENV is not production)
|
|
14
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
15
|
+
console.log('[requireAdmin] Development mode - bypassing admin auth');
|
|
16
|
+
return next();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const apiKey = req.headers['x-frigg-admin-api-key'];
|
|
20
|
+
|
|
21
|
+
if (!apiKey) {
|
|
22
|
+
console.error('[requireAdmin] Missing x-frigg-admin-api-key header');
|
|
23
|
+
return res.status(401).json({
|
|
24
|
+
status: 'error',
|
|
25
|
+
message: 'Unauthorized - Admin API key required',
|
|
26
|
+
code: 'MISSING_API_KEY',
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (apiKey !== process.env.ADMIN_API_KEY) {
|
|
31
|
+
console.error('[requireAdmin] Invalid API key provided');
|
|
32
|
+
return res.status(401).json({
|
|
33
|
+
status: 'error',
|
|
34
|
+
message: 'Unauthorized - Invalid admin API key',
|
|
35
|
+
code: 'INVALID_API_KEY',
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
console.log('[requireAdmin] Admin authentication successful');
|
|
40
|
+
next();
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
module.exports = { requireAdmin };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const Boom = require('@hapi/boom');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Require logged in user middleware
|
|
5
|
+
* Ensures req.user was successfully loaded by loadUser middleware
|
|
6
|
+
*
|
|
7
|
+
* Uses DDD pattern: Middleware checks domain entity existence
|
|
8
|
+
* req.user is populated by loadUser middleware using GetUserFromBearerToken use case
|
|
9
|
+
*/
|
|
10
|
+
const requireLoggedInUser = (req, res, next) => {
|
|
11
|
+
// Check if user was successfully loaded by loadUser middleware
|
|
12
|
+
if (!req.user || !req.user.getId()) {
|
|
13
|
+
throw Boom.unauthorized('Invalid Token');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
next();
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
module.exports = { requireLoggedInUser };
|
package/handlers/routers/user.js
CHANGED
|
@@ -15,17 +15,33 @@ const catchAsyncError = require('express-async-handler');
|
|
|
15
15
|
const { loadAppDefinition } = require('../app-definition-loader');
|
|
16
16
|
|
|
17
17
|
const router = express();
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
18
|
+
|
|
19
|
+
// Lazy-initialized repositories and use cases (deferred until first request)
|
|
20
|
+
let _userRepository, _createIndividualUser, _loginUser, _createTokenForUserId;
|
|
21
|
+
|
|
22
|
+
function ensureInitialized() {
|
|
23
|
+
if (!_userRepository) {
|
|
24
|
+
const { userConfig } = loadAppDefinition();
|
|
25
|
+
_userRepository = createUserRepository();
|
|
26
|
+
_createIndividualUser = new CreateIndividualUser({
|
|
27
|
+
userRepository: _userRepository,
|
|
28
|
+
userConfig,
|
|
29
|
+
});
|
|
30
|
+
_loginUser = new LoginUser({
|
|
31
|
+
userRepository: _userRepository,
|
|
32
|
+
userConfig,
|
|
33
|
+
});
|
|
34
|
+
_createTokenForUserId = new CreateTokenForUserId({
|
|
35
|
+
userRepository: _userRepository,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Lazy initialization middleware — runs once on first request
|
|
41
|
+
router.use((req, res, next) => {
|
|
42
|
+
ensureInitialized();
|
|
43
|
+
next();
|
|
27
44
|
});
|
|
28
|
-
const createTokenForUserId = new CreateTokenForUserId({ userRepository });
|
|
29
45
|
|
|
30
46
|
// define the login endpoint
|
|
31
47
|
router.route('/user/login').post(
|
|
@@ -34,8 +50,8 @@ router.route('/user/login').post(
|
|
|
34
50
|
'username',
|
|
35
51
|
'password',
|
|
36
52
|
]);
|
|
37
|
-
const user = await
|
|
38
|
-
const token = await
|
|
53
|
+
const user = await _loginUser.execute({ username, password });
|
|
54
|
+
const token = await _createTokenForUserId.execute(user.getId(), 120);
|
|
39
55
|
res.status(201);
|
|
40
56
|
res.json({ token });
|
|
41
57
|
})
|
|
@@ -48,11 +64,11 @@ router.route('/user/create').post(
|
|
|
48
64
|
'password',
|
|
49
65
|
]);
|
|
50
66
|
|
|
51
|
-
const user = await
|
|
67
|
+
const user = await _createIndividualUser.execute({
|
|
52
68
|
username,
|
|
53
69
|
password,
|
|
54
70
|
});
|
|
55
|
-
const token = await
|
|
71
|
+
const token = await _createTokenForUserId.execute(user.getId(), 120);
|
|
56
72
|
res.status(201);
|
|
57
73
|
res.json({ token });
|
|
58
74
|
})
|
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
const { createHandler } = require('@friggframework/core');
|
|
2
|
-
const {
|
|
2
|
+
const {
|
|
3
|
+
createWebsocketConnectionRepository,
|
|
4
|
+
} = require('../../database/websocket-connection-repository-factory');
|
|
3
5
|
|
|
4
|
-
|
|
6
|
+
let _websocketConnectionRepository;
|
|
7
|
+
|
|
8
|
+
function getRepository() {
|
|
9
|
+
if (!_websocketConnectionRepository) {
|
|
10
|
+
_websocketConnectionRepository =
|
|
11
|
+
createWebsocketConnectionRepository();
|
|
12
|
+
}
|
|
13
|
+
return _websocketConnectionRepository;
|
|
14
|
+
}
|
|
5
15
|
|
|
6
16
|
const handleWebSocketConnection = async (event, context) => {
|
|
7
17
|
// Handle different WebSocket events
|
|
@@ -10,7 +20,9 @@ const handleWebSocketConnection = async (event, context) => {
|
|
|
10
20
|
// Handle new connection
|
|
11
21
|
try {
|
|
12
22
|
const connectionId = event.requestContext.connectionId;
|
|
13
|
-
await
|
|
23
|
+
await getRepository().createConnection(
|
|
24
|
+
connectionId
|
|
25
|
+
);
|
|
14
26
|
console.log(`Stored new connection: ${connectionId}`);
|
|
15
27
|
return { statusCode: 200, body: 'Connected.' };
|
|
16
28
|
} catch (error) {
|
|
@@ -22,7 +34,9 @@ const handleWebSocketConnection = async (event, context) => {
|
|
|
22
34
|
// Handle disconnection
|
|
23
35
|
try {
|
|
24
36
|
const connectionId = event.requestContext.connectionId;
|
|
25
|
-
await
|
|
37
|
+
await getRepository().deleteConnection(
|
|
38
|
+
connectionId
|
|
39
|
+
);
|
|
26
40
|
console.log(`Removed connection: ${connectionId}`);
|
|
27
41
|
return { statusCode: 200, body: 'Disconnected.' };
|
|
28
42
|
} catch (error) {
|
|
@@ -5,9 +5,10 @@ class CheckIntegrationsHealthUseCase {
|
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
execute() {
|
|
8
|
-
const moduleDefinitions =
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
const moduleDefinitions =
|
|
9
|
+
this.moduleFactory && this.moduleFactory.moduleDefinitions
|
|
10
|
+
? this.moduleFactory.moduleDefinitions
|
|
11
|
+
: [];
|
|
11
12
|
|
|
12
13
|
const integrationClasses = Array.isArray(this.integrationClasses)
|
|
13
14
|
? this.integrationClasses
|
|
@@ -15,13 +16,19 @@ class CheckIntegrationsHealthUseCase {
|
|
|
15
16
|
|
|
16
17
|
// Extract module names from definitions
|
|
17
18
|
const moduleTypes = Array.isArray(moduleDefinitions)
|
|
18
|
-
? moduleDefinitions.map(
|
|
19
|
+
? moduleDefinitions.map(
|
|
20
|
+
(def) => def.moduleName || def.name || def.label || 'Unknown'
|
|
21
|
+
)
|
|
19
22
|
: [];
|
|
20
23
|
|
|
21
24
|
// Extract integration names from classes
|
|
22
|
-
const integrationNames = integrationClasses.map(IntegrationClass => {
|
|
25
|
+
const integrationNames = integrationClasses.map((IntegrationClass) => {
|
|
23
26
|
try {
|
|
24
|
-
return
|
|
27
|
+
return (
|
|
28
|
+
IntegrationClass.Definition?.name ||
|
|
29
|
+
IntegrationClass.name ||
|
|
30
|
+
'Unknown'
|
|
31
|
+
);
|
|
25
32
|
} catch {
|
|
26
33
|
return 'Unknown';
|
|
27
34
|
}
|
|
@@ -49,16 +49,28 @@ const {
|
|
|
49
49
|
const {
|
|
50
50
|
CheckDatabaseStateUseCase,
|
|
51
51
|
} = require('../../database/use-cases/check-database-state-use-case');
|
|
52
|
-
const {
|
|
53
|
-
MigrationStatusRepositoryS3,
|
|
54
|
-
} = require('../../database/repositories/migration-status-repository-s3');
|
|
55
|
-
|
|
56
52
|
// Inject prisma-runner as dependency
|
|
57
53
|
const prismaRunner = require('../../database/utils/prisma-runner');
|
|
58
54
|
|
|
59
|
-
//
|
|
60
|
-
const
|
|
61
|
-
|
|
55
|
+
// Migration status repository is loaded from the resolved provider.
|
|
56
|
+
const { resolveProvider } = require('../../providers/resolve-provider');
|
|
57
|
+
|
|
58
|
+
let _migrationStatusRepository = null;
|
|
59
|
+
function getMigrationStatusRepository() {
|
|
60
|
+
if (!_migrationStatusRepository) {
|
|
61
|
+
const provider = resolveProvider();
|
|
62
|
+
const MigrationStatusRepository = provider.MigrationStatusRepositoryS3;
|
|
63
|
+
if (!MigrationStatusRepository) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
`Provider '${provider.name}' does not export a MigrationStatusRepository`
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
const bucketName =
|
|
69
|
+
process.env.S3_BUCKET_NAME || process.env.MIGRATION_STATUS_BUCKET;
|
|
70
|
+
_migrationStatusRepository = new MigrationStatusRepository(bucketName);
|
|
71
|
+
}
|
|
72
|
+
return _migrationStatusRepository;
|
|
73
|
+
}
|
|
62
74
|
|
|
63
75
|
/**
|
|
64
76
|
* Sanitizes error messages to prevent credential leaks
|
|
@@ -68,19 +80,27 @@ const migrationStatusRepository = new MigrationStatusRepositoryS3(bucketName);
|
|
|
68
80
|
function sanitizeError(errorMessage) {
|
|
69
81
|
if (!errorMessage) return 'Unknown error';
|
|
70
82
|
|
|
71
|
-
return
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
83
|
+
return (
|
|
84
|
+
String(errorMessage)
|
|
85
|
+
// Remove PostgreSQL connection strings
|
|
86
|
+
.replace(
|
|
87
|
+
/postgresql:\/\/[^@\s]+@[^\s/]+/gi,
|
|
88
|
+
'postgresql://***:***@***'
|
|
89
|
+
)
|
|
90
|
+
// Remove MongoDB connection strings
|
|
91
|
+
.replace(
|
|
92
|
+
/mongodb(\+srv)?:\/\/[^@\s]+@[^\s/]+/gi,
|
|
93
|
+
'mongodb$1://***:***@***'
|
|
94
|
+
)
|
|
95
|
+
// Remove password parameters
|
|
96
|
+
.replace(/password[=:]\s*[^\s,;)]+/gi, 'password=***')
|
|
97
|
+
// Remove API keys
|
|
98
|
+
.replace(/apikey[=:]\s*[^\s,;)]+/gi, 'apikey=***')
|
|
99
|
+
.replace(/api[_-]?key[=:]\s*[^\s,;)]+/gi, 'api_key=***')
|
|
100
|
+
// Remove tokens
|
|
101
|
+
.replace(/token[=:]\s*[^\s,;)]+/gi, 'token=***')
|
|
102
|
+
.replace(/bearer\s+[^\s,;)]+/gi, 'bearer ***')
|
|
103
|
+
);
|
|
84
104
|
}
|
|
85
105
|
|
|
86
106
|
/**
|
|
@@ -145,11 +165,18 @@ exports.handler = async (event, context) => {
|
|
|
145
165
|
console.log('Database Migration Lambda Started');
|
|
146
166
|
console.log('========================================');
|
|
147
167
|
console.log('Event:', JSON.stringify(event, null, 2));
|
|
148
|
-
console.log(
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
168
|
+
console.log(
|
|
169
|
+
'Context:',
|
|
170
|
+
JSON.stringify(
|
|
171
|
+
{
|
|
172
|
+
requestId: context.requestId,
|
|
173
|
+
functionName: context.functionName,
|
|
174
|
+
remainingTimeInMillis: context.getRemainingTimeInMillis(),
|
|
175
|
+
},
|
|
176
|
+
null,
|
|
177
|
+
2
|
|
178
|
+
)
|
|
179
|
+
);
|
|
153
180
|
|
|
154
181
|
// Extract migration parameters from event
|
|
155
182
|
const { migrationId, dbType, stage } = extractMigrationParams(event);
|
|
@@ -164,7 +191,9 @@ exports.handler = async (event, context) => {
|
|
|
164
191
|
console.log(`========================================`);
|
|
165
192
|
|
|
166
193
|
try {
|
|
167
|
-
const checkDbStateUseCase = new CheckDatabaseStateUseCase({
|
|
194
|
+
const checkDbStateUseCase = new CheckDatabaseStateUseCase({
|
|
195
|
+
prismaRunner,
|
|
196
|
+
});
|
|
168
197
|
const status = await checkDbStateUseCase.execute(dbType, stage);
|
|
169
198
|
|
|
170
199
|
console.log('✓ Database state check completed');
|
|
@@ -217,8 +246,10 @@ exports.handler = async (event, context) => {
|
|
|
217
246
|
|
|
218
247
|
// Update migration status to RUNNING (if migrationId provided)
|
|
219
248
|
if (migrationId) {
|
|
220
|
-
console.log(
|
|
221
|
-
|
|
249
|
+
console.log(
|
|
250
|
+
`\n✓ Updating migration status to RUNNING: ${migrationId}`
|
|
251
|
+
);
|
|
252
|
+
await getMigrationStatusRepository().update({
|
|
222
253
|
migrationId,
|
|
223
254
|
stage,
|
|
224
255
|
state: 'RUNNING',
|
|
@@ -255,8 +286,10 @@ exports.handler = async (event, context) => {
|
|
|
255
286
|
|
|
256
287
|
// Update migration status to COMPLETED (if migrationId provided)
|
|
257
288
|
if (migrationId) {
|
|
258
|
-
console.log(
|
|
259
|
-
|
|
289
|
+
console.log(
|
|
290
|
+
`\n✓ Updating migration status to COMPLETED: ${migrationId}`
|
|
291
|
+
);
|
|
292
|
+
await getMigrationStatusRepository().update({
|
|
260
293
|
migrationId,
|
|
261
294
|
stage,
|
|
262
295
|
state: 'COMPLETED',
|
|
@@ -284,7 +317,6 @@ exports.handler = async (event, context) => {
|
|
|
284
317
|
statusCode: 200,
|
|
285
318
|
body: JSON.stringify(responseBody),
|
|
286
319
|
};
|
|
287
|
-
|
|
288
320
|
} catch (error) {
|
|
289
321
|
console.error('\n========================================');
|
|
290
322
|
console.error('Migration Failed');
|
|
@@ -317,8 +349,10 @@ exports.handler = async (event, context) => {
|
|
|
317
349
|
// Update migration status to FAILED (if migrationId provided)
|
|
318
350
|
if (migrationId) {
|
|
319
351
|
try {
|
|
320
|
-
console.log(
|
|
321
|
-
|
|
352
|
+
console.log(
|
|
353
|
+
`\n✓ Updating migration status to FAILED: ${migrationId}`
|
|
354
|
+
);
|
|
355
|
+
await getMigrationStatusRepository().update({
|
|
322
356
|
migrationId,
|
|
323
357
|
stage,
|
|
324
358
|
state: 'FAILED',
|
|
@@ -327,7 +361,10 @@ exports.handler = async (event, context) => {
|
|
|
327
361
|
failedAt: new Date().toISOString(),
|
|
328
362
|
});
|
|
329
363
|
} catch (updateError) {
|
|
330
|
-
console.error(
|
|
364
|
+
console.error(
|
|
365
|
+
'Failed to update migration status:',
|
|
366
|
+
updateError.message
|
|
367
|
+
);
|
|
331
368
|
// Continue - don't let status update failure block error response
|
|
332
369
|
}
|
|
333
370
|
}
|
|
@@ -337,7 +374,9 @@ exports.handler = async (event, context) => {
|
|
|
337
374
|
error: sanitizedError,
|
|
338
375
|
errorType: error.name || 'Error',
|
|
339
376
|
// Only include stack traces in development environments
|
|
340
|
-
...(stage === 'dev' || stage === 'local' || stage === 'test'
|
|
377
|
+
...(stage === 'dev' || stage === 'local' || stage === 'test'
|
|
378
|
+
? { stack: error.stack }
|
|
379
|
+
: {}),
|
|
341
380
|
};
|
|
342
381
|
|
|
343
382
|
if (migrationId) {
|
|
@@ -2,26 +2,37 @@ const { createHandler } = require('@friggframework/core');
|
|
|
2
2
|
const { loadAppDefinition } = require('../app-definition-loader');
|
|
3
3
|
const { createQueueWorker } = require('../backend-utils');
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
const { integrations: integrationClasses } = loadAppDefinition();
|
|
5
|
+
let _handlers;
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
function ensureHandlers() {
|
|
8
|
+
if (!_handlers) {
|
|
9
|
+
_handlers = {};
|
|
10
|
+
const { integrations: integrationClasses } = loadAppDefinition();
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
eventName: `Queue Worker for ${IntegrationClass.Definition.name}`,
|
|
14
|
-
isUserFacingResponse: false,
|
|
15
|
-
method: async (event, context) => {
|
|
16
|
-
const worker = new defaultQueueWorker();
|
|
17
|
-
await worker.run(event, context);
|
|
18
|
-
return {
|
|
19
|
-
message: 'Successfully processed the Generic Queue Worker',
|
|
20
|
-
input: event,
|
|
21
|
-
};
|
|
22
|
-
},
|
|
23
|
-
}),
|
|
24
|
-
};
|
|
25
|
-
});
|
|
12
|
+
integrationClasses.forEach((IntegrationClass) => {
|
|
13
|
+
const defaultQueueWorker = createQueueWorker(IntegrationClass);
|
|
26
14
|
|
|
27
|
-
|
|
15
|
+
_handlers[`${IntegrationClass.Definition.name}`] = {
|
|
16
|
+
queueWorker: createHandler({
|
|
17
|
+
eventName: `Queue Worker for ${IntegrationClass.Definition.name}`,
|
|
18
|
+
isUserFacingResponse: false,
|
|
19
|
+
method: async (event, context) => {
|
|
20
|
+
const worker = new defaultQueueWorker();
|
|
21
|
+
await worker.run(event, context);
|
|
22
|
+
return {
|
|
23
|
+
message: 'Successfully processed the Generic Queue Worker',
|
|
24
|
+
input: event,
|
|
25
|
+
};
|
|
26
|
+
},
|
|
27
|
+
}),
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return _handlers;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
module.exports = {
|
|
35
|
+
get handlers() {
|
|
36
|
+
return ensureHandlers();
|
|
37
|
+
},
|
|
38
|
+
};
|
package/index.js
CHANGED
|
@@ -21,7 +21,6 @@ const {
|
|
|
21
21
|
} = require('./database/index');
|
|
22
22
|
const {
|
|
23
23
|
createUserRepository,
|
|
24
|
-
UserRepositoryMongo,
|
|
25
24
|
UserRepositoryPostgres,
|
|
26
25
|
} = require('./user/repositories/user-repository-factory');
|
|
27
26
|
const {
|
|
@@ -30,9 +29,7 @@ const {
|
|
|
30
29
|
const {
|
|
31
30
|
GetUserFromAdopterJwt,
|
|
32
31
|
} = require('./user/use-cases/get-user-from-adopter-jwt');
|
|
33
|
-
const {
|
|
34
|
-
AuthenticateUser,
|
|
35
|
-
} = require('./user/use-cases/authenticate-user');
|
|
32
|
+
const { AuthenticateUser } = require('./user/use-cases/authenticate-user');
|
|
36
33
|
|
|
37
34
|
const {
|
|
38
35
|
CredentialRepository,
|
|
@@ -43,18 +40,14 @@ const {
|
|
|
43
40
|
const {
|
|
44
41
|
IntegrationMappingRepository,
|
|
45
42
|
} = require('./integrations/repositories/integration-mapping-repository');
|
|
46
|
-
const {
|
|
47
|
-
CreateProcess,
|
|
48
|
-
} = require('./integrations/use-cases/create-process');
|
|
43
|
+
const { CreateProcess } = require('./integrations/use-cases/create-process');
|
|
49
44
|
const {
|
|
50
45
|
UpdateProcessState,
|
|
51
46
|
} = require('./integrations/use-cases/update-process-state');
|
|
52
47
|
const {
|
|
53
48
|
UpdateProcessMetrics,
|
|
54
49
|
} = require('./integrations/use-cases/update-process-metrics');
|
|
55
|
-
const {
|
|
56
|
-
GetProcess,
|
|
57
|
-
} = require('./integrations/use-cases/get-process');
|
|
50
|
+
const { GetProcess } = require('./integrations/use-cases/get-process');
|
|
58
51
|
const { Cryptor } = require('./encrypt');
|
|
59
52
|
const {
|
|
60
53
|
BaseError,
|
|
@@ -70,12 +63,11 @@ const {
|
|
|
70
63
|
checkRequiredParams,
|
|
71
64
|
getModulesDefinitionFromIntegrationClasses,
|
|
72
65
|
LoadIntegrationContextUseCase,
|
|
66
|
+
createProcessRepository,
|
|
73
67
|
} = require('./integrations/index');
|
|
74
68
|
const { TimeoutCatcher } = require('./lambda/index');
|
|
75
69
|
const { debug, initDebugLog, flushDebugLog } = require('./logs/index');
|
|
76
70
|
const {
|
|
77
|
-
Credential,
|
|
78
|
-
Entity,
|
|
79
71
|
ApiKeyRequester,
|
|
80
72
|
BasicAuthRequester,
|
|
81
73
|
OAuth2Requester,
|
|
@@ -86,7 +78,31 @@ const {
|
|
|
86
78
|
const application = require('./application');
|
|
87
79
|
const utils = require('./utils');
|
|
88
80
|
|
|
89
|
-
const {
|
|
81
|
+
const {
|
|
82
|
+
QueuerUtil,
|
|
83
|
+
QueueProvider,
|
|
84
|
+
QueueClientInterface,
|
|
85
|
+
createQueueProvider,
|
|
86
|
+
QUEUE_PROVIDERS,
|
|
87
|
+
} = require('./queues');
|
|
88
|
+
|
|
89
|
+
const {
|
|
90
|
+
EncryptionKeyProviderInterface,
|
|
91
|
+
} = require('./encrypt/encryption-key-provider-interface');
|
|
92
|
+
const {
|
|
93
|
+
AesEncryptionKeyProvider,
|
|
94
|
+
} = require('./encrypt/aes-encryption-key-provider');
|
|
95
|
+
const {
|
|
96
|
+
WebSocketMessageSenderInterface,
|
|
97
|
+
StaleConnectionError,
|
|
98
|
+
} = require('./websocket/websocket-message-sender-interface');
|
|
99
|
+
|
|
100
|
+
const {
|
|
101
|
+
resolveProvider,
|
|
102
|
+
determineProviderName,
|
|
103
|
+
providerPackageName,
|
|
104
|
+
KNOWN_PROVIDERS,
|
|
105
|
+
} = require('./providers');
|
|
90
106
|
|
|
91
107
|
module.exports = {
|
|
92
108
|
// assertions
|
|
@@ -110,7 +126,7 @@ module.exports = {
|
|
|
110
126
|
TokenRepository,
|
|
111
127
|
WebsocketConnectionRepository,
|
|
112
128
|
createUserRepository,
|
|
113
|
-
UserRepositoryMongo,
|
|
129
|
+
get UserRepositoryMongo() { return require('./user/repositories/user-repository-factory').UserRepositoryMongo; },
|
|
114
130
|
UserRepositoryPostgres,
|
|
115
131
|
GetUserFromXFriggHeaders,
|
|
116
132
|
GetUserFromAdopterJwt,
|
|
@@ -138,6 +154,7 @@ module.exports = {
|
|
|
138
154
|
UpdateProcessState,
|
|
139
155
|
UpdateProcessMetrics,
|
|
140
156
|
GetProcess,
|
|
157
|
+
createProcessRepository,
|
|
141
158
|
|
|
142
159
|
// application - Command factories for integration developers
|
|
143
160
|
application,
|
|
@@ -147,6 +164,7 @@ module.exports = {
|
|
|
147
164
|
createEntityCommands: application.createEntityCommands,
|
|
148
165
|
createCredentialCommands: application.createCredentialCommands,
|
|
149
166
|
createSchedulerCommands: application.createSchedulerCommands,
|
|
167
|
+
createAdminScriptCommands: application.createAdminScriptCommands,
|
|
150
168
|
findIntegrationContextByExternalEntityId:
|
|
151
169
|
application.findIntegrationContextByExternalEntityId,
|
|
152
170
|
integrationCommands: application.integrationCommands,
|
|
@@ -160,8 +178,6 @@ module.exports = {
|
|
|
160
178
|
flushDebugLog,
|
|
161
179
|
|
|
162
180
|
// module plugin
|
|
163
|
-
Credential,
|
|
164
|
-
Entity,
|
|
165
181
|
ApiKeyRequester,
|
|
166
182
|
BasicAuthRequester,
|
|
167
183
|
OAuth2Requester,
|
|
@@ -170,6 +186,24 @@ module.exports = {
|
|
|
170
186
|
ModuleFactory,
|
|
171
187
|
// queues
|
|
172
188
|
QueuerUtil,
|
|
189
|
+
QueueProvider,
|
|
190
|
+
QueueClientInterface,
|
|
191
|
+
createQueueProvider,
|
|
192
|
+
QUEUE_PROVIDERS,
|
|
193
|
+
|
|
194
|
+
// encryption interfaces
|
|
195
|
+
EncryptionKeyProviderInterface,
|
|
196
|
+
AesEncryptionKeyProvider,
|
|
197
|
+
|
|
198
|
+
// websocket interfaces
|
|
199
|
+
WebSocketMessageSenderInterface,
|
|
200
|
+
StaleConnectionError,
|
|
201
|
+
|
|
202
|
+
// providers
|
|
203
|
+
resolveProvider,
|
|
204
|
+
determineProviderName,
|
|
205
|
+
providerPackageName,
|
|
206
|
+
KNOWN_PROVIDERS,
|
|
173
207
|
|
|
174
208
|
// utils
|
|
175
209
|
...utils,
|