@friggframework/core 2.0.0--canary.548.c8ae0ca.0 → 2.0.0--canary.545.c40eca4.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.
Files changed (237) hide show
  1. package/CHANGELOG.md +66 -67
  2. package/CLAUDE.md +148 -124
  3. package/README.md +165 -130
  4. package/admin-scripts/index.js +52 -0
  5. package/admin-scripts/repositories/admin-api-key-repository-documentdb.js +21 -0
  6. package/admin-scripts/repositories/admin-api-key-repository-factory.js +51 -0
  7. package/admin-scripts/repositories/admin-api-key-repository-interface.js +121 -0
  8. package/admin-scripts/repositories/admin-api-key-repository-mongo.js +155 -0
  9. package/admin-scripts/repositories/admin-api-key-repository-postgres.js +189 -0
  10. package/admin-scripts/repositories/admin-process-repository-documentdb.js +21 -0
  11. package/admin-scripts/repositories/admin-process-repository-factory.js +49 -0
  12. package/admin-scripts/repositories/admin-process-repository-interface.js +150 -0
  13. package/admin-scripts/repositories/admin-process-repository-mongo.js +213 -0
  14. package/admin-scripts/repositories/admin-process-repository-postgres.js +251 -0
  15. package/admin-scripts/repositories/script-execution-repository-documentdb.js +21 -0
  16. package/admin-scripts/repositories/script-execution-repository-factory.js +51 -0
  17. package/admin-scripts/repositories/script-execution-repository-interface.js +193 -0
  18. package/admin-scripts/repositories/script-execution-repository-mongo.js +278 -0
  19. package/admin-scripts/repositories/script-execution-repository-postgres.js +320 -0
  20. package/admin-scripts/repositories/script-schedule-repository-documentdb.js +21 -0
  21. package/admin-scripts/repositories/script-schedule-repository-factory.js +49 -0
  22. package/admin-scripts/repositories/script-schedule-repository-interface.js +108 -0
  23. package/admin-scripts/repositories/script-schedule-repository-mongo.js +179 -0
  24. package/admin-scripts/repositories/script-schedule-repository-postgres.js +210 -0
  25. package/application/commands/admin-script-commands.js +348 -0
  26. package/application/commands/integration-commands.js +12 -6
  27. package/application/index.js +5 -3
  28. package/assertions/get.js +17 -7
  29. package/associations/association.js +59 -57
  30. package/core/CLAUDE.md +222 -156
  31. package/core/Worker.js +33 -12
  32. package/credential/credential-router.js +262 -0
  33. package/credential/repositories/credential-repository-documentdb.js +71 -1
  34. package/credential/repositories/credential-repository-factory.js +4 -6
  35. package/credential/repositories/credential-repository-interface.js +8 -2
  36. package/credential/repositories/credential-repository-mongo.js +45 -4
  37. package/credential/repositories/credential-repository-postgres.js +44 -3
  38. package/credential/repositories/credential-repository.js +3 -1
  39. package/credential/use-cases/delete-credential-for-user.js +50 -0
  40. package/credential/use-cases/get-credential-for-user.js +21 -3
  41. package/credential/use-cases/list-credentials-for-user.js +31 -0
  42. package/credential/use-cases/reauthorize-credential.js +103 -0
  43. package/credential/use-cases/update-authentication-status.js +5 -2
  44. package/database/MONGODB_TRANSACTION_FIX.md +72 -52
  45. package/database/config.js +13 -59
  46. package/database/documentdb-encryption-service.js +29 -13
  47. package/database/documentdb-utils.js +21 -12
  48. package/database/encryption/README.md +53 -36
  49. package/database/encryption/encryption-schema-registry.js +29 -23
  50. package/database/encryption/field-encryption-service.js +15 -4
  51. package/database/encryption/logger.js +3 -2
  52. package/database/encryption/prisma-encryption-extension.js +5 -8
  53. package/database/prisma.js +22 -14
  54. package/database/repositories/health-check-repository-factory.js +7 -5
  55. package/database/repositories/health-check-repository-interface.js +15 -5
  56. package/database/repositories/health-check-repository-postgres.js +1 -1
  57. package/database/use-cases/check-database-health-use-case.js +3 -2
  58. package/database/use-cases/check-database-state-use-case.js +8 -7
  59. package/database/use-cases/get-database-state-via-worker-use-case.js +15 -12
  60. package/database/use-cases/get-migration-status-use-case.js +4 -2
  61. package/database/use-cases/run-database-migration-use-case.js +41 -9
  62. package/database/use-cases/test-encryption-use-case.js +4 -5
  63. package/database/use-cases/trigger-database-migration-use-case.js +9 -8
  64. package/database/utils/mongodb-collection-utils.js +11 -3
  65. package/database/utils/mongodb-schema-init.js +10 -4
  66. package/database/utils/prisma-runner.js +144 -74
  67. package/database/utils/prisma-schema-parser.js +2 -2
  68. package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +135 -80
  69. package/encrypt/Cryptor.js +54 -49
  70. package/encrypt/aes-encryption-key-provider.js +82 -0
  71. package/encrypt/encryption-key-provider-interface.js +50 -0
  72. package/errors/fetch-error.js +1 -1
  73. package/generated/prisma-mongodb/edge.js +59 -4
  74. package/generated/prisma-mongodb/index-browser.js +49 -1
  75. package/generated/prisma-mongodb/index.d.ts +4023 -61
  76. package/generated/prisma-mongodb/index.js +59 -4
  77. package/generated/prisma-mongodb/package.json +1 -1
  78. package/generated/prisma-mongodb/schema.prisma +87 -0
  79. package/generated/prisma-mongodb/wasm.js +59 -4
  80. package/generated/prisma-postgresql/edge.js +58 -4
  81. package/generated/prisma-postgresql/index-browser.js +48 -1
  82. package/generated/prisma-postgresql/index.d.ts +4738 -54
  83. package/generated/prisma-postgresql/index.js +58 -4
  84. package/generated/prisma-postgresql/package.json +1 -1
  85. package/generated/prisma-postgresql/schema.prisma +85 -0
  86. package/generated/prisma-postgresql/wasm.js +58 -4
  87. package/handlers/WEBHOOKS.md +104 -81
  88. package/handlers/app-definition-loader.js +53 -10
  89. package/handlers/app-handler-helpers.js +14 -3
  90. package/handlers/backend-utils.js +0 -1
  91. package/handlers/database-migration-handler.js +64 -45
  92. package/handlers/middleware/admin-auth.js +53 -0
  93. package/handlers/routers/HEALTHCHECK.md +170 -135
  94. package/handlers/routers/admin.js +474 -0
  95. package/handlers/routers/auth.js +51 -9
  96. package/handlers/routers/db-migration.handler.js +2 -3
  97. package/handlers/routers/db-migration.js +102 -66
  98. package/handlers/routers/docs.js +180 -0
  99. package/handlers/routers/health.js +84 -283
  100. package/handlers/routers/integration-defined-routers.js +44 -33
  101. package/handlers/routers/integration-webhook-routers.js +73 -52
  102. package/handlers/routers/middleware/loadUser.js +39 -0
  103. package/handlers/routers/middleware/requireAdmin.js +43 -0
  104. package/handlers/routers/middleware/requireLoggedInUser.js +19 -0
  105. package/handlers/routers/user.js +30 -14
  106. package/handlers/routers/websocket.js +18 -4
  107. package/handlers/use-cases/check-integrations-health-use-case.js +13 -6
  108. package/handlers/workers/db-migration.js +74 -35
  109. package/handlers/workers/integration-defined-workers.js +31 -20
  110. package/index.js +50 -16
  111. package/infrastructure/scheduler/index.js +15 -11
  112. package/infrastructure/scheduler/netlify-scheduler-adapter.js +185 -0
  113. package/infrastructure/scheduler/scheduler-service-factory.js +38 -31
  114. package/integrations/WEBHOOK-QUICKSTART.md +21 -14
  115. package/integrations/index.js +4 -0
  116. package/integrations/integration-base.js +9 -6
  117. package/integrations/integration-router.js +1828 -157
  118. package/integrations/options.js +47 -20
  119. package/integrations/repositories/integration-mapping-repository-factory.js +4 -8
  120. package/integrations/repositories/integration-repository-documentdb.js +53 -24
  121. package/integrations/repositories/integration-repository-factory.js +6 -6
  122. package/integrations/repositories/integration-repository-interface.js +27 -9
  123. package/integrations/repositories/integration-repository-postgres.js +3 -3
  124. package/integrations/repositories/process-repository-factory.js +4 -7
  125. package/integrations/repositories/process-repository-interface.js +9 -5
  126. package/integrations/repositories/process-repository-mongo.js +7 -3
  127. package/integrations/repositories/process-repository-postgres.js +2 -2
  128. package/integrations/tests/doubles/config-capturing-integration.js +9 -8
  129. package/integrations/tests/doubles/dummy-integration-class.js +81 -8
  130. package/integrations/tests/doubles/test-integration-repository.js +51 -11
  131. package/integrations/use-cases/create-integration.js +36 -32
  132. package/integrations/use-cases/create-process.js +20 -9
  133. package/integrations/use-cases/delete-integration-for-user.js +5 -4
  134. package/integrations/use-cases/execute-proxy-request.js +564 -0
  135. package/integrations/use-cases/get-integration-for-user.js +25 -10
  136. package/integrations/use-cases/get-integration-instance-by-definition.js +13 -7
  137. package/integrations/use-cases/get-integrations-for-user.js +4 -1
  138. package/integrations/use-cases/get-possible-integrations.js +1 -1
  139. package/integrations/use-cases/get-process.js +5 -6
  140. package/integrations/use-cases/index.js +3 -1
  141. package/integrations/use-cases/load-integration-context.js +1 -5
  142. package/integrations/use-cases/update-process-state.js +10 -8
  143. package/integrations/utils/map-integration-dto.js +9 -3
  144. package/jest-setup.js +1 -1
  145. package/jest-teardown.js +1 -1
  146. package/lambda/TimeoutCatcher.js +32 -30
  147. package/lambda/index.js +1 -1
  148. package/logs/index.js +3 -3
  149. package/modules/domain/entities/AuthorizationSession.js +131 -0
  150. package/modules/domain/entities/index.js +10 -0
  151. package/modules/module.js +4 -9
  152. package/modules/repositories/authorization-session-repository-factory.js +53 -0
  153. package/modules/repositories/authorization-session-repository-interface.js +75 -0
  154. package/modules/repositories/authorization-session-repository-mongo.js +169 -0
  155. package/modules/repositories/authorization-session-repository-postgres.js +170 -0
  156. package/modules/repositories/module-repository-documentdb.js +89 -41
  157. package/modules/repositories/module-repository-factory.js +4 -6
  158. package/modules/repositories/module-repository-interface.js +13 -0
  159. package/modules/repositories/module-repository-mongo.js +40 -5
  160. package/modules/repositories/module-repository-postgres.js +42 -5
  161. package/modules/repositories/module-repository.js +28 -0
  162. package/modules/requester/api-key.js +0 -2
  163. package/modules/requester/basic.js +0 -1
  164. package/modules/requester/oauth-2.js +3 -14
  165. package/modules/test/mock-api/definition.js +15 -10
  166. package/modules/test/mock-api/mocks/hubspot.js +36 -36
  167. package/modules/tests/doubles/test-module-factory.js +10 -4
  168. package/modules/tests/doubles/test-module-repository.js +1 -1
  169. package/modules/use-cases/delete-module-entity.js +23 -0
  170. package/modules/use-cases/get-authorization-requirements.js +110 -0
  171. package/modules/use-cases/get-entities-for-user.js +1 -1
  172. package/modules/use-cases/get-entity-options-by-id.js +8 -6
  173. package/modules/use-cases/get-module-entity-by-id.js +16 -0
  174. package/modules/use-cases/get-module.js +12 -9
  175. package/modules/use-cases/process-authorization-callback.js +12 -6
  176. package/modules/use-cases/process-authorization-step.js +160 -0
  177. package/modules/use-cases/refresh-entity-options.js +8 -6
  178. package/modules/use-cases/start-authorization-session.js +86 -0
  179. package/modules/use-cases/test-module-auth.js +8 -6
  180. package/modules/use-cases/update-module-entity.js +27 -0
  181. package/modules/utils/map-module-dto.js +2 -2
  182. package/openapi/openapi-spec-generator.js +370 -0
  183. package/openapi/openapi-v1.yaml +1360 -0
  184. package/openapi/openapi-v2.yaml +1535 -0
  185. package/package.json +7 -9
  186. package/prisma-mongodb/schema.prisma +87 -0
  187. package/prisma-postgresql/migrations/20260222000000_add_admin_process_and_script_schedule/migration.sql +55 -0
  188. package/prisma-postgresql/schema.prisma +85 -0
  189. package/providers/index.js +13 -0
  190. package/providers/resolve-provider.js +93 -0
  191. package/queues/index.js +19 -0
  192. package/queues/providers/index.js +7 -0
  193. package/queues/providers/netlify-background-provider.js +76 -0
  194. package/queues/providers/qstash-queue-provider.js +122 -0
  195. package/queues/queue-client-interface.js +55 -0
  196. package/queues/queue-provider-factory.js +93 -0
  197. package/queues/queue-provider.js +46 -0
  198. package/queues/queuer-util.js +33 -25
  199. package/syncs/repositories/sync-repository-documentdb.js +39 -19
  200. package/syncs/repositories/sync-repository-factory.js +4 -4
  201. package/syncs/repositories/sync-repository-interface.js +6 -2
  202. package/syncs/repositories/sync-repository-postgres.js +19 -13
  203. package/syncs/sync.js +104 -100
  204. package/token/repositories/token-repository-factory.js +4 -6
  205. package/types/assertions/index.d.ts +72 -72
  206. package/types/core/index.d.ts +98 -53
  207. package/types/errors/index.d.ts +61 -54
  208. package/types/eslint-config/index.d.ts +40 -40
  209. package/types/lambda/index.d.ts +26 -26
  210. package/types/logs/index.d.ts +4 -4
  211. package/types/prettier-config/index.d.ts +5 -5
  212. package/types/test-environment/index.d.ts +14 -14
  213. package/types/tsconfig.json +95 -93
  214. package/user/repositories/user-repository-factory.js +4 -4
  215. package/user/tests/doubles/test-user-repository.js +5 -2
  216. package/user/use-cases/authenticate-user.js +2 -4
  217. package/user/use-cases/authenticate-with-shared-secret.js +1 -1
  218. package/user/use-cases/create-individual-user.js +8 -7
  219. package/user/use-cases/create-organization-user.js +1 -1
  220. package/user/use-cases/create-token-for-user-id.js +1 -1
  221. package/user/use-cases/delete-user.js +47 -0
  222. package/user/use-cases/get-user-from-adopter-jwt.js +0 -2
  223. package/user/use-cases/get-user-from-bearer-token.js +7 -3
  224. package/user/use-cases/get-user-from-x-frigg-headers.js +14 -11
  225. package/user/use-cases/login-user.js +8 -8
  226. package/user/user.js +18 -4
  227. package/utils/backend-path.js +2 -2
  228. package/utils/index.js +4 -1
  229. package/websocket/repositories/websocket-connection-repository-documentdb.js +46 -21
  230. package/websocket/repositories/websocket-connection-repository-factory.js +4 -8
  231. package/websocket/repositories/websocket-connection-repository-mongo.js +26 -16
  232. package/websocket/repositories/websocket-connection-repository-postgres.js +26 -15
  233. package/websocket/repositories/websocket-connection-repository.js +26 -20
  234. package/websocket/websocket-message-sender-interface.js +38 -0
  235. package/database/adapters/lambda-invoker.js +0 -97
  236. package/database/repositories/migration-status-repository-s3.js +0 -137
  237. package/infrastructure/scheduler/eventbridge-scheduler-adapter.js +0 -184
@@ -1,8 +1,9 @@
1
1
  const { IntegrationBase } = require('../../integration-base');
2
+ const { Options } = require('../../options');
2
3
 
3
4
  class DummyModule {
4
5
  static definition = {
5
- getName: () => 'dummy'
6
+ getName: () => 'dummy',
6
7
  };
7
8
  }
8
9
 
@@ -11,21 +12,25 @@ class DummyIntegration extends IntegrationBase {
11
12
  name: 'dummy',
12
13
  version: '1.0.0',
13
14
  modules: {
14
- dummy: DummyModule
15
+ dummy: DummyModule,
15
16
  },
16
17
  display: {
17
18
  label: 'Dummy Integration',
18
19
  description: 'A dummy integration for testing',
19
20
  detailsUrl: 'https://example.com',
20
- icon: 'dummy-icon'
21
- }
21
+ icon: 'dummy-icon',
22
+ },
22
23
  };
23
24
 
24
25
  static getOptionDetails() {
26
+ const options = new Options({
27
+ module: Object.values(this.Definition.modules)[0],
28
+ ...this.Definition,
29
+ });
25
30
  return {
26
31
  name: this.Definition.name,
27
32
  version: this.Definition.version,
28
- display: this.Definition.display
33
+ ...options.get(),
29
34
  };
30
35
  }
31
36
 
@@ -41,11 +46,11 @@ class DummyIntegration extends IntegrationBase {
41
46
  };
42
47
 
43
48
  this.updateIntegrationStatus = {
44
- execute: jest.fn().mockResolvedValue({})
49
+ execute: jest.fn().mockResolvedValue({}),
45
50
  };
46
51
 
47
52
  this.updateIntegrationMessages = {
48
- execute: jest.fn().mockResolvedValue({})
53
+ execute: jest.fn().mockResolvedValue({}),
49
54
  };
50
55
  }
51
56
 
@@ -102,4 +107,72 @@ class DummyIntegration extends IntegrationBase {
102
107
  }
103
108
  }
104
109
 
105
- module.exports = { DummyIntegration };
110
+ class DummyIntegrationWithGlobalEntity extends IntegrationBase {
111
+ static Definition = {
112
+ name: 'dummy-with-global',
113
+ version: '1.0.0',
114
+ modules: { dummy: DummyModule },
115
+ display: { label: 'Dummy With Global', description: 'Test' },
116
+ entities: {
117
+ sharedService: {
118
+ type: 'shared-api',
119
+ global: true,
120
+ required: true,
121
+ },
122
+ },
123
+ };
124
+
125
+ constructor(params) {
126
+ super(params);
127
+ this.sendSpy = jest.fn();
128
+ this.integrationRepository = {
129
+ updateIntegrationById: jest.fn().mockResolvedValue({}),
130
+ findIntegrationById: jest.fn().mockResolvedValue({}),
131
+ };
132
+ this.updateIntegrationStatus = { execute: jest.fn().mockResolvedValue({}) };
133
+ this.updateIntegrationMessages = { execute: jest.fn().mockResolvedValue({}) };
134
+ }
135
+
136
+ async loadDynamicUserActions() { return {}; }
137
+ async send(event, data) { this.sendSpy(event, data); return { event, data }; }
138
+ async initialize() { return; }
139
+ async onCreate() { return; }
140
+ }
141
+
142
+ class DummyIntegrationWithOptionalGlobalEntity extends IntegrationBase {
143
+ static Definition = {
144
+ name: 'dummy-with-optional-global',
145
+ version: '1.0.0',
146
+ modules: { dummy: DummyModule },
147
+ display: { label: 'Dummy With Optional Global', description: 'Test' },
148
+ entities: {
149
+ optionalService: {
150
+ type: 'optional-api',
151
+ global: true,
152
+ required: false,
153
+ },
154
+ },
155
+ };
156
+
157
+ constructor(params) {
158
+ super(params);
159
+ this.sendSpy = jest.fn();
160
+ this.integrationRepository = {
161
+ updateIntegrationById: jest.fn().mockResolvedValue({}),
162
+ findIntegrationById: jest.fn().mockResolvedValue({}),
163
+ };
164
+ this.updateIntegrationStatus = { execute: jest.fn().mockResolvedValue({}) };
165
+ this.updateIntegrationMessages = { execute: jest.fn().mockResolvedValue({}) };
166
+ }
167
+
168
+ async loadDynamicUserActions() { return {}; }
169
+ async send(event, data) { this.sendSpy(event, data); return { event, data }; }
170
+ async initialize() { return; }
171
+ async onCreate() { return; }
172
+ }
173
+
174
+ module.exports = {
175
+ DummyIntegration,
176
+ DummyIntegrationWithGlobalEntity,
177
+ DummyIntegrationWithOptionalGlobalEntity,
178
+ };
@@ -31,13 +31,21 @@ class TestIntegrationRepository {
31
31
  }
32
32
 
33
33
  async findIntegrationsByUserId(userId) {
34
- const results = Array.from(this.store.values()).filter(r => r.userId === userId);
35
- this.operationHistory.push({ operation: 'findByUserId', userId, count: results.length });
34
+ const results = Array.from(this.store.values()).filter(
35
+ (r) => r.userId === userId
36
+ );
37
+ this.operationHistory.push({
38
+ operation: 'findByUserId',
39
+ userId,
40
+ count: results.length,
41
+ });
36
42
  return results;
37
43
  }
38
44
 
39
45
  async findIntegrationByUserId(userId) {
40
- const record = Array.from(this.store.values()).find((r) => r.userId === userId);
46
+ const record = Array.from(this.store.values()).find(
47
+ (r) => r.userId === userId
48
+ );
41
49
  this.operationHistory.push({
42
50
  operation: 'findSingleByUserId',
43
51
  userId,
@@ -49,30 +57,52 @@ class TestIntegrationRepository {
49
57
  async updateIntegrationMessages(id, type, title, body, timestamp) {
50
58
  const rec = this.store.get(id);
51
59
  if (!rec) {
52
- this.operationHistory.push({ operation: 'updateMessages', id, success: false });
60
+ this.operationHistory.push({
61
+ operation: 'updateMessages',
62
+ id,
63
+ success: false,
64
+ });
53
65
  return false;
54
66
  }
55
67
  if (!rec.messages[type]) rec.messages[type] = [];
56
68
  rec.messages[type].push({ title, message: body, timestamp });
57
- this.operationHistory.push({ operation: 'updateMessages', id, type, success: true });
69
+ this.operationHistory.push({
70
+ operation: 'updateMessages',
71
+ id,
72
+ type,
73
+ success: true,
74
+ });
58
75
  return true;
59
76
  }
60
77
 
61
78
  async updateIntegrationConfig(id, config) {
62
79
  const rec = this.store.get(id);
63
80
  if (!rec) {
64
- this.operationHistory.push({ operation: 'updateConfig', id, success: false });
81
+ this.operationHistory.push({
82
+ operation: 'updateConfig',
83
+ id,
84
+ success: false,
85
+ });
65
86
  throw new Error(`Integration with id ${id} not found`);
66
87
  }
67
88
  rec.config = config;
68
- this.operationHistory.push({ operation: 'updateConfig', id, success: true });
89
+ this.operationHistory.push({
90
+ operation: 'updateConfig',
91
+ id,
92
+ success: true,
93
+ });
69
94
  return rec;
70
95
  }
71
96
 
72
97
  async deleteIntegrationById(id) {
73
98
  const existed = this.store.has(id);
74
99
  const result = this.store.delete(id);
75
- this.operationHistory.push({ operation: 'delete', id, existed, success: result });
100
+ this.operationHistory.push({
101
+ operation: 'delete',
102
+ id,
103
+ existed,
104
+ success: result,
105
+ });
76
106
  return result;
77
107
  }
78
108
 
@@ -80,9 +110,19 @@ class TestIntegrationRepository {
80
110
  const rec = this.store.get(id);
81
111
  if (rec) {
82
112
  rec.status = status;
83
- this.operationHistory.push({ operation: 'updateStatus', id, status, success: true });
113
+ this.operationHistory.push({
114
+ operation: 'updateStatus',
115
+ id,
116
+ status,
117
+ success: true,
118
+ });
84
119
  } else {
85
- this.operationHistory.push({ operation: 'updateStatus', id, status, success: false });
120
+ this.operationHistory.push({
121
+ operation: 'updateStatus',
122
+ id,
123
+ status,
124
+ success: false,
125
+ });
86
126
  }
87
127
  return !!rec;
88
128
  }
@@ -96,4 +136,4 @@ class TestIntegrationRepository {
96
136
  }
97
137
  }
98
138
 
99
- module.exports = { TestIntegrationRepository };
139
+ module.exports = { TestIntegrationRepository };
@@ -1,56 +1,60 @@
1
- // Removed Integration wrapper - using IntegrationBase directly
2
1
  const {
3
2
  mapIntegrationClassToIntegrationDTO,
4
3
  } = require('../utils/map-integration-dto');
5
4
 
6
- /**
7
- * Use case for creating a new integration instance.
8
- * @class CreateIntegration
9
- */
10
5
  class CreateIntegration {
11
- /**
12
- * Creates a new CreateIntegration instance.
13
- * @param {Object} params - Configuration parameters.
14
- * @param {import('../repositories/integration-repository-interface').IntegrationRepositoryInterface} params.integrationRepository - Repository for integration data operations.
15
- * @param {import('../integration-classes').IntegrationClasses} params.integrationClasses - Array of available integration classes.
16
- * @param {import('../../modules/module-factory').ModuleFactory} params.moduleFactory - Service for module instantiation and management.
17
- */
18
6
  constructor({ integrationRepository, integrationClasses, moduleFactory }) {
19
7
  this.integrationRepository = integrationRepository;
20
8
  this.integrationClasses = integrationClasses;
21
9
  this.moduleFactory = moduleFactory;
22
10
  }
23
11
 
24
- /**
25
- * Executes the integration creation process.
26
- * @async
27
- * @param {string[]} entities - Array of entity IDs to associate with the integration.
28
- * @param {string} userId - ID of the user creating the integration.
29
- * @param {Object} config - Configuration object for the integration.
30
- * @param {string} config.type - Type of integration to create.
31
- * @returns {Promise<Object>} The created integration DTO.
32
- * @throws {Error} When integration class is not found for the specified type.
33
- */
34
12
  async execute(entities, userId, config) {
35
- const integrationRecord =
36
- await this.integrationRepository.createIntegration(
37
- entities,
38
- userId,
39
- config
40
- );
41
-
42
13
  const integrationClass = this.integrationClasses.find(
43
14
  (integrationClass) =>
44
- integrationClass.Definition.name ===
45
- integrationRecord.config.type
15
+ integrationClass.Definition.name === config.type
46
16
  );
47
17
 
48
18
  if (!integrationClass) {
49
19
  throw new Error(
50
- `No integration class found for type: ${integrationRecord.config.type}`
20
+ `No integration class found for type: ${config.type}`
51
21
  );
52
22
  }
53
23
 
24
+ const allEntities = [...entities];
25
+
26
+ if (integrationClass.Definition?.entities) {
27
+ for (const [entityKey, entityConfig] of Object.entries(
28
+ integrationClass.Definition.entities
29
+ )) {
30
+ if (entityConfig.global === true) {
31
+ const globalEntity =
32
+ await this.moduleFactory.moduleRepository.findEntity({
33
+ moduleName: entityConfig.type,
34
+ isGlobal: true,
35
+ });
36
+
37
+ if (globalEntity && globalEntity.credential?.authIsValid) {
38
+ allEntities.push(globalEntity.id.toString());
39
+ } else if (entityConfig.required !== false) {
40
+ const reason = !globalEntity
41
+ ? 'not found'
42
+ : 'exists but credential is invalid';
43
+ throw new Error(
44
+ `Required global entity "${entityConfig.type}" ${reason}. Admin must configure this entity first.`
45
+ );
46
+ }
47
+ }
48
+ }
49
+ }
50
+
51
+ const integrationRecord =
52
+ await this.integrationRepository.createIntegration(
53
+ allEntities,
54
+ userId,
55
+ config
56
+ );
57
+
54
58
  const modules = [];
55
59
  for (const entityId of integrationRecord.entitiesIds) {
56
60
  const moduleInstance = await this.moduleFactory.getModuleInstance(
@@ -1,15 +1,15 @@
1
1
  /**
2
2
  * CreateProcess Use Case
3
- *
3
+ *
4
4
  * Creates a new process record for tracking long-running operations.
5
5
  * Validates required fields and delegates persistence to the repository.
6
- *
6
+ *
7
7
  * Design Philosophy:
8
8
  * - Use cases encapsulate business logic
9
9
  * - Validation happens at the use case layer
10
10
  * - Repositories handle only data access
11
11
  * - Process model is generic and reusable
12
- *
12
+ *
13
13
  * @example
14
14
  * const createProcess = new CreateProcess({ processRepository });
15
15
  * const process = await createProcess.execute({
@@ -68,7 +68,9 @@ class CreateProcess {
68
68
 
69
69
  // Delegate to repository
70
70
  try {
71
- const createdProcess = await this.processRepository.create(processToCreate);
71
+ const createdProcess = await this.processRepository.create(
72
+ processToCreate
73
+ );
72
74
  return createdProcess;
73
75
  } catch (error) {
74
76
  throw new Error(`Failed to create process: ${error.message}`);
@@ -83,11 +85,15 @@ class CreateProcess {
83
85
  */
84
86
  _validateProcessData(processData) {
85
87
  const requiredFields = ['userId', 'integrationId', 'name', 'type'];
86
- const missingFields = requiredFields.filter(field => !processData[field]);
88
+ const missingFields = requiredFields.filter(
89
+ (field) => !processData[field]
90
+ );
87
91
 
88
92
  if (missingFields.length > 0) {
89
93
  throw new Error(
90
- `Missing required fields for process creation: ${missingFields.join(', ')}`
94
+ `Missing required fields for process creation: ${missingFields.join(
95
+ ', '
96
+ )}`
91
97
  );
92
98
  }
93
99
 
@@ -115,14 +121,19 @@ class CreateProcess {
115
121
  if (processData.results && typeof processData.results !== 'object') {
116
122
  throw new Error('results must be an object');
117
123
  }
118
- if (processData.childProcesses && !Array.isArray(processData.childProcesses)) {
124
+ if (
125
+ processData.childProcesses &&
126
+ !Array.isArray(processData.childProcesses)
127
+ ) {
119
128
  throw new Error('childProcesses must be an array');
120
129
  }
121
- if (processData.parentProcessId && typeof processData.parentProcessId !== 'string') {
130
+ if (
131
+ processData.parentProcessId &&
132
+ typeof processData.parentProcessId !== 'string'
133
+ ) {
122
134
  throw new Error('parentProcessId must be a string');
123
135
  }
124
136
  }
125
137
  }
126
138
 
127
139
  module.exports = { CreateProcess };
128
-
@@ -59,10 +59,11 @@ class DeleteIntegrationForUser {
59
59
 
60
60
  for (const entityId of integrationRecord.entitiesIds) {
61
61
  try {
62
- const moduleInstance = await this.moduleFactory.getModuleInstance(
63
- entityId,
64
- integrationRecord.userId
65
- );
62
+ const moduleInstance =
63
+ await this.moduleFactory.getModuleInstance(
64
+ entityId,
65
+ integrationRecord.userId
66
+ );
66
67
  modules.push(moduleInstance);
67
68
  } catch (error) {
68
69
  console.error(