@friggframework/core 2.0.0--canary.396.0dd37aa.0 → 2.0.0--canary.397.216d54b.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.
@@ -1,28 +1,52 @@
1
1
  const Boom = require('@hapi/boom');
2
2
 
3
3
  class DeleteIntegrationForUser {
4
- constructor({ integrationRepository }) {
4
+ constructor({ integrationRepository, integrationClasses }) {
5
5
 
6
6
  /**
7
7
  * @type {import('../integration-repository').IntegrationRepository}
8
8
  */
9
9
  this.integrationRepository = integrationRepository;
10
+ this.integrationClasses = integrationClasses;
10
11
  }
11
12
 
12
13
  async execute(integrationId, userId) {
13
- const integration = await this.integrationRepository.findIntegrationById(integrationId);
14
+ const integrationRecord = await this.integrationRepository.findIntegrationById(integrationId);
14
15
 
15
- if (!integration) {
16
+ if (!integrationRecord) {
16
17
  throw Boom.notFound(
17
18
  `Integration with id of ${integrationId} does not exist`
18
19
  );
19
20
  }
20
21
 
21
- if (integration.user.toString() !== userId.toString()) {
22
- throw Boom.forbidden('User does not have access to this integration');
22
+ const integrationClass = this.integrationClasses.find(
23
+ (integrationClass) => integrationClass.Definition.name === integrationRecord.config.type
24
+ );
25
+
26
+ if (integrationRecord.userId !== userId) {
27
+ throw new Error(
28
+ `Integration ${integrationId} does not belong to User ${userId}`
29
+ );
23
30
  }
24
31
 
32
+ const integrationInstance = new Integration({
33
+ id: integrationRecord.id,
34
+ userId: integrationRecord.userId,
35
+ entities: integrationRecord.entitiesIds,
36
+ config: integrationRecord.config,
37
+ status: integrationRecord.status,
38
+ version: integrationRecord.version,
39
+ messages: integrationRecord.messages,
40
+ integrationClass: integrationClass,
41
+ modules: [],
42
+ });
43
+
44
+ // 6. Complete async initialization (load dynamic actions, register handlers)
45
+ await integrationInstance.initialize();
46
+ await integrationInstance.send('ON_DELETE');
47
+
25
48
  await this.integrationRepository.deleteIntegrationById(integrationId);
49
+
26
50
  }
27
51
  }
28
52
 
@@ -0,0 +1,73 @@
1
+ const { Integration } = require('../integration');
2
+
3
+ class GetIntegrationInstance {
4
+
5
+ /**
6
+ * @class GetIntegrationInstance
7
+ * @description Use case for retrieving a single integration instance by ID and user.
8
+ * @param {Object} params
9
+ * @param {import('../integration-repository').IntegrationRepository} params.integrationRepository - Repository for integration data access
10
+ * @param {Array<import('../integration').Integration>} params.integrationClasses - Array of available integration classes
11
+ * @param {import('../module-plugin/module-service').ModuleService} params.moduleService - Service for module instantiation and management
12
+ */
13
+ constructor({
14
+ integrationRepository,
15
+ integrationClasses,
16
+ moduleService,
17
+ }) {
18
+ this.integrationRepository = integrationRepository;
19
+ this.integrationClasses = integrationClasses;
20
+ this.moduleService = moduleService;
21
+ }
22
+
23
+ async execute(integrationId, userId) {
24
+ const integrationRecord = await this.integrationRepository.findIntegrationById(integrationId);
25
+
26
+ if (!integrationRecord) {
27
+ throw new Error(`No integration found by the ID of ${integrationId}`);
28
+ }
29
+
30
+ const integrationClass = this.integrationClasses.find(
31
+ (integrationClass) => integrationClass.Definition.name === integrationRecord.config.type
32
+ );
33
+
34
+ if (!integrationClass) {
35
+ throw new Error(`No integration class found for type: ${integrationRecord.config.type}`);
36
+ }
37
+
38
+ if (integrationRecord.userId !== userId) {
39
+ throw new Error(
40
+ `Integration ${integrationId} does not belong to User ${userId}`
41
+ );
42
+ }
43
+
44
+
45
+ const modules = [];
46
+ for (const entityId of integrationRecord.entitiesIds) {
47
+ const moduleInstance = await this.moduleService.getModuleInstance(
48
+ entityId,
49
+ integrationRecord.userId
50
+ );
51
+ modules.push(moduleInstance);
52
+ }
53
+
54
+ const integrationInstance = new Integration({
55
+ id: integrationRecord.id,
56
+ userId: integrationRecord.userId,
57
+ entities: integrationRecord.entitiesIds,
58
+ config: integrationRecord.config,
59
+ status: integrationRecord.status,
60
+ version: integrationRecord.version,
61
+ messages: integrationRecord.messages,
62
+ integrationClass: integrationClass,
63
+ modules
64
+ });
65
+
66
+
67
+ await integrationInstance.initialize();
68
+
69
+ return integrationInstance;
70
+ }
71
+ }
72
+
73
+ module.exports = { GetIntegrationInstance };
@@ -32,7 +32,7 @@ class GetIntegrationsForUser {
32
32
  const modules = [];
33
33
  for (const entity of entities) {
34
34
  const moduleInstance = await this.moduleService.getModuleInstance(
35
- entity._id,
35
+ entity.id,
36
36
  integrationRecord.userId
37
37
  );
38
38
  modules.push(moduleInstance);
@@ -2,12 +2,11 @@ const { Integration } = require('../integration');
2
2
  const { mapIntegrationClassToIntegrationDTO } = require('../utils/map-integration-dto');
3
3
 
4
4
 
5
- // todo: remove this use case
6
- class GetIntegration {
5
+ class UpdateIntegration {
7
6
 
8
7
  /**
9
- * @class GetIntegration
10
- * @description Use case for retrieving a single integration by ID and user.
8
+ * @class UpdateIntegration
9
+ * @description Use case for updating a single integration by ID and user.
11
10
  * @param {Object} params
12
11
  * @param {import('../integration-repository').IntegrationRepository} params.integrationRepository - Repository for integration data access
13
12
  * @param {Array<import('../integration').Integration>} params.integrationClasses - Array of available integration classes
@@ -23,7 +22,7 @@ class GetIntegration {
23
22
  this.moduleService = moduleService;
24
23
  }
25
24
 
26
- async execute(integrationId, userId) {
25
+ async execute(integrationId, userId, config) {
27
26
  // 1. Get integration record from repository
28
27
  const integrationRecord = await this.integrationRepository.findIntegrationById(integrationId);
29
28
 
@@ -31,6 +30,11 @@ class GetIntegration {
31
30
  throw new Error(`No integration found by the ID of ${integrationId}`);
32
31
  }
33
32
 
33
+ // 2. Get the correct Integration class by type
34
+ const integrationClass = this.integrationClasses.find(
35
+ (integrationClass) => integrationClass.Definition.name === integrationRecord.config.type
36
+ );
37
+
34
38
  if (!integrationClass) {
35
39
  throw new Error(`No integration class found for type: ${integrationRecord.config.type}`);
36
40
  }
@@ -41,11 +45,6 @@ class GetIntegration {
41
45
  );
42
46
  }
43
47
 
44
- // 2. Get the correct Integration class by type
45
- const integrationClass = this.integrationClasses.find(
46
- (integrationClass) => integrationClass.Definition.name === integrationRecord.config.type
47
- );
48
-
49
48
 
50
49
  // 3. Load modules based on entity references
51
50
  const modules = [];
@@ -59,14 +58,13 @@ class GetIntegration {
59
58
 
60
59
  // 4. Create the Integration domain entity with modules
61
60
  const integrationInstance = new Integration({
62
- id: integrationRecord._id.toString(),
61
+ id: integrationRecord.id,
63
62
  userId: integrationRecord.userId,
64
63
  entities: integrationRecord.entitiesIds,
65
64
  config: integrationRecord.config,
66
65
  status: integrationRecord.status,
67
66
  version: integrationRecord.version,
68
67
  messages: integrationRecord.messages,
69
- entityReference: integrationRecord.entityReference,
70
68
  integrationClass: integrationClass,
71
69
  modules
72
70
  });
@@ -74,9 +72,10 @@ class GetIntegration {
74
72
 
75
73
  // 6. Complete async initialization (load dynamic actions, register handlers)
76
74
  await integrationInstance.initialize();
75
+ await integrationInstance.send('ON_UPDATE', { config });
77
76
 
78
77
  return mapIntegrationClassToIntegrationDTO(integrationInstance);
79
78
  }
80
79
  }
81
80
 
82
- module.exports = { GetIntegration };
81
+ module.exports = { UpdateIntegration };
@@ -19,4 +19,19 @@ function mapIntegrationClassToIntegrationDTO(integration) {
19
19
  };
20
20
  }
21
21
 
22
- module.exports = { mapIntegrationClassToIntegrationDTO };
22
+
23
+ const getModulesDefinitionFromIntegrationClasses = (integrationClasses) => {
24
+ return [
25
+ ...new Set(
26
+ integrationClasses
27
+ .map((integration) =>
28
+ Object.values(integration.Definition.modules).map(
29
+ (module) => module.definition
30
+ )
31
+ )
32
+ .flat()
33
+ ),
34
+ ];
35
+ };
36
+
37
+ module.exports = { mapIntegrationClassToIntegrationDTO, getModulesDefinitionFromIntegrationClasses };
@@ -6,7 +6,6 @@ const { BasicAuthRequester } = require('./requester/basic');
6
6
  const { OAuth2Requester } = require('./requester/oauth-2');
7
7
  const { Requester } = require('./requester/requester');
8
8
  const { ModuleConstants } = require('./ModuleConstants');
9
- const { ModuleFactory } = require('./module-factory');
10
9
 
11
10
  module.exports = {
12
11
  Credential,
@@ -17,5 +16,4 @@ module.exports = {
17
16
  OAuth2Requester,
18
17
  Requester,
19
18
  ModuleConstants,
20
- ModuleFactory,
21
19
  };
@@ -48,11 +48,22 @@ class ModuleRepository {
48
48
  }
49
49
 
50
50
  async findEntitiesByIds(entityIds) {
51
- return Entity.find(
51
+ const entities = await Entity.find(
52
52
  { _id: { $in: entityIds } },
53
- '-dateCreated -dateUpdated -user -credentials -credential -__t -__v',
53
+ '',
54
54
  { lean: true }
55
55
  );
56
+
57
+ return entities.map(e => ({
58
+ id: e._id.toString(),
59
+ accountId: e.accountId,
60
+ credentialId: e.credential.toString(),
61
+ userId: e.user.toString(),
62
+ name: e.name,
63
+ externalId: e.externalId,
64
+ type: e.__t,
65
+ moduleName: e.moduleName,
66
+ }));
56
67
  }
57
68
  }
58
69
 
@@ -9,6 +9,7 @@ const { ModuleConstants } = require('./ModuleConstants');
9
9
 
10
10
  class Module extends Delegate {
11
11
 
12
+ //todo: entity should be replaced with actual entity properties
12
13
  /**
13
14
  *
14
15
  * @param {Object} params
@@ -25,8 +26,6 @@ class Module extends Delegate {
25
26
  this.entity = entityObj;
26
27
  this.credential = entityObj?.credential;
27
28
  this.definition = definition;
28
- this.getEntityOptions = this.definition.getEntityOptions;
29
- this.refreshEntityOptions = this.definition.refreshEntityOptions;
30
29
  this.name = this.definition.moduleName;
31
30
  this.modelName = this.definition.modelName;
32
31
  this.apiClass = this.definition.API;
@@ -56,6 +55,15 @@ class Module extends Delegate {
56
55
  return this.name;
57
56
  }
58
57
 
58
+ getEntityOptions() {
59
+ return this.definition.getEntityOptions()
60
+ }
61
+
62
+ async refreshEntityOptions(options) {
63
+ await this.definition.refreshEntityOptions(options);
64
+ return this.getEntityOptions();
65
+ }
66
+
59
67
  apiParamsFromCredential(credential) {
60
68
  return _.pick(credential, ...this.apiPropertiesToPersist?.credential);
61
69
  }
@@ -103,22 +111,6 @@ class Module extends Delegate {
103
111
  return this.CredentialModel;
104
112
  }
105
113
 
106
- // todo: remove this method from all places
107
- // async getEntitiesForUserId(userId) {
108
- // // Only return non-internal fields. Leverages "select" and "options" to non-excepted fields and a pure object.
109
- // const list = await this.EntityModel.find(
110
- // { user: userId },
111
- // '-dateCreated -dateUpdated -user -credentials -credential -__t -__v',
112
- // { lean: true }
113
- // );
114
- // console.log('getEntitiesForUserId list', list, userId);
115
- // return list.map((entity) => ({
116
- // id: entity._id,
117
- // type: this.getName(),
118
- // ...entity,
119
- // }));
120
- // }
121
-
122
114
  async validateAuthorizationRequirements() {
123
115
  const requirements = await this.getAuthorizationRequirements();
124
116
  let valid = true;
@@ -0,0 +1,58 @@
1
+ const { Module } = require('../module');
2
+
3
+ class GetEntityOptionsById {
4
+ /**
5
+ * @param {Object} params
6
+ * @param {import('../module-repository').ModuleRepository} params.moduleRepository
7
+ * @param {} params.moduleDefinitions
8
+ */
9
+ constructor({ moduleRepository, moduleDefinitions }) {
10
+ this.moduleRepository = moduleRepository;
11
+ this.moduleDefinitions = moduleDefinitions;
12
+ }
13
+
14
+ /**
15
+ * Retrieve a Module instance for a given user and entity/module type.
16
+ * @param {string} userId
17
+ * @param {string} entityId
18
+ */
19
+ async execute(entityId, userId) {
20
+ const entity = await this.moduleRepository.findEntityById(
21
+ entityId,
22
+ userId
23
+ );
24
+
25
+ if (!entity) {
26
+ throw new Error(`Entity ${entityId} not found`);
27
+ }
28
+
29
+ if (entity.userId !== userId) {
30
+ throw new Error(
31
+ `Entity ${entityId} does not belong to user ${userId}`
32
+ );
33
+ }
34
+
35
+ const entityType = entity.type;
36
+ const moduleDefinition = this.moduleDefinitions.find((def) => {
37
+ const modelName = Module.getEntityModelFromDefinition(def).modelName;
38
+ return entityType === modelName;
39
+ });
40
+
41
+ if (!moduleDefinition) {
42
+ throw new Error(
43
+ `Module definition not found for entity type: ${entityType}`
44
+ );
45
+ }
46
+
47
+ const module = new Module({
48
+ userId,
49
+ entity,
50
+ definition: moduleDefinition,
51
+ });
52
+
53
+ const entityOptions = await module.getEntityOptions();
54
+ return entityOptions;
55
+ }
56
+ }
57
+
58
+ module.exports = { GetEntityOptionsById };
@@ -0,0 +1,34 @@
1
+ const { Module } = require('../module');
2
+
3
+ class GetEntityOptionsByType {
4
+ /**
5
+ * @param {Object} params
6
+ * @param {} params.moduleDefinitions
7
+ */
8
+ constructor({ moduleDefinitions }) {
9
+ this.moduleDefinitions = moduleDefinitions;
10
+ }
11
+
12
+ /**
13
+ * Retrieve a Module instance for a given user and entity/module type.
14
+ * @param {string} userId
15
+ * @param {string} type – human-readable module/entity type (e.g. "Hubspot")
16
+ */
17
+ async execute(userId, type) {
18
+ const moduleDefinition = this.moduleDefinitions.find(
19
+ (def) => def.getName() === type
20
+ );
21
+ if (!moduleDefinition) {
22
+ throw new Error(`Module definition not found for type: ${type}`);
23
+ }
24
+ const moduleInstance = new Module({
25
+ userId,
26
+ definition: moduleDefinition,
27
+ });
28
+
29
+ const entityOptions = await moduleInstance.getEntityOptions();
30
+ return entityOptions;
31
+ }
32
+ }
33
+
34
+ module.exports = { GetEntityOptionsByType };
@@ -0,0 +1,31 @@
1
+ const { Module } = require('../module');
2
+
3
+ class GetModuleInstanceFromType {
4
+ /**
5
+ * @param {Object} params
6
+ * @param {} params.moduleDefinitions
7
+ */
8
+ constructor({ moduleDefinitions }) {
9
+ this.moduleDefinitions = moduleDefinitions;
10
+ }
11
+
12
+ /**
13
+ * Retrieve a Module instance for a given user and entity/module type.
14
+ * @param {string} userId
15
+ * @param {string} type – human-readable module/entity type (e.g. "Hubspot")
16
+ */
17
+ async execute(userId, type) {
18
+ const moduleDefinition = this.moduleDefinitions.find(
19
+ (def) => def.getName() === type
20
+ );
21
+ if (!moduleDefinition) {
22
+ throw new Error(`Module definition not found for type: ${type}`);
23
+ }
24
+ return new Module({
25
+ userId,
26
+ definition: moduleDefinition,
27
+ });
28
+ }
29
+ }
30
+
31
+ module.exports = { GetModuleInstanceFromType };
@@ -0,0 +1,56 @@
1
+ const { Module } = require('../module');
2
+
3
+ class GetModule {
4
+ constructor({ moduleRepository, moduleDefinitions }) {
5
+ this.moduleRepository = moduleRepository;
6
+ this.moduleDefinitions = moduleDefinitions;
7
+ }
8
+
9
+ async execute(entityId, userId) {
10
+ const entity = await this.moduleRepository.findEntityById(
11
+ entityId,
12
+ userId
13
+ );
14
+
15
+ if (!entity) {
16
+ throw new Error(`Entity ${entityId} not found`);
17
+ }
18
+
19
+ if (entity.userId !== userId) {
20
+ throw new Error(
21
+ `Entity ${entityId} does not belong to user ${userId}`
22
+ );
23
+ }
24
+
25
+ const entityType = entity.type;
26
+ const moduleDefinition = this.moduleDefinitions.find((def) => {
27
+ const modelName = Module.getEntityModelFromDefinition(def).modelName;
28
+ return entityType === modelName;
29
+ });
30
+
31
+ if (!moduleDefinition) {
32
+ throw new Error(
33
+ `Module definition not found for entity type: ${entityType}`
34
+ );
35
+ }
36
+
37
+ const module = new Module({
38
+ userId,
39
+ entity,
40
+ definition: moduleDefinition,
41
+ });
42
+
43
+ // todo: this properties should be methods in the Module class
44
+ return {
45
+ id: module.entity.id,
46
+ name: module.entity.name,
47
+ type: module.entity.moduleName,
48
+ moduleName: module.entity.moduleName,
49
+ credential: module.credential,
50
+ externalId: module.entity.externalId,
51
+ userId: module.entity.user.toString(),
52
+ }
53
+ }
54
+ }
55
+
56
+ module.exports = { GetModule };
@@ -0,0 +1,58 @@
1
+ const { Module } = require('../module');
2
+
3
+ class RefreshEntityOptions {
4
+ /**
5
+ * @param {Object} params
6
+ * @param {import('../module-repository').ModuleRepository} params.moduleRepository
7
+ * @param {} params.moduleDefinitions
8
+ */
9
+ constructor({ moduleRepository, moduleDefinitions }) {
10
+ this.moduleRepository = moduleRepository;
11
+ this.moduleDefinitions = moduleDefinitions;
12
+ }
13
+
14
+ /**
15
+ * Retrieve a Module instance for a given user and entity/module type.
16
+ * @param {string} userId
17
+ * @param {string} entityId
18
+ */
19
+ async execute(entityId, userId, options) {
20
+ const entity = await this.moduleRepository.findEntityById(
21
+ entityId,
22
+ userId
23
+ );
24
+
25
+ if (!entity) {
26
+ throw new Error(`Entity ${entityId} not found`);
27
+ }
28
+
29
+ if (entity.userId !== userId) {
30
+ throw new Error(
31
+ `Entity ${entityId} does not belong to user ${userId}`
32
+ );
33
+ }
34
+
35
+ const entityType = entity.type;
36
+ const moduleDefinition = this.moduleDefinitions.find((def) => {
37
+ const modelName = Module.getEntityModelFromDefinition(def).modelName;
38
+ return entityType === modelName;
39
+ });
40
+
41
+ if (!moduleDefinition) {
42
+ throw new Error(
43
+ `Module definition not found for entity type: ${entityType}`
44
+ );
45
+ }
46
+
47
+ const module = new Module({
48
+ userId,
49
+ entity,
50
+ definition: moduleDefinition,
51
+ });
52
+
53
+ await module.refreshEntityOptions(options);
54
+ return module.getEntityOptions();
55
+ }
56
+ }
57
+
58
+ module.exports = { RefreshEntityOptions };
@@ -0,0 +1,54 @@
1
+ const { Module } = require('../module');
2
+
3
+ class TestModuleAuth {
4
+ /**
5
+ * @param {Object} params - Configuration parameters.
6
+ * @param {import('./module-repository').ModuleRepository} params.moduleRepository - Repository for module data operations.
7
+ * @param {Array<Object>} params.moduleDefinitions - Array of module definitions.
8
+ */
9
+ constructor({ moduleRepository, moduleDefinitions }) {
10
+ this.moduleRepository = moduleRepository;
11
+ this.moduleDefinitions = moduleDefinitions;
12
+ }
13
+
14
+ async execute(entityId, userId) {
15
+ const entity = await this.moduleRepository.findEntityById(
16
+ entityId,
17
+ userId
18
+ );
19
+
20
+ if (!entity) {
21
+ throw new Error(`Entity ${entityId} not found`);
22
+ }
23
+
24
+ if (entity.userId !== userId) {
25
+ throw new Error(
26
+ `Entity ${entityId} does not belong to user ${userId}`
27
+ );
28
+ }
29
+
30
+ const entityType = entity.type;
31
+ const moduleDefinition = this.moduleDefinitions.find((def) => {
32
+ const modelName = Module.getEntityModelFromDefinition(def).modelName;
33
+ return entityType === modelName;
34
+ });
35
+
36
+ if (!moduleDefinition) {
37
+ throw new Error(
38
+ `Module definition not found for entity type: ${entityType}`
39
+ );
40
+ }
41
+
42
+ const module = new Module({
43
+ userId,
44
+ entity,
45
+ definition: moduleDefinition,
46
+ });
47
+
48
+ const testAuthResponse = await module.testAuth();
49
+
50
+ return testAuthResponse;
51
+ }
52
+ }
53
+
54
+ module.exports = { TestModuleAuth };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@friggframework/core",
3
3
  "prettier": "@friggframework/prettier-config",
4
- "version": "2.0.0--canary.396.0dd37aa.0",
4
+ "version": "2.0.0--canary.397.216d54b.0",
5
5
  "dependencies": {
6
6
  "@hapi/boom": "^10.0.1",
7
7
  "aws-sdk": "^2.1200.0",
@@ -22,9 +22,9 @@
22
22
  "uuid": "^9.0.1"
23
23
  },
24
24
  "devDependencies": {
25
- "@friggframework/eslint-config": "2.0.0--canary.396.0dd37aa.0",
26
- "@friggframework/prettier-config": "2.0.0--canary.396.0dd37aa.0",
27
- "@friggframework/test": "2.0.0--canary.396.0dd37aa.0",
25
+ "@friggframework/eslint-config": "2.0.0--canary.397.216d54b.0",
26
+ "@friggframework/prettier-config": "2.0.0--canary.397.216d54b.0",
27
+ "@friggframework/test": "2.0.0--canary.397.216d54b.0",
28
28
  "@types/lodash": "4.17.15",
29
29
  "@typescript-eslint/eslint-plugin": "^8.0.0",
30
30
  "chai": "^4.3.6",
@@ -53,5 +53,5 @@
53
53
  },
54
54
  "homepage": "https://github.com/friggframework/frigg#readme",
55
55
  "description": "",
56
- "gitHead": "0dd37aa78998c9291f90e3fdeb0e07096e2e140a"
56
+ "gitHead": "216d54b42aece5fa6473620fca6ee1ae11a46d8b"
57
57
  }