@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
package/integrations/options.js
CHANGED
|
@@ -4,11 +4,8 @@ const { get } = require('../assertions');
|
|
|
4
4
|
class Options {
|
|
5
5
|
constructor(params) {
|
|
6
6
|
this.module = get(params, 'module');
|
|
7
|
-
this.
|
|
7
|
+
this.modules = params.modules || {}; // Store modules for requiredEntities extraction
|
|
8
8
|
this.hasUserConfig = Boolean(get(params, 'hasUserConfig', false));
|
|
9
|
-
this.requiresNewEntity = Boolean(
|
|
10
|
-
get(params, 'requiresNewEntity', false)
|
|
11
|
-
);
|
|
12
9
|
if (!params.display) {
|
|
13
10
|
throw new RequiredPropertyError({
|
|
14
11
|
parent: this,
|
|
@@ -17,37 +14,67 @@ class Options {
|
|
|
17
14
|
}
|
|
18
15
|
|
|
19
16
|
this.display = {};
|
|
17
|
+
// Required fields
|
|
20
18
|
this.display.name = get(params.display, 'label');
|
|
21
19
|
this.display.description = get(params.display, 'description');
|
|
22
|
-
|
|
23
|
-
this.display.
|
|
20
|
+
// Optional fields - use defaults if not provided
|
|
21
|
+
this.display.detailsUrl = params.display.detailsUrl || null;
|
|
22
|
+
this.display.icon = params.display.icon || null;
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
get() {
|
|
26
|
+
// Extract module names from the modules object to determine required entities
|
|
27
|
+
const requiredEntities = this.modules ? Object.keys(this.modules) : [];
|
|
28
|
+
|
|
29
|
+
// Get module type name - handle both getName() method and moduleName property
|
|
30
|
+
const moduleType = this._getModuleTypeName();
|
|
31
|
+
|
|
27
32
|
return {
|
|
28
|
-
type:
|
|
33
|
+
type: moduleType,
|
|
29
34
|
|
|
30
35
|
// Flag for if the User can configure any settings
|
|
31
36
|
hasUserConfig: this.hasUserConfig,
|
|
32
37
|
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
// if this is true it means we need to create a new entity for every integration pair and not use an
|
|
38
|
-
// existing one. This would be true for scenarios where the client wishes to have individual control over
|
|
39
|
-
// the integerations it has connected to its app. They would want this to let their users only delete
|
|
40
|
-
// single integrations without notifying our server.
|
|
41
|
-
requiresNewEntity: this.requiresNewEntity,
|
|
38
|
+
// Array of module/entity type names required for this integration (e.g., ['nagaris', 'creditorwatch'])
|
|
39
|
+
// UI uses this to check if user has connected the necessary accounts before creating integration
|
|
40
|
+
requiredEntities: requiredEntities,
|
|
42
41
|
|
|
43
42
|
// this is information required for the display side of things on the front end
|
|
44
43
|
display: this.display,
|
|
45
|
-
|
|
46
|
-
// this is information for post-authentication config, using jsonSchema and uiSchema for display on the frontend
|
|
47
|
-
// Maybe include but probably not, I like making someone make a follow-on request
|
|
48
|
-
// configOptions: this.configOptions,
|
|
49
44
|
};
|
|
50
45
|
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Get the module type name from the module definition.
|
|
49
|
+
* Supports both:
|
|
50
|
+
* - getName() method (standard Frigg API modules)
|
|
51
|
+
* - moduleName property (custom API modules)
|
|
52
|
+
* @returns {string} The module type name
|
|
53
|
+
* @private
|
|
54
|
+
*/
|
|
55
|
+
_getModuleTypeName() {
|
|
56
|
+
const definition = this.module?.definition;
|
|
57
|
+
if (!definition) {
|
|
58
|
+
return 'unknown';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Try getName() method first (standard pattern)
|
|
62
|
+
if (typeof definition.getName === 'function') {
|
|
63
|
+
return definition.getName();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Fall back to moduleName property
|
|
67
|
+
if (definition.moduleName) {
|
|
68
|
+
return definition.moduleName;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Last resort - try name property
|
|
72
|
+
if (definition.name) {
|
|
73
|
+
return definition.name;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return 'unknown';
|
|
77
|
+
}
|
|
51
78
|
}
|
|
52
79
|
|
|
53
80
|
module.exports = { Options };
|
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
const {
|
|
2
|
-
IntegrationMappingRepositoryMongo,
|
|
3
|
-
} = require('./integration-mapping-repository-mongo');
|
|
4
1
|
const {
|
|
5
2
|
IntegrationMappingRepositoryPostgres,
|
|
6
3
|
} = require('./integration-mapping-repository-postgres');
|
|
7
|
-
const {
|
|
8
|
-
IntegrationMappingRepositoryDocumentDB,
|
|
9
|
-
} = require('./integration-mapping-repository-documentdb');
|
|
10
4
|
const config = require('../../database/config');
|
|
11
5
|
|
|
12
6
|
/**
|
|
@@ -33,12 +27,14 @@ function createIntegrationMappingRepository() {
|
|
|
33
27
|
|
|
34
28
|
switch (dbType) {
|
|
35
29
|
case 'mongodb':
|
|
30
|
+
const { IntegrationMappingRepositoryMongo } = require('./integration-mapping-repository-mongo');
|
|
36
31
|
return new IntegrationMappingRepositoryMongo();
|
|
37
32
|
|
|
38
33
|
case 'postgresql':
|
|
39
34
|
return new IntegrationMappingRepositoryPostgres();
|
|
40
35
|
|
|
41
36
|
case 'documentdb':
|
|
37
|
+
const { IntegrationMappingRepositoryDocumentDB } = require('./integration-mapping-repository-documentdb');
|
|
42
38
|
return new IntegrationMappingRepositoryDocumentDB();
|
|
43
39
|
|
|
44
40
|
default:
|
|
@@ -51,7 +47,7 @@ function createIntegrationMappingRepository() {
|
|
|
51
47
|
module.exports = {
|
|
52
48
|
createIntegrationMappingRepository,
|
|
53
49
|
// Export adapters for direct testing
|
|
54
|
-
IntegrationMappingRepositoryMongo,
|
|
50
|
+
get IntegrationMappingRepositoryMongo() { return require('./integration-mapping-repository-mongo').IntegrationMappingRepositoryMongo; },
|
|
55
51
|
IntegrationMappingRepositoryPostgres,
|
|
56
|
-
IntegrationMappingRepositoryDocumentDB,
|
|
52
|
+
get IntegrationMappingRepositoryDocumentDB() { return require('./integration-mapping-repository-documentdb').IntegrationMappingRepositoryDocumentDB; },
|
|
57
53
|
};
|
|
@@ -29,13 +29,17 @@ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
|
|
|
29
29
|
async deleteIntegrationById(integrationId) {
|
|
30
30
|
const objectId = toObjectId(integrationId);
|
|
31
31
|
if (!objectId) return { acknowledged: true, deletedCount: 0 };
|
|
32
|
-
const result = await deleteOne(this.prisma, 'Integration', {
|
|
32
|
+
const result = await deleteOne(this.prisma, 'Integration', {
|
|
33
|
+
_id: objectId,
|
|
34
|
+
});
|
|
33
35
|
const deleted = result?.n ?? 0;
|
|
34
36
|
return { acknowledged: true, deletedCount: deleted };
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
async findIntegrationByName(name) {
|
|
38
|
-
const doc = await findOne(this.prisma, 'Integration', {
|
|
40
|
+
const doc = await findOne(this.prisma, 'Integration', {
|
|
41
|
+
'config.type': name,
|
|
42
|
+
});
|
|
39
43
|
if (!doc) {
|
|
40
44
|
throw new Error(`Integration with name ${name} not found`);
|
|
41
45
|
}
|
|
@@ -47,7 +51,9 @@ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
|
|
|
47
51
|
if (!objectId) {
|
|
48
52
|
throw new Error(`Integration with id ${id} not found`);
|
|
49
53
|
}
|
|
50
|
-
const doc = await findOne(this.prisma, 'Integration', {
|
|
54
|
+
const doc = await findOne(this.prisma, 'Integration', {
|
|
55
|
+
_id: objectId,
|
|
56
|
+
});
|
|
51
57
|
if (!doc) {
|
|
52
58
|
throw new Error(`Integration with id ${id} not found`);
|
|
53
59
|
}
|
|
@@ -79,12 +85,16 @@ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
|
|
|
79
85
|
if (!objectId) {
|
|
80
86
|
throw new Error(`Integration ${integrationId} not found`);
|
|
81
87
|
}
|
|
82
|
-
const existing = await findOne(this.prisma, 'Integration', {
|
|
88
|
+
const existing = await findOne(this.prisma, 'Integration', {
|
|
89
|
+
_id: objectId,
|
|
90
|
+
});
|
|
83
91
|
if (!existing) {
|
|
84
92
|
throw new Error(`Integration ${integrationId} not found`);
|
|
85
93
|
}
|
|
86
94
|
const messages = this._extractMessages(existing);
|
|
87
|
-
const list = Array.isArray(messages[messageType])
|
|
95
|
+
const list = Array.isArray(messages[messageType])
|
|
96
|
+
? [...messages[messageType]]
|
|
97
|
+
: [];
|
|
88
98
|
list.push({
|
|
89
99
|
title: messageTitle ?? null,
|
|
90
100
|
message: messageBody,
|
|
@@ -125,17 +135,26 @@ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
|
|
|
125
135
|
createdAt: now,
|
|
126
136
|
updatedAt: now,
|
|
127
137
|
};
|
|
128
|
-
const insertedId = await insertOne(
|
|
129
|
-
|
|
138
|
+
const insertedId = await insertOne(
|
|
139
|
+
this.prisma,
|
|
140
|
+
'Integration',
|
|
141
|
+
document
|
|
142
|
+
);
|
|
143
|
+
const created = await findOne(this.prisma, 'Integration', {
|
|
144
|
+
_id: insertedId,
|
|
145
|
+
});
|
|
130
146
|
if (!created) {
|
|
131
|
-
console.error(
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
147
|
+
console.error(
|
|
148
|
+
'[IntegrationRepositoryDocumentDB] Integration not found after insert',
|
|
149
|
+
{
|
|
150
|
+
insertedId: fromObjectId(insertedId),
|
|
151
|
+
userId,
|
|
152
|
+
config,
|
|
153
|
+
}
|
|
154
|
+
);
|
|
136
155
|
throw new Error(
|
|
137
156
|
'Failed to create integration: Document not found after insert. ' +
|
|
138
|
-
|
|
157
|
+
'This indicates a database consistency issue.'
|
|
139
158
|
);
|
|
140
159
|
}
|
|
141
160
|
return this._mapIntegration(created);
|
|
@@ -144,7 +163,9 @@ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
|
|
|
144
163
|
async findIntegrationByUserId(userId) {
|
|
145
164
|
const objectId = toObjectId(userId);
|
|
146
165
|
if (!objectId) return null;
|
|
147
|
-
const doc = await findOne(this.prisma, 'Integration', {
|
|
166
|
+
const doc = await findOne(this.prisma, 'Integration', {
|
|
167
|
+
userId: objectId,
|
|
168
|
+
});
|
|
148
169
|
return doc ? this._mapIntegration(doc) : null;
|
|
149
170
|
}
|
|
150
171
|
|
|
@@ -167,15 +188,20 @@ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
|
|
|
167
188
|
},
|
|
168
189
|
}
|
|
169
190
|
);
|
|
170
|
-
const updated = await findOne(this.prisma, 'Integration', {
|
|
191
|
+
const updated = await findOne(this.prisma, 'Integration', {
|
|
192
|
+
_id: objectId,
|
|
193
|
+
});
|
|
171
194
|
if (!updated) {
|
|
172
|
-
console.error(
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
195
|
+
console.error(
|
|
196
|
+
'[IntegrationRepositoryDocumentDB] Integration not found after update',
|
|
197
|
+
{
|
|
198
|
+
integrationId: fromObjectId(objectId),
|
|
199
|
+
config,
|
|
200
|
+
}
|
|
201
|
+
);
|
|
176
202
|
throw new Error(
|
|
177
203
|
'Failed to update integration: Document not found after update. ' +
|
|
178
|
-
|
|
204
|
+
'This indicates a database consistency issue.'
|
|
179
205
|
);
|
|
180
206
|
}
|
|
181
207
|
return this._mapIntegration(updated);
|
|
@@ -185,7 +211,9 @@ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
|
|
|
185
211
|
const messages = this._extractMessages(doc);
|
|
186
212
|
return {
|
|
187
213
|
id: fromObjectId(doc?._id),
|
|
188
|
-
entitiesIds: (doc?.entityIds || []).map((value) =>
|
|
214
|
+
entitiesIds: (doc?.entityIds || []).map((value) =>
|
|
215
|
+
fromObjectId(value)
|
|
216
|
+
),
|
|
189
217
|
userId: fromObjectId(doc?.userId),
|
|
190
218
|
config: doc?.config ?? null,
|
|
191
219
|
version: doc?.version ?? null,
|
|
@@ -195,7 +223,10 @@ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
|
|
|
195
223
|
}
|
|
196
224
|
|
|
197
225
|
_extractMessages(doc) {
|
|
198
|
-
const base =
|
|
226
|
+
const base =
|
|
227
|
+
doc?.messages && typeof doc.messages === 'object'
|
|
228
|
+
? doc.messages
|
|
229
|
+
: {};
|
|
199
230
|
return {
|
|
200
231
|
errors: base.errors ?? doc?.errors ?? [],
|
|
201
232
|
warnings: base.warnings ?? doc?.warnings ?? [],
|
|
@@ -206,5 +237,3 @@ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
|
|
|
206
237
|
}
|
|
207
238
|
|
|
208
239
|
module.exports = { IntegrationRepositoryDocumentDB };
|
|
209
|
-
|
|
210
|
-
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
const { IntegrationRepositoryMongo } = require('./integration-repository-mongo');
|
|
2
|
-
const { IntegrationRepositoryPostgres } = require('./integration-repository-postgres');
|
|
3
1
|
const {
|
|
4
|
-
|
|
5
|
-
} = require('./integration-repository-
|
|
2
|
+
IntegrationRepositoryPostgres,
|
|
3
|
+
} = require('./integration-repository-postgres');
|
|
6
4
|
const config = require('../../database/config');
|
|
7
5
|
|
|
8
6
|
/**
|
|
@@ -27,12 +25,14 @@ function createIntegrationRepository() {
|
|
|
27
25
|
|
|
28
26
|
switch (dbType) {
|
|
29
27
|
case 'mongodb':
|
|
28
|
+
const { IntegrationRepositoryMongo } = require('./integration-repository-mongo');
|
|
30
29
|
return new IntegrationRepositoryMongo();
|
|
31
30
|
|
|
32
31
|
case 'postgresql':
|
|
33
32
|
return new IntegrationRepositoryPostgres();
|
|
34
33
|
|
|
35
34
|
case 'documentdb':
|
|
35
|
+
const { IntegrationRepositoryDocumentDB } = require('./integration-repository-documentdb');
|
|
36
36
|
return new IntegrationRepositoryDocumentDB();
|
|
37
37
|
|
|
38
38
|
default:
|
|
@@ -45,7 +45,7 @@ function createIntegrationRepository() {
|
|
|
45
45
|
module.exports = {
|
|
46
46
|
createIntegrationRepository,
|
|
47
47
|
// Export adapters for direct testing
|
|
48
|
-
IntegrationRepositoryMongo,
|
|
48
|
+
get IntegrationRepositoryMongo() { return require('./integration-repository-mongo').IntegrationRepositoryMongo; },
|
|
49
49
|
IntegrationRepositoryPostgres,
|
|
50
|
-
IntegrationRepositoryDocumentDB,
|
|
50
|
+
get IntegrationRepositoryDocumentDB() { return require('./integration-repository-documentdb').IntegrationRepositoryDocumentDB; },
|
|
51
51
|
};
|
|
@@ -18,7 +18,9 @@ class IntegrationRepositoryInterface {
|
|
|
18
18
|
* @abstract
|
|
19
19
|
*/
|
|
20
20
|
async findIntegrationsByUserId(userId) {
|
|
21
|
-
throw new Error(
|
|
21
|
+
throw new Error(
|
|
22
|
+
'Method findIntegrationsByUserId must be implemented by subclass'
|
|
23
|
+
);
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
/**
|
|
@@ -29,7 +31,9 @@ class IntegrationRepositoryInterface {
|
|
|
29
31
|
* @abstract
|
|
30
32
|
*/
|
|
31
33
|
async deleteIntegrationById(integrationId) {
|
|
32
|
-
throw new Error(
|
|
34
|
+
throw new Error(
|
|
35
|
+
'Method deleteIntegrationById must be implemented by subclass'
|
|
36
|
+
);
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
/**
|
|
@@ -40,7 +44,9 @@ class IntegrationRepositoryInterface {
|
|
|
40
44
|
* @abstract
|
|
41
45
|
*/
|
|
42
46
|
async findIntegrationByName(name) {
|
|
43
|
-
throw new Error(
|
|
47
|
+
throw new Error(
|
|
48
|
+
'Method findIntegrationByName must be implemented by subclass'
|
|
49
|
+
);
|
|
44
50
|
}
|
|
45
51
|
|
|
46
52
|
/**
|
|
@@ -51,7 +57,9 @@ class IntegrationRepositoryInterface {
|
|
|
51
57
|
* @abstract
|
|
52
58
|
*/
|
|
53
59
|
async findIntegrationById(id) {
|
|
54
|
-
throw new Error(
|
|
60
|
+
throw new Error(
|
|
61
|
+
'Method findIntegrationById must be implemented by subclass'
|
|
62
|
+
);
|
|
55
63
|
}
|
|
56
64
|
|
|
57
65
|
/**
|
|
@@ -63,7 +71,9 @@ class IntegrationRepositoryInterface {
|
|
|
63
71
|
* @abstract
|
|
64
72
|
*/
|
|
65
73
|
async updateIntegrationStatus(integrationId, status) {
|
|
66
|
-
throw new Error(
|
|
74
|
+
throw new Error(
|
|
75
|
+
'Method updateIntegrationStatus must be implemented by subclass'
|
|
76
|
+
);
|
|
67
77
|
}
|
|
68
78
|
|
|
69
79
|
/**
|
|
@@ -84,7 +94,9 @@ class IntegrationRepositoryInterface {
|
|
|
84
94
|
messageBody,
|
|
85
95
|
messageTimestamp
|
|
86
96
|
) {
|
|
87
|
-
throw new Error(
|
|
97
|
+
throw new Error(
|
|
98
|
+
'Method updateIntegrationMessages must be implemented by subclass'
|
|
99
|
+
);
|
|
88
100
|
}
|
|
89
101
|
|
|
90
102
|
/**
|
|
@@ -97,7 +109,9 @@ class IntegrationRepositoryInterface {
|
|
|
97
109
|
* @abstract
|
|
98
110
|
*/
|
|
99
111
|
async createIntegration(entities, userId, config) {
|
|
100
|
-
throw new Error(
|
|
112
|
+
throw new Error(
|
|
113
|
+
'Method createIntegration must be implemented by subclass'
|
|
114
|
+
);
|
|
101
115
|
}
|
|
102
116
|
|
|
103
117
|
/**
|
|
@@ -108,7 +122,9 @@ class IntegrationRepositoryInterface {
|
|
|
108
122
|
* @abstract
|
|
109
123
|
*/
|
|
110
124
|
async findIntegrationByUserId(userId) {
|
|
111
|
-
throw new Error(
|
|
125
|
+
throw new Error(
|
|
126
|
+
'Method findIntegrationByUserId must be implemented by subclass'
|
|
127
|
+
);
|
|
112
128
|
}
|
|
113
129
|
|
|
114
130
|
/**
|
|
@@ -120,7 +136,9 @@ class IntegrationRepositoryInterface {
|
|
|
120
136
|
* @abstract
|
|
121
137
|
*/
|
|
122
138
|
async updateIntegrationConfig(integrationId, config) {
|
|
123
|
-
throw new Error(
|
|
139
|
+
throw new Error(
|
|
140
|
+
'Method updateIntegrationConfig must be implemented by subclass'
|
|
141
|
+
);
|
|
124
142
|
}
|
|
125
143
|
}
|
|
126
144
|
|
|
@@ -49,12 +49,12 @@ class IntegrationRepositoryPostgres extends IntegrationRepositoryInterface {
|
|
|
49
49
|
...integration,
|
|
50
50
|
id: integration.id?.toString(),
|
|
51
51
|
userId: integration.userId?.toString(),
|
|
52
|
-
entities: integration.entities?.map(e => ({
|
|
52
|
+
entities: integration.entities?.map((e) => ({
|
|
53
53
|
...e,
|
|
54
54
|
id: e.id?.toString(),
|
|
55
55
|
userId: e.userId?.toString(),
|
|
56
|
-
credentialId: e.credentialId?.toString()
|
|
57
|
-
}))
|
|
56
|
+
credentialId: e.credentialId?.toString(),
|
|
57
|
+
})),
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
const { ProcessRepositoryMongo } = require('./process-repository-mongo');
|
|
2
1
|
const { ProcessRepositoryPostgres } = require('./process-repository-postgres');
|
|
3
|
-
const {
|
|
4
|
-
ProcessRepositoryDocumentDB,
|
|
5
|
-
} = require('./process-repository-documentdb');
|
|
6
2
|
const config = require('../../database/config');
|
|
7
3
|
|
|
8
4
|
/**
|
|
@@ -28,12 +24,14 @@ function createProcessRepository() {
|
|
|
28
24
|
|
|
29
25
|
switch (dbType) {
|
|
30
26
|
case 'mongodb':
|
|
27
|
+
const { ProcessRepositoryMongo } = require('./process-repository-mongo');
|
|
31
28
|
return new ProcessRepositoryMongo();
|
|
32
29
|
|
|
33
30
|
case 'postgresql':
|
|
34
31
|
return new ProcessRepositoryPostgres();
|
|
35
32
|
|
|
36
33
|
case 'documentdb':
|
|
34
|
+
const { ProcessRepositoryDocumentDB } = require('./process-repository-documentdb');
|
|
37
35
|
return new ProcessRepositoryDocumentDB();
|
|
38
36
|
|
|
39
37
|
default:
|
|
@@ -46,8 +44,7 @@ function createProcessRepository() {
|
|
|
46
44
|
module.exports = {
|
|
47
45
|
createProcessRepository,
|
|
48
46
|
// Export adapters for direct testing
|
|
49
|
-
ProcessRepositoryMongo,
|
|
47
|
+
get ProcessRepositoryMongo() { return require('./process-repository-mongo').ProcessRepositoryMongo; },
|
|
50
48
|
ProcessRepositoryPostgres,
|
|
51
|
-
ProcessRepositoryDocumentDB,
|
|
49
|
+
get ProcessRepositoryDocumentDB() { return require('./process-repository-documentdb').ProcessRepositoryDocumentDB; },
|
|
52
50
|
};
|
|
53
|
-
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ProcessRepository Interface
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Defines the contract for Process data access operations.
|
|
5
5
|
* Implementations must provide concrete methods for all operations.
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
7
|
* This interface supports the Hexagonal Architecture pattern by:
|
|
8
8
|
* - Defining clear boundaries between domain logic and data access
|
|
9
9
|
* - Allowing multiple implementations (MongoDB, PostgreSQL, in-memory)
|
|
@@ -54,7 +54,9 @@ class ProcessRepositoryInterface {
|
|
|
54
54
|
* @returns {Promise<Array>} Array of process records
|
|
55
55
|
*/
|
|
56
56
|
async findByIntegrationAndType(integrationId, type) {
|
|
57
|
-
throw new Error(
|
|
57
|
+
throw new Error(
|
|
58
|
+
'Method findByIntegrationAndType() must be implemented'
|
|
59
|
+
);
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
/**
|
|
@@ -63,7 +65,10 @@ class ProcessRepositoryInterface {
|
|
|
63
65
|
* @param {string[]} [excludeStates=['COMPLETED', 'ERROR']] - States to exclude
|
|
64
66
|
* @returns {Promise<Array>} Array of active process records
|
|
65
67
|
*/
|
|
66
|
-
async findActiveProcesses(
|
|
68
|
+
async findActiveProcesses(
|
|
69
|
+
integrationId,
|
|
70
|
+
excludeStates = ['COMPLETED', 'ERROR']
|
|
71
|
+
) {
|
|
67
72
|
throw new Error('Method findActiveProcesses() must be implemented');
|
|
68
73
|
}
|
|
69
74
|
|
|
@@ -87,4 +92,3 @@ class ProcessRepositoryInterface {
|
|
|
87
92
|
}
|
|
88
93
|
|
|
89
94
|
module.exports = { ProcessRepositoryInterface };
|
|
90
|
-
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
const { prisma } = require('../../database/prisma');
|
|
2
|
-
const {
|
|
2
|
+
const {
|
|
3
|
+
ProcessRepositoryInterface,
|
|
4
|
+
} = require('./process-repository-interface');
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
7
|
* MongoDB Process Repository Adapter
|
|
@@ -118,7 +120,10 @@ class ProcessRepositoryMongo extends ProcessRepositoryInterface {
|
|
|
118
120
|
* @param {string[]} [excludeStates=['COMPLETED', 'ERROR']] - States to exclude
|
|
119
121
|
* @returns {Promise<Array>} Array of active process records
|
|
120
122
|
*/
|
|
121
|
-
async findActiveProcesses(
|
|
123
|
+
async findActiveProcesses(
|
|
124
|
+
integrationId,
|
|
125
|
+
excludeStates = ['COMPLETED', 'ERROR']
|
|
126
|
+
) {
|
|
122
127
|
const processes = await this.prisma.process.findMany({
|
|
123
128
|
where: {
|
|
124
129
|
integrationId,
|
|
@@ -187,4 +192,3 @@ class ProcessRepositoryMongo extends ProcessRepositoryInterface {
|
|
|
187
192
|
}
|
|
188
193
|
|
|
189
194
|
module.exports = { ProcessRepositoryMongo };
|
|
190
|
-
|
|
@@ -199,8 +199,8 @@ class ProcessRepositoryPostgres extends ProcessRepositoryInterface {
|
|
|
199
199
|
results: process.results,
|
|
200
200
|
childProcesses: Array.isArray(process.childProcesses)
|
|
201
201
|
? process.childProcesses.length > 0 &&
|
|
202
|
-
|
|
203
|
-
|
|
202
|
+
typeof process.childProcesses[0] === 'object' &&
|
|
203
|
+
process.childProcesses[0] !== null
|
|
204
204
|
? process.childProcesses.map((child) => String(child.id))
|
|
205
205
|
: process.childProcesses
|
|
206
206
|
: [],
|
|
@@ -2,7 +2,7 @@ const { IntegrationBase } = require('../../integration-base');
|
|
|
2
2
|
|
|
3
3
|
class ConfigCapturingModule {
|
|
4
4
|
static definition = {
|
|
5
|
-
getName: () => 'config-capturing-module'
|
|
5
|
+
getName: () => 'config-capturing-module',
|
|
6
6
|
};
|
|
7
7
|
}
|
|
8
8
|
|
|
@@ -11,14 +11,15 @@ class ConfigCapturingIntegration extends IntegrationBase {
|
|
|
11
11
|
name: 'config-capturing',
|
|
12
12
|
version: '1.0.0',
|
|
13
13
|
modules: {
|
|
14
|
-
primary: ConfigCapturingModule
|
|
14
|
+
primary: ConfigCapturingModule,
|
|
15
15
|
},
|
|
16
16
|
display: {
|
|
17
17
|
label: 'Config Capturing Integration',
|
|
18
|
-
description:
|
|
18
|
+
description:
|
|
19
|
+
'Test double for capturing config state during updates',
|
|
19
20
|
detailsUrl: 'https://example.com',
|
|
20
|
-
icon: 'test-icon'
|
|
21
|
-
}
|
|
21
|
+
icon: 'test-icon',
|
|
22
|
+
},
|
|
22
23
|
};
|
|
23
24
|
|
|
24
25
|
static _capturedOnUpdateState = null;
|
|
@@ -38,10 +39,10 @@ class ConfigCapturingIntegration extends IntegrationBase {
|
|
|
38
39
|
findIntegrationById: jest.fn().mockResolvedValue({}),
|
|
39
40
|
};
|
|
40
41
|
this.updateIntegrationStatus = {
|
|
41
|
-
execute: jest.fn().mockResolvedValue({})
|
|
42
|
+
execute: jest.fn().mockResolvedValue({}),
|
|
42
43
|
};
|
|
43
44
|
this.updateIntegrationMessages = {
|
|
44
|
-
execute: jest.fn().mockResolvedValue({})
|
|
45
|
+
execute: jest.fn().mockResolvedValue({}),
|
|
45
46
|
};
|
|
46
47
|
}
|
|
47
48
|
|
|
@@ -52,7 +53,7 @@ class ConfigCapturingIntegration extends IntegrationBase {
|
|
|
52
53
|
async onUpdate(params) {
|
|
53
54
|
ConfigCapturingIntegration._capturedOnUpdateState = {
|
|
54
55
|
thisConfig: JSON.parse(JSON.stringify(this.config)),
|
|
55
|
-
paramsConfig: params.config
|
|
56
|
+
paramsConfig: params.config,
|
|
56
57
|
};
|
|
57
58
|
|
|
58
59
|
this.config = this._deepMerge(this.config, params.config);
|