@friggframework/core 2.0.0--canary.395.af305ea.0 → 2.0.0--canary.396.d14a555.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.
@@ -0,0 +1,9 @@
1
+ const { Credential } = require('../module-plugin');
2
+
3
+ class CredentialRepository {
4
+ async findCredentialById(id) {
5
+ return Credential.findById(id);
6
+ }
7
+ }
8
+
9
+ module.exports = { CredentialRepository };
@@ -0,0 +1,21 @@
1
+ class GetCredentialForUser {
2
+ constructor({ credentialRepository }) {
3
+ this.credentialRepository = credentialRepository;
4
+ }
5
+
6
+ async execute(credentialId, userId) {
7
+ const credential = await this.credentialRepository.findCredentialById(credentialId);
8
+
9
+ if (!credential) {
10
+ throw new Error(`Credential with id ${credentialId} not found`);
11
+ }
12
+
13
+ if (credential.user.toString() !== userId.toString()) {
14
+ throw new Error(`Credential ${credentialId} does not belong to user ${userId}`);
15
+ }
16
+
17
+ return credential;
18
+ }
19
+ }
20
+
21
+ module.exports = { GetCredentialForUser };
@@ -44,7 +44,7 @@ const loadRouterFromObject = (IntegrationClass, routerObject) => {
44
44
  );
45
45
  router[method.toLowerCase()](path, async (req, res, next) => {
46
46
  try {
47
- const integration = new IntegrationClass({});
47
+ const integration = new IntegrationClass();
48
48
  await integration.loadModules();
49
49
  await integration.registerEventHandlers();
50
50
  const result = await integration.send(event, { req, res, next });
@@ -64,7 +64,7 @@ const createQueueWorker = (integrationClass, integrationFactory) => {
64
64
  try {
65
65
  let instance;
66
66
  if (!params.integrationId) {
67
- instance = new integrationClass({});
67
+ instance = new integrationClass();
68
68
  await instance.loadModules();
69
69
  // await instance.loadUserActions();
70
70
  await instance.registerEventHandlers();
@@ -4,7 +4,7 @@ const {
4
4
  loadAppDefinition,
5
5
  } = require('./../backend-utils');
6
6
  const { UserRepository } = require('../../user/user-repository');
7
- const { IntegrationFactory, IntegrationHelper } = require('../../integrations/integration-factory');
7
+ const { IntegrationFactory } = require('../../integrations/integration-factory');
8
8
  const { GetUserFromBearerToken } = require('../../user/use-cases/get-user-from-bearer-token');
9
9
 
10
10
  const { integrations, userConfig } = loadAppDefinition();
@@ -19,7 +19,6 @@ const router = createIntegrationRouter({
19
19
  factory: {
20
20
  moduleFactory: integrationFactory.moduleFactory,
21
21
  integrationFactory,
22
- IntegrationHelper
23
22
  },
24
23
  getUserFromBearerToken,
25
24
  });
package/index.js CHANGED
@@ -39,7 +39,6 @@ const {
39
39
  Options,
40
40
  IntegrationMapping,
41
41
  IntegrationFactory,
42
- IntegrationHelper,
43
42
  createIntegrationRouter,
44
43
  checkRequiredParams,
45
44
  } = require('./integrations/index');
@@ -56,7 +55,6 @@ const {
56
55
  Requester,
57
56
  ModuleConstants,
58
57
  ModuleFactory,
59
- Auther,
60
58
  } = require('./module-plugin/index');
61
59
  const utils = require('./utils');
62
60
 
@@ -109,7 +107,6 @@ module.exports = {
109
107
  Options,
110
108
  IntegrationMapping,
111
109
  IntegrationFactory,
112
- IntegrationHelper,
113
110
  checkRequiredParams,
114
111
  createIntegrationRouter,
115
112
 
@@ -132,8 +129,6 @@ module.exports = {
132
129
  Requester,
133
130
  ModuleConstants,
134
131
  ModuleFactory,
135
- Auther,
136
-
137
132
  // queues
138
133
  QueuerUtil,
139
134
 
@@ -1,5 +1,6 @@
1
1
  const { IntegrationMapping } = require('./integration-mapping');
2
2
  const { Options } = require('./options');
3
+
3
4
  const constantsToBeMigrated = {
4
5
  defaultEvents: {
5
6
  ON_CREATE: 'ON_CREATE',
@@ -19,6 +20,7 @@ const constantsToBeMigrated = {
19
20
  };
20
21
 
21
22
  class IntegrationBase {
23
+
22
24
  static getOptionDetails() {
23
25
  const options = new Options({
24
26
  module: Object.values(this.Definition.modules)[0], // This is a placeholder until we revamp the frontend
@@ -26,6 +28,7 @@ class IntegrationBase {
26
28
  });
27
29
  return options.get();
28
30
  }
31
+
29
32
  /**
30
33
  * CHILDREN SHOULD SPECIFY A DEFINITION FOR THE INTEGRATION
31
34
  */
@@ -197,9 +200,9 @@ class IntegrationBase {
197
200
  return this.record;
198
201
  }
199
202
 
200
- async onUpdate(params) {}
203
+ async onUpdate(params) { }
201
204
 
202
- async onDelete(params) {}
205
+ async onDelete(params) { }
203
206
 
204
207
  async getConfigOptions() {
205
208
  const options = {
@@ -236,10 +239,10 @@ class IntegrationBase {
236
239
  const dynamicUserActions = await this.loadDynamicUserActions();
237
240
  const filteredDynamicActions = actionType
238
241
  ? Object.fromEntries(
239
- Object.entries(dynamicUserActions).filter(
240
- ([_, event]) => event.userActionType === actionType
241
- )
242
- )
242
+ Object.entries(dynamicUserActions).filter(
243
+ ([_, event]) => event.userActionType === actionType
244
+ )
245
+ )
243
246
  : dynamicUserActions;
244
247
  return { ...userActions, ...filteredDynamicActions };
245
248
  }
@@ -1,6 +1,5 @@
1
- const { ModuleFactory, Credential, Entity } = require('../module-plugin');
1
+ const { ModuleFactory, Entity } = require('../module-plugin');
2
2
  const { IntegrationModel } = require('./integration-model');
3
- const _ = require('lodash');
4
3
 
5
4
  class IntegrationFactory {
6
5
  constructor(integrationClasses = []) {
@@ -108,10 +107,13 @@ class IntegrationFactory {
108
107
  );
109
108
  }
110
109
 
110
+ // getIntegrationClassByType is only used here
111
111
  const integrationClass = this.getIntegrationClassByType(
112
112
  integrationRecord.config.type
113
113
  );
114
114
 
115
+ // here we should instantiate an Integration Domain class along with the integration record and it should happen in a use case class
116
+ // Actually, this integrationClass is a subclass of IntegrationBase.
115
117
  const instance = new integrationClass({
116
118
  userId,
117
119
  integrationId,
@@ -133,29 +135,8 @@ class IntegrationFactory {
133
135
  );
134
136
  instance[key] = moduleInstance;
135
137
  }
136
- } else {
137
- // for each entity, get the moduleinstance and load them according to their keys
138
- // If it's the first entity, load the moduleinstance into primary as well
139
- // If it's the second entity, load the moduleinstance into target as well
140
- const moduleTypesAndKeys =
141
- this.getModuleTypesAndKeys(integrationClass);
142
- for (let i = 0; i < integrationRecord.entities.length; i++) {
143
- const entityId = integrationRecord.entities[i];
144
- const moduleInstance =
145
- await this.moduleFactory.getModuleInstanceFromEntityId(
146
- entityId,
147
- integrationRecord.user
148
- );
149
- const moduleType = moduleInstance.getName();
150
- const key = moduleTypesAndKeys[moduleType];
151
- instance[key] = moduleInstance;
152
- if (i === 0) {
153
- instance.primary = moduleInstance;
154
- } else if (i === 1) {
155
- instance.target = moduleInstance;
156
- }
157
- }
158
138
  }
139
+
159
140
  instance.record = integrationRecord;
160
141
 
161
142
  try {
@@ -185,11 +166,8 @@ class IntegrationFactory {
185
166
  userId,
186
167
  });
187
168
  }
188
- }
189
169
 
190
- // todo: this should be split into use case classes
191
- const IntegrationHelper = {
192
- getFormattedIntegration: async function (integrationRecord) {
170
+ async getFormattedIntegration(integrationRecord) {
193
171
  const integrationObj = {
194
172
  id: integrationRecord.id,
195
173
  status: integrationRecord.status,
@@ -211,40 +189,7 @@ const IntegrationHelper = {
211
189
  });
212
190
  }
213
191
  return integrationObj;
214
- },
215
-
216
- getIntegrationsForUserId: async function (userId) {
217
- const integrationList = await IntegrationModel.find({ user: userId });
218
- return await Promise.all(
219
- integrationList.map(
220
- async (integrationRecord) =>
221
- await IntegrationHelper.getFormattedIntegration(
222
- integrationRecord
223
- )
224
- )
225
- );
226
- },
227
-
228
- deleteIntegrationForUserById: async function (userId, integrationId) {
229
- const integrationList = await IntegrationModel.find({
230
- user: userId,
231
- _id: integrationId,
232
- });
233
- if (integrationList.length !== 1) {
234
- throw new Error(
235
- `Integration with id of ${integrationId} does not exist for this user`
236
- );
237
- }
238
- await IntegrationModel.deleteOne({ _id: integrationId });
239
- },
240
-
241
- getIntegrationById: async function (id) {
242
- return IntegrationModel.findById(id).populate('entities');
243
- },
244
-
245
- listCredentials: async function (options) {
246
- return Credential.find(options);
247
- },
248
- };
192
+ }
193
+ }
249
194
 
250
- module.exports = { IntegrationFactory, IntegrationHelper };
195
+ module.exports = { IntegrationFactory };
@@ -0,0 +1,26 @@
1
+ const { IntegrationModel } = require('./integration-model');
2
+
3
+ class IntegrationRepository {
4
+ async findIntegrationsByUserId(userId) {
5
+ return IntegrationModel.find({ user: userId });
6
+ }
7
+
8
+ async deleteIntegrationById(integrationId) {
9
+ return IntegrationModel.deleteOne({ _id: integrationId });
10
+ }
11
+
12
+ async findIntegrationById(id) {
13
+ return IntegrationModel.findById(id).populate('entities');
14
+ }
15
+
16
+ async createIntegration(entities, userId, config) {
17
+ return IntegrationModel.create({
18
+ entities: entities,
19
+ user: userId,
20
+ config,
21
+ version: '0.0.0',
22
+ });
23
+ }
24
+ }
25
+
26
+ module.exports = { IntegrationRepository };
@@ -3,19 +3,57 @@ const { get } = require('../assertions');
3
3
  const Boom = require('@hapi/boom');
4
4
  const catchAsyncError = require('express-async-handler');
5
5
  const { debug } = require('../logs');
6
+ const { IntegrationRepository } = require('./integration-repository');
7
+ const { DeleteIntegrationForUser } = require('./use-cases/delete-integration-for-user');
8
+ const { GetIntegrationForUser } = require('./use-cases/get-integration-for-user');
9
+ const { GetIntegrationsForUser } = require('./use-cases/get-integrations-for-user');
10
+ const { CredentialRepository } = require('../credential/credential-repository');
11
+ const { GetCredentialForUser } = require('../credential/use-cases/get-credential-for-user');
12
+ const { CreateIntegration } = require('./use-cases/create-integration');
13
+ const { ModuleService } = require('../module-plugin/module-service');
14
+ const { ModuleRepository } = require('../module-plugin/module-repository');
15
+ const { loadAppDefinition } = require('../backend-utils');
16
+
17
+
18
+ const { integrations } = loadAppDefinition();
19
+ const moduleRepository = new ModuleRepository();
20
+ const integrationRepository = new IntegrationRepository();
21
+ const credentialRepository = new CredentialRepository();
22
+ const moduleService = new ModuleService({ moduleRepository, moduleDefinitions: { ...getModules() } });
23
+ const deleteIntegrationForUser = new DeleteIntegrationForUser({ integrationRepository });
24
+ const getIntegrationForUser = new GetIntegrationForUser({ integrationRepository });
25
+ const getIntegrationsForUser = new GetIntegrationsForUser({ integrationRepository });
26
+ const getCredentialForUser = new GetCredentialForUser({ credentialRepository });
27
+ const createIntegration = new CreateIntegration({
28
+ integrationRepository,
29
+ integrationClasses: integrations,
30
+ moduleService,
31
+ });
32
+
33
+ // todo: move this into a utils file
34
+ const getModules = () => {
35
+ return [
36
+ ...new Set(
37
+ integrations
38
+ .map((integration) =>
39
+ Object.values(integration.Definition.modules).map(
40
+ (module) => module.definition
41
+ )
42
+ )
43
+ .flat()
44
+ ),
45
+ ];
46
+ }
6
47
 
7
-
8
- // todo: dont send moduleFactory, integrationFactory, and IntegrationHelper as a factory object, instead send them as separate
9
- // params and import IntegrationHelper where needed.
48
+ // todo: dont send moduleFactory and integrationFactory as a factory object, instead send them as separate params.
10
49
  // todo: this could be a use case class
11
50
  /**
12
51
  * Creates an Express router with integration and entity routes configured
13
52
  * @param {Object} params - Configuration parameters for the router
14
53
  * @param {express.Router} [params.router] - Optional Express router instance, creates new one if not provided
15
- * @param {Object} params.factory - Factory object containing moduleFactory, integrationFactory, and IntegrationHelper
54
+ * @param {Object} params.factory - Factory object containing moduleFactory and integrationFactory
16
55
  * @param {Object} params.factory.moduleFactory - Factory for creating and managing API modules
17
56
  * @param {Object} params.factory.integrationFactory - Factory for creating and managing integrations
18
- * @param {Object} params.factory.IntegrationHelper - Helper utilities for integration operations
19
57
  * @param {import('../user/use-cases/get-user-from-bearer-token').GetUserFromBearerToken} params.getUserFromBearerToken - Use case for retrieving a user from a bearer token
20
58
  * @returns {express.Router} Configured Express router with integration and entity routes
21
59
  */
@@ -54,14 +92,14 @@ function checkRequiredParams(params, requiredKeys) {
54
92
  /**
55
93
  * Sets up integration-related routes on the provided Express router
56
94
  * @param {express.Router} router - Express router instance to add routes to
57
- * @param {Object} factory - Factory object containing moduleFactory, integrationFactory, and IntegrationHelper
95
+ * @param {Object} factory - Factory object containing moduleFactory and integrationFactory
58
96
  * @param {Object} factory.moduleFactory - Factory for creating and managing API modules
59
97
  * @param {Object} factory.integrationFactory - Factory for creating and managing integrations
60
- * @param {Object} factory.IntegrationHelper - Helper utilities for integration operations
61
98
  * @param {import('../user/use-cases/get-user-from-bearer-token').GetUserFromBearerToken} getUserFromBearerToken - Use case for retrieving a user from a bearer token
62
99
  */
63
100
  function setIntegrationRoutes(router, factory, getUserFromBearerToken) {
64
- const { moduleFactory, integrationFactory, IntegrationHelper } = factory;
101
+ const { moduleFactory, integrationFactory } = factory;
102
+
65
103
  router.route('/api/integrations').get(
66
104
  catchAsyncError(async (req, res) => {
67
105
  const user = await getUserFromBearerToken.execute(
@@ -72,7 +110,7 @@ function setIntegrationRoutes(router, factory, getUserFromBearerToken) {
72
110
  results.entities.authorized =
73
111
  await moduleFactory.getEntitiesForUser(userId);
74
112
  results.integrations =
75
- await IntegrationHelper.getIntegrationsForUserId(userId);
113
+ await getIntegrationsForUser.execute(userId);
76
114
 
77
115
  for (const integrationRecord of results.integrations) {
78
116
  const integration =
@@ -100,7 +138,7 @@ function setIntegrationRoutes(router, factory, getUserFromBearerToken) {
100
138
  get(params.config, 'type');
101
139
 
102
140
  // create integration
103
- const integration = await integrationFactory.createIntegration(
141
+ const integration = await createIntegration.execute(
104
142
  params.entities,
105
143
  userId,
106
144
  params.config
@@ -113,7 +151,7 @@ function setIntegrationRoutes(router, factory, getUserFromBearerToken) {
113
151
  await integration.send('ON_CREATE', {});
114
152
 
115
153
  res.status(201).json(
116
- await IntegrationHelper.getFormattedIntegration(
154
+ await integrationFactory.getFormattedIntegration(
117
155
  integration.record
118
156
  )
119
157
  );
@@ -141,7 +179,7 @@ function setIntegrationRoutes(router, factory, getUserFromBearerToken) {
141
179
  await integration.send('ON_UPDATE', params);
142
180
 
143
181
  res.json(
144
- await IntegrationHelper.getFormattedIntegration(
182
+ await integrationFactory.getFormattedIntegration(
145
183
  integration.record
146
184
  )
147
185
  );
@@ -153,11 +191,10 @@ function setIntegrationRoutes(router, factory, getUserFromBearerToken) {
153
191
  const user = await getUserFromBearerToken.execute(
154
192
  req.headers.authorization
155
193
  );
156
- const userId = user.getId();
157
194
  const params = checkRequiredParams(req.params, ['integrationId']);
158
195
  const integration =
159
196
  await integrationFactory.getInstanceFromIntegrationId({
160
- userId,
197
+ userId: user.getId(),
161
198
  integrationId: params.integrationId,
162
199
  });
163
200
 
@@ -165,12 +202,9 @@ function setIntegrationRoutes(router, factory, getUserFromBearerToken) {
165
202
  `Calling onUpdate on the ${integration?.constructor?.Definition?.name} Integration with no arguments`
166
203
  );
167
204
  await integration.send('ON_DELETE');
168
- await IntegrationHelper.deleteIntegrationForUserById(
169
- userId,
170
- params.integrationId
171
- );
205
+ await deleteIntegrationForUser.execute(params.integrationId, user.getId());
172
206
 
173
- res.status(201).json({});
207
+ res.status(204).json({});
174
208
  })
175
209
  );
176
210
 
@@ -309,13 +343,14 @@ function setIntegrationRoutes(router, factory, getUserFromBearerToken) {
309
343
  const user = await getUserFromBearerToken.execute(
310
344
  req.headers.authorization
311
345
  );
346
+
347
+ if (!user) {
348
+ throw Boom.forbidden('User not found');
349
+ }
350
+
312
351
  const params = checkRequiredParams(req.params, ['integrationId']);
313
- const integration = await IntegrationHelper.getIntegrationById(
314
- {
315
- integrationId: params.integrationId,
316
- userId: user.getId(),
317
- }
318
- );
352
+ const integration = await getIntegrationForUser.execute(params.integrationId, user.getId());
353
+
319
354
  // We could perhaps augment router with dynamic options? Haven't decided yet, but here may be the place
320
355
 
321
356
  res.json({
@@ -364,11 +399,11 @@ function setIntegrationRoutes(router, factory, getUserFromBearerToken) {
364
399
  /**
365
400
  * Sets up entity-related routes for the integration router
366
401
  * @param {Object} router - Express router instance
367
- * @param {Object} factory - Factory object containing moduleFactory and IntegrationHelper
402
+ * @param {Object} factory - Factory object containing moduleFactory
368
403
  * @param {import('../user/use-cases/get-user-from-bearer-token').GetUserFromBearerToken} getUserFromBearerToken - Use case for retrieving a user from a bearer token
369
404
  */
370
405
  function setEntityRoutes(router, factory, getUserFromBearerToken) {
371
- const { moduleFactory, IntegrationHelper } = factory;
406
+ const { moduleFactory } = factory;
372
407
  const getModuleInstance = async (userId, entityType) => {
373
408
  if (!moduleFactory.checkIsValidType(entityType)) {
374
409
  throw Boom.badRequest(
@@ -437,8 +472,9 @@ function setEntityRoutes(router, factory, getUserFromBearerToken) {
437
472
  checkRequiredParams(req.body.data, ['credential_id']);
438
473
 
439
474
  // May want to pass along the user ID as well so credential ID's can't be fished???
440
- const credential = await IntegrationHelper.getCredentialById(
441
- params.data.credential_id
475
+ const credential = await getCredentialForUser.execute(
476
+ params.data.credential_id,
477
+ userId
442
478
  );
443
479
 
444
480
  if (!credential) {
@@ -465,8 +501,9 @@ function setEntityRoutes(router, factory, getUserFromBearerToken) {
465
501
  const userId = user.getId();
466
502
  // TODO May want to pass along the user ID as well so credential ID's can't be fished???
467
503
  // TODO **flagging this for review** -MW
468
- const credential = await IntegrationHelper.getCredentialById(
469
- req.params.credentialId
504
+ const credential = await getCredentialForUser.execute(
505
+ req.params.credentialId,
506
+ userId
470
507
  );
471
508
  if (credential.user._id.toString() !== userId) {
472
509
  throw Boom.forbidden('Credential does not belong to user');
@@ -0,0 +1,156 @@
1
+ /**
2
+ * Integration Domain Entity
3
+ * Represents a configured integration with its data and behavior
4
+ * Uses the strategy pattern to delegate behavior to the integration class
5
+ * This is the main class that is used to interact with integrations
6
+ */
7
+ class Integration {
8
+ constructor({
9
+ id,
10
+ userId,
11
+ entities,
12
+ config,
13
+ status,
14
+ version,
15
+ messages,
16
+ entityReference,
17
+ integrationClass,
18
+ modules = {}
19
+ }) {
20
+ // Data from record
21
+ this.id = id;
22
+ this.userId = userId;
23
+ this.entities = entities;
24
+ this.config = config;
25
+ this.status = status;
26
+ this.version = version;
27
+ this.messages = messages;
28
+ this.entityReference = entityReference;
29
+
30
+ // Integration behavior (strategy pattern)
31
+ this.integrationClass = integrationClass;
32
+
33
+ // Loaded modules
34
+ this.modules = modules;
35
+
36
+ // Initialize basic behavior (sync parts only)
37
+ this._initializeBasicBehavior();
38
+
39
+ // Return a Proxy to handle dynamic method delegation
40
+ return new Proxy(this, {
41
+ get(target, prop) {
42
+ // First, check if property exists on Integration entity
43
+ if (prop in target) {
44
+ return target[prop];
45
+ }
46
+
47
+ // Then, check if it exists on the behavior instance
48
+ if (target.behavior && prop in target.behavior) {
49
+ const value = target.behavior[prop];
50
+
51
+ // If it's a function, bind the context to the Integration entity
52
+ if (typeof value === 'function') {
53
+ return value.bind(target);
54
+ }
55
+
56
+ return value;
57
+ }
58
+
59
+ // Return undefined for non-existent properties
60
+ return undefined;
61
+ }
62
+ });
63
+ }
64
+
65
+ _initializeBasicBehavior() {
66
+ // Initialize basic behavior (sync parts only)
67
+ if (this.integrationClass) {
68
+ // Create instance for behavior delegation
69
+ this.behavior = new this.integrationClass({
70
+ userId: this.userId,
71
+ integrationId: this.id
72
+ });
73
+
74
+ // Copy events
75
+ this.events = this.behavior.events || {};
76
+ this.defaultEvents = this.behavior.defaultEvents || {};
77
+ }
78
+ }
79
+
80
+ async initialize() {
81
+ // Complete async initialization
82
+ if (this.behavior) {
83
+ // Load dynamic user actions
84
+ try {
85
+ const additionalUserActions = await this.loadDynamicUserActions();
86
+ this.events = { ...this.events, ...additionalUserActions };
87
+ } catch (e) {
88
+ this.addError(e);
89
+ }
90
+
91
+ // Register event handlers
92
+ await this.registerEventHandlers();
93
+ }
94
+ }
95
+
96
+ // Core methods that should always be on Integration entity
97
+ // These override any behavior methods with the same name
98
+
99
+ // Module access helpers
100
+ getModule(key) {
101
+ return this.modules[key];
102
+ }
103
+
104
+ setModule(key, module) {
105
+ this.modules[key] = module;
106
+ // Also set on behavior for backward compatibility
107
+ if (this.behavior) {
108
+ this.behavior[key] = module;
109
+ }
110
+ }
111
+
112
+ // State management
113
+ addError(error) {
114
+ if (!this.messages.errors) {
115
+ this.messages.errors = [];
116
+ }
117
+ this.messages.errors.push(error);
118
+ this.status = 'ERROR';
119
+ }
120
+
121
+ addWarning(warning) {
122
+ if (!this.messages.warnings) {
123
+ this.messages.warnings = [];
124
+ }
125
+ this.messages.warnings.push(warning);
126
+ }
127
+
128
+ // Domain methods
129
+ isActive() {
130
+ return this.status === 'ENABLED' || this.status === 'ACTIVE';
131
+ }
132
+
133
+ needsConfiguration() {
134
+ return this.status === 'NEEDS_CONFIG';
135
+ }
136
+
137
+ hasErrors() {
138
+ return this.status === 'ERROR';
139
+ }
140
+
141
+ belongsToUser(userId) {
142
+ return this.userId.toString() === userId.toString();
143
+ }
144
+
145
+ // Get the underlying behavior instance (useful for debugging or special cases)
146
+ getBehavior() {
147
+ return this.behavior;
148
+ }
149
+
150
+ // Check if a method exists (either on entity or behavior)
151
+ hasMethod(methodName) {
152
+ return methodName in this || (this.behavior && methodName in this.behavior);
153
+ }
154
+ }
155
+
156
+ module.exports = { Integration };
@@ -1,5 +1,5 @@
1
1
  const { RequiredPropertyError } = require('../errors');
2
- const { get, getAndVerifyType } = require('../assertions');
2
+ const { get } = require('../assertions');
3
3
 
4
4
  class Options {
5
5
  constructor(params) {