@friggframework/core 2.0.0-next.6 → 2.0.0-next.60
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 +694 -0
- package/README.md +959 -50
- package/application/commands/README.md +451 -0
- package/application/commands/credential-commands.js +245 -0
- package/application/commands/entity-commands.js +336 -0
- package/application/commands/integration-commands.js +210 -0
- package/application/commands/user-commands.js +283 -0
- package/application/index.js +69 -0
- package/core/CLAUDE.md +690 -0
- package/core/Worker.js +8 -21
- package/core/create-handler.js +14 -7
- package/credential/repositories/credential-repository-documentdb.js +304 -0
- package/credential/repositories/credential-repository-factory.js +54 -0
- package/credential/repositories/credential-repository-interface.js +98 -0
- package/credential/repositories/credential-repository-mongo.js +269 -0
- package/credential/repositories/credential-repository-postgres.js +291 -0
- package/credential/repositories/credential-repository.js +302 -0
- package/credential/use-cases/get-credential-for-user.js +25 -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/documentdb-encryption-service.js +330 -0
- package/database/documentdb-utils.js +136 -0
- package/database/encryption/README.md +839 -0
- package/database/encryption/documentdb-encryption-service.md +3575 -0
- package/database/encryption/encryption-schema-registry.js +268 -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 +61 -21
- package/database/models/WebsocketConnection.js +16 -10
- package/database/models/readme.md +1 -0
- package/database/prisma.js +182 -0
- package/database/repositories/health-check-repository-documentdb.js +134 -0
- package/database/repositories/health-check-repository-factory.js +48 -0
- package/database/repositories/health-check-repository-interface.js +82 -0
- package/database/repositories/health-check-repository-mongodb.js +89 -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 +139 -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 +477 -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/errors/client-safe-error.js +26 -0
- package/errors/fetch-error.js +2 -1
- package/errors/index.js +2 -0
- 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 +22903 -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 +3977 -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 +360 -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 +25077 -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 +3977 -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 +343 -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 +186 -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 +326 -0
- package/handlers/routers/health.js +516 -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 +326 -55
- package/integrations/integration-router.js +374 -179
- package/integrations/options.js +1 -1
- package/integrations/repositories/integration-mapping-repository-documentdb.js +280 -0
- package/integrations/repositories/integration-mapping-repository-factory.js +57 -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-documentdb.js +210 -0
- package/integrations/repositories/integration-repository-factory.js +51 -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-documentdb.js +243 -0
- package/integrations/repositories/process-repository-factory.js +53 -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-documentdb.js +307 -0
- package/modules/repositories/module-repository-factory.js +40 -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/modules/requester/api-key.js +52 -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 +71 -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 +74 -0
- package/modules/use-cases/process-authorization-callback.js +133 -0
- package/modules/use-cases/refresh-entity-options.js +72 -0
- package/modules/use-cases/test-module-auth.js +72 -0
- package/modules/utils/map-module-dto.js +18 -0
- package/package.json +82 -50
- package/prisma-mongodb/schema.prisma +360 -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/20251112195422_update_user_unique_constraints/migration.sql +25 -0
- package/prisma-postgresql/migrations/migration_lock.toml +3 -0
- package/prisma-postgresql/schema.prisma +343 -0
- package/queues/queuer-util.js +27 -22
- package/syncs/manager.js +468 -443
- package/syncs/repositories/sync-repository-documentdb.js +240 -0
- package/syncs/repositories/sync-repository-factory.js +43 -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-documentdb.js +137 -0
- package/token/repositories/token-repository-factory.js +40 -0
- package/token/repositories/token-repository-interface.js +131 -0
- package/token/repositories/token-repository-mongo.js +219 -0
- package/token/repositories/token-repository-postgres.js +264 -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-documentdb.js +441 -0
- package/user/repositories/user-repository-factory.js +52 -0
- package/user/repositories/user-repository-interface.js +201 -0
- package/user/repositories/user-repository-mongo.js +308 -0
- package/user/repositories/user-repository-postgres.js +360 -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 +132 -0
- package/user/use-cases/login-user.js +122 -0
- package/user/user.js +125 -0
- package/utils/backend-path.js +38 -0
- package/utils/index.js +6 -0
- package/websocket/repositories/websocket-connection-repository-documentdb.js +119 -0
- package/websocket/repositories/websocket-connection-repository-factory.js +44 -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/api-key.js +0 -36
- 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/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,130 @@ 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');
|
|
158
|
+
}
|
|
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);
|
|
118
201
|
}
|
|
119
|
-
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Returns the modules as object with keys as module names.
|
|
206
|
+
* Uses the keys from Definition.modules to attach modules correctly.
|
|
207
|
+
*
|
|
208
|
+
* Example:
|
|
209
|
+
* Definition.modules = { attio: {...}, quo: { definition: { getName: () => 'quo-attio' } } }
|
|
210
|
+
* Module with getName()='quo-attio' gets attached as this.quo (not this['quo-attio'])
|
|
211
|
+
*
|
|
212
|
+
* @private
|
|
213
|
+
* @param {Array} integrationModules - Array of module instances
|
|
214
|
+
* @returns {Object} The modules object
|
|
215
|
+
*/
|
|
216
|
+
_appendModules(integrationModules) {
|
|
217
|
+
const modules = {};
|
|
218
|
+
|
|
219
|
+
// Build reverse mapping: definition.getName() → referenceKey
|
|
220
|
+
// e.g., 'quo-attio' → 'quo', 'attio' → 'attio'
|
|
221
|
+
const moduleNameToKey = {};
|
|
222
|
+
if (this.constructor.Definition?.modules) {
|
|
223
|
+
for (const [key, moduleConfig] of Object.entries(this.constructor.Definition.modules)) {
|
|
224
|
+
const definition = moduleConfig.definition;
|
|
225
|
+
if (definition) {
|
|
226
|
+
// Use getName() if available, fallback to moduleName
|
|
227
|
+
const definitionName = typeof definition.getName === 'function'
|
|
228
|
+
? definition.getName()
|
|
229
|
+
: definition.moduleName;
|
|
230
|
+
if (definitionName) {
|
|
231
|
+
moduleNameToKey[definitionName] = key;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
for (const module of integrationModules) {
|
|
238
|
+
const moduleName =
|
|
239
|
+
typeof module.getName === 'function'
|
|
240
|
+
? module.getName()
|
|
241
|
+
: module.name;
|
|
242
|
+
|
|
243
|
+
// Use the reference key from Definition.modules if available,
|
|
244
|
+
// otherwise fall back to moduleName
|
|
245
|
+
const key = moduleNameToKey[moduleName] || moduleName;
|
|
246
|
+
|
|
247
|
+
if (key) {
|
|
248
|
+
modules[key] = module;
|
|
249
|
+
this[key] = module;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return modules;
|
|
120
254
|
}
|
|
121
255
|
|
|
122
256
|
async validateConfig() {
|
|
123
257
|
const configOptions = await this.getConfigOptions();
|
|
124
|
-
const currentConfig = this.
|
|
258
|
+
const currentConfig = this.getConfig();
|
|
125
259
|
let needsConfig = false;
|
|
126
260
|
for (const option of configOptions) {
|
|
127
261
|
if (option.required) {
|
|
@@ -133,56 +267,62 @@ class IntegrationBase {
|
|
|
133
267
|
)
|
|
134
268
|
) {
|
|
135
269
|
needsConfig = true;
|
|
136
|
-
this.
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
270
|
+
await this.updateIntegrationMessages.execute(
|
|
271
|
+
this.id,
|
|
272
|
+
'warnings',
|
|
273
|
+
'Config Validation Error',
|
|
274
|
+
`Missing required field of ${option.label}`,
|
|
275
|
+
Date.now()
|
|
276
|
+
);
|
|
141
277
|
}
|
|
142
278
|
}
|
|
143
279
|
}
|
|
144
280
|
if (needsConfig) {
|
|
145
|
-
this.
|
|
146
|
-
await this.record.save();
|
|
281
|
+
await this.updateIntegrationStatus.execute(this.id, 'NEEDS_CONFIG');
|
|
147
282
|
}
|
|
148
283
|
}
|
|
149
284
|
|
|
150
285
|
async testAuth() {
|
|
151
286
|
let didAuthPass = true;
|
|
152
287
|
|
|
153
|
-
for (const module of Object.keys(
|
|
288
|
+
for (const module of Object.keys(this.constructor.Definition.modules)) {
|
|
154
289
|
try {
|
|
155
290
|
await this[module].testAuth();
|
|
156
291
|
} catch {
|
|
157
292
|
didAuthPass = false;
|
|
158
|
-
this.
|
|
159
|
-
|
|
160
|
-
|
|
293
|
+
await this.updateIntegrationMessages.execute(
|
|
294
|
+
this.id,
|
|
295
|
+
'errors',
|
|
296
|
+
'Authentication Error',
|
|
297
|
+
`There was an error with your ${this[
|
|
161
298
|
module
|
|
162
299
|
].constructor.getName()} Entity.
|
|
163
300
|
Please reconnect/re-authenticate, or reach out to Support for assistance.`,
|
|
164
|
-
|
|
165
|
-
|
|
301
|
+
Date.now()
|
|
302
|
+
);
|
|
166
303
|
}
|
|
167
304
|
}
|
|
168
305
|
|
|
169
306
|
if (!didAuthPass) {
|
|
170
|
-
this.
|
|
171
|
-
this.record.markModified('messages.error');
|
|
172
|
-
await this.record.save();
|
|
307
|
+
await this.updateIntegrationStatus.execute(this.id, 'ERROR');
|
|
173
308
|
}
|
|
174
309
|
}
|
|
175
310
|
|
|
176
311
|
async getMapping(sourceId) {
|
|
177
|
-
|
|
312
|
+
// todo: not sure we should call the repository directly from here
|
|
313
|
+
return this.integrationMappingRepository.findMappingBy(
|
|
314
|
+
this.id,
|
|
315
|
+
sourceId
|
|
316
|
+
);
|
|
178
317
|
}
|
|
179
318
|
|
|
180
319
|
async upsertMapping(sourceId, mapping) {
|
|
181
320
|
if (!sourceId) {
|
|
182
321
|
throw new Error(`sourceId must be set`);
|
|
183
322
|
}
|
|
184
|
-
|
|
185
|
-
|
|
323
|
+
// todo: not sure we should call the repository directly from here
|
|
324
|
+
return await this.integrationMappingRepository.upsertMapping(
|
|
325
|
+
this.id,
|
|
186
326
|
sourceId,
|
|
187
327
|
mapping
|
|
188
328
|
);
|
|
@@ -191,13 +331,13 @@ class IntegrationBase {
|
|
|
191
331
|
/**
|
|
192
332
|
* CHILDREN CAN OVERRIDE THESE CONFIGURATION METHODS
|
|
193
333
|
*/
|
|
194
|
-
async onCreate(
|
|
195
|
-
this.
|
|
196
|
-
await this.record.save();
|
|
197
|
-
return this.record;
|
|
334
|
+
async onCreate({ integrationId }) {
|
|
335
|
+
await this.updateIntegrationStatus.execute(integrationId, 'ENABLED');
|
|
198
336
|
}
|
|
199
337
|
|
|
200
|
-
async onUpdate(params) {
|
|
338
|
+
async onUpdate(params) {
|
|
339
|
+
return this.validateConfig();
|
|
340
|
+
}
|
|
201
341
|
|
|
202
342
|
async onDelete(params) {}
|
|
203
343
|
|
|
@@ -224,7 +364,6 @@ class IntegrationBase {
|
|
|
224
364
|
return {};
|
|
225
365
|
}
|
|
226
366
|
async loadUserActions({ actionType } = {}) {
|
|
227
|
-
console.log('loadUserActions called with actionType:', actionType);
|
|
228
367
|
const userActions = {};
|
|
229
368
|
for (const [key, event] of Object.entries(this.events)) {
|
|
230
369
|
if (event.type === constantsToBeMigrated.types.USER_ACTION) {
|
|
@@ -259,6 +398,138 @@ class IntegrationBase {
|
|
|
259
398
|
};
|
|
260
399
|
return options;
|
|
261
400
|
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* WEBHOOK EVENT HANDLERS
|
|
404
|
+
*/
|
|
405
|
+
async onWebhookReceived({ req, res }) {
|
|
406
|
+
// Default: queue webhook for processing
|
|
407
|
+
const body = req.body;
|
|
408
|
+
const integrationId = req.params.integrationId || null;
|
|
409
|
+
|
|
410
|
+
await this.queueWebhook({
|
|
411
|
+
integrationId,
|
|
412
|
+
body,
|
|
413
|
+
headers: req.headers,
|
|
414
|
+
query: req.query,
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
res.status(200).json({ received: true });
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
async onWebhook({ data }) {
|
|
421
|
+
// Default: no-op, integrations override this
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
async queueWebhook(data) {
|
|
425
|
+
const { QueuerUtil } = require('../queues');
|
|
426
|
+
|
|
427
|
+
const queueName = `${this.constructor.Definition.name
|
|
428
|
+
.toUpperCase()
|
|
429
|
+
.replace(/-/g, '_')}_QUEUE_URL`;
|
|
430
|
+
const queueUrl = process.env[queueName];
|
|
431
|
+
|
|
432
|
+
if (!queueUrl) {
|
|
433
|
+
throw new Error(`Queue URL not found for ${queueName}`);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
return QueuerUtil.send(
|
|
437
|
+
{
|
|
438
|
+
event: 'ON_WEBHOOK',
|
|
439
|
+
data,
|
|
440
|
+
},
|
|
441
|
+
queueUrl
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// === Domain Methods (moved from Integration.js) ===
|
|
446
|
+
|
|
447
|
+
getConfig() {
|
|
448
|
+
return this.config;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
getModule(key) {
|
|
452
|
+
return this.modules[key];
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
setModule(key, module) {
|
|
456
|
+
this.modules[key] = module;
|
|
457
|
+
this[key] = module;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
addError(error) {
|
|
461
|
+
if (!this.messages.errors) {
|
|
462
|
+
this.messages.errors = [];
|
|
463
|
+
}
|
|
464
|
+
this.messages.errors.push(error);
|
|
465
|
+
this.status = 'ERROR';
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
addWarning(warning) {
|
|
469
|
+
if (!this.messages.warnings) {
|
|
470
|
+
this.messages.warnings = [];
|
|
471
|
+
}
|
|
472
|
+
this.messages.warnings.push(warning);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
isActive() {
|
|
476
|
+
return this.status === 'ENABLED' || this.status === 'ACTIVE';
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
needsConfiguration() {
|
|
480
|
+
return this.status === 'NEEDS_CONFIG';
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
hasErrors() {
|
|
484
|
+
return this.status === 'ERROR';
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
belongsToUser(userId) {
|
|
488
|
+
return this.userId.toString() === userId.toString();
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
registerEventHandlers() {
|
|
492
|
+
this.on = {
|
|
493
|
+
...this.defaultEvents,
|
|
494
|
+
...this.events,
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
async initialize() {
|
|
499
|
+
try {
|
|
500
|
+
const additionalUserActions = await this.loadDynamicUserActions();
|
|
501
|
+
this.events = { ...this.events, ...additionalUserActions };
|
|
502
|
+
} catch (e) {
|
|
503
|
+
this.addError(e);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
this.registerEventHandlers();
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
async send(event, object) {
|
|
510
|
+
if (!this.on[event]) {
|
|
511
|
+
throw new Error(
|
|
512
|
+
`Event ${event} is not defined in the Integration event object`
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
return this.on[event].handler.call(this, object);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
getOptionDetails() {
|
|
519
|
+
const options = new Options({
|
|
520
|
+
module: Object.values(this.constructor.Definition.modules)[0],
|
|
521
|
+
...this.constructor.Definition,
|
|
522
|
+
});
|
|
523
|
+
return options.get();
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
// Legacy method for backward compatibility
|
|
527
|
+
async loadModules() {
|
|
528
|
+
// This method was used in the old architecture for loading modules
|
|
529
|
+
// In the new architecture, modules are injected via constructor
|
|
530
|
+
// For backward compatibility, this is a no-op
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
262
533
|
}
|
|
263
534
|
|
|
264
535
|
module.exports = { IntegrationBase };
|