@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
package/integrations/options.js
CHANGED
|
@@ -4,8 +4,11 @@ const { get } = require('../assertions');
|
|
|
4
4
|
class Options {
|
|
5
5
|
constructor(params) {
|
|
6
6
|
this.module = get(params, 'module');
|
|
7
|
-
this.
|
|
7
|
+
this.isMany = Boolean(get(params, 'isMany', false));
|
|
8
8
|
this.hasUserConfig = Boolean(get(params, 'hasUserConfig', false));
|
|
9
|
+
this.requiresNewEntity = Boolean(
|
|
10
|
+
get(params, 'requiresNewEntity', false)
|
|
11
|
+
);
|
|
9
12
|
if (!params.display) {
|
|
10
13
|
throw new RequiredPropertyError({
|
|
11
14
|
parent: this,
|
|
@@ -14,66 +17,36 @@ class Options {
|
|
|
14
17
|
}
|
|
15
18
|
|
|
16
19
|
this.display = {};
|
|
17
|
-
// Required fields
|
|
18
20
|
this.display.name = get(params.display, 'label');
|
|
19
21
|
this.display.description = get(params.display, 'description');
|
|
20
|
-
|
|
21
|
-
this.display.
|
|
22
|
-
this.display.icon = params.display.icon || null;
|
|
22
|
+
this.display.detailsUrl = get(params.display, 'detailsUrl');
|
|
23
|
+
this.display.icon = get(params.display, 'icon');
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
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
|
-
|
|
32
27
|
return {
|
|
33
|
-
type:
|
|
28
|
+
type: this.module.definition.getName(),
|
|
34
29
|
|
|
35
30
|
// Flag for if the User can configure any settings
|
|
36
31
|
hasUserConfig: this.hasUserConfig,
|
|
37
32
|
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
|
|
33
|
+
// if this integration can be used multiple times with the same integration pair. For example I want to
|
|
34
|
+
// connect two different Etsy shops to the same Freshbooks account.
|
|
35
|
+
isMany: this.isMany,
|
|
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,
|
|
41
42
|
|
|
42
43
|
// this is information required for the display side of things on the front end
|
|
43
44
|
display: this.display,
|
|
44
|
-
};
|
|
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
45
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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';
|
|
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
|
+
};
|
|
77
50
|
}
|
|
78
51
|
}
|
|
79
52
|
|
|
@@ -29,17 +29,13 @@ 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', {
|
|
33
|
-
_id: objectId,
|
|
34
|
-
});
|
|
32
|
+
const result = await deleteOne(this.prisma, 'Integration', { _id: objectId });
|
|
35
33
|
const deleted = result?.n ?? 0;
|
|
36
34
|
return { acknowledged: true, deletedCount: deleted };
|
|
37
35
|
}
|
|
38
36
|
|
|
39
37
|
async findIntegrationByName(name) {
|
|
40
|
-
const doc = await findOne(this.prisma, 'Integration', {
|
|
41
|
-
'config.type': name,
|
|
42
|
-
});
|
|
38
|
+
const doc = await findOne(this.prisma, 'Integration', { 'config.type': name });
|
|
43
39
|
if (!doc) {
|
|
44
40
|
throw new Error(`Integration with name ${name} not found`);
|
|
45
41
|
}
|
|
@@ -51,9 +47,7 @@ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
|
|
|
51
47
|
if (!objectId) {
|
|
52
48
|
throw new Error(`Integration with id ${id} not found`);
|
|
53
49
|
}
|
|
54
|
-
const doc = await findOne(this.prisma, 'Integration', {
|
|
55
|
-
_id: objectId,
|
|
56
|
-
});
|
|
50
|
+
const doc = await findOne(this.prisma, 'Integration', { _id: objectId });
|
|
57
51
|
if (!doc) {
|
|
58
52
|
throw new Error(`Integration with id ${id} not found`);
|
|
59
53
|
}
|
|
@@ -85,16 +79,12 @@ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
|
|
|
85
79
|
if (!objectId) {
|
|
86
80
|
throw new Error(`Integration ${integrationId} not found`);
|
|
87
81
|
}
|
|
88
|
-
const existing = await findOne(this.prisma, 'Integration', {
|
|
89
|
-
_id: objectId,
|
|
90
|
-
});
|
|
82
|
+
const existing = await findOne(this.prisma, 'Integration', { _id: objectId });
|
|
91
83
|
if (!existing) {
|
|
92
84
|
throw new Error(`Integration ${integrationId} not found`);
|
|
93
85
|
}
|
|
94
86
|
const messages = this._extractMessages(existing);
|
|
95
|
-
const list = Array.isArray(messages[messageType])
|
|
96
|
-
? [...messages[messageType]]
|
|
97
|
-
: [];
|
|
87
|
+
const list = Array.isArray(messages[messageType]) ? [...messages[messageType]] : [];
|
|
98
88
|
list.push({
|
|
99
89
|
title: messageTitle ?? null,
|
|
100
90
|
message: messageBody,
|
|
@@ -135,26 +125,17 @@ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
|
|
|
135
125
|
createdAt: now,
|
|
136
126
|
updatedAt: now,
|
|
137
127
|
};
|
|
138
|
-
const insertedId = await insertOne(
|
|
139
|
-
|
|
140
|
-
'Integration',
|
|
141
|
-
document
|
|
142
|
-
);
|
|
143
|
-
const created = await findOne(this.prisma, 'Integration', {
|
|
144
|
-
_id: insertedId,
|
|
145
|
-
});
|
|
128
|
+
const insertedId = await insertOne(this.prisma, 'Integration', document);
|
|
129
|
+
const created = await findOne(this.prisma, 'Integration', { _id: insertedId });
|
|
146
130
|
if (!created) {
|
|
147
|
-
console.error(
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
config,
|
|
153
|
-
}
|
|
154
|
-
);
|
|
131
|
+
console.error('[IntegrationRepositoryDocumentDB] Integration not found after insert', {
|
|
132
|
+
insertedId: fromObjectId(insertedId),
|
|
133
|
+
userId,
|
|
134
|
+
config,
|
|
135
|
+
});
|
|
155
136
|
throw new Error(
|
|
156
137
|
'Failed to create integration: Document not found after insert. ' +
|
|
157
|
-
|
|
138
|
+
'This indicates a database consistency issue.'
|
|
158
139
|
);
|
|
159
140
|
}
|
|
160
141
|
return this._mapIntegration(created);
|
|
@@ -163,9 +144,7 @@ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
|
|
|
163
144
|
async findIntegrationByUserId(userId) {
|
|
164
145
|
const objectId = toObjectId(userId);
|
|
165
146
|
if (!objectId) return null;
|
|
166
|
-
const doc = await findOne(this.prisma, 'Integration', {
|
|
167
|
-
userId: objectId,
|
|
168
|
-
});
|
|
147
|
+
const doc = await findOne(this.prisma, 'Integration', { userId: objectId });
|
|
169
148
|
return doc ? this._mapIntegration(doc) : null;
|
|
170
149
|
}
|
|
171
150
|
|
|
@@ -188,20 +167,15 @@ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
|
|
|
188
167
|
},
|
|
189
168
|
}
|
|
190
169
|
);
|
|
191
|
-
const updated = await findOne(this.prisma, 'Integration', {
|
|
192
|
-
_id: objectId,
|
|
193
|
-
});
|
|
170
|
+
const updated = await findOne(this.prisma, 'Integration', { _id: objectId });
|
|
194
171
|
if (!updated) {
|
|
195
|
-
console.error(
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
config,
|
|
200
|
-
}
|
|
201
|
-
);
|
|
172
|
+
console.error('[IntegrationRepositoryDocumentDB] Integration not found after update', {
|
|
173
|
+
integrationId: fromObjectId(objectId),
|
|
174
|
+
config,
|
|
175
|
+
});
|
|
202
176
|
throw new Error(
|
|
203
177
|
'Failed to update integration: Document not found after update. ' +
|
|
204
|
-
|
|
178
|
+
'This indicates a database consistency issue.'
|
|
205
179
|
);
|
|
206
180
|
}
|
|
207
181
|
return this._mapIntegration(updated);
|
|
@@ -211,9 +185,7 @@ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
|
|
|
211
185
|
const messages = this._extractMessages(doc);
|
|
212
186
|
return {
|
|
213
187
|
id: fromObjectId(doc?._id),
|
|
214
|
-
entitiesIds: (doc?.entityIds || []).map((value) =>
|
|
215
|
-
fromObjectId(value)
|
|
216
|
-
),
|
|
188
|
+
entitiesIds: (doc?.entityIds || []).map((value) => fromObjectId(value)),
|
|
217
189
|
userId: fromObjectId(doc?.userId),
|
|
218
190
|
config: doc?.config ?? null,
|
|
219
191
|
version: doc?.version ?? null,
|
|
@@ -223,10 +195,7 @@ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
|
|
|
223
195
|
}
|
|
224
196
|
|
|
225
197
|
_extractMessages(doc) {
|
|
226
|
-
const base =
|
|
227
|
-
doc?.messages && typeof doc.messages === 'object'
|
|
228
|
-
? doc.messages
|
|
229
|
-
: {};
|
|
198
|
+
const base = doc?.messages && typeof doc.messages === 'object' ? doc.messages : {};
|
|
230
199
|
return {
|
|
231
200
|
errors: base.errors ?? doc?.errors ?? [],
|
|
232
201
|
warnings: base.warnings ?? doc?.warnings ?? [],
|
|
@@ -237,3 +206,5 @@ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
|
|
|
237
206
|
}
|
|
238
207
|
|
|
239
208
|
module.exports = { IntegrationRepositoryDocumentDB };
|
|
209
|
+
|
|
210
|
+
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
const {
|
|
2
|
-
|
|
3
|
-
} = require('./integration-repository-mongo');
|
|
4
|
-
const {
|
|
5
|
-
IntegrationRepositoryPostgres,
|
|
6
|
-
} = require('./integration-repository-postgres');
|
|
1
|
+
const { IntegrationRepositoryMongo } = require('./integration-repository-mongo');
|
|
2
|
+
const { IntegrationRepositoryPostgres } = require('./integration-repository-postgres');
|
|
7
3
|
const {
|
|
8
4
|
IntegrationRepositoryDocumentDB,
|
|
9
5
|
} = require('./integration-repository-documentdb');
|
|
@@ -18,9 +18,7 @@ class IntegrationRepositoryInterface {
|
|
|
18
18
|
* @abstract
|
|
19
19
|
*/
|
|
20
20
|
async findIntegrationsByUserId(userId) {
|
|
21
|
-
throw new Error(
|
|
22
|
-
'Method findIntegrationsByUserId must be implemented by subclass'
|
|
23
|
-
);
|
|
21
|
+
throw new Error('Method findIntegrationsByUserId must be implemented by subclass');
|
|
24
22
|
}
|
|
25
23
|
|
|
26
24
|
/**
|
|
@@ -31,9 +29,7 @@ class IntegrationRepositoryInterface {
|
|
|
31
29
|
* @abstract
|
|
32
30
|
*/
|
|
33
31
|
async deleteIntegrationById(integrationId) {
|
|
34
|
-
throw new Error(
|
|
35
|
-
'Method deleteIntegrationById must be implemented by subclass'
|
|
36
|
-
);
|
|
32
|
+
throw new Error('Method deleteIntegrationById must be implemented by subclass');
|
|
37
33
|
}
|
|
38
34
|
|
|
39
35
|
/**
|
|
@@ -44,9 +40,7 @@ class IntegrationRepositoryInterface {
|
|
|
44
40
|
* @abstract
|
|
45
41
|
*/
|
|
46
42
|
async findIntegrationByName(name) {
|
|
47
|
-
throw new Error(
|
|
48
|
-
'Method findIntegrationByName must be implemented by subclass'
|
|
49
|
-
);
|
|
43
|
+
throw new Error('Method findIntegrationByName must be implemented by subclass');
|
|
50
44
|
}
|
|
51
45
|
|
|
52
46
|
/**
|
|
@@ -57,9 +51,7 @@ class IntegrationRepositoryInterface {
|
|
|
57
51
|
* @abstract
|
|
58
52
|
*/
|
|
59
53
|
async findIntegrationById(id) {
|
|
60
|
-
throw new Error(
|
|
61
|
-
'Method findIntegrationById must be implemented by subclass'
|
|
62
|
-
);
|
|
54
|
+
throw new Error('Method findIntegrationById must be implemented by subclass');
|
|
63
55
|
}
|
|
64
56
|
|
|
65
57
|
/**
|
|
@@ -71,9 +63,7 @@ class IntegrationRepositoryInterface {
|
|
|
71
63
|
* @abstract
|
|
72
64
|
*/
|
|
73
65
|
async updateIntegrationStatus(integrationId, status) {
|
|
74
|
-
throw new Error(
|
|
75
|
-
'Method updateIntegrationStatus must be implemented by subclass'
|
|
76
|
-
);
|
|
66
|
+
throw new Error('Method updateIntegrationStatus must be implemented by subclass');
|
|
77
67
|
}
|
|
78
68
|
|
|
79
69
|
/**
|
|
@@ -94,9 +84,7 @@ class IntegrationRepositoryInterface {
|
|
|
94
84
|
messageBody,
|
|
95
85
|
messageTimestamp
|
|
96
86
|
) {
|
|
97
|
-
throw new Error(
|
|
98
|
-
'Method updateIntegrationMessages must be implemented by subclass'
|
|
99
|
-
);
|
|
87
|
+
throw new Error('Method updateIntegrationMessages must be implemented by subclass');
|
|
100
88
|
}
|
|
101
89
|
|
|
102
90
|
/**
|
|
@@ -109,9 +97,7 @@ class IntegrationRepositoryInterface {
|
|
|
109
97
|
* @abstract
|
|
110
98
|
*/
|
|
111
99
|
async createIntegration(entities, userId, config) {
|
|
112
|
-
throw new Error(
|
|
113
|
-
'Method createIntegration must be implemented by subclass'
|
|
114
|
-
);
|
|
100
|
+
throw new Error('Method createIntegration must be implemented by subclass');
|
|
115
101
|
}
|
|
116
102
|
|
|
117
103
|
/**
|
|
@@ -122,9 +108,7 @@ class IntegrationRepositoryInterface {
|
|
|
122
108
|
* @abstract
|
|
123
109
|
*/
|
|
124
110
|
async findIntegrationByUserId(userId) {
|
|
125
|
-
throw new Error(
|
|
126
|
-
'Method findIntegrationByUserId must be implemented by subclass'
|
|
127
|
-
);
|
|
111
|
+
throw new Error('Method findIntegrationByUserId must be implemented by subclass');
|
|
128
112
|
}
|
|
129
113
|
|
|
130
114
|
/**
|
|
@@ -136,9 +120,7 @@ class IntegrationRepositoryInterface {
|
|
|
136
120
|
* @abstract
|
|
137
121
|
*/
|
|
138
122
|
async updateIntegrationConfig(integrationId, config) {
|
|
139
|
-
throw new Error(
|
|
140
|
-
'Method updateIntegrationConfig must be implemented by subclass'
|
|
141
|
-
);
|
|
123
|
+
throw new Error('Method updateIntegrationConfig must be implemented by subclass');
|
|
142
124
|
}
|
|
143
125
|
}
|
|
144
126
|
|
|
@@ -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(
|
|
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,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,9 +54,7 @@ class ProcessRepositoryInterface {
|
|
|
54
54
|
* @returns {Promise<Array>} Array of process records
|
|
55
55
|
*/
|
|
56
56
|
async findByIntegrationAndType(integrationId, type) {
|
|
57
|
-
throw new Error(
|
|
58
|
-
'Method findByIntegrationAndType() must be implemented'
|
|
59
|
-
);
|
|
57
|
+
throw new Error('Method findByIntegrationAndType() must be implemented');
|
|
60
58
|
}
|
|
61
59
|
|
|
62
60
|
/**
|
|
@@ -65,10 +63,7 @@ class ProcessRepositoryInterface {
|
|
|
65
63
|
* @param {string[]} [excludeStates=['COMPLETED', 'ERROR']] - States to exclude
|
|
66
64
|
* @returns {Promise<Array>} Array of active process records
|
|
67
65
|
*/
|
|
68
|
-
async findActiveProcesses(
|
|
69
|
-
integrationId,
|
|
70
|
-
excludeStates = ['COMPLETED', 'ERROR']
|
|
71
|
-
) {
|
|
66
|
+
async findActiveProcesses(integrationId, excludeStates = ['COMPLETED', 'ERROR']) {
|
|
72
67
|
throw new Error('Method findActiveProcesses() must be implemented');
|
|
73
68
|
}
|
|
74
69
|
|
|
@@ -92,3 +87,4 @@ class ProcessRepositoryInterface {
|
|
|
92
87
|
}
|
|
93
88
|
|
|
94
89
|
module.exports = { ProcessRepositoryInterface };
|
|
90
|
+
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
const { prisma } = require('../../database/prisma');
|
|
2
|
-
const {
|
|
3
|
-
ProcessRepositoryInterface,
|
|
4
|
-
} = require('./process-repository-interface');
|
|
2
|
+
const { ProcessRepositoryInterface } = require('./process-repository-interface');
|
|
5
3
|
|
|
6
4
|
/**
|
|
7
5
|
* MongoDB Process Repository Adapter
|
|
@@ -120,10 +118,7 @@ class ProcessRepositoryMongo extends ProcessRepositoryInterface {
|
|
|
120
118
|
* @param {string[]} [excludeStates=['COMPLETED', 'ERROR']] - States to exclude
|
|
121
119
|
* @returns {Promise<Array>} Array of active process records
|
|
122
120
|
*/
|
|
123
|
-
async findActiveProcesses(
|
|
124
|
-
integrationId,
|
|
125
|
-
excludeStates = ['COMPLETED', 'ERROR']
|
|
126
|
-
) {
|
|
121
|
+
async findActiveProcesses(integrationId, excludeStates = ['COMPLETED', 'ERROR']) {
|
|
127
122
|
const processes = await this.prisma.process.findMany({
|
|
128
123
|
where: {
|
|
129
124
|
integrationId,
|
|
@@ -192,3 +187,4 @@ class ProcessRepositoryMongo extends ProcessRepositoryInterface {
|
|
|
192
187
|
}
|
|
193
188
|
|
|
194
189
|
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,15 +11,14 @@ 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:
|
|
19
|
-
'Test double for capturing config state during updates',
|
|
18
|
+
description: 'Test double for capturing config state during updates',
|
|
20
19
|
detailsUrl: 'https://example.com',
|
|
21
|
-
icon: 'test-icon'
|
|
22
|
-
}
|
|
20
|
+
icon: 'test-icon'
|
|
21
|
+
}
|
|
23
22
|
};
|
|
24
23
|
|
|
25
24
|
static _capturedOnUpdateState = null;
|
|
@@ -39,10 +38,10 @@ class ConfigCapturingIntegration extends IntegrationBase {
|
|
|
39
38
|
findIntegrationById: jest.fn().mockResolvedValue({}),
|
|
40
39
|
};
|
|
41
40
|
this.updateIntegrationStatus = {
|
|
42
|
-
execute: jest.fn().mockResolvedValue({})
|
|
41
|
+
execute: jest.fn().mockResolvedValue({})
|
|
43
42
|
};
|
|
44
43
|
this.updateIntegrationMessages = {
|
|
45
|
-
execute: jest.fn().mockResolvedValue({})
|
|
44
|
+
execute: jest.fn().mockResolvedValue({})
|
|
46
45
|
};
|
|
47
46
|
}
|
|
48
47
|
|
|
@@ -53,7 +52,7 @@ class ConfigCapturingIntegration extends IntegrationBase {
|
|
|
53
52
|
async onUpdate(params) {
|
|
54
53
|
ConfigCapturingIntegration._capturedOnUpdateState = {
|
|
55
54
|
thisConfig: JSON.parse(JSON.stringify(this.config)),
|
|
56
|
-
paramsConfig: params.config
|
|
55
|
+
paramsConfig: params.config
|
|
57
56
|
};
|
|
58
57
|
|
|
59
58
|
this.config = this._deepMerge(this.config, params.config);
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
const { IntegrationBase } = require('../../integration-base');
|
|
2
|
-
const { Options } = require('../../options');
|
|
3
2
|
|
|
4
3
|
class DummyModule {
|
|
5
4
|
static definition = {
|
|
6
|
-
getName: () => 'dummy'
|
|
5
|
+
getName: () => 'dummy'
|
|
7
6
|
};
|
|
8
7
|
}
|
|
9
8
|
|
|
@@ -12,25 +11,21 @@ class DummyIntegration extends IntegrationBase {
|
|
|
12
11
|
name: 'dummy',
|
|
13
12
|
version: '1.0.0',
|
|
14
13
|
modules: {
|
|
15
|
-
dummy: DummyModule
|
|
14
|
+
dummy: DummyModule
|
|
16
15
|
},
|
|
17
16
|
display: {
|
|
18
17
|
label: 'Dummy Integration',
|
|
19
18
|
description: 'A dummy integration for testing',
|
|
20
19
|
detailsUrl: 'https://example.com',
|
|
21
|
-
icon: 'dummy-icon'
|
|
22
|
-
}
|
|
20
|
+
icon: 'dummy-icon'
|
|
21
|
+
}
|
|
23
22
|
};
|
|
24
23
|
|
|
25
24
|
static getOptionDetails() {
|
|
26
|
-
const options = new Options({
|
|
27
|
-
module: Object.values(this.Definition.modules)[0],
|
|
28
|
-
...this.Definition,
|
|
29
|
-
});
|
|
30
25
|
return {
|
|
31
26
|
name: this.Definition.name,
|
|
32
27
|
version: this.Definition.version,
|
|
33
|
-
|
|
28
|
+
display: this.Definition.display
|
|
34
29
|
};
|
|
35
30
|
}
|
|
36
31
|
|
|
@@ -46,11 +41,11 @@ class DummyIntegration extends IntegrationBase {
|
|
|
46
41
|
};
|
|
47
42
|
|
|
48
43
|
this.updateIntegrationStatus = {
|
|
49
|
-
execute: jest.fn().mockResolvedValue({})
|
|
44
|
+
execute: jest.fn().mockResolvedValue({})
|
|
50
45
|
};
|
|
51
46
|
|
|
52
47
|
this.updateIntegrationMessages = {
|
|
53
|
-
execute: jest.fn().mockResolvedValue({})
|
|
48
|
+
execute: jest.fn().mockResolvedValue({})
|
|
54
49
|
};
|
|
55
50
|
}
|
|
56
51
|
|
|
@@ -107,72 +102,4 @@ class DummyIntegration extends IntegrationBase {
|
|
|
107
102
|
}
|
|
108
103
|
}
|
|
109
104
|
|
|
110
|
-
|
|
111
|
-
static Definition = {
|
|
112
|
-
name: 'dummy-with-global',
|
|
113
|
-
version: '1.0.0',
|
|
114
|
-
modules: { dummy: DummyModule },
|
|
115
|
-
display: { label: 'Dummy With Global', description: 'Test' },
|
|
116
|
-
entities: {
|
|
117
|
-
sharedService: {
|
|
118
|
-
type: 'shared-api',
|
|
119
|
-
global: true,
|
|
120
|
-
required: true,
|
|
121
|
-
},
|
|
122
|
-
},
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
constructor(params) {
|
|
126
|
-
super(params);
|
|
127
|
-
this.sendSpy = jest.fn();
|
|
128
|
-
this.integrationRepository = {
|
|
129
|
-
updateIntegrationById: jest.fn().mockResolvedValue({}),
|
|
130
|
-
findIntegrationById: jest.fn().mockResolvedValue({}),
|
|
131
|
-
};
|
|
132
|
-
this.updateIntegrationStatus = { execute: jest.fn().mockResolvedValue({}) };
|
|
133
|
-
this.updateIntegrationMessages = { execute: jest.fn().mockResolvedValue({}) };
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
async loadDynamicUserActions() { return {}; }
|
|
137
|
-
async send(event, data) { this.sendSpy(event, data); return { event, data }; }
|
|
138
|
-
async initialize() { return; }
|
|
139
|
-
async onCreate() { return; }
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
class DummyIntegrationWithOptionalGlobalEntity extends IntegrationBase {
|
|
143
|
-
static Definition = {
|
|
144
|
-
name: 'dummy-with-optional-global',
|
|
145
|
-
version: '1.0.0',
|
|
146
|
-
modules: { dummy: DummyModule },
|
|
147
|
-
display: { label: 'Dummy With Optional Global', description: 'Test' },
|
|
148
|
-
entities: {
|
|
149
|
-
optionalService: {
|
|
150
|
-
type: 'optional-api',
|
|
151
|
-
global: true,
|
|
152
|
-
required: false,
|
|
153
|
-
},
|
|
154
|
-
},
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
constructor(params) {
|
|
158
|
-
super(params);
|
|
159
|
-
this.sendSpy = jest.fn();
|
|
160
|
-
this.integrationRepository = {
|
|
161
|
-
updateIntegrationById: jest.fn().mockResolvedValue({}),
|
|
162
|
-
findIntegrationById: jest.fn().mockResolvedValue({}),
|
|
163
|
-
};
|
|
164
|
-
this.updateIntegrationStatus = { execute: jest.fn().mockResolvedValue({}) };
|
|
165
|
-
this.updateIntegrationMessages = { execute: jest.fn().mockResolvedValue({}) };
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
async loadDynamicUserActions() { return {}; }
|
|
169
|
-
async send(event, data) { this.sendSpy(event, data); return { event, data }; }
|
|
170
|
-
async initialize() { return; }
|
|
171
|
-
async onCreate() { return; }
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
module.exports = {
|
|
175
|
-
DummyIntegration,
|
|
176
|
-
DummyIntegrationWithGlobalEntity,
|
|
177
|
-
DummyIntegrationWithOptionalGlobalEntity,
|
|
178
|
-
};
|
|
105
|
+
module.exports = { DummyIntegration };
|