@friggframework/core 2.0.0--canary.522.cbd3d5a.0 → 2.0.0--canary.517.35ee143.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 +67 -66
- package/CLAUDE.md +124 -148
- package/README.md +130 -165
- package/admin-scripts/index.js +16 -30
- package/admin-scripts/repositories/{admin-api-key-repository-documentdb.js → admin-process-repository-documentdb.js} +5 -5
- package/admin-scripts/repositories/{admin-api-key-repository-factory.js → admin-process-repository-factory.js} +15 -19
- 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-schedule-repository-factory.js +2 -6
- package/admin-scripts/repositories/script-schedule-repository-interface.js +14 -36
- package/admin-scripts/repositories/script-schedule-repository-mongo.js +13 -25
- package/admin-scripts/repositories/script-schedule-repository-postgres.js +13 -25
- package/application/commands/admin-script-commands.js +102 -266
- package/application/commands/integration-commands.js +6 -12
- package/application/index.js +3 -1
- package/assertions/get.js +4 -1
- package/associations/association.js +57 -59
- package/associations/model.js +41 -41
- package/core/CLAUDE.md +156 -222
- package/core/Worker.js +1 -5
- package/credential/repositories/credential-repository-documentdb.js +1 -71
- package/credential/repositories/credential-repository-interface.js +2 -8
- package/credential/repositories/credential-repository-mongo.js +4 -45
- package/credential/repositories/credential-repository-postgres.js +3 -44
- package/credential/repositories/credential-repository.js +4 -6
- package/credential/use-cases/get-credential-for-user.js +3 -21
- package/credential/use-cases/update-authentication-status.js +2 -5
- package/database/MONGODB_TRANSACTION_FIX.md +52 -72
- package/database/adapters/lambda-invoker.js +7 -8
- package/database/config.js +13 -15
- package/database/documentdb-encryption-service.js +13 -29
- package/database/documentdb-utils.js +12 -21
- package/database/encryption/README.md +36 -53
- package/database/encryption/encryption-schema-registry.js +9 -21
- package/database/encryption/field-encryption-service.js +4 -15
- package/database/encryption/logger.js +2 -3
- package/database/encryption/prisma-encryption-extension.js +8 -5
- package/database/index.js +2 -4
- package/database/models/IndividualUser.js +15 -15
- package/database/models/OrganizationUser.js +4 -6
- package/database/models/UserModel.js +2 -2
- package/database/models/WebsocketConnection.js +1 -4
- package/database/mongoose.js +2 -2
- package/database/prisma.js +14 -22
- package/database/repositories/health-check-repository-documentdb.js +7 -22
- package/database/repositories/health-check-repository-factory.js +3 -9
- package/database/repositories/health-check-repository-interface.js +5 -15
- package/database/repositories/health-check-repository-mongodb.js +6 -9
- package/database/repositories/health-check-repository-postgres.js +1 -1
- package/database/repositories/migration-status-repository-s3.js +5 -10
- package/database/use-cases/check-database-health-use-case.js +2 -3
- package/database/use-cases/check-database-state-use-case.js +7 -9
- package/database/use-cases/get-database-state-via-worker-use-case.js +12 -15
- package/database/use-cases/get-migration-status-use-case.js +2 -4
- package/database/use-cases/run-database-migration-use-case.js +9 -41
- package/database/use-cases/test-encryption-use-case.js +5 -4
- package/database/use-cases/trigger-database-migration-use-case.js +8 -9
- package/database/utils/mongodb-collection-utils.js +3 -11
- package/database/utils/mongodb-schema-init.js +4 -10
- package/database/utils/prisma-runner.js +74 -144
- package/database/utils/prisma-schema-parser.js +2 -2
- package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +80 -135
- package/encrypt/Cryptor.js +2 -8
- package/errors/fetch-error.js +1 -1
- package/generated/prisma-mongodb/edge.js +16 -59
- package/generated/prisma-mongodb/index-browser.js +12 -62
- package/generated/prisma-mongodb/index.d.ts +4850 -8136
- package/generated/prisma-mongodb/index.js +16 -59
- package/generated/prisma-mongodb/package.json +1 -1
- package/generated/prisma-mongodb/schema.prisma +33 -75
- package/generated/prisma-mongodb/wasm.js +16 -59
- package/generated/prisma-postgresql/edge.js +15 -59
- package/generated/prisma-postgresql/index-browser.js +11 -62
- package/generated/prisma-postgresql/index.d.ts +5963 -8930
- package/generated/prisma-postgresql/index.js +15 -59
- package/generated/prisma-postgresql/package.json +1 -1
- package/generated/prisma-postgresql/schema.prisma +33 -73
- package/generated/prisma-postgresql/wasm.js +15 -59
- package/handlers/WEBHOOKS.md +81 -104
- package/handlers/app-definition-loader.js +1 -1
- package/handlers/app-handler-helpers.js +2 -14
- package/handlers/backend-utils.js +1 -0
- package/handlers/database-migration-handler.js +45 -64
- package/handlers/middleware/admin-auth.js +53 -0
- package/handlers/routers/HEALTHCHECK.md +135 -170
- package/handlers/routers/auth.js +2 -23
- package/handlers/routers/db-migration.handler.js +3 -2
- package/handlers/routers/db-migration.js +33 -69
- package/handlers/routers/health.js +8 -23
- package/handlers/routers/integration-defined-routers.js +4 -4
- package/handlers/routers/integration-webhook-routers.js +7 -17
- package/handlers/routers/websocket.js +3 -9
- package/handlers/use-cases/check-integrations-health-use-case.js +6 -13
- package/handlers/workers/db-migration.js +26 -54
- package/index.js +9 -5
- package/integrations/WEBHOOK-QUICKSTART.md +14 -21
- package/integrations/index.js +0 -4
- package/integrations/integration-base.js +6 -9
- package/integrations/integration-router.js +146 -1817
- package/integrations/options.js +20 -47
- package/integrations/repositories/integration-repository-documentdb.js +24 -53
- package/integrations/repositories/integration-repository-factory.js +2 -6
- package/integrations/repositories/integration-repository-interface.js +9 -27
- package/integrations/repositories/integration-repository-postgres.js +3 -3
- package/integrations/repositories/process-repository-factory.js +1 -0
- package/integrations/repositories/process-repository-interface.js +5 -9
- package/integrations/repositories/process-repository-mongo.js +3 -7
- package/integrations/repositories/process-repository-postgres.js +2 -2
- package/integrations/tests/doubles/config-capturing-integration.js +8 -9
- package/integrations/tests/doubles/dummy-integration-class.js +8 -81
- package/integrations/tests/doubles/test-integration-repository.js +11 -51
- package/integrations/use-cases/create-integration.js +32 -36
- package/integrations/use-cases/create-process.js +9 -20
- package/integrations/use-cases/delete-integration-for-user.js +4 -5
- package/integrations/use-cases/get-integration-for-user.js +10 -25
- package/integrations/use-cases/get-integration-instance-by-definition.js +7 -13
- package/integrations/use-cases/get-integrations-for-user.js +1 -4
- package/integrations/use-cases/get-possible-integrations.js +1 -1
- package/integrations/use-cases/get-process.js +6 -5
- package/integrations/use-cases/index.js +1 -3
- package/integrations/use-cases/load-integration-context.js +5 -1
- package/integrations/use-cases/update-process-state.js +8 -10
- package/integrations/utils/map-integration-dto.js +3 -9
- package/jest-setup.js +1 -1
- package/jest-teardown.js +1 -1
- package/lambda/TimeoutCatcher.js +30 -32
- package/lambda/index.js +1 -1
- package/logs/index.js +3 -3
- package/modules/module.js +1 -3
- package/modules/repositories/module-repository-documentdb.js +48 -114
- package/modules/repositories/module-repository-interface.js +0 -13
- package/modules/repositories/module-repository-mongo.js +6 -46
- package/modules/repositories/module-repository-postgres.js +6 -48
- package/modules/repositories/module-repository.js +1 -34
- package/modules/requester/api-key.js +2 -0
- package/modules/requester/basic.js +1 -0
- package/modules/requester/oauth-2.js +2 -3
- package/modules/test/mock-api/definition.js +10 -15
- package/modules/test/mock-api/mocks/hubspot.js +36 -36
- package/modules/tests/doubles/test-module-factory.js +4 -10
- package/modules/tests/doubles/test-module-repository.js +1 -1
- package/modules/use-cases/get-entities-for-user.js +1 -1
- package/modules/use-cases/get-entity-options-by-id.js +6 -8
- package/modules/use-cases/get-module.js +9 -12
- package/modules/use-cases/process-authorization-callback.js +6 -12
- package/modules/use-cases/refresh-entity-options.js +6 -8
- package/modules/use-cases/test-module-auth.js +6 -8
- package/modules/utils/map-module-dto.js +2 -2
- package/package.json +5 -7
- package/prisma-mongodb/schema.prisma +33 -75
- package/prisma-postgresql/schema.prisma +33 -73
- package/queues/queuer-util.js +1 -5
- package/syncs/model.js +51 -51
- package/syncs/repositories/sync-repository-documentdb.js +19 -39
- package/syncs/repositories/sync-repository-interface.js +2 -6
- package/syncs/repositories/sync-repository-postgres.js +13 -19
- package/syncs/sync.js +100 -104
- package/token/repositories/token-repository-factory.js +3 -1
- package/types/assertions/index.d.ts +72 -72
- package/types/associations/index.d.ts +57 -57
- package/types/core/index.d.ts +53 -59
- package/types/database/index.d.ts +2 -2
- package/types/encrypt/index.d.ts +3 -3
- package/types/errors/index.d.ts +54 -61
- package/types/eslint-config/index.d.ts +40 -40
- package/types/integrations/index.d.ts +183 -185
- package/types/lambda/index.d.ts +26 -26
- package/types/logs/index.d.ts +4 -4
- package/types/module-plugin/index.d.ts +237 -239
- package/types/prettier-config/index.d.ts +5 -5
- package/types/syncs/index.d.ts +108 -102
- package/types/test-environment/index.d.ts +14 -14
- package/types/tsconfig.json +93 -95
- package/user/tests/doubles/test-user-repository.js +2 -5
- package/user/use-cases/authenticate-user.js +4 -2
- package/user/use-cases/authenticate-with-shared-secret.js +1 -1
- package/user/use-cases/create-individual-user.js +7 -8
- 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/get-user-from-adopter-jwt.js +2 -0
- package/user/use-cases/get-user-from-bearer-token.js +3 -7
- package/user/use-cases/get-user-from-x-frigg-headers.js +11 -14
- package/user/use-cases/login-user.js +8 -8
- package/user/user.js +4 -18
- package/utils/backend-path.js +2 -2
- package/utils/index.js +1 -4
- package/websocket/repositories/websocket-connection-repository-documentdb.js +8 -21
- package/websocket/repositories/websocket-connection-repository-mongo.js +4 -8
- package/websocket/repositories/websocket-connection-repository-postgres.js +4 -8
- package/websocket/repositories/websocket-connection-repository.js +4 -8
- package/admin-scripts/repositories/admin-api-key-repository-interface.js +0 -121
- package/admin-scripts/repositories/admin-api-key-repository-mongo.js +0 -155
- package/admin-scripts/repositories/admin-api-key-repository-postgres.js +0 -189
- package/admin-scripts/repositories/script-execution-repository-documentdb.js +0 -21
- package/admin-scripts/repositories/script-execution-repository-factory.js +0 -55
- package/admin-scripts/repositories/script-execution-repository-interface.js +0 -193
- package/admin-scripts/repositories/script-execution-repository-mongo.js +0 -278
- package/admin-scripts/repositories/script-execution-repository-postgres.js +0 -320
- package/credential/credential-router.js +0 -262
- package/credential/use-cases/delete-credential-for-user.js +0 -50
- package/credential/use-cases/list-credentials-for-user.js +0 -31
- package/credential/use-cases/reauthorize-credential.js +0 -103
- package/handlers/routers/admin.js +0 -450
- package/handlers/routers/docs.js +0 -180
- package/handlers/routers/middleware/loadUser.js +0 -39
- package/handlers/routers/middleware/requireAdmin.js +0 -41
- package/handlers/routers/middleware/requireLoggedInUser.js +0 -19
- package/integrations/use-cases/execute-proxy-request.js +0 -564
- package/modules/domain/entities/AuthorizationSession.js +0 -131
- package/modules/domain/entities/index.js +0 -10
- package/modules/repositories/authorization-session-repository-factory.js +0 -55
- package/modules/repositories/authorization-session-repository-interface.js +0 -75
- package/modules/repositories/authorization-session-repository-mongo.js +0 -169
- package/modules/repositories/authorization-session-repository-postgres.js +0 -170
- package/modules/use-cases/delete-module-entity.js +0 -23
- package/modules/use-cases/get-authorization-requirements.js +0 -110
- package/modules/use-cases/get-module-entity-by-id.js +0 -16
- package/modules/use-cases/process-authorization-step.js +0 -160
- package/modules/use-cases/start-authorization-session.js +0 -86
- package/modules/use-cases/update-module-entity.js +0 -27
- package/openapi/openapi-spec-generator.js +0 -370
- package/openapi/openapi-v1.yaml +0 -1360
- package/openapi/openapi-v2.yaml +0 -1535
- package/user/use-cases/delete-user.js +0 -47
|
@@ -31,21 +31,13 @@ class TestIntegrationRepository {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
async findIntegrationsByUserId(userId) {
|
|
34
|
-
const results = Array.from(this.store.values()).filter(
|
|
35
|
-
|
|
36
|
-
);
|
|
37
|
-
this.operationHistory.push({
|
|
38
|
-
operation: 'findByUserId',
|
|
39
|
-
userId,
|
|
40
|
-
count: results.length,
|
|
41
|
-
});
|
|
34
|
+
const results = Array.from(this.store.values()).filter(r => r.userId === userId);
|
|
35
|
+
this.operationHistory.push({ operation: 'findByUserId', userId, count: results.length });
|
|
42
36
|
return results;
|
|
43
37
|
}
|
|
44
38
|
|
|
45
39
|
async findIntegrationByUserId(userId) {
|
|
46
|
-
const record = Array.from(this.store.values()).find(
|
|
47
|
-
(r) => r.userId === userId
|
|
48
|
-
);
|
|
40
|
+
const record = Array.from(this.store.values()).find((r) => r.userId === userId);
|
|
49
41
|
this.operationHistory.push({
|
|
50
42
|
operation: 'findSingleByUserId',
|
|
51
43
|
userId,
|
|
@@ -57,52 +49,30 @@ class TestIntegrationRepository {
|
|
|
57
49
|
async updateIntegrationMessages(id, type, title, body, timestamp) {
|
|
58
50
|
const rec = this.store.get(id);
|
|
59
51
|
if (!rec) {
|
|
60
|
-
this.operationHistory.push({
|
|
61
|
-
operation: 'updateMessages',
|
|
62
|
-
id,
|
|
63
|
-
success: false,
|
|
64
|
-
});
|
|
52
|
+
this.operationHistory.push({ operation: 'updateMessages', id, success: false });
|
|
65
53
|
return false;
|
|
66
54
|
}
|
|
67
55
|
if (!rec.messages[type]) rec.messages[type] = [];
|
|
68
56
|
rec.messages[type].push({ title, message: body, timestamp });
|
|
69
|
-
this.operationHistory.push({
|
|
70
|
-
operation: 'updateMessages',
|
|
71
|
-
id,
|
|
72
|
-
type,
|
|
73
|
-
success: true,
|
|
74
|
-
});
|
|
57
|
+
this.operationHistory.push({ operation: 'updateMessages', id, type, success: true });
|
|
75
58
|
return true;
|
|
76
59
|
}
|
|
77
60
|
|
|
78
61
|
async updateIntegrationConfig(id, config) {
|
|
79
62
|
const rec = this.store.get(id);
|
|
80
63
|
if (!rec) {
|
|
81
|
-
this.operationHistory.push({
|
|
82
|
-
operation: 'updateConfig',
|
|
83
|
-
id,
|
|
84
|
-
success: false,
|
|
85
|
-
});
|
|
64
|
+
this.operationHistory.push({ operation: 'updateConfig', id, success: false });
|
|
86
65
|
throw new Error(`Integration with id ${id} not found`);
|
|
87
66
|
}
|
|
88
67
|
rec.config = config;
|
|
89
|
-
this.operationHistory.push({
|
|
90
|
-
operation: 'updateConfig',
|
|
91
|
-
id,
|
|
92
|
-
success: true,
|
|
93
|
-
});
|
|
68
|
+
this.operationHistory.push({ operation: 'updateConfig', id, success: true });
|
|
94
69
|
return rec;
|
|
95
70
|
}
|
|
96
71
|
|
|
97
72
|
async deleteIntegrationById(id) {
|
|
98
73
|
const existed = this.store.has(id);
|
|
99
74
|
const result = this.store.delete(id);
|
|
100
|
-
this.operationHistory.push({
|
|
101
|
-
operation: 'delete',
|
|
102
|
-
id,
|
|
103
|
-
existed,
|
|
104
|
-
success: result,
|
|
105
|
-
});
|
|
75
|
+
this.operationHistory.push({ operation: 'delete', id, existed, success: result });
|
|
106
76
|
return result;
|
|
107
77
|
}
|
|
108
78
|
|
|
@@ -110,19 +80,9 @@ class TestIntegrationRepository {
|
|
|
110
80
|
const rec = this.store.get(id);
|
|
111
81
|
if (rec) {
|
|
112
82
|
rec.status = status;
|
|
113
|
-
this.operationHistory.push({
|
|
114
|
-
operation: 'updateStatus',
|
|
115
|
-
id,
|
|
116
|
-
status,
|
|
117
|
-
success: true,
|
|
118
|
-
});
|
|
83
|
+
this.operationHistory.push({ operation: 'updateStatus', id, status, success: true });
|
|
119
84
|
} else {
|
|
120
|
-
this.operationHistory.push({
|
|
121
|
-
operation: 'updateStatus',
|
|
122
|
-
id,
|
|
123
|
-
status,
|
|
124
|
-
success: false,
|
|
125
|
-
});
|
|
85
|
+
this.operationHistory.push({ operation: 'updateStatus', id, status, success: false });
|
|
126
86
|
}
|
|
127
87
|
return !!rec;
|
|
128
88
|
}
|
|
@@ -136,4 +96,4 @@ class TestIntegrationRepository {
|
|
|
136
96
|
}
|
|
137
97
|
}
|
|
138
98
|
|
|
139
|
-
module.exports = { TestIntegrationRepository };
|
|
99
|
+
module.exports = { TestIntegrationRepository };
|
|
@@ -1,60 +1,56 @@
|
|
|
1
|
+
// Removed Integration wrapper - using IntegrationBase directly
|
|
1
2
|
const {
|
|
2
3
|
mapIntegrationClassToIntegrationDTO,
|
|
3
4
|
} = require('../utils/map-integration-dto');
|
|
4
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Use case for creating a new integration instance.
|
|
8
|
+
* @class CreateIntegration
|
|
9
|
+
*/
|
|
5
10
|
class CreateIntegration {
|
|
11
|
+
/**
|
|
12
|
+
* Creates a new CreateIntegration instance.
|
|
13
|
+
* @param {Object} params - Configuration parameters.
|
|
14
|
+
* @param {import('../repositories/integration-repository-interface').IntegrationRepositoryInterface} params.integrationRepository - Repository for integration data operations.
|
|
15
|
+
* @param {import('../integration-classes').IntegrationClasses} params.integrationClasses - Array of available integration classes.
|
|
16
|
+
* @param {import('../../modules/module-factory').ModuleFactory} params.moduleFactory - Service for module instantiation and management.
|
|
17
|
+
*/
|
|
6
18
|
constructor({ integrationRepository, integrationClasses, moduleFactory }) {
|
|
7
19
|
this.integrationRepository = integrationRepository;
|
|
8
20
|
this.integrationClasses = integrationClasses;
|
|
9
21
|
this.moduleFactory = moduleFactory;
|
|
10
22
|
}
|
|
11
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Executes the integration creation process.
|
|
26
|
+
* @async
|
|
27
|
+
* @param {string[]} entities - Array of entity IDs to associate with the integration.
|
|
28
|
+
* @param {string} userId - ID of the user creating the integration.
|
|
29
|
+
* @param {Object} config - Configuration object for the integration.
|
|
30
|
+
* @param {string} config.type - Type of integration to create.
|
|
31
|
+
* @returns {Promise<Object>} The created integration DTO.
|
|
32
|
+
* @throws {Error} When integration class is not found for the specified type.
|
|
33
|
+
*/
|
|
12
34
|
async execute(entities, userId, config) {
|
|
35
|
+
const integrationRecord =
|
|
36
|
+
await this.integrationRepository.createIntegration(
|
|
37
|
+
entities,
|
|
38
|
+
userId,
|
|
39
|
+
config
|
|
40
|
+
);
|
|
41
|
+
|
|
13
42
|
const integrationClass = this.integrationClasses.find(
|
|
14
43
|
(integrationClass) =>
|
|
15
|
-
integrationClass.Definition.name ===
|
|
44
|
+
integrationClass.Definition.name ===
|
|
45
|
+
integrationRecord.config.type
|
|
16
46
|
);
|
|
17
47
|
|
|
18
48
|
if (!integrationClass) {
|
|
19
49
|
throw new Error(
|
|
20
|
-
`No integration class found for type: ${config.type}`
|
|
50
|
+
`No integration class found for type: ${integrationRecord.config.type}`
|
|
21
51
|
);
|
|
22
52
|
}
|
|
23
53
|
|
|
24
|
-
const allEntities = [...entities];
|
|
25
|
-
|
|
26
|
-
if (integrationClass.Definition?.entities) {
|
|
27
|
-
for (const [entityKey, entityConfig] of Object.entries(
|
|
28
|
-
integrationClass.Definition.entities
|
|
29
|
-
)) {
|
|
30
|
-
if (entityConfig.global === true) {
|
|
31
|
-
const globalEntity =
|
|
32
|
-
await this.moduleFactory.moduleRepository.findEntity({
|
|
33
|
-
moduleName: entityConfig.type,
|
|
34
|
-
isGlobal: true,
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
if (globalEntity && globalEntity.credential?.authIsValid) {
|
|
38
|
-
allEntities.push(globalEntity.id.toString());
|
|
39
|
-
} else if (entityConfig.required !== false) {
|
|
40
|
-
const reason = !globalEntity
|
|
41
|
-
? 'not found'
|
|
42
|
-
: 'exists but credential is invalid';
|
|
43
|
-
throw new Error(
|
|
44
|
-
`Required global entity "${entityConfig.type}" ${reason}. Admin must configure this entity first.`
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const integrationRecord =
|
|
52
|
-
await this.integrationRepository.createIntegration(
|
|
53
|
-
allEntities,
|
|
54
|
-
userId,
|
|
55
|
-
config
|
|
56
|
-
);
|
|
57
|
-
|
|
58
54
|
const modules = [];
|
|
59
55
|
for (const entityId of integrationRecord.entitiesIds) {
|
|
60
56
|
const moduleInstance = await this.moduleFactory.getModuleInstance(
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* CreateProcess Use Case
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Creates a new process record for tracking long-running operations.
|
|
5
5
|
* Validates required fields and delegates persistence to the repository.
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
7
|
* Design Philosophy:
|
|
8
8
|
* - Use cases encapsulate business logic
|
|
9
9
|
* - Validation happens at the use case layer
|
|
10
10
|
* - Repositories handle only data access
|
|
11
11
|
* - Process model is generic and reusable
|
|
12
|
-
*
|
|
12
|
+
*
|
|
13
13
|
* @example
|
|
14
14
|
* const createProcess = new CreateProcess({ processRepository });
|
|
15
15
|
* const process = await createProcess.execute({
|
|
@@ -68,9 +68,7 @@ class CreateProcess {
|
|
|
68
68
|
|
|
69
69
|
// Delegate to repository
|
|
70
70
|
try {
|
|
71
|
-
const createdProcess = await this.processRepository.create(
|
|
72
|
-
processToCreate
|
|
73
|
-
);
|
|
71
|
+
const createdProcess = await this.processRepository.create(processToCreate);
|
|
74
72
|
return createdProcess;
|
|
75
73
|
} catch (error) {
|
|
76
74
|
throw new Error(`Failed to create process: ${error.message}`);
|
|
@@ -85,15 +83,11 @@ class CreateProcess {
|
|
|
85
83
|
*/
|
|
86
84
|
_validateProcessData(processData) {
|
|
87
85
|
const requiredFields = ['userId', 'integrationId', 'name', 'type'];
|
|
88
|
-
const missingFields = requiredFields.filter(
|
|
89
|
-
(field) => !processData[field]
|
|
90
|
-
);
|
|
86
|
+
const missingFields = requiredFields.filter(field => !processData[field]);
|
|
91
87
|
|
|
92
88
|
if (missingFields.length > 0) {
|
|
93
89
|
throw new Error(
|
|
94
|
-
`Missing required fields for process creation: ${missingFields.join(
|
|
95
|
-
', '
|
|
96
|
-
)}`
|
|
90
|
+
`Missing required fields for process creation: ${missingFields.join(', ')}`
|
|
97
91
|
);
|
|
98
92
|
}
|
|
99
93
|
|
|
@@ -121,19 +115,14 @@ class CreateProcess {
|
|
|
121
115
|
if (processData.results && typeof processData.results !== 'object') {
|
|
122
116
|
throw new Error('results must be an object');
|
|
123
117
|
}
|
|
124
|
-
if (
|
|
125
|
-
processData.childProcesses &&
|
|
126
|
-
!Array.isArray(processData.childProcesses)
|
|
127
|
-
) {
|
|
118
|
+
if (processData.childProcesses && !Array.isArray(processData.childProcesses)) {
|
|
128
119
|
throw new Error('childProcesses must be an array');
|
|
129
120
|
}
|
|
130
|
-
if (
|
|
131
|
-
processData.parentProcessId &&
|
|
132
|
-
typeof processData.parentProcessId !== 'string'
|
|
133
|
-
) {
|
|
121
|
+
if (processData.parentProcessId && typeof processData.parentProcessId !== 'string') {
|
|
134
122
|
throw new Error('parentProcessId must be a string');
|
|
135
123
|
}
|
|
136
124
|
}
|
|
137
125
|
}
|
|
138
126
|
|
|
139
127
|
module.exports = { CreateProcess };
|
|
128
|
+
|
|
@@ -59,11 +59,10 @@ class DeleteIntegrationForUser {
|
|
|
59
59
|
|
|
60
60
|
for (const entityId of integrationRecord.entitiesIds) {
|
|
61
61
|
try {
|
|
62
|
-
const moduleInstance =
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
);
|
|
62
|
+
const moduleInstance = await this.moduleFactory.getModuleInstance(
|
|
63
|
+
entityId,
|
|
64
|
+
integrationRecord.userId
|
|
65
|
+
);
|
|
67
66
|
modules.push(moduleInstance);
|
|
68
67
|
} catch (error) {
|
|
69
68
|
console.error(
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
// Removed Integration wrapper - using IntegrationBase directly
|
|
2
|
-
const {
|
|
3
|
-
mapIntegrationClassToIntegrationDTO,
|
|
4
|
-
} = require('../utils/map-integration-dto');
|
|
2
|
+
const { mapIntegrationClassToIntegrationDTO } = require('../utils/map-integration-dto');
|
|
5
3
|
const Boom = require('@hapi/boom');
|
|
6
4
|
|
|
7
5
|
/**
|
|
@@ -17,12 +15,8 @@ class GetIntegrationForUser {
|
|
|
17
15
|
* @param {import('../../modules/module-factory').ModuleFactory} params.moduleFactory - Service for module instantiation and management.
|
|
18
16
|
* @param {import('../../modules/module-repository-interface').ModuleRepositoryInterface} params.moduleRepository - Repository for module and entity data operations.
|
|
19
17
|
*/
|
|
20
|
-
constructor({
|
|
21
|
-
|
|
22
|
-
integrationClasses,
|
|
23
|
-
moduleFactory,
|
|
24
|
-
moduleRepository,
|
|
25
|
-
}) {
|
|
18
|
+
constructor({ integrationRepository, integrationClasses, moduleFactory, moduleRepository }) {
|
|
19
|
+
|
|
26
20
|
/**
|
|
27
21
|
* @type {import('../integration-repository-interface').IntegrationRepositoryInterface}
|
|
28
22
|
*/
|
|
@@ -42,28 +36,19 @@ class GetIntegrationForUser {
|
|
|
42
36
|
* @throws {Boom.forbidden} When user does not have access to the integration.
|
|
43
37
|
*/
|
|
44
38
|
async execute(integrationId, userId) {
|
|
45
|
-
const integrationRecord =
|
|
46
|
-
|
|
47
|
-
const entities = await this.moduleRepository.findEntitiesByIds(
|
|
48
|
-
integrationRecord.entitiesIds
|
|
49
|
-
);
|
|
39
|
+
const integrationRecord = await this.integrationRepository.findIntegrationById(integrationId);
|
|
40
|
+
const entities = await this.moduleRepository.findEntitiesByIds(integrationRecord.entitiesIds);
|
|
50
41
|
|
|
51
42
|
if (!integrationRecord) {
|
|
52
|
-
throw Boom.notFound(
|
|
53
|
-
`Integration with id of ${integrationId} does not exist`
|
|
54
|
-
);
|
|
43
|
+
throw Boom.notFound(`Integration with id of ${integrationId} does not exist`);
|
|
55
44
|
}
|
|
56
45
|
|
|
57
46
|
if (integrationRecord.userId.toString() !== userId.toString()) {
|
|
58
|
-
throw Boom.forbidden(
|
|
59
|
-
'User does not have access to this integration'
|
|
60
|
-
);
|
|
47
|
+
throw Boom.forbidden('User does not have access to this integration');
|
|
61
48
|
}
|
|
62
49
|
|
|
63
50
|
const integrationClass = this.integrationClasses.find(
|
|
64
|
-
(integrationClass) =>
|
|
65
|
-
integrationClass.Definition.name ===
|
|
66
|
-
integrationRecord.config.type
|
|
51
|
+
(integrationClass) => integrationClass.Definition.name === integrationRecord.config.type
|
|
67
52
|
);
|
|
68
53
|
|
|
69
54
|
const modules = [];
|
|
@@ -83,11 +68,11 @@ class GetIntegrationForUser {
|
|
|
83
68
|
status: integrationRecord.status,
|
|
84
69
|
version: integrationRecord.version,
|
|
85
70
|
messages: integrationRecord.messages,
|
|
86
|
-
modules
|
|
71
|
+
modules
|
|
87
72
|
});
|
|
88
73
|
|
|
89
74
|
return mapIntegrationClassToIntegrationDTO(integrationInstance);
|
|
90
75
|
}
|
|
91
76
|
}
|
|
92
77
|
|
|
93
|
-
module.exports = { GetIntegrationForUser };
|
|
78
|
+
module.exports = { GetIntegrationForUser };
|
|
@@ -14,6 +14,7 @@ class GetIntegrationInstanceByDefinition {
|
|
|
14
14
|
* @param {import('../../modules/module-repository-interface').ModuleRepositoryInterface} params.moduleRepository - Repository for module and entity data operations.
|
|
15
15
|
*/
|
|
16
16
|
constructor({ integrationRepository, moduleFactory, moduleRepository }) {
|
|
17
|
+
|
|
17
18
|
/**
|
|
18
19
|
* @type {import('../integration-repository-interface').IntegrationRepositoryInterface}
|
|
19
20
|
*/
|
|
@@ -29,20 +30,13 @@ class GetIntegrationInstanceByDefinition {
|
|
|
29
30
|
* @throws {Boom.notFound} When integration with the specified definition does not exist.
|
|
30
31
|
*/
|
|
31
32
|
async execute(integrationClass) {
|
|
32
|
-
const integrationRecord =
|
|
33
|
-
await this.integrationRepository.findIntegrationByName(
|
|
34
|
-
integrationClass.Definition.name
|
|
35
|
-
);
|
|
33
|
+
const integrationRecord = await this.integrationRepository.findIntegrationByName(integrationClass.Definition.name);
|
|
36
34
|
|
|
37
35
|
if (!integrationRecord) {
|
|
38
|
-
throw Boom.notFound(
|
|
39
|
-
`Integration with name of ${integrationClass.Definition.name} does not exist`
|
|
40
|
-
);
|
|
36
|
+
throw Boom.notFound(`Integration with name of ${integrationClass.Definition.name} does not exist`);
|
|
41
37
|
}
|
|
42
38
|
|
|
43
|
-
const entities = await this.moduleRepository.findEntitiesByIds(
|
|
44
|
-
integrationRecord.entitiesIds
|
|
45
|
-
);
|
|
39
|
+
const entities = await this.moduleRepository.findEntitiesByIds(integrationRecord.entitiesIds);
|
|
46
40
|
|
|
47
41
|
const modules = [];
|
|
48
42
|
for (const entity of entities) {
|
|
@@ -61,13 +55,13 @@ class GetIntegrationInstanceByDefinition {
|
|
|
61
55
|
status: integrationRecord.status,
|
|
62
56
|
version: integrationRecord.version,
|
|
63
57
|
messages: integrationRecord.messages,
|
|
64
|
-
modules
|
|
58
|
+
modules
|
|
65
59
|
});
|
|
66
60
|
|
|
67
61
|
await integrationInstance.initialize();
|
|
68
62
|
|
|
69
|
-
return integrationInstance
|
|
63
|
+
return integrationInstance
|
|
70
64
|
}
|
|
71
65
|
}
|
|
72
66
|
|
|
73
|
-
module.exports = { GetIntegrationInstanceByDefinition };
|
|
67
|
+
module.exports = { GetIntegrationInstanceByDefinition };
|
|
@@ -71,10 +71,7 @@ class GetIntegrationsForUser {
|
|
|
71
71
|
config: integrationRecord.config,
|
|
72
72
|
status: integrationRecord.status,
|
|
73
73
|
version: integrationRecord.version,
|
|
74
|
-
messages: integrationRecord.messages || {
|
|
75
|
-
errors: [],
|
|
76
|
-
warnings: [],
|
|
77
|
-
},
|
|
74
|
+
messages: integrationRecord.messages || { errors: [], warnings: [] },
|
|
78
75
|
modules,
|
|
79
76
|
options: integrationClass.getOptionDetails(),
|
|
80
77
|
};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* GetProcess Use Case
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Retrieves a process by ID with proper error handling.
|
|
5
5
|
* Simple use case that delegates to repository.
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
7
|
* Design Philosophy:
|
|
8
8
|
* - Use cases provide consistent error handling
|
|
9
9
|
* - Business logic layer between controllers and repositories
|
|
10
10
|
* - Return null for not found vs throwing error (configurable)
|
|
11
|
-
*
|
|
11
|
+
*
|
|
12
12
|
* @example
|
|
13
13
|
* const getProcess = new GetProcess({ processRepository });
|
|
14
14
|
* const process = await getProcess.execute(processId);
|
|
@@ -75,12 +75,13 @@ class GetProcess {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
const processes = await Promise.all(
|
|
78
|
-
processIds.map(
|
|
78
|
+
processIds.map(id => this.execute(id))
|
|
79
79
|
);
|
|
80
80
|
|
|
81
81
|
// Filter out nulls (not found)
|
|
82
|
-
return processes.filter(
|
|
82
|
+
return processes.filter(p => p !== null);
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
module.exports = { GetProcess };
|
|
87
|
+
|
|
@@ -6,7 +6,6 @@ const { CreateProcess } = require('./create-process');
|
|
|
6
6
|
const { UpdateProcessState } = require('./update-process-state');
|
|
7
7
|
const { UpdateProcessMetrics } = require('./update-process-metrics');
|
|
8
8
|
const { GetProcess } = require('./get-process');
|
|
9
|
-
const { ExecuteProxyRequest } = require('./execute-proxy-request');
|
|
10
9
|
|
|
11
10
|
module.exports = {
|
|
12
11
|
GetIntegrationsForUser,
|
|
@@ -17,5 +16,4 @@ module.exports = {
|
|
|
17
16
|
UpdateProcessState,
|
|
18
17
|
UpdateProcessMetrics,
|
|
19
18
|
GetProcess,
|
|
20
|
-
|
|
21
|
-
};
|
|
19
|
+
};
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
class LoadIntegrationContextUseCase {
|
|
2
|
-
constructor({
|
|
2
|
+
constructor({
|
|
3
|
+
integrationRepository,
|
|
4
|
+
moduleRepository,
|
|
5
|
+
moduleFactory,
|
|
6
|
+
}) {
|
|
3
7
|
if (!integrationRepository) {
|
|
4
8
|
throw new Error('integrationRepository is required');
|
|
5
9
|
}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* UpdateProcessState Use Case
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Updates the state of a process and optionally merges context updates.
|
|
5
5
|
* Handles state transitions in the process state machine.
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
7
|
* Design Philosophy:
|
|
8
8
|
* - State transitions are explicit and tracked
|
|
9
9
|
* - Context updates are merged (not replaced) to preserve data
|
|
10
10
|
* - Repository handles persistence, use case handles business logic
|
|
11
|
-
*
|
|
11
|
+
*
|
|
12
12
|
* State Machine (CRM Sync Example):
|
|
13
|
-
* INITIALIZING → FETCHING_TOTAL → QUEUING_PAGES → PROCESSING_BATCHES →
|
|
13
|
+
* INITIALIZING → FETCHING_TOTAL → QUEUING_PAGES → PROCESSING_BATCHES →
|
|
14
14
|
* COMPLETING → COMPLETED
|
|
15
|
-
*
|
|
15
|
+
*
|
|
16
16
|
* Any state can transition to ERROR on failure.
|
|
17
|
-
*
|
|
17
|
+
*
|
|
18
18
|
* @example
|
|
19
19
|
* const updateProcessState = new UpdateProcessState({ processRepository });
|
|
20
20
|
* await updateProcessState.execute(processId, 'FETCHING_TOTAL', {
|
|
@@ -75,10 +75,7 @@ class UpdateProcessState {
|
|
|
75
75
|
|
|
76
76
|
// Persist updates
|
|
77
77
|
try {
|
|
78
|
-
const updatedProcess = await this.processRepository.update(
|
|
79
|
-
processId,
|
|
80
|
-
updates
|
|
81
|
-
);
|
|
78
|
+
const updatedProcess = await this.processRepository.update(processId, updates);
|
|
82
79
|
return updatedProcess;
|
|
83
80
|
} catch (error) {
|
|
84
81
|
throw new Error(`Failed to update process state: ${error.message}`);
|
|
@@ -119,3 +116,4 @@ class UpdateProcessState {
|
|
|
119
116
|
}
|
|
120
117
|
|
|
121
118
|
module.exports = { UpdateProcessState };
|
|
119
|
+
|
|
@@ -15,14 +15,11 @@ function mapIntegrationClassToIntegrationDTO(integration) {
|
|
|
15
15
|
version: integration.version,
|
|
16
16
|
messages: integration.messages,
|
|
17
17
|
userActions: integration.userActions,
|
|
18
|
-
options:
|
|
19
|
-
integration.options ||
|
|
20
|
-
(typeof integration.getOptionDetails === 'function'
|
|
21
|
-
? integration.getOptionDetails()
|
|
22
|
-
: null),
|
|
18
|
+
options: integration.options || (typeof integration.getOptionDetails === 'function' ? integration.getOptionDetails() : null),
|
|
23
19
|
};
|
|
24
20
|
}
|
|
25
21
|
|
|
22
|
+
|
|
26
23
|
const getModulesDefinitionFromIntegrationClasses = (integrationClasses) => {
|
|
27
24
|
return [
|
|
28
25
|
...new Set(
|
|
@@ -37,7 +34,4 @@ const getModulesDefinitionFromIntegrationClasses = (integrationClasses) => {
|
|
|
37
34
|
];
|
|
38
35
|
};
|
|
39
36
|
|
|
40
|
-
module.exports = {
|
|
41
|
-
mapIntegrationClassToIntegrationDTO,
|
|
42
|
-
getModulesDefinitionFromIntegrationClasses,
|
|
43
|
-
};
|
|
37
|
+
module.exports = { mapIntegrationClassToIntegrationDTO, getModulesDefinitionFromIntegrationClasses };
|
package/jest-setup.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const {globalSetup} = require('@friggframework/test');
|
|
2
2
|
module.exports = globalSetup;
|
package/jest-teardown.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const {globalTeardown} = require('@friggframework/test');
|
|
2
2
|
module.exports = globalTeardown;
|
package/lambda/TimeoutCatcher.js
CHANGED
|
@@ -2,44 +2,42 @@ const isPositive = (n) => Number.isFinite(n) && n > 0;
|
|
|
2
2
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
3
3
|
|
|
4
4
|
class TimeoutCatcher {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
5
|
+
constructor({ work, timeout, cleanUp = () => {}, cleanUpTime = 2_000 }) {
|
|
6
|
+
this.isFinished = false;
|
|
7
|
+
this.work = work;
|
|
8
|
+
this.cleanUp = cleanUp;
|
|
9
|
+
this.waitTime = timeout - cleanUpTime;
|
|
10
|
+
|
|
11
|
+
if (!isPositive(this.waitTime))
|
|
12
|
+
throw new Error("Wait time was not a positive number of milliseconds");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async watch() {
|
|
16
|
+
try {
|
|
17
|
+
await Promise.race([this.doWork(), this.exitBeforeTimeout()]);
|
|
18
|
+
return true;
|
|
19
|
+
} catch (error) {
|
|
20
|
+
if (error.isSentinelTimeout) return false;
|
|
21
|
+
throw error;
|
|
15
22
|
}
|
|
23
|
+
}
|
|
16
24
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
} catch (error) {
|
|
22
|
-
if (error.isSentinelTimeout) return false;
|
|
23
|
-
throw error;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
async doWork() {
|
|
28
|
-
await this.work();
|
|
29
|
-
this.isFinished = true;
|
|
30
|
-
}
|
|
25
|
+
async doWork() {
|
|
26
|
+
await this.work();
|
|
27
|
+
this.isFinished = true;
|
|
28
|
+
}
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
async exitBeforeTimeout() {
|
|
31
|
+
await sleep(this.waitTime);
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
if (!this.isFinished) {
|
|
34
|
+
await this.cleanUp();
|
|
37
35
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
36
|
+
const error = new Error("Sentinel Timed Out");
|
|
37
|
+
error.isSentinelTimeout = true;
|
|
38
|
+
throw error;
|
|
42
39
|
}
|
|
40
|
+
}
|
|
43
41
|
}
|
|
44
42
|
|
|
45
43
|
module.exports = { TimeoutCatcher };
|
package/lambda/index.js
CHANGED
package/logs/index.js
CHANGED