@friggframework/core 2.0.0-next.5 → 2.0.0-next.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +693 -0
- package/README.md +959 -50
- package/application/commands/README.md +421 -0
- package/application/commands/credential-commands.js +224 -0
- package/application/commands/entity-commands.js +315 -0
- package/application/commands/integration-commands.js +179 -0
- package/application/commands/user-commands.js +213 -0
- package/application/index.js +69 -0
- package/core/CLAUDE.md +690 -0
- package/core/Worker.js +8 -21
- package/core/create-handler.js +2 -7
- package/credential/repositories/credential-repository-factory.js +47 -0
- package/credential/repositories/credential-repository-interface.js +98 -0
- package/credential/repositories/credential-repository-mongo.js +307 -0
- package/credential/repositories/credential-repository-postgres.js +313 -0
- package/credential/repositories/credential-repository.js +302 -0
- package/credential/use-cases/get-credential-for-user.js +21 -0
- package/credential/use-cases/update-authentication-status.js +15 -0
- package/database/MONGODB_TRANSACTION_FIX.md +198 -0
- package/database/adapters/lambda-invoker.js +97 -0
- package/database/config.js +154 -0
- package/database/encryption/README.md +684 -0
- package/database/encryption/encryption-schema-registry.js +141 -0
- package/database/encryption/field-encryption-service.js +226 -0
- package/database/encryption/logger.js +79 -0
- package/database/encryption/prisma-encryption-extension.js +222 -0
- package/database/index.js +25 -12
- package/database/models/WebsocketConnection.js +16 -10
- package/database/models/readme.md +1 -0
- package/database/prisma.js +222 -0
- package/database/repositories/health-check-repository-factory.js +43 -0
- package/database/repositories/health-check-repository-interface.js +87 -0
- package/database/repositories/health-check-repository-mongodb.js +91 -0
- package/database/repositories/health-check-repository-postgres.js +82 -0
- package/database/repositories/health-check-repository.js +108 -0
- package/database/repositories/migration-status-repository-s3.js +137 -0
- package/database/use-cases/check-database-health-use-case.js +29 -0
- package/database/use-cases/check-database-state-use-case.js +81 -0
- package/database/use-cases/check-encryption-health-use-case.js +83 -0
- package/database/use-cases/get-database-state-via-worker-use-case.js +61 -0
- package/database/use-cases/get-migration-status-use-case.js +93 -0
- package/database/use-cases/run-database-migration-use-case.js +137 -0
- package/database/use-cases/test-encryption-use-case.js +253 -0
- package/database/use-cases/trigger-database-migration-use-case.js +157 -0
- package/database/utils/mongodb-collection-utils.js +91 -0
- package/database/utils/mongodb-schema-init.js +106 -0
- package/database/utils/prisma-runner.js +400 -0
- package/database/utils/prisma-schema-parser.js +182 -0
- package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +517 -0
- package/encrypt/Cryptor.js +34 -168
- package/encrypt/index.js +1 -2
- package/encrypt/test-encrypt.js +0 -2
- package/generated/prisma-mongodb/client.d.ts +1 -0
- package/generated/prisma-mongodb/client.js +4 -0
- package/generated/prisma-mongodb/default.d.ts +1 -0
- package/generated/prisma-mongodb/default.js +4 -0
- package/generated/prisma-mongodb/edge.d.ts +1 -0
- package/generated/prisma-mongodb/edge.js +334 -0
- package/generated/prisma-mongodb/index-browser.js +316 -0
- package/generated/prisma-mongodb/index.d.ts +22898 -0
- package/generated/prisma-mongodb/index.js +359 -0
- package/generated/prisma-mongodb/package.json +183 -0
- package/generated/prisma-mongodb/query-engine-debian-openssl-3.0.x +0 -0
- package/generated/prisma-mongodb/query-engine-rhel-openssl-3.0.x +0 -0
- package/generated/prisma-mongodb/runtime/binary.d.ts +1 -0
- package/generated/prisma-mongodb/runtime/binary.js +289 -0
- package/generated/prisma-mongodb/runtime/edge-esm.js +34 -0
- package/generated/prisma-mongodb/runtime/edge.js +34 -0
- package/generated/prisma-mongodb/runtime/index-browser.d.ts +370 -0
- package/generated/prisma-mongodb/runtime/index-browser.js +16 -0
- package/generated/prisma-mongodb/runtime/library.d.ts +3982 -0
- package/generated/prisma-mongodb/runtime/react-native.js +83 -0
- package/generated/prisma-mongodb/runtime/wasm-compiler-edge.js +84 -0
- package/generated/prisma-mongodb/runtime/wasm-engine-edge.js +36 -0
- package/generated/prisma-mongodb/schema.prisma +362 -0
- package/generated/prisma-mongodb/wasm-edge-light-loader.mjs +4 -0
- package/generated/prisma-mongodb/wasm-worker-loader.mjs +4 -0
- package/generated/prisma-mongodb/wasm.d.ts +1 -0
- package/generated/prisma-mongodb/wasm.js +341 -0
- package/generated/prisma-postgresql/client.d.ts +1 -0
- package/generated/prisma-postgresql/client.js +4 -0
- package/generated/prisma-postgresql/default.d.ts +1 -0
- package/generated/prisma-postgresql/default.js +4 -0
- package/generated/prisma-postgresql/edge.d.ts +1 -0
- package/generated/prisma-postgresql/edge.js +356 -0
- package/generated/prisma-postgresql/index-browser.js +338 -0
- package/generated/prisma-postgresql/index.d.ts +25072 -0
- package/generated/prisma-postgresql/index.js +381 -0
- package/generated/prisma-postgresql/package.json +183 -0
- package/generated/prisma-postgresql/query-engine-debian-openssl-3.0.x +0 -0
- package/generated/prisma-postgresql/query-engine-rhel-openssl-3.0.x +0 -0
- package/generated/prisma-postgresql/query_engine_bg.js +2 -0
- package/generated/prisma-postgresql/query_engine_bg.wasm +0 -0
- package/generated/prisma-postgresql/runtime/binary.d.ts +1 -0
- package/generated/prisma-postgresql/runtime/binary.js +289 -0
- package/generated/prisma-postgresql/runtime/edge-esm.js +34 -0
- package/generated/prisma-postgresql/runtime/edge.js +34 -0
- package/generated/prisma-postgresql/runtime/index-browser.d.ts +370 -0
- package/generated/prisma-postgresql/runtime/index-browser.js +16 -0
- package/generated/prisma-postgresql/runtime/library.d.ts +3982 -0
- package/generated/prisma-postgresql/runtime/react-native.js +83 -0
- package/generated/prisma-postgresql/runtime/wasm-compiler-edge.js +84 -0
- package/generated/prisma-postgresql/runtime/wasm-engine-edge.js +36 -0
- package/generated/prisma-postgresql/schema.prisma +345 -0
- package/generated/prisma-postgresql/wasm-edge-light-loader.mjs +4 -0
- package/generated/prisma-postgresql/wasm-worker-loader.mjs +4 -0
- package/generated/prisma-postgresql/wasm.d.ts +1 -0
- package/generated/prisma-postgresql/wasm.js +363 -0
- package/handlers/WEBHOOKS.md +653 -0
- package/handlers/app-definition-loader.js +38 -0
- package/handlers/app-handler-helpers.js +56 -0
- package/handlers/backend-utils.js +180 -0
- package/handlers/database-migration-handler.js +227 -0
- package/handlers/integration-event-dispatcher.js +54 -0
- package/handlers/routers/HEALTHCHECK.md +342 -0
- package/handlers/routers/auth.js +15 -0
- package/handlers/routers/db-migration.handler.js +29 -0
- package/handlers/routers/db-migration.js +256 -0
- package/handlers/routers/health.js +519 -0
- package/handlers/routers/integration-defined-routers.js +45 -0
- package/handlers/routers/integration-webhook-routers.js +67 -0
- package/handlers/routers/user.js +63 -0
- package/handlers/routers/websocket.js +57 -0
- package/handlers/use-cases/check-external-apis-health-use-case.js +81 -0
- package/handlers/use-cases/check-integrations-health-use-case.js +44 -0
- package/handlers/workers/db-migration.js +352 -0
- package/handlers/workers/integration-defined-workers.js +27 -0
- package/index.js +77 -22
- package/integrations/WEBHOOK-QUICKSTART.md +151 -0
- package/integrations/index.js +12 -10
- package/integrations/integration-base.js +296 -54
- package/integrations/integration-router.js +381 -182
- package/integrations/options.js +1 -1
- package/integrations/repositories/integration-mapping-repository-factory.js +50 -0
- package/integrations/repositories/integration-mapping-repository-interface.js +106 -0
- package/integrations/repositories/integration-mapping-repository-mongo.js +161 -0
- package/integrations/repositories/integration-mapping-repository-postgres.js +227 -0
- package/integrations/repositories/integration-mapping-repository.js +156 -0
- package/integrations/repositories/integration-repository-factory.js +44 -0
- package/integrations/repositories/integration-repository-interface.js +127 -0
- package/integrations/repositories/integration-repository-mongo.js +303 -0
- package/integrations/repositories/integration-repository-postgres.js +352 -0
- package/integrations/repositories/process-repository-factory.js +46 -0
- package/integrations/repositories/process-repository-interface.js +90 -0
- package/integrations/repositories/process-repository-mongo.js +190 -0
- package/integrations/repositories/process-repository-postgres.js +217 -0
- package/integrations/tests/doubles/dummy-integration-class.js +83 -0
- package/integrations/tests/doubles/test-integration-repository.js +99 -0
- package/integrations/use-cases/create-integration.js +83 -0
- package/integrations/use-cases/create-process.js +128 -0
- package/integrations/use-cases/delete-integration-for-user.js +101 -0
- package/integrations/use-cases/find-integration-context-by-external-entity-id.js +72 -0
- package/integrations/use-cases/get-integration-for-user.js +78 -0
- package/integrations/use-cases/get-integration-instance-by-definition.js +67 -0
- package/integrations/use-cases/get-integration-instance.js +83 -0
- package/integrations/use-cases/get-integrations-for-user.js +88 -0
- package/integrations/use-cases/get-possible-integrations.js +27 -0
- package/integrations/use-cases/get-process.js +87 -0
- package/integrations/use-cases/index.js +19 -0
- package/integrations/use-cases/load-integration-context.js +71 -0
- package/integrations/use-cases/update-integration-messages.js +44 -0
- package/integrations/use-cases/update-integration-status.js +32 -0
- package/integrations/use-cases/update-integration.js +93 -0
- package/integrations/use-cases/update-process-metrics.js +201 -0
- package/integrations/use-cases/update-process-state.js +119 -0
- package/integrations/utils/map-integration-dto.js +37 -0
- package/jest-global-setup-noop.js +3 -0
- package/jest-global-teardown-noop.js +3 -0
- package/logs/logger.js +0 -4
- package/{module-plugin → modules}/entity.js +1 -1
- package/{module-plugin → modules}/index.js +0 -8
- package/modules/module-factory.js +56 -0
- package/modules/module.js +221 -0
- package/modules/repositories/module-repository-factory.js +33 -0
- package/modules/repositories/module-repository-interface.js +129 -0
- package/modules/repositories/module-repository-mongo.js +377 -0
- package/modules/repositories/module-repository-postgres.js +426 -0
- package/modules/repositories/module-repository.js +316 -0
- package/{module-plugin → modules}/requester/requester.js +1 -0
- package/{module-plugin → modules}/test/mock-api/api.js +8 -3
- package/{module-plugin → modules}/test/mock-api/definition.js +12 -8
- package/modules/tests/doubles/test-module-factory.js +16 -0
- package/modules/tests/doubles/test-module-repository.js +39 -0
- package/modules/use-cases/get-entities-for-user.js +32 -0
- package/modules/use-cases/get-entity-options-by-id.js +59 -0
- package/modules/use-cases/get-entity-options-by-type.js +34 -0
- package/modules/use-cases/get-module-instance-from-type.js +31 -0
- package/modules/use-cases/get-module.js +55 -0
- package/modules/use-cases/process-authorization-callback.js +122 -0
- package/modules/use-cases/refresh-entity-options.js +59 -0
- package/modules/use-cases/test-module-auth.js +55 -0
- package/modules/utils/map-module-dto.js +18 -0
- package/package.json +82 -50
- package/prisma-mongodb/schema.prisma +362 -0
- package/prisma-postgresql/migrations/20250930193005_init/migration.sql +315 -0
- package/prisma-postgresql/migrations/20251006135218_init/migration.sql +9 -0
- package/prisma-postgresql/migrations/20251010000000_remove_unused_entity_reference_map/migration.sql +3 -0
- package/prisma-postgresql/migrations/migration_lock.toml +3 -0
- package/prisma-postgresql/schema.prisma +345 -0
- package/queues/queuer-util.js +28 -15
- package/syncs/manager.js +468 -443
- package/syncs/repositories/sync-repository-factory.js +38 -0
- package/syncs/repositories/sync-repository-interface.js +109 -0
- package/syncs/repositories/sync-repository-mongo.js +239 -0
- package/syncs/repositories/sync-repository-postgres.js +319 -0
- package/syncs/sync.js +0 -1
- package/token/repositories/token-repository-factory.js +33 -0
- package/token/repositories/token-repository-interface.js +131 -0
- package/token/repositories/token-repository-mongo.js +212 -0
- package/token/repositories/token-repository-postgres.js +257 -0
- package/token/repositories/token-repository.js +219 -0
- package/types/core/index.d.ts +2 -2
- package/types/integrations/index.d.ts +2 -6
- package/types/module-plugin/index.d.ts +5 -59
- package/types/syncs/index.d.ts +0 -2
- package/user/repositories/user-repository-factory.js +46 -0
- package/user/repositories/user-repository-interface.js +198 -0
- package/user/repositories/user-repository-mongo.js +291 -0
- package/user/repositories/user-repository-postgres.js +350 -0
- package/user/tests/doubles/test-user-repository.js +72 -0
- package/user/use-cases/authenticate-user.js +127 -0
- package/user/use-cases/authenticate-with-shared-secret.js +48 -0
- package/user/use-cases/create-individual-user.js +61 -0
- package/user/use-cases/create-organization-user.js +47 -0
- package/user/use-cases/create-token-for-user-id.js +30 -0
- package/user/use-cases/get-user-from-adopter-jwt.js +149 -0
- package/user/use-cases/get-user-from-bearer-token.js +77 -0
- package/user/use-cases/get-user-from-x-frigg-headers.js +106 -0
- package/user/use-cases/login-user.js +122 -0
- package/user/user.js +93 -0
- package/utils/backend-path.js +38 -0
- package/utils/index.js +6 -0
- package/websocket/repositories/websocket-connection-repository-factory.js +37 -0
- package/websocket/repositories/websocket-connection-repository-interface.js +106 -0
- package/websocket/repositories/websocket-connection-repository-mongo.js +156 -0
- package/websocket/repositories/websocket-connection-repository-postgres.js +196 -0
- package/websocket/repositories/websocket-connection-repository.js +161 -0
- package/database/models/State.js +0 -9
- package/database/models/Token.js +0 -70
- package/database/mongo.js +0 -45
- package/encrypt/Cryptor.test.js +0 -32
- package/encrypt/encrypt.js +0 -132
- package/encrypt/encrypt.test.js +0 -1069
- package/errors/base-error.test.js +0 -32
- package/errors/fetch-error.test.js +0 -79
- package/errors/halt-error.test.js +0 -11
- package/errors/validation-errors.test.js +0 -120
- package/integrations/create-frigg-backend.js +0 -31
- package/integrations/integration-factory.js +0 -251
- package/integrations/integration-mapping.js +0 -43
- package/integrations/integration-model.js +0 -46
- package/integrations/integration-user.js +0 -144
- package/integrations/test/integration-base.test.js +0 -144
- package/lambda/TimeoutCatcher.test.js +0 -68
- package/logs/logger.test.js +0 -76
- package/module-plugin/auther.js +0 -393
- package/module-plugin/credential.js +0 -22
- package/module-plugin/entity-manager.js +0 -70
- package/module-plugin/manager.js +0 -169
- package/module-plugin/module-factory.js +0 -61
- package/module-plugin/requester/requester.test.js +0 -28
- package/module-plugin/test/auther.test.js +0 -97
- /package/{module-plugin → modules}/ModuleConstants.js +0 -0
- /package/{module-plugin → modules}/requester/api-key.js +0 -0
- /package/{module-plugin → modules}/requester/basic.js +0 -0
- /package/{module-plugin → modules}/requester/oauth-2.js +0 -0
- /package/{module-plugin → modules}/test/mock-api/mocks/hubspot.js +0 -0
|
@@ -1,5 +1,17 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const {
|
|
2
|
+
createIntegrationMappingRepository,
|
|
3
|
+
} = require('./repositories/integration-mapping-repository-factory');
|
|
2
4
|
const { Options } = require('./options');
|
|
5
|
+
const {
|
|
6
|
+
UpdateIntegrationStatus,
|
|
7
|
+
} = require('./use-cases/update-integration-status');
|
|
8
|
+
const {
|
|
9
|
+
createIntegrationRepository,
|
|
10
|
+
} = require('./repositories/integration-repository-factory');
|
|
11
|
+
const {
|
|
12
|
+
UpdateIntegrationMessages,
|
|
13
|
+
} = require('./use-cases/update-integration-messages');
|
|
14
|
+
|
|
3
15
|
const constantsToBeMigrated = {
|
|
4
16
|
defaultEvents: {
|
|
5
17
|
ON_CREATE: 'ON_CREATE',
|
|
@@ -10,6 +22,8 @@ const constantsToBeMigrated = {
|
|
|
10
22
|
GET_USER_ACTIONS: 'GET_USER_ACTIONS',
|
|
11
23
|
GET_USER_ACTION_OPTIONS: 'GET_USER_ACTION_OPTIONS',
|
|
12
24
|
REFRESH_USER_ACTION_OPTIONS: 'REFRESH_USER_ACTION_OPTIONS',
|
|
25
|
+
WEBHOOK_RECEIVED: 'WEBHOOK_RECEIVED', // HTTP handler, no DB
|
|
26
|
+
ON_WEBHOOK: 'ON_WEBHOOK', // Queue worker, DB-connected
|
|
13
27
|
// etc...
|
|
14
28
|
},
|
|
15
29
|
types: {
|
|
@@ -19,6 +33,16 @@ const constantsToBeMigrated = {
|
|
|
19
33
|
};
|
|
20
34
|
|
|
21
35
|
class IntegrationBase {
|
|
36
|
+
// todo: maybe we can pass this as Dependency Injection in the sub-class constructor
|
|
37
|
+
integrationRepository = createIntegrationRepository();
|
|
38
|
+
integrationMappingRepository = createIntegrationMappingRepository();
|
|
39
|
+
updateIntegrationStatus = new UpdateIntegrationStatus({
|
|
40
|
+
integrationRepository: this.integrationRepository,
|
|
41
|
+
});
|
|
42
|
+
updateIntegrationMessages = new UpdateIntegrationMessages({
|
|
43
|
+
integrationRepository: this.integrationRepository,
|
|
44
|
+
});
|
|
45
|
+
|
|
22
46
|
static getOptionDetails() {
|
|
23
47
|
const options = new Options({
|
|
24
48
|
module: Object.values(this.Definition.modules)[0], // This is a placeholder until we revamp the frontend
|
|
@@ -26,6 +50,7 @@ class IntegrationBase {
|
|
|
26
50
|
});
|
|
27
51
|
return options.get();
|
|
28
52
|
}
|
|
53
|
+
|
|
29
54
|
/**
|
|
30
55
|
* CHILDREN SHOULD SPECIFY A DEFINITION FOR THE INTEGRATION
|
|
31
56
|
*/
|
|
@@ -50,29 +75,30 @@ class IntegrationBase {
|
|
|
50
75
|
static getCurrentVersion() {
|
|
51
76
|
return this.Definition.version;
|
|
52
77
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
78
|
+
|
|
79
|
+
// REMOVED: registerEventHandlers() - Event handling is now done by IntegrationEventDispatcher
|
|
80
|
+
|
|
81
|
+
constructor(params = {}) {
|
|
82
|
+
this.modules = {};
|
|
83
|
+
this.events = this.events || {};
|
|
84
|
+
this.messages = { errors: [], warnings: [] };
|
|
85
|
+
this._isHydrated = false;
|
|
86
|
+
|
|
87
|
+
if (params && Object.keys(params).length > 0) {
|
|
88
|
+
this.setIntegrationRecord({
|
|
89
|
+
record: {
|
|
90
|
+
id: params.id,
|
|
91
|
+
userId: params.userId,
|
|
92
|
+
entities: params.entities,
|
|
93
|
+
config: params.config,
|
|
94
|
+
status: params.status,
|
|
95
|
+
version: params.version,
|
|
96
|
+
messages: params.messages,
|
|
97
|
+
},
|
|
98
|
+
modules: params.modules || [],
|
|
99
|
+
});
|
|
66
100
|
}
|
|
67
|
-
}
|
|
68
|
-
registerEventHandlers() {
|
|
69
|
-
this.on = {
|
|
70
|
-
...this.defaultEvents,
|
|
71
|
-
...this.events,
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
101
|
|
|
75
|
-
constructor(params) {
|
|
76
102
|
this.defaultEvents = {
|
|
77
103
|
[constantsToBeMigrated.defaultEvents.ON_CREATE]: {
|
|
78
104
|
type: constantsToBeMigrated.types.LIFE_CYCLE_EVENT,
|
|
@@ -106,22 +132,99 @@ class IntegrationBase {
|
|
|
106
132
|
type: constantsToBeMigrated.types.LIFE_CYCLE_EVENT,
|
|
107
133
|
handler: this.refreshActionOptions,
|
|
108
134
|
},
|
|
135
|
+
[constantsToBeMigrated.defaultEvents.WEBHOOK_RECEIVED]: {
|
|
136
|
+
type: constantsToBeMigrated.types.LIFE_CYCLE_EVENT,
|
|
137
|
+
handler: this.onWebhookReceived,
|
|
138
|
+
},
|
|
139
|
+
[constantsToBeMigrated.defaultEvents.ON_WEBHOOK]: {
|
|
140
|
+
type: constantsToBeMigrated.types.LIFE_CYCLE_EVENT,
|
|
141
|
+
handler: this.onWebhook,
|
|
142
|
+
},
|
|
109
143
|
};
|
|
110
|
-
this.loadModules();
|
|
111
144
|
}
|
|
112
145
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
146
|
+
// todo: debate wether we want to keep this pattern to set the record or not.
|
|
147
|
+
/**
|
|
148
|
+
* Persist the database record and module instances onto this integration instance.
|
|
149
|
+
* Accepts either a plain object containing the persisted fields or an object with
|
|
150
|
+
* a `record` property plus a `modules` collection.
|
|
151
|
+
* @param {Object} payload
|
|
152
|
+
* @param {Object} [payload.record]
|
|
153
|
+
* @param {Array} [payload.modules]
|
|
154
|
+
*/
|
|
155
|
+
setIntegrationRecord(payload = {}) {
|
|
156
|
+
if (!payload || Object.keys(payload).length === 0) {
|
|
157
|
+
throw new Error('setIntegrationRecord requires integration data');
|
|
118
158
|
}
|
|
119
|
-
|
|
159
|
+
|
|
160
|
+
const integrationRecord = payload.record;
|
|
161
|
+
const integrationModules = payload.modules ?? [];
|
|
162
|
+
|
|
163
|
+
if (!integrationRecord) {
|
|
164
|
+
throw new Error('Integration record not provided');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const { id, userId, entities, config, status, version, messages } =
|
|
168
|
+
integrationRecord;
|
|
169
|
+
|
|
170
|
+
this.id = id;
|
|
171
|
+
this.userId = userId;
|
|
172
|
+
this.entities = entities;
|
|
173
|
+
this.config = config;
|
|
174
|
+
this.status = status;
|
|
175
|
+
this.version = version;
|
|
176
|
+
this.messages = messages || { errors: [], warnings: [] };
|
|
177
|
+
|
|
178
|
+
this.modules = this._appendModules(integrationModules);
|
|
179
|
+
|
|
180
|
+
this.record = {
|
|
181
|
+
id: this.id,
|
|
182
|
+
userId: this.userId,
|
|
183
|
+
entities: this.entities,
|
|
184
|
+
config: this.config,
|
|
185
|
+
status: this.status,
|
|
186
|
+
version: this.version,
|
|
187
|
+
messages: this.messages,
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
this._isHydrated = Boolean(this.id);
|
|
191
|
+
return this;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
get isHydrated() {
|
|
195
|
+
return this._isHydrated;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
assertHydrated(message = 'Integration instance is not hydrated') {
|
|
199
|
+
if (!this.isHydrated) {
|
|
200
|
+
throw new Error(message);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Returns the modules as object with keys as module names.
|
|
206
|
+
* @private
|
|
207
|
+
* @param {Array} integrationModules - Array of module instances
|
|
208
|
+
* @returns {Object} The modules object
|
|
209
|
+
*/
|
|
210
|
+
_appendModules(integrationModules) {
|
|
211
|
+
const modules = {};
|
|
212
|
+
for (const module of integrationModules) {
|
|
213
|
+
const key =
|
|
214
|
+
typeof module.getName === 'function'
|
|
215
|
+
? module.getName()
|
|
216
|
+
: module.name;
|
|
217
|
+
if (key) {
|
|
218
|
+
modules[key] = module;
|
|
219
|
+
this[key] = module;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return modules;
|
|
120
223
|
}
|
|
121
224
|
|
|
122
225
|
async validateConfig() {
|
|
123
226
|
const configOptions = await this.getConfigOptions();
|
|
124
|
-
const currentConfig = this.
|
|
227
|
+
const currentConfig = this.getConfig();
|
|
125
228
|
let needsConfig = false;
|
|
126
229
|
for (const option of configOptions) {
|
|
127
230
|
if (option.required) {
|
|
@@ -133,56 +236,62 @@ class IntegrationBase {
|
|
|
133
236
|
)
|
|
134
237
|
) {
|
|
135
238
|
needsConfig = true;
|
|
136
|
-
this.
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
239
|
+
await this.updateIntegrationMessages.execute(
|
|
240
|
+
this.id,
|
|
241
|
+
'warnings',
|
|
242
|
+
'Config Validation Error',
|
|
243
|
+
`Missing required field of ${option.label}`,
|
|
244
|
+
Date.now()
|
|
245
|
+
);
|
|
141
246
|
}
|
|
142
247
|
}
|
|
143
248
|
}
|
|
144
249
|
if (needsConfig) {
|
|
145
|
-
this.
|
|
146
|
-
await this.record.save();
|
|
250
|
+
await this.updateIntegrationStatus.execute(this.id, 'NEEDS_CONFIG');
|
|
147
251
|
}
|
|
148
252
|
}
|
|
149
253
|
|
|
150
254
|
async testAuth() {
|
|
151
255
|
let didAuthPass = true;
|
|
152
256
|
|
|
153
|
-
for (const module of Object.keys(
|
|
257
|
+
for (const module of Object.keys(this.constructor.Definition.modules)) {
|
|
154
258
|
try {
|
|
155
259
|
await this[module].testAuth();
|
|
156
260
|
} catch {
|
|
157
261
|
didAuthPass = false;
|
|
158
|
-
this.
|
|
159
|
-
|
|
160
|
-
|
|
262
|
+
await this.updateIntegrationMessages.execute(
|
|
263
|
+
this.id,
|
|
264
|
+
'errors',
|
|
265
|
+
'Authentication Error',
|
|
266
|
+
`There was an error with your ${this[
|
|
161
267
|
module
|
|
162
268
|
].constructor.getName()} Entity.
|
|
163
269
|
Please reconnect/re-authenticate, or reach out to Support for assistance.`,
|
|
164
|
-
|
|
165
|
-
|
|
270
|
+
Date.now()
|
|
271
|
+
);
|
|
166
272
|
}
|
|
167
273
|
}
|
|
168
274
|
|
|
169
275
|
if (!didAuthPass) {
|
|
170
|
-
this.
|
|
171
|
-
this.record.markModified('messages.error');
|
|
172
|
-
await this.record.save();
|
|
276
|
+
await this.updateIntegrationStatus.execute(this.id, 'ERROR');
|
|
173
277
|
}
|
|
174
278
|
}
|
|
175
279
|
|
|
176
280
|
async getMapping(sourceId) {
|
|
177
|
-
|
|
281
|
+
// todo: not sure we should call the repository directly from here
|
|
282
|
+
return this.integrationMappingRepository.findMappingBy(
|
|
283
|
+
this.id,
|
|
284
|
+
sourceId
|
|
285
|
+
);
|
|
178
286
|
}
|
|
179
287
|
|
|
180
288
|
async upsertMapping(sourceId, mapping) {
|
|
181
289
|
if (!sourceId) {
|
|
182
290
|
throw new Error(`sourceId must be set`);
|
|
183
291
|
}
|
|
184
|
-
|
|
185
|
-
|
|
292
|
+
// todo: not sure we should call the repository directly from here
|
|
293
|
+
return await this.integrationMappingRepository.upsertMapping(
|
|
294
|
+
this.id,
|
|
186
295
|
sourceId,
|
|
187
296
|
mapping
|
|
188
297
|
);
|
|
@@ -191,13 +300,13 @@ class IntegrationBase {
|
|
|
191
300
|
/**
|
|
192
301
|
* CHILDREN CAN OVERRIDE THESE CONFIGURATION METHODS
|
|
193
302
|
*/
|
|
194
|
-
async onCreate(
|
|
195
|
-
this.
|
|
196
|
-
await this.record.save();
|
|
197
|
-
return this.record;
|
|
303
|
+
async onCreate({ integrationId }) {
|
|
304
|
+
await this.updateIntegrationStatus.execute(integrationId, 'ENABLED');
|
|
198
305
|
}
|
|
199
306
|
|
|
200
|
-
async onUpdate(params) {
|
|
307
|
+
async onUpdate(params) {
|
|
308
|
+
return this.validateConfig();
|
|
309
|
+
}
|
|
201
310
|
|
|
202
311
|
async onDelete(params) {}
|
|
203
312
|
|
|
@@ -259,6 +368,139 @@ class IntegrationBase {
|
|
|
259
368
|
};
|
|
260
369
|
return options;
|
|
261
370
|
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* WEBHOOK EVENT HANDLERS
|
|
374
|
+
*/
|
|
375
|
+
async onWebhookReceived({ req, res }) {
|
|
376
|
+
// Default: queue webhook for processing
|
|
377
|
+
const body = req.body;
|
|
378
|
+
const integrationId = req.params.integrationId || null;
|
|
379
|
+
|
|
380
|
+
await this.queueWebhook({
|
|
381
|
+
integrationId,
|
|
382
|
+
body,
|
|
383
|
+
headers: req.headers,
|
|
384
|
+
query: req.query,
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
res.status(200).json({ received: true });
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
async onWebhook({ data }) {
|
|
391
|
+
// Default: no-op, integrations override this
|
|
392
|
+
console.log('Webhook received:', data);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
async queueWebhook(data) {
|
|
396
|
+
const { QueuerUtil } = require('../queues');
|
|
397
|
+
|
|
398
|
+
const queueName = `${this.constructor.Definition.name
|
|
399
|
+
.toUpperCase()
|
|
400
|
+
.replace(/-/g, '_')}_QUEUE_URL`;
|
|
401
|
+
const queueUrl = process.env[queueName];
|
|
402
|
+
|
|
403
|
+
if (!queueUrl) {
|
|
404
|
+
throw new Error(`Queue URL not found for ${queueName}`);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return QueuerUtil.send(
|
|
408
|
+
{
|
|
409
|
+
event: 'ON_WEBHOOK',
|
|
410
|
+
data,
|
|
411
|
+
},
|
|
412
|
+
queueUrl
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// === Domain Methods (moved from Integration.js) ===
|
|
417
|
+
|
|
418
|
+
getConfig() {
|
|
419
|
+
return this.config;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
getModule(key) {
|
|
423
|
+
return this.modules[key];
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
setModule(key, module) {
|
|
427
|
+
this.modules[key] = module;
|
|
428
|
+
this[key] = module;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
addError(error) {
|
|
432
|
+
if (!this.messages.errors) {
|
|
433
|
+
this.messages.errors = [];
|
|
434
|
+
}
|
|
435
|
+
this.messages.errors.push(error);
|
|
436
|
+
this.status = 'ERROR';
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
addWarning(warning) {
|
|
440
|
+
if (!this.messages.warnings) {
|
|
441
|
+
this.messages.warnings = [];
|
|
442
|
+
}
|
|
443
|
+
this.messages.warnings.push(warning);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
isActive() {
|
|
447
|
+
return this.status === 'ENABLED' || this.status === 'ACTIVE';
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
needsConfiguration() {
|
|
451
|
+
return this.status === 'NEEDS_CONFIG';
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
hasErrors() {
|
|
455
|
+
return this.status === 'ERROR';
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
belongsToUser(userId) {
|
|
459
|
+
return this.userId.toString() === userId.toString();
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
registerEventHandlers() {
|
|
463
|
+
this.on = {
|
|
464
|
+
...this.defaultEvents,
|
|
465
|
+
...this.events,
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
async initialize() {
|
|
470
|
+
try {
|
|
471
|
+
const additionalUserActions = await this.loadDynamicUserActions();
|
|
472
|
+
this.events = { ...this.events, ...additionalUserActions };
|
|
473
|
+
} catch (e) {
|
|
474
|
+
this.addError(e);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
this.registerEventHandlers();
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
async send(event, object) {
|
|
481
|
+
if (!this.on[event]) {
|
|
482
|
+
throw new Error(
|
|
483
|
+
`Event ${event} is not defined in the Integration event object`
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
return this.on[event].handler.call(this, object);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
getOptionDetails() {
|
|
490
|
+
const options = new Options({
|
|
491
|
+
module: Object.values(this.constructor.Definition.modules)[0],
|
|
492
|
+
...this.constructor.Definition,
|
|
493
|
+
});
|
|
494
|
+
return options.get();
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// Legacy method for backward compatibility
|
|
498
|
+
async loadModules() {
|
|
499
|
+
// This method was used in the old architecture for loading modules
|
|
500
|
+
// In the new architecture, modules are injected via constructor
|
|
501
|
+
// For backward compatibility, this is a no-op
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
262
504
|
}
|
|
263
505
|
|
|
264
506
|
module.exports = { IntegrationBase };
|