@friggframework/core 2.0.0--canary.397.84ecb0e.0 → 2.0.0--canary.397.e634da9.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,9 +1,7 @@
1
1
  const { Router } = require('express');
2
2
  const { Worker } = require('@friggframework/core');
3
- const { loadAppDefinition } = require('./app-definition-loader');
4
3
  const { IntegrationRepository } = require('../integrations/integration-repository');
5
4
  const { ModuleFactory } = require('../modules/module-factory');
6
- const { GetIntegrationInstance } = require('../integrations/use-cases/get-integration-instance');
7
5
  const { getModulesDefinitionFromIntegrationClasses } = require('../integrations/utils/map-integration-dto');
8
6
  const { ModuleRepository } = require('../modules/module-repository');
9
7
  const { GetIntegrationInstanceByDefinition } = require('../integrations/use-cases/get-integration-instance-by-definition');
@@ -14,14 +12,15 @@ const loadRouterFromObject = (IntegrationClass, routerObject) => {
14
12
  const moduleRepository = new ModuleRepository();
15
13
  const moduleFactory = new ModuleFactory({
16
14
  moduleRepository,
17
- moduleDefinitions: getModulesDefinitionFromIntegrationClasses(integrationClasses),
15
+ moduleDefinitions: getModulesDefinitionFromIntegrationClasses([IntegrationClass]),
18
16
  });
19
-
20
17
  const router = Router();
21
18
  const { path, method, event } = routerObject;
19
+
22
20
  console.log(
23
21
  `Registering ${method} ${path} for ${IntegrationClass.Definition.name}`
24
22
  );
23
+
25
24
  router[method.toLowerCase()](path, async (req, res, next) => {
26
25
  try {
27
26
  const getIntegrationInstanceByDefinition = new GetIntegrationInstanceByDefinition({
@@ -29,7 +28,7 @@ const loadRouterFromObject = (IntegrationClass, routerObject) => {
29
28
  moduleFactory,
30
29
  moduleRepository,
31
30
  });
32
- const integration = await getIntegrationInstanceByDefinition.execute(IntegrationClass.Definition);
31
+ const integration = await getIntegrationInstanceByDefinition.execute(IntegrationClass);
33
32
  const result = await integration.send(event, { req, res, next });
34
33
  res.json(result);
35
34
  } catch (error) {
@@ -43,39 +42,25 @@ const loadRouterFromObject = (IntegrationClass, routerObject) => {
43
42
  //todo: this should be in a use case class
44
43
  const createQueueWorker = (integrationClass) => {
45
44
  class QueueWorker extends Worker {
45
+
46
+ integrationRepository = new IntegrationRepository();
47
+ moduleRepository = new ModuleRepository();
48
+ moduleFactory = new ModuleFactory({
49
+ moduleRepository: this.moduleRepository,
50
+ moduleDefinitions: getModulesDefinitionFromIntegrationClasses([integrationClass]),
51
+ });
52
+
46
53
  async _run(params, context) {
47
54
  try {
48
- let integrationInstance;
49
- if (!params.integrationId) {
50
- integrationInstance = new integrationClass();
51
- await integrationInstance.loadModules();
52
- await integrationInstance.registerEventHandlers();
53
- console.log(
54
- `${params.event} for ${integrationClass.Definition.name} integration with no integrationId`
55
- );
56
- } else {
57
- const { integrations: integrationClasses } = loadAppDefinition();
58
- const integrationRepository = new IntegrationRepository();
59
- const moduleRepository = new ModuleRepository();
60
- const moduleFactory = new ModuleFactory({
61
- moduleRepository,
62
- moduleDefinitions: getModulesDefinitionFromIntegrationClasses(integrationClasses),
63
- });
64
-
65
- const getIntegrationInstance = new GetIntegrationInstance({
66
- integrationRepository,
67
- integrationClasses,
68
- moduleFactory,
69
- });
55
+ const getIntegrationInstanceByDefinition = new GetIntegrationInstanceByDefinition({
56
+ integrationRepository: this.integrationRepository,
57
+ moduleFactory: this.moduleFactory,
58
+ moduleRepository: this.moduleRepository,
59
+ });
70
60
 
71
- // todo: are we going to have the userId available here?
72
- integrationInstance = await getIntegrationInstance.execute(params.integrationId, params.userId);
73
- console.log(
74
- `${params.event} for ${integrationInstance.record.config.type} of integrationId: ${params.integrationId}`
75
- );
76
- }
61
+ const integration = await getIntegrationInstanceByDefinition.execute(integrationClass);
77
62
 
78
- const res = await integrationInstance.send(params.event, {
63
+ const res = await integration.send(params.event, {
79
64
  data: params.data,
80
65
  context,
81
66
  });
@@ -69,7 +69,30 @@ class IntegrationBase {
69
69
  };
70
70
  }
71
71
 
72
- constructor(params) {
72
+ constructor(params = {}) {
73
+ // Data from database record (when instantiated by use cases)
74
+ this.id = params.id;
75
+ this.userId = params.userId || params.integrationId; // fallback for legacy
76
+ this.entities = params.entities;
77
+ this.config = params.config;
78
+ this.status = params.status;
79
+ this.version = params.version;
80
+ this.messages = params.messages || { errors: [], warnings: [] };
81
+
82
+ // Module instances (injected by factory)
83
+ this.modules = {};
84
+ if (params.modules) {
85
+ for (const mod of params.modules) {
86
+ const key = typeof mod.getName === 'function' ? mod.getName() : mod.name;
87
+ if (key) {
88
+ this.modules[key] = mod;
89
+ this[key] = mod; // Direct access (e.g., this.hubspot)
90
+ }
91
+ }
92
+ }
93
+
94
+ // Initialize events object (will be populated by child classes)
95
+ this.events = this.events || {};
73
96
 
74
97
  this.defaultEvents = {
75
98
  [constantsToBeMigrated.defaultEvents.ON_CREATE]: {
@@ -148,7 +171,7 @@ class IntegrationBase {
148
171
  async testAuth() {
149
172
  let didAuthPass = true;
150
173
 
151
- for (const module of Object.keys(IntegrationBase.Definition.modules)) {
174
+ for (const module of Object.keys(this.constructor.Definition.modules)) {
152
175
  try {
153
176
  await this[module].testAuth();
154
177
  } catch {
@@ -257,6 +280,81 @@ class IntegrationBase {
257
280
  };
258
281
  return options;
259
282
  }
283
+
284
+ // === Domain Methods (moved from Integration.js) ===
285
+
286
+ getConfig() {
287
+ return this.config;
288
+ }
289
+
290
+ getModule(key) {
291
+ return this.modules[key];
292
+ }
293
+
294
+ setModule(key, module) {
295
+ this.modules[key] = module;
296
+ this[key] = module;
297
+ }
298
+
299
+ addError(error) {
300
+ if (!this.messages.errors) {
301
+ this.messages.errors = [];
302
+ }
303
+ this.messages.errors.push(error);
304
+ this.status = 'ERROR';
305
+ }
306
+
307
+ addWarning(warning) {
308
+ if (!this.messages.warnings) {
309
+ this.messages.warnings = [];
310
+ }
311
+ this.messages.warnings.push(warning);
312
+ }
313
+
314
+ isActive() {
315
+ return this.status === 'ENABLED' || this.status === 'ACTIVE';
316
+ }
317
+
318
+ needsConfiguration() {
319
+ return this.status === 'NEEDS_CONFIG';
320
+ }
321
+
322
+ hasErrors() {
323
+ return this.status === 'ERROR';
324
+ }
325
+
326
+ belongsToUser(userId) {
327
+ return this.userId.toString() === userId.toString();
328
+ }
329
+
330
+ async initialize() {
331
+ // Load dynamic user actions
332
+ try {
333
+ const additionalUserActions = await this.loadDynamicUserActions();
334
+ this.events = { ...this.events, ...additionalUserActions };
335
+ } catch (e) {
336
+ this.addError(e);
337
+ }
338
+
339
+ // Register event handlers
340
+ await this.registerEventHandlers();
341
+ }
342
+
343
+ getOptionDetails() {
344
+ const options = new Options({
345
+ module: Object.values(this.constructor.Definition.modules)[0],
346
+ ...this.constructor.Definition,
347
+ });
348
+ return options.get();
349
+ }
350
+
351
+ // Legacy method for backward compatibility
352
+ async loadModules() {
353
+ // This method was used in the old architecture for loading modules
354
+ // In the new architecture, modules are injected via constructor
355
+ // For backward compatibility, this is a no-op
356
+ return;
357
+ }
260
358
  }
261
359
 
262
360
  module.exports = { IntegrationBase };
@@ -4,7 +4,7 @@ class IntegrationRepository {
4
4
  async findIntegrationsByUserId(userId) {
5
5
  const integrationRecords = await IntegrationModel.find({ user: userId }, '', { lean: true }).populate('entities');
6
6
  return integrationRecords.map(integrationRecord => ({
7
- id: integrationRecord._id,
7
+ id: integrationRecord._id.toString(),
8
8
  entitiesIds: integrationRecord.entities.map(e => e._id),
9
9
  userId: integrationRecord.user.toString(),
10
10
  config: integrationRecord.config,
@@ -21,7 +21,7 @@ class IntegrationRepository {
21
21
  async findIntegrationByName(name) {
22
22
  const integrationRecord = await IntegrationModel.findOne({ 'config.type': name }, '', { lean: true }).populate('entities');
23
23
  return {
24
- id: integrationRecord._id,
24
+ id: integrationRecord._id.toString(),
25
25
  entitiesIds: integrationRecord.entities.map(e => e._id),
26
26
  userId: integrationRecord.user.toString(),
27
27
  config: integrationRecord.config,
@@ -34,7 +34,7 @@ class IntegrationRepository {
34
34
  async findIntegrationById(id) {
35
35
  const integrationRecord = await IntegrationModel.findById(id, '', { lean: true }).populate('entities');
36
36
  return {
37
- id: integrationRecord._id,
37
+ id: integrationRecord._id.toString(),
38
38
  entitiesIds: integrationRecord.entities.map(e => e._id),
39
39
  userId: integrationRecord.user.toString(),
40
40
  config: integrationRecord.config,
@@ -66,7 +66,7 @@ class IntegrationRepository {
66
66
  });
67
67
 
68
68
  return {
69
- id: integrationRecord._id,
69
+ id: integrationRecord._id.toString(),
70
70
  entitiesIds: integrationRecord.entities.map(e => e._id),
71
71
  userId: integrationRecord.user.toString(),
72
72
  config: integrationRecord.config,
@@ -103,6 +103,19 @@ class Integration {
103
103
  });
104
104
  }
105
105
 
106
+ _rebindEventHandlers(events) {
107
+ const reboundEvents = {};
108
+ for (const [key, event] of Object.entries(events)) {
109
+ reboundEvents[key] = {
110
+ ...event,
111
+ handler: typeof event.handler === 'function'
112
+ ? event.handler.bind(this)
113
+ : event.handler
114
+ };
115
+ }
116
+ return reboundEvents;
117
+ }
118
+
106
119
  _initializeBasicBehavior() {
107
120
  // Initialize basic behavior (sync parts only)
108
121
  if (this.integrationClass) {
@@ -112,9 +125,9 @@ class Integration {
112
125
  integrationId: this.id
113
126
  });
114
127
 
115
- // Copy events
116
- this.events = this.behavior.events || {};
117
- this.defaultEvents = this.behavior.defaultEvents || {};
128
+ // Copy events and rebind handlers to the Integration wrapper
129
+ this.events = this._rebindEventHandlers(this.behavior.events || {});
130
+ this.defaultEvents = this._rebindEventHandlers(this.behavior.defaultEvents || {});
118
131
 
119
132
  // -----------------------------------------------------------------
120
133
  // Inject the real Module instances (with credentials) so that any
@@ -134,7 +147,7 @@ class Integration {
134
147
  for (const key of Object.getOwnPropertyNames(proto)) {
135
148
  if (key === 'constructor') continue;
136
149
  if (typeof proto[key] === 'function' && this[key] === undefined) {
137
- this[key] = proto[key].bind(this.behavior);
150
+ this[key] = proto[key].bind(this);
138
151
  }
139
152
  }
140
153
  proto = Object.getPrototypeOf(proto);
@@ -148,7 +161,7 @@ class Integration {
148
161
  // Load dynamic user actions
149
162
  try {
150
163
  const additionalUserActions = await this.loadDynamicUserActions();
151
- this.events = { ...this.events, ...additionalUserActions };
164
+ this.events = { ...this.events, ...this._rebindEventHandlers(additionalUserActions) };
152
165
  } catch (e) {
153
166
  this.addError(e);
154
167
  }
@@ -1,4 +1,4 @@
1
- const { Integration } = require('../integration');
1
+ // Removed Integration wrapper - using IntegrationBase directly
2
2
  const { mapIntegrationClassToIntegrationDTO } = require('../utils/map-integration-dto');
3
3
 
4
4
  /**
@@ -50,7 +50,7 @@ class CreateIntegration {
50
50
  modules.push(moduleInstance);
51
51
  }
52
52
 
53
- const integrationInstance = new Integration({
53
+ const integrationInstance = new integrationClass({
54
54
  id: integrationRecord.id,
55
55
  userId: integrationRecord.userId,
56
56
  entities: integrationRecord.entitiesIds,
@@ -58,7 +58,6 @@ class CreateIntegration {
58
58
  status: integrationRecord.status,
59
59
  version: integrationRecord.version,
60
60
  messages: integrationRecord.messages,
61
- integrationClass: integrationClass,
62
61
  modules
63
62
  });
64
63
 
@@ -1,5 +1,5 @@
1
1
  const Boom = require('@hapi/boom');
2
- const { Integration } = require('../integration');
2
+ // Removed Integration wrapper - using IntegrationBase directly
3
3
 
4
4
  /**
5
5
  * Use case for deleting an integration for a specific user.
@@ -49,7 +49,7 @@ class DeleteIntegrationForUser {
49
49
  );
50
50
  }
51
51
 
52
- const integrationInstance = new Integration({
52
+ const integrationInstance = new integrationClass({
53
53
  id: integrationRecord.id,
54
54
  userId: integrationRecord.userId,
55
55
  entities: integrationRecord.entitiesIds,
@@ -57,7 +57,6 @@ class DeleteIntegrationForUser {
57
57
  status: integrationRecord.status,
58
58
  version: integrationRecord.version,
59
59
  messages: integrationRecord.messages,
60
- integrationClass: integrationClass,
61
60
  modules: [],
62
61
  });
63
62
 
@@ -1,4 +1,4 @@
1
- const { Integration } = require('../integration');
1
+ // Removed Integration wrapper - using IntegrationBase directly
2
2
  const { mapIntegrationClassToIntegrationDTO } = require('../utils/map-integration-dto');
3
3
  const Boom = require('@hapi/boom');
4
4
 
@@ -60,7 +60,7 @@ class GetIntegrationForUser {
60
60
  modules.push(moduleInstance);
61
61
  }
62
62
 
63
- const integrationInstance = new Integration({
63
+ const integrationInstance = new integrationClass({
64
64
  id: integrationRecord._id,
65
65
  userId: integrationRecord.userId,
66
66
  entities: entities,
@@ -68,8 +68,6 @@ class GetIntegrationForUser {
68
68
  status: integrationRecord.status,
69
69
  version: integrationRecord.version,
70
70
  messages: integrationRecord.messages,
71
- entityReference: integrationRecord.entityReference,
72
- integrationClass: integrationClass,
73
71
  modules
74
72
  });
75
73
 
@@ -1,5 +1,4 @@
1
- const { Integration } = require('../integration');
2
- const { mapIntegrationClassToIntegrationDTO } = require('../utils/map-integration-dto');
1
+ // Removed Integration wrapper - using IntegrationBase directly
3
2
  const Boom = require('@hapi/boom');
4
3
 
5
4
  /**
@@ -30,36 +29,37 @@ class GetIntegrationInstanceByDefinition {
30
29
  * @returns {Promise<Object>} The integration DTO for the specified definition.
31
30
  * @throws {Boom.notFound} When integration with the specified definition does not exist.
32
31
  */
33
- async execute(definition) {
34
- const integrationRecord = await this.integrationRepository.findIntegrationByName(definition.name);
35
- const entities = await this.moduleRepository.findEntitiesByIds(integrationRecord.entitiesIds);
32
+ async execute(integrationClass) {
33
+ const integrationRecord = await this.integrationRepository.findIntegrationByName(integrationClass.Definition.name);
36
34
 
37
35
  if (!integrationRecord) {
38
- throw Boom.notFound(`Integration with name of ${definition.name} does not exist`);
36
+ throw Boom.notFound(`Integration with name of ${integrationClass.Definition.name} does not exist`);
39
37
  }
40
38
 
39
+ const entities = await this.moduleRepository.findEntitiesByIds(integrationRecord.entitiesIds);
40
+
41
41
  const modules = [];
42
42
  for (const entity of entities) {
43
43
  const moduleInstance = await this.moduleFactory.getModuleInstance(
44
- entity._id,
44
+ entity.id,
45
45
  integrationRecord.userId
46
46
  );
47
47
  modules.push(moduleInstance);
48
48
  }
49
49
 
50
- const integrationInstance = new Integration({
51
- id: integrationRecord._id,
50
+ const integrationInstance = new integrationClass({
51
+ id: integrationRecord.id,
52
52
  userId: integrationRecord.userId,
53
53
  entities: entities,
54
54
  config: integrationRecord.config,
55
55
  status: integrationRecord.status,
56
56
  version: integrationRecord.version,
57
57
  messages: integrationRecord.messages,
58
- entityReference: integrationRecord.entityReference,
59
- integrationClass: integrationClass,
60
58
  modules
61
59
  });
62
60
 
61
+ await integrationInstance.initialize();
62
+
63
63
  return integrationInstance
64
64
  }
65
65
  }
@@ -1,4 +1,4 @@
1
- const { Integration } = require('../integration');
1
+ // Removed Integration wrapper - using IntegrationBase directly
2
2
 
3
3
  /**
4
4
  * Use case for retrieving a single integration instance by ID and user.
@@ -62,7 +62,7 @@ class GetIntegrationInstance {
62
62
  modules.push(moduleInstance);
63
63
  }
64
64
 
65
- const integrationInstance = new Integration({
65
+ const integrationInstance = new integrationClass({
66
66
  id: integrationRecord.id,
67
67
  userId: integrationRecord.userId,
68
68
  entities: integrationRecord.entitiesIds,
@@ -70,11 +70,9 @@ class GetIntegrationInstance {
70
70
  status: integrationRecord.status,
71
71
  version: integrationRecord.version,
72
72
  messages: integrationRecord.messages,
73
- integrationClass: integrationClass,
74
73
  modules
75
74
  });
76
75
 
77
-
78
76
  await integrationInstance.initialize();
79
77
 
80
78
  return integrationInstance;
@@ -1,4 +1,4 @@
1
- const { Integration } = require('../integration');
1
+ // Removed Integration wrapper - using IntegrationBase directly
2
2
  const { mapIntegrationClassToIntegrationDTO } = require('../utils/map-integration-dto');
3
3
 
4
4
  /**
@@ -52,7 +52,7 @@ class GetIntegrationsForUser {
52
52
  modules.push(moduleInstance);
53
53
  }
54
54
 
55
- const integrationInstance = new Integration({
55
+ const integrationInstance = new integrationClass({
56
56
  id: integrationRecord.id,
57
57
  userId: integrationRecord.userId,
58
58
  entities: entities,
@@ -60,7 +60,6 @@ class GetIntegrationsForUser {
60
60
  status: integrationRecord.status,
61
61
  version: integrationRecord.version,
62
62
  messages: integrationRecord.messages,
63
- integrationClass: integrationClass,
64
63
  modules
65
64
  });
66
65
 
@@ -1,4 +1,4 @@
1
- const { Integration } = require('../integration');
1
+ // Removed Integration wrapper - using IntegrationBase directly
2
2
  const { mapIntegrationClassToIntegrationDTO } = require('../utils/map-integration-dto');
3
3
 
4
4
  /**
@@ -68,7 +68,7 @@ class UpdateIntegration {
68
68
  }
69
69
 
70
70
  // 4. Create the Integration domain entity with modules and updated config
71
- const integrationInstance = new Integration({
71
+ const integrationInstance = new integrationClass({
72
72
  id: integrationRecord.id,
73
73
  userId: integrationRecord.userId,
74
74
  entities: integrationRecord.entitiesIds,
@@ -76,7 +76,6 @@ class UpdateIntegration {
76
76
  status: integrationRecord.status,
77
77
  version: integrationRecord.version,
78
78
  messages: integrationRecord.messages,
79
- integrationClass: integrationClass,
80
79
  modules
81
80
  });
82
81
 
@@ -34,7 +34,7 @@ class ModuleFactory {
34
34
 
35
35
  const moduleName = entity.moduleName;
36
36
  const moduleDefinition = this.moduleDefinitions.find((def) => {
37
- return moduleName === def.modelName;
37
+ return moduleName === def.moduleName;
38
38
  });
39
39
 
40
40
  if (!moduleDefinition) {
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.397.84ecb0e.0",
4
+ "version": "2.0.0--canary.397.e634da9.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.397.84ecb0e.0",
26
- "@friggframework/prettier-config": "2.0.0--canary.397.84ecb0e.0",
27
- "@friggframework/test": "2.0.0--canary.397.84ecb0e.0",
25
+ "@friggframework/eslint-config": "2.0.0--canary.397.e634da9.0",
26
+ "@friggframework/prettier-config": "2.0.0--canary.397.e634da9.0",
27
+ "@friggframework/test": "2.0.0--canary.397.e634da9.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": "84ecb0ef85262bbb8c2c063dd595684d63599649"
56
+ "gitHead": "e634da9cd6c4e10ca19280b4f1e11d02eeeada51"
57
57
  }