@friggframework/core 2.0.0-next.5 → 2.0.0-next.50

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 (267) hide show
  1. package/CLAUDE.md +693 -0
  2. package/README.md +959 -50
  3. package/application/commands/README.md +421 -0
  4. package/application/commands/credential-commands.js +224 -0
  5. package/application/commands/entity-commands.js +315 -0
  6. package/application/commands/integration-commands.js +179 -0
  7. package/application/commands/user-commands.js +213 -0
  8. package/application/index.js +69 -0
  9. package/core/CLAUDE.md +690 -0
  10. package/core/Worker.js +8 -21
  11. package/core/create-handler.js +2 -7
  12. package/credential/repositories/credential-repository-factory.js +47 -0
  13. package/credential/repositories/credential-repository-interface.js +98 -0
  14. package/credential/repositories/credential-repository-mongo.js +307 -0
  15. package/credential/repositories/credential-repository-postgres.js +313 -0
  16. package/credential/repositories/credential-repository.js +302 -0
  17. package/credential/use-cases/get-credential-for-user.js +21 -0
  18. package/credential/use-cases/update-authentication-status.js +15 -0
  19. package/database/MONGODB_TRANSACTION_FIX.md +198 -0
  20. package/database/adapters/lambda-invoker.js +97 -0
  21. package/database/config.js +154 -0
  22. package/database/encryption/README.md +684 -0
  23. package/database/encryption/encryption-schema-registry.js +141 -0
  24. package/database/encryption/field-encryption-service.js +226 -0
  25. package/database/encryption/logger.js +79 -0
  26. package/database/encryption/prisma-encryption-extension.js +222 -0
  27. package/database/index.js +25 -12
  28. package/database/models/WebsocketConnection.js +16 -10
  29. package/database/models/readme.md +1 -0
  30. package/database/prisma.js +222 -0
  31. package/database/repositories/health-check-repository-factory.js +43 -0
  32. package/database/repositories/health-check-repository-interface.js +87 -0
  33. package/database/repositories/health-check-repository-mongodb.js +91 -0
  34. package/database/repositories/health-check-repository-postgres.js +82 -0
  35. package/database/repositories/health-check-repository.js +108 -0
  36. package/database/repositories/migration-status-repository-s3.js +137 -0
  37. package/database/use-cases/check-database-health-use-case.js +29 -0
  38. package/database/use-cases/check-database-state-use-case.js +81 -0
  39. package/database/use-cases/check-encryption-health-use-case.js +83 -0
  40. package/database/use-cases/get-database-state-via-worker-use-case.js +61 -0
  41. package/database/use-cases/get-migration-status-use-case.js +93 -0
  42. package/database/use-cases/run-database-migration-use-case.js +137 -0
  43. package/database/use-cases/test-encryption-use-case.js +253 -0
  44. package/database/use-cases/trigger-database-migration-use-case.js +157 -0
  45. package/database/utils/mongodb-collection-utils.js +91 -0
  46. package/database/utils/mongodb-schema-init.js +106 -0
  47. package/database/utils/prisma-runner.js +400 -0
  48. package/database/utils/prisma-schema-parser.js +182 -0
  49. package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +517 -0
  50. package/encrypt/Cryptor.js +34 -168
  51. package/encrypt/index.js +1 -2
  52. package/encrypt/test-encrypt.js +0 -2
  53. package/generated/prisma-mongodb/client.d.ts +1 -0
  54. package/generated/prisma-mongodb/client.js +4 -0
  55. package/generated/prisma-mongodb/default.d.ts +1 -0
  56. package/generated/prisma-mongodb/default.js +4 -0
  57. package/generated/prisma-mongodb/edge.d.ts +1 -0
  58. package/generated/prisma-mongodb/edge.js +334 -0
  59. package/generated/prisma-mongodb/index-browser.js +316 -0
  60. package/generated/prisma-mongodb/index.d.ts +22898 -0
  61. package/generated/prisma-mongodb/index.js +359 -0
  62. package/generated/prisma-mongodb/package.json +183 -0
  63. package/generated/prisma-mongodb/query-engine-debian-openssl-3.0.x +0 -0
  64. package/generated/prisma-mongodb/query-engine-rhel-openssl-3.0.x +0 -0
  65. package/generated/prisma-mongodb/runtime/binary.d.ts +1 -0
  66. package/generated/prisma-mongodb/runtime/binary.js +289 -0
  67. package/generated/prisma-mongodb/runtime/edge-esm.js +34 -0
  68. package/generated/prisma-mongodb/runtime/edge.js +34 -0
  69. package/generated/prisma-mongodb/runtime/index-browser.d.ts +370 -0
  70. package/generated/prisma-mongodb/runtime/index-browser.js +16 -0
  71. package/generated/prisma-mongodb/runtime/library.d.ts +3982 -0
  72. package/generated/prisma-mongodb/runtime/react-native.js +83 -0
  73. package/generated/prisma-mongodb/runtime/wasm-compiler-edge.js +84 -0
  74. package/generated/prisma-mongodb/runtime/wasm-engine-edge.js +36 -0
  75. package/generated/prisma-mongodb/schema.prisma +362 -0
  76. package/generated/prisma-mongodb/wasm-edge-light-loader.mjs +4 -0
  77. package/generated/prisma-mongodb/wasm-worker-loader.mjs +4 -0
  78. package/generated/prisma-mongodb/wasm.d.ts +1 -0
  79. package/generated/prisma-mongodb/wasm.js +341 -0
  80. package/generated/prisma-postgresql/client.d.ts +1 -0
  81. package/generated/prisma-postgresql/client.js +4 -0
  82. package/generated/prisma-postgresql/default.d.ts +1 -0
  83. package/generated/prisma-postgresql/default.js +4 -0
  84. package/generated/prisma-postgresql/edge.d.ts +1 -0
  85. package/generated/prisma-postgresql/edge.js +356 -0
  86. package/generated/prisma-postgresql/index-browser.js +338 -0
  87. package/generated/prisma-postgresql/index.d.ts +25072 -0
  88. package/generated/prisma-postgresql/index.js +381 -0
  89. package/generated/prisma-postgresql/package.json +183 -0
  90. package/generated/prisma-postgresql/query-engine-debian-openssl-3.0.x +0 -0
  91. package/generated/prisma-postgresql/query-engine-rhel-openssl-3.0.x +0 -0
  92. package/generated/prisma-postgresql/query_engine_bg.js +2 -0
  93. package/generated/prisma-postgresql/query_engine_bg.wasm +0 -0
  94. package/generated/prisma-postgresql/runtime/binary.d.ts +1 -0
  95. package/generated/prisma-postgresql/runtime/binary.js +289 -0
  96. package/generated/prisma-postgresql/runtime/edge-esm.js +34 -0
  97. package/generated/prisma-postgresql/runtime/edge.js +34 -0
  98. package/generated/prisma-postgresql/runtime/index-browser.d.ts +370 -0
  99. package/generated/prisma-postgresql/runtime/index-browser.js +16 -0
  100. package/generated/prisma-postgresql/runtime/library.d.ts +3982 -0
  101. package/generated/prisma-postgresql/runtime/react-native.js +83 -0
  102. package/generated/prisma-postgresql/runtime/wasm-compiler-edge.js +84 -0
  103. package/generated/prisma-postgresql/runtime/wasm-engine-edge.js +36 -0
  104. package/generated/prisma-postgresql/schema.prisma +345 -0
  105. package/generated/prisma-postgresql/wasm-edge-light-loader.mjs +4 -0
  106. package/generated/prisma-postgresql/wasm-worker-loader.mjs +4 -0
  107. package/generated/prisma-postgresql/wasm.d.ts +1 -0
  108. package/generated/prisma-postgresql/wasm.js +363 -0
  109. package/handlers/WEBHOOKS.md +653 -0
  110. package/handlers/app-definition-loader.js +38 -0
  111. package/handlers/app-handler-helpers.js +56 -0
  112. package/handlers/backend-utils.js +180 -0
  113. package/handlers/database-migration-handler.js +227 -0
  114. package/handlers/integration-event-dispatcher.js +54 -0
  115. package/handlers/routers/HEALTHCHECK.md +342 -0
  116. package/handlers/routers/auth.js +15 -0
  117. package/handlers/routers/db-migration.handler.js +29 -0
  118. package/handlers/routers/db-migration.js +256 -0
  119. package/handlers/routers/health.js +519 -0
  120. package/handlers/routers/integration-defined-routers.js +45 -0
  121. package/handlers/routers/integration-webhook-routers.js +67 -0
  122. package/handlers/routers/user.js +63 -0
  123. package/handlers/routers/websocket.js +57 -0
  124. package/handlers/use-cases/check-external-apis-health-use-case.js +81 -0
  125. package/handlers/use-cases/check-integrations-health-use-case.js +44 -0
  126. package/handlers/workers/db-migration.js +352 -0
  127. package/handlers/workers/integration-defined-workers.js +27 -0
  128. package/index.js +77 -22
  129. package/integrations/WEBHOOK-QUICKSTART.md +151 -0
  130. package/integrations/index.js +12 -10
  131. package/integrations/integration-base.js +296 -54
  132. package/integrations/integration-router.js +381 -182
  133. package/integrations/options.js +1 -1
  134. package/integrations/repositories/integration-mapping-repository-factory.js +50 -0
  135. package/integrations/repositories/integration-mapping-repository-interface.js +106 -0
  136. package/integrations/repositories/integration-mapping-repository-mongo.js +161 -0
  137. package/integrations/repositories/integration-mapping-repository-postgres.js +227 -0
  138. package/integrations/repositories/integration-mapping-repository.js +156 -0
  139. package/integrations/repositories/integration-repository-factory.js +44 -0
  140. package/integrations/repositories/integration-repository-interface.js +127 -0
  141. package/integrations/repositories/integration-repository-mongo.js +303 -0
  142. package/integrations/repositories/integration-repository-postgres.js +352 -0
  143. package/integrations/repositories/process-repository-factory.js +46 -0
  144. package/integrations/repositories/process-repository-interface.js +90 -0
  145. package/integrations/repositories/process-repository-mongo.js +190 -0
  146. package/integrations/repositories/process-repository-postgres.js +217 -0
  147. package/integrations/tests/doubles/dummy-integration-class.js +83 -0
  148. package/integrations/tests/doubles/test-integration-repository.js +99 -0
  149. package/integrations/use-cases/create-integration.js +83 -0
  150. package/integrations/use-cases/create-process.js +128 -0
  151. package/integrations/use-cases/delete-integration-for-user.js +101 -0
  152. package/integrations/use-cases/find-integration-context-by-external-entity-id.js +72 -0
  153. package/integrations/use-cases/get-integration-for-user.js +78 -0
  154. package/integrations/use-cases/get-integration-instance-by-definition.js +67 -0
  155. package/integrations/use-cases/get-integration-instance.js +83 -0
  156. package/integrations/use-cases/get-integrations-for-user.js +87 -0
  157. package/integrations/use-cases/get-possible-integrations.js +27 -0
  158. package/integrations/use-cases/get-process.js +87 -0
  159. package/integrations/use-cases/index.js +19 -0
  160. package/integrations/use-cases/load-integration-context.js +71 -0
  161. package/integrations/use-cases/update-integration-messages.js +44 -0
  162. package/integrations/use-cases/update-integration-status.js +32 -0
  163. package/integrations/use-cases/update-integration.js +93 -0
  164. package/integrations/use-cases/update-process-metrics.js +201 -0
  165. package/integrations/use-cases/update-process-state.js +119 -0
  166. package/integrations/utils/map-integration-dto.js +36 -0
  167. package/jest-global-setup-noop.js +3 -0
  168. package/jest-global-teardown-noop.js +3 -0
  169. package/logs/logger.js +0 -4
  170. package/{module-plugin → modules}/entity.js +1 -1
  171. package/{module-plugin → modules}/index.js +0 -8
  172. package/modules/module-factory.js +56 -0
  173. package/modules/module.js +221 -0
  174. package/modules/repositories/module-repository-factory.js +33 -0
  175. package/modules/repositories/module-repository-interface.js +129 -0
  176. package/modules/repositories/module-repository-mongo.js +377 -0
  177. package/modules/repositories/module-repository-postgres.js +426 -0
  178. package/modules/repositories/module-repository.js +316 -0
  179. package/{module-plugin → modules}/requester/requester.js +1 -0
  180. package/{module-plugin → modules}/test/mock-api/api.js +8 -3
  181. package/{module-plugin → modules}/test/mock-api/definition.js +12 -8
  182. package/modules/tests/doubles/test-module-factory.js +16 -0
  183. package/modules/tests/doubles/test-module-repository.js +39 -0
  184. package/modules/use-cases/get-entities-for-user.js +32 -0
  185. package/modules/use-cases/get-entity-options-by-id.js +59 -0
  186. package/modules/use-cases/get-entity-options-by-type.js +34 -0
  187. package/modules/use-cases/get-module-instance-from-type.js +31 -0
  188. package/modules/use-cases/get-module.js +55 -0
  189. package/modules/use-cases/process-authorization-callback.js +122 -0
  190. package/modules/use-cases/refresh-entity-options.js +59 -0
  191. package/modules/use-cases/test-module-auth.js +55 -0
  192. package/modules/utils/map-module-dto.js +18 -0
  193. package/package.json +82 -50
  194. package/prisma-mongodb/schema.prisma +362 -0
  195. package/prisma-postgresql/migrations/20250930193005_init/migration.sql +315 -0
  196. package/prisma-postgresql/migrations/20251006135218_init/migration.sql +9 -0
  197. package/prisma-postgresql/migrations/20251010000000_remove_unused_entity_reference_map/migration.sql +3 -0
  198. package/prisma-postgresql/migrations/migration_lock.toml +3 -0
  199. package/prisma-postgresql/schema.prisma +345 -0
  200. package/queues/queuer-util.js +28 -15
  201. package/syncs/manager.js +468 -443
  202. package/syncs/repositories/sync-repository-factory.js +38 -0
  203. package/syncs/repositories/sync-repository-interface.js +109 -0
  204. package/syncs/repositories/sync-repository-mongo.js +239 -0
  205. package/syncs/repositories/sync-repository-postgres.js +319 -0
  206. package/syncs/sync.js +0 -1
  207. package/token/repositories/token-repository-factory.js +33 -0
  208. package/token/repositories/token-repository-interface.js +131 -0
  209. package/token/repositories/token-repository-mongo.js +212 -0
  210. package/token/repositories/token-repository-postgres.js +257 -0
  211. package/token/repositories/token-repository.js +219 -0
  212. package/types/core/index.d.ts +2 -2
  213. package/types/integrations/index.d.ts +2 -6
  214. package/types/module-plugin/index.d.ts +5 -59
  215. package/types/syncs/index.d.ts +0 -2
  216. package/user/repositories/user-repository-factory.js +46 -0
  217. package/user/repositories/user-repository-interface.js +198 -0
  218. package/user/repositories/user-repository-mongo.js +291 -0
  219. package/user/repositories/user-repository-postgres.js +350 -0
  220. package/user/tests/doubles/test-user-repository.js +72 -0
  221. package/user/use-cases/authenticate-user.js +127 -0
  222. package/user/use-cases/authenticate-with-shared-secret.js +48 -0
  223. package/user/use-cases/create-individual-user.js +61 -0
  224. package/user/use-cases/create-organization-user.js +47 -0
  225. package/user/use-cases/create-token-for-user-id.js +30 -0
  226. package/user/use-cases/get-user-from-adopter-jwt.js +149 -0
  227. package/user/use-cases/get-user-from-bearer-token.js +77 -0
  228. package/user/use-cases/get-user-from-x-frigg-headers.js +106 -0
  229. package/user/use-cases/login-user.js +122 -0
  230. package/user/user.js +93 -0
  231. package/utils/backend-path.js +38 -0
  232. package/utils/index.js +6 -0
  233. package/websocket/repositories/websocket-connection-repository-factory.js +37 -0
  234. package/websocket/repositories/websocket-connection-repository-interface.js +106 -0
  235. package/websocket/repositories/websocket-connection-repository-mongo.js +156 -0
  236. package/websocket/repositories/websocket-connection-repository-postgres.js +196 -0
  237. package/websocket/repositories/websocket-connection-repository.js +161 -0
  238. package/database/models/State.js +0 -9
  239. package/database/models/Token.js +0 -70
  240. package/database/mongo.js +0 -45
  241. package/encrypt/Cryptor.test.js +0 -32
  242. package/encrypt/encrypt.js +0 -132
  243. package/encrypt/encrypt.test.js +0 -1069
  244. package/errors/base-error.test.js +0 -32
  245. package/errors/fetch-error.test.js +0 -79
  246. package/errors/halt-error.test.js +0 -11
  247. package/errors/validation-errors.test.js +0 -120
  248. package/integrations/create-frigg-backend.js +0 -31
  249. package/integrations/integration-factory.js +0 -251
  250. package/integrations/integration-mapping.js +0 -43
  251. package/integrations/integration-model.js +0 -46
  252. package/integrations/integration-user.js +0 -144
  253. package/integrations/test/integration-base.test.js +0 -144
  254. package/lambda/TimeoutCatcher.test.js +0 -68
  255. package/logs/logger.test.js +0 -76
  256. package/module-plugin/auther.js +0 -393
  257. package/module-plugin/credential.js +0 -22
  258. package/module-plugin/entity-manager.js +0 -70
  259. package/module-plugin/manager.js +0 -169
  260. package/module-plugin/module-factory.js +0 -61
  261. package/module-plugin/requester/requester.test.js +0 -28
  262. package/module-plugin/test/auther.test.js +0 -97
  263. /package/{module-plugin → modules}/ModuleConstants.js +0 -0
  264. /package/{module-plugin → modules}/requester/api-key.js +0 -0
  265. /package/{module-plugin → modules}/requester/basic.js +0 -0
  266. /package/{module-plugin → modules}/requester/oauth-2.js +0 -0
  267. /package/{module-plugin → modules}/test/mock-api/mocks/hubspot.js +0 -0
@@ -2,23 +2,221 @@ const express = require('express');
2
2
  const { get } = require('../assertions');
3
3
  const Boom = require('@hapi/boom');
4
4
  const catchAsyncError = require('express-async-handler');
5
- const { debug } = require('../logs');
6
- function createIntegrationRouter(params) {
7
- const router = get(params, 'router', express());
8
- const factory = get(params, 'factory');
9
- const getUserId = get(params, 'getUserId', (req) => null);
10
- const requireLoggedInUser = get(
11
- params,
12
- 'requireLoggedInUser',
13
- (req, res, next) => next()
14
- );
15
-
16
- router.all('/api/entities*', requireLoggedInUser);
17
- router.all('/api/authorize', requireLoggedInUser);
18
- router.all('/api/integrations*', requireLoggedInUser);
19
-
20
- setIntegrationRoutes(router, factory, getUserId);
21
- setEntityRoutes(router, factory, getUserId);
5
+ const {
6
+ createIntegrationRepository,
7
+ } = require('./repositories/integration-repository-factory');
8
+ const {
9
+ DeleteIntegrationForUser,
10
+ } = require('./use-cases/delete-integration-for-user');
11
+ const {
12
+ GetIntegrationsForUser,
13
+ } = require('./use-cases/get-integrations-for-user');
14
+ const {
15
+ createCredentialRepository,
16
+ } = require('../credential/repositories/credential-repository-factory');
17
+ const {
18
+ GetCredentialForUser,
19
+ } = require('../credential/use-cases/get-credential-for-user');
20
+ const { CreateIntegration } = require('./use-cases/create-integration');
21
+ const { ModuleFactory } = require('../modules/module-factory');
22
+ const {
23
+ createModuleRepository,
24
+ } = require('../modules/repositories/module-repository-factory');
25
+ const {
26
+ GetEntitiesForUser,
27
+ } = require('../modules/use-cases/get-entities-for-user');
28
+ const { loadAppDefinition } = require('../handlers/app-definition-loader');
29
+ const {
30
+ GetIntegrationInstance,
31
+ } = require('./use-cases/get-integration-instance');
32
+ const { UpdateIntegration } = require('./use-cases/update-integration');
33
+ const {
34
+ getModulesDefinitionFromIntegrationClasses,
35
+ } = require('./utils/map-integration-dto');
36
+ const {
37
+ GetModuleInstanceFromType,
38
+ } = require('../modules/use-cases/get-module-instance-from-type');
39
+ const {
40
+ GetEntityOptionsByType,
41
+ } = require('../modules/use-cases/get-entity-options-by-type');
42
+ const { TestModuleAuth } = require('../modules/use-cases/test-module-auth');
43
+ const { GetModule } = require('../modules/use-cases/get-module');
44
+ const {
45
+ GetEntityOptionsById,
46
+ } = require('../modules/use-cases/get-entity-options-by-id');
47
+ const {
48
+ RefreshEntityOptions,
49
+ } = require('../modules/use-cases/refresh-entity-options');
50
+ const {
51
+ GetPossibleIntegrations,
52
+ } = require('./use-cases/get-possible-integrations');
53
+ const {
54
+ createUserRepository,
55
+ } = require('../user/repositories/user-repository-factory');
56
+ const {
57
+ GetUserFromBearerToken,
58
+ } = require('../user/use-cases/get-user-from-bearer-token');
59
+ const {
60
+ GetUserFromXFriggHeaders,
61
+ } = require('../user/use-cases/get-user-from-x-frigg-headers');
62
+ const {
63
+ GetUserFromAdopterJwt,
64
+ } = require('../user/use-cases/get-user-from-adopter-jwt');
65
+ const {
66
+ AuthenticateWithSharedSecret,
67
+ } = require('../user/use-cases/authenticate-with-shared-secret');
68
+ const {
69
+ AuthenticateUser,
70
+ } = require('../user/use-cases/authenticate-user');
71
+ const {
72
+ ProcessAuthorizationCallback,
73
+ } = require('../modules/use-cases/process-authorization-callback');
74
+
75
+ function createIntegrationRouter() {
76
+ const { integrations: integrationClasses, userConfig } =
77
+ loadAppDefinition();
78
+ const moduleRepository = createModuleRepository();
79
+ const integrationRepository = createIntegrationRepository();
80
+ const credentialRepository = createCredentialRepository();
81
+ const userRepository = createUserRepository();
82
+
83
+ const getUserFromBearerToken = new GetUserFromBearerToken({
84
+ userRepository,
85
+ userConfig,
86
+ });
87
+
88
+ const getUserFromXFriggHeaders = new GetUserFromXFriggHeaders({
89
+ userRepository,
90
+ userConfig,
91
+ });
92
+
93
+ const getUserFromAdopterJwt = new GetUserFromAdopterJwt({
94
+ userRepository,
95
+ userConfig,
96
+ });
97
+
98
+ const authenticateWithSharedSecret = new AuthenticateWithSharedSecret();
99
+
100
+ const authenticateUser = new AuthenticateUser({
101
+ getUserFromBearerToken,
102
+ getUserFromXFriggHeaders,
103
+ getUserFromAdopterJwt,
104
+ authenticateWithSharedSecret,
105
+ userConfig,
106
+ });
107
+
108
+ const moduleFactory = new ModuleFactory({
109
+ moduleRepository,
110
+ moduleDefinitions:
111
+ getModulesDefinitionFromIntegrationClasses(integrationClasses),
112
+ });
113
+ const deleteIntegrationForUser = new DeleteIntegrationForUser({
114
+ integrationRepository,
115
+ integrationClasses,
116
+ moduleFactory,
117
+ });
118
+
119
+ const getIntegrationsForUser = new GetIntegrationsForUser({
120
+ integrationRepository,
121
+ integrationClasses,
122
+ moduleFactory,
123
+ moduleRepository,
124
+ });
125
+
126
+ const getCredentialForUser = new GetCredentialForUser({
127
+ credentialRepository,
128
+ });
129
+
130
+ const createIntegration = new CreateIntegration({
131
+ integrationRepository,
132
+ integrationClasses,
133
+ moduleFactory,
134
+ });
135
+
136
+ const getEntitiesForUser = new GetEntitiesForUser({
137
+ moduleRepository,
138
+ moduleDefinitions:
139
+ getModulesDefinitionFromIntegrationClasses(integrationClasses),
140
+ });
141
+
142
+ const getIntegrationInstance = new GetIntegrationInstance({
143
+ integrationRepository,
144
+ integrationClasses,
145
+ moduleFactory,
146
+ });
147
+
148
+ const updateIntegration = new UpdateIntegration({
149
+ integrationRepository,
150
+ integrationClasses,
151
+ moduleFactory,
152
+ });
153
+
154
+ const getModuleInstanceFromType = new GetModuleInstanceFromType({
155
+ moduleDefinitions:
156
+ getModulesDefinitionFromIntegrationClasses(integrationClasses),
157
+ });
158
+
159
+ const getEntityOptionsByType = new GetEntityOptionsByType({
160
+ moduleDefinitions:
161
+ getModulesDefinitionFromIntegrationClasses(integrationClasses),
162
+ });
163
+
164
+ const testModuleAuth = new TestModuleAuth({
165
+ moduleRepository,
166
+ moduleDefinitions:
167
+ getModulesDefinitionFromIntegrationClasses(integrationClasses),
168
+ });
169
+
170
+ const getModule = new GetModule({
171
+ moduleRepository,
172
+ moduleDefinitions:
173
+ getModulesDefinitionFromIntegrationClasses(integrationClasses),
174
+ });
175
+
176
+ const getEntityOptionsById = new GetEntityOptionsById({
177
+ moduleRepository,
178
+ moduleDefinitions:
179
+ getModulesDefinitionFromIntegrationClasses(integrationClasses),
180
+ });
181
+
182
+ const refreshEntityOptions = new RefreshEntityOptions({
183
+ moduleRepository,
184
+ moduleDefinitions:
185
+ getModulesDefinitionFromIntegrationClasses(integrationClasses),
186
+ });
187
+
188
+ const getPossibleIntegrations = new GetPossibleIntegrations({
189
+ integrationClasses,
190
+ });
191
+
192
+ const processAuthorizationCallback = new ProcessAuthorizationCallback({
193
+ moduleRepository,
194
+ credentialRepository,
195
+ moduleDefinitions:
196
+ getModulesDefinitionFromIntegrationClasses(integrationClasses),
197
+ });
198
+
199
+ const router = express();
200
+
201
+ setIntegrationRoutes(router, authenticateUser, {
202
+ createIntegration,
203
+ deleteIntegrationForUser,
204
+ getIntegrationsForUser,
205
+ getEntitiesForUser,
206
+ getIntegrationInstance,
207
+ updateIntegration,
208
+ getPossibleIntegrations,
209
+ });
210
+ setEntityRoutes(router, authenticateUser, {
211
+ getCredentialForUser,
212
+ getModuleInstanceFromType,
213
+ getEntityOptionsByType,
214
+ testModuleAuth,
215
+ getModule,
216
+ getEntityOptionsById,
217
+ refreshEntityOptions,
218
+ processAuthorizationCallback,
219
+ });
22
220
  return router;
23
221
  }
24
222
 
@@ -36,121 +234,103 @@ function checkRequiredParams(params, requiredKeys) {
36
234
 
37
235
  if (missingKeys.length > 0) {
38
236
  throw Boom.badRequest(
39
- `Missing Parameter${
40
- missingKeys.length === 1 ? '' : 's'
41
- }: ${missingKeys.join(', ')} ${
42
- missingKeys.length === 1 ? 'is' : 'are'
237
+ `Missing Parameter${missingKeys.length === 1 ? '' : 's'
238
+ }: ${missingKeys.join(', ')} ${missingKeys.length === 1 ? 'is' : 'are'
43
239
  } required.`
44
240
  );
45
241
  }
46
242
  return returnDict;
47
243
  }
48
244
 
49
- function setIntegrationRoutes(router, factory, getUserId) {
50
- const { moduleFactory, integrationFactory, IntegrationHelper } = factory;
245
+ /**
246
+ * Sets up integration-related routes on the provided Express router
247
+ * @param {express.Router} router - Express router instance to add routes to
248
+ * @param {import('../user/use-cases/authenticate-user').AuthenticateUser} authenticateUser - Use case for multi-mode user authentication
249
+ * @param {Object} useCases - use cases for integration management
250
+ */
251
+ function setIntegrationRoutes(router, authenticateUser, useCases) {
252
+ const {
253
+ createIntegration,
254
+ deleteIntegrationForUser,
255
+ getIntegrationsForUser,
256
+ getEntitiesForUser,
257
+ getIntegrationInstance,
258
+ updateIntegration,
259
+ getPossibleIntegrations,
260
+ } = useCases;
51
261
  router.route('/api/integrations').get(
52
262
  catchAsyncError(async (req, res) => {
53
- const results = await integrationFactory.getIntegrationOptions();
54
- results.entities.authorized =
55
- await moduleFactory.getEntitiesForUser(getUserId(req));
56
- results.integrations =
57
- await IntegrationHelper.getIntegrationsForUserId(
58
- getUserId(req)
59
- );
263
+ const user = await authenticateUser.execute(req);
264
+ const userId = user.getId();
265
+ const integrations = await getIntegrationsForUser.execute(userId);
266
+ const results = {
267
+ entities: {
268
+ options: await getPossibleIntegrations.execute(),
269
+ authorized: await getEntitiesForUser.execute(userId),
270
+ },
271
+ integrations: integrations,
272
+ };
60
273
 
61
- for (const integrationRecord of results.integrations) {
62
- const integration =
63
- await integrationFactory.getInstanceFromIntegrationId({
64
- integrationId: integrationRecord.id,
65
- userId: getUserId(req),
66
- });
67
- integrationRecord.userActions = integration.userActions;
68
- }
69
274
  res.json(results);
70
275
  })
71
276
  );
72
277
 
73
278
  router.route('/api/integrations').post(
74
279
  catchAsyncError(async (req, res) => {
280
+ const user = await authenticateUser.execute(req);
281
+ const userId = user.getId();
75
282
  const params = checkRequiredParams(req.body, [
76
283
  'entities',
77
284
  'config',
78
285
  ]);
79
- // throw if not value
286
+
80
287
  get(params.config, 'type');
81
288
 
82
- // create integration
83
- const integration = await integrationFactory.createIntegration(
289
+ const integration = await createIntegration.execute(
84
290
  params.entities,
85
- getUserId(req),
291
+ userId,
86
292
  params.config
87
293
  );
88
294
 
89
- // post integration initialization
90
- debug(
91
- `Calling onCreate on the ${integration?.constructor?.Config?.name} Integration with no arguments`
92
- );
93
- await integration.send('ON_CREATE', {});
94
-
95
- res.status(201).json(
96
- await IntegrationHelper.getFormattedIntegration(
97
- integration.record
98
- )
99
- );
295
+ res.status(201).json(integration);
100
296
  })
101
297
  );
102
298
 
103
299
  router.route('/api/integrations/:integrationId').patch(
104
300
  catchAsyncError(async (req, res) => {
301
+ const user = await authenticateUser.execute(req);
302
+ const userId = user.getId();
105
303
  const params = checkRequiredParams(req.body, ['config']);
106
304
 
107
- const integration =
108
- await integrationFactory.getInstanceFromIntegrationId({
109
- integrationId: req.params.integrationId,
110
- userId: getUserId(req),
111
- });
112
-
113
- debug(
114
- `Calling onUpdate on the ${integration?.constructor?.Config?.name} Integration arguments: `,
115
- params
116
- );
117
- await integration.send('ON_UPDATE', params);
118
-
119
- res.json(
120
- await IntegrationHelper.getFormattedIntegration(
121
- integration.record
122
- )
305
+ const integration = await updateIntegration.execute(
306
+ req.params.integrationId,
307
+ userId,
308
+ params.config
123
309
  );
310
+ res.json(integration);
124
311
  })
125
312
  );
126
313
 
127
314
  router.route('/api/integrations/:integrationId').delete(
128
315
  catchAsyncError(async (req, res) => {
316
+ const user = await authenticateUser.execute(req);
129
317
  const params = checkRequiredParams(req.params, ['integrationId']);
130
- const integration =
131
- await integrationFactory.getInstanceFromIntegrationId({
132
- userId: getUserId(req),
133
- integrationId: params.integrationId,
134
- });
135
-
136
- debug(
137
- `Calling onUpdate on the ${integration?.constructor?.Definition?.name} Integration with no arguments`
138
- );
139
- await integration.send('ON_DELETE');
140
- await IntegrationHelper.deleteIntegrationForUserById(
141
- getUserId(req),
142
- params.integrationId
318
+ await deleteIntegrationForUser.execute(
319
+ params.integrationId,
320
+ user.getId()
143
321
  );
144
-
145
- res.status(201).json({});
322
+ res.status(204).json({});
146
323
  })
147
324
  );
148
325
 
149
326
  router.route('/api/integrations/:integrationId/config/options').get(
150
327
  catchAsyncError(async (req, res) => {
328
+ const user = await authenticateUser.execute(req);
151
329
  const params = checkRequiredParams(req.params, ['integrationId']);
152
- const integration =
153
- await integrationFactory.getInstanceFromIntegrationId(params);
330
+ const integration = await getIntegrationInstance.execute(
331
+ params.integrationId,
332
+ user.getId()
333
+ );
154
334
  res.json(await integration.send('GET_CONFIG_OPTIONS'));
155
335
  })
156
336
  );
@@ -159,13 +339,14 @@ function setIntegrationRoutes(router, factory, getUserId) {
159
339
  .route('/api/integrations/:integrationId/config/options/refresh')
160
340
  .post(
161
341
  catchAsyncError(async (req, res) => {
342
+ const user = await authenticateUser.execute(req);
162
343
  const params = checkRequiredParams(req.params, [
163
344
  'integrationId',
164
345
  ]);
165
- const integration =
166
- await integrationFactory.getInstanceFromIntegrationId(
167
- params
168
- );
346
+ const integration = await getIntegrationInstance.execute(
347
+ params.integrationId,
348
+ user.getId()
349
+ );
169
350
 
170
351
  res.json(
171
352
  await integration.send('REFRESH_CONFIG_OPTIONS', req.body)
@@ -174,9 +355,12 @@ function setIntegrationRoutes(router, factory, getUserId) {
174
355
  );
175
356
  router.route('/api/integrations/:integrationId/actions').all(
176
357
  catchAsyncError(async (req, res) => {
358
+ const user = await authenticateUser.execute(req);
177
359
  const params = checkRequiredParams(req.params, ['integrationId']);
178
- const integration =
179
- await integrationFactory.getInstanceFromIntegrationId(params);
360
+ const integration = await getIntegrationInstance.execute(
361
+ params.integrationId,
362
+ user.getId()
363
+ );
180
364
  res.json(await integration.send('GET_USER_ACTIONS', req.body));
181
365
  })
182
366
  );
@@ -185,14 +369,15 @@ function setIntegrationRoutes(router, factory, getUserId) {
185
369
  .route('/api/integrations/:integrationId/actions/:actionId/options')
186
370
  .all(
187
371
  catchAsyncError(async (req, res) => {
372
+ const user = await authenticateUser.execute(req);
188
373
  const params = checkRequiredParams(req.params, [
189
374
  'integrationId',
190
375
  'actionId',
191
376
  ]);
192
- const integration =
193
- await integrationFactory.getInstanceFromIntegrationId(
194
- params
195
- );
377
+ const integration = await getIntegrationInstance.execute(
378
+ params.integrationId,
379
+ user.getId()
380
+ );
196
381
 
197
382
  res.json(
198
383
  await integration.send('GET_USER_ACTION_OPTIONS', {
@@ -209,14 +394,15 @@ function setIntegrationRoutes(router, factory, getUserId) {
209
394
  )
210
395
  .post(
211
396
  catchAsyncError(async (req, res) => {
397
+ const user = await authenticateUser.execute(req);
212
398
  const params = checkRequiredParams(req.params, [
213
399
  'integrationId',
214
400
  'actionId',
215
401
  ]);
216
- const integration =
217
- await integrationFactory.getInstanceFromIntegrationId(
218
- params
219
- );
402
+ const integration = await getIntegrationInstance.execute(
403
+ params.integrationId,
404
+ user.getId()
405
+ );
220
406
 
221
407
  res.json(
222
408
  await integration.send('REFRESH_USER_ACTION_OPTIONS', {
@@ -229,23 +415,33 @@ function setIntegrationRoutes(router, factory, getUserId) {
229
415
 
230
416
  router.route('/api/integrations/:integrationId/actions/:actionId').post(
231
417
  catchAsyncError(async (req, res) => {
418
+ const user = await authenticateUser.execute(req);
232
419
  const params = checkRequiredParams(req.params, [
233
420
  'integrationId',
234
421
  'actionId',
235
422
  ]);
236
- const integration =
237
- await integrationFactory.getInstanceFromIntegrationId(params);
238
-
423
+ const integration = await getIntegrationInstance.execute(
424
+ params.integrationId,
425
+ user.getId()
426
+ );
239
427
  res.json(await integration.send(params.actionId, req.body));
240
428
  })
241
429
  );
242
430
 
243
431
  router.route('/api/integrations/:integrationId').get(
244
432
  catchAsyncError(async (req, res) => {
433
+ const user = await authenticateUser.execute(req);
434
+
435
+ if (!user) {
436
+ throw Boom.forbidden('User not found');
437
+ }
438
+
245
439
  const params = checkRequiredParams(req.params, ['integrationId']);
246
- const integration = await IntegrationHelper.getIntegrationById(
247
- params.integrationId
440
+ const integration = await getIntegrationInstance.execute(
441
+ params.integrationId,
442
+ user.getId()
248
443
  );
444
+
249
445
  // We could perhaps augment router with dynamic options? Haven't decided yet, but here may be the place
250
446
 
251
447
  res.json({
@@ -259,12 +455,12 @@ function setIntegrationRoutes(router, factory, getUserId) {
259
455
 
260
456
  router.route('/api/integrations/:integrationId/test-auth').get(
261
457
  catchAsyncError(async (req, res) => {
458
+ const user = await authenticateUser.execute(req);
262
459
  const params = checkRequiredParams(req.params, ['integrationId']);
263
- const instance =
264
- await integrationFactory.getInstanceFromIntegrationId({
265
- userId: getUserId(req),
266
- integrationId: params.integrationId,
267
- });
460
+ const instance = await getIntegrationInstance.execute(
461
+ params.integrationId,
462
+ user.getId()
463
+ );
268
464
 
269
465
  if (!instance) {
270
466
  throw Boom.notFound();
@@ -286,57 +482,67 @@ function setIntegrationRoutes(router, factory, getUserId) {
286
482
  );
287
483
  }
288
484
 
289
- function setEntityRoutes(router, factory, getUserId) {
290
- const { moduleFactory, IntegrationHelper } = factory;
291
- const getModuleInstance = async (req, entityType) => {
292
- if (!moduleFactory.checkIsValidType(entityType)) {
293
- throw Boom.badRequest(
294
- `Error: Invalid entity type of ${entityType}, options are ${moduleFactory.moduleTypes.join(
295
- ', '
296
- )}`
297
- );
298
- }
299
- return await moduleFactory.getInstanceFromTypeName(
300
- entityType,
301
- getUserId(req)
302
- );
303
- };
485
+ /**
486
+ * Sets up entity-related routes for the integration router
487
+ * @param {Object} router - Express router instance
488
+ * @param {import('../user/use-cases/authenticate-user').AuthenticateUser} authenticateUser - Use case for multi-mode user authentication
489
+ */
490
+ function setEntityRoutes(router, authenticateUser, useCases) {
491
+ const {
492
+ getCredentialForUser,
493
+ getModuleInstanceFromType,
494
+ getEntityOptionsByType,
495
+ testModuleAuth,
496
+ getModule,
497
+ getEntityOptionsById,
498
+ refreshEntityOptions,
499
+ processAuthorizationCallback,
500
+ } = useCases;
304
501
 
305
502
  router.route('/api/authorize').get(
306
503
  catchAsyncError(async (req, res) => {
504
+ const user = await authenticateUser.execute(req);
505
+ const userId = user.getId();
307
506
  const params = checkRequiredParams(req.query, ['entityType']);
308
- const module = await getModuleInstance(req, params.entityType);
507
+ const module = await getModuleInstanceFromType.execute(
508
+ userId,
509
+ params.entityType
510
+ );
309
511
  const areRequirementsValid =
310
512
  module.validateAuthorizationRequirements();
311
513
  if (!areRequirementsValid) {
312
514
  throw new Error(
313
- `Error: EntityManager of type ${params.entityType} requires a valid url`
515
+ `Error: Entity of type ${params.entityType} requires a valid url`
314
516
  );
315
517
  }
316
518
 
317
- res.json(await module.getAuthorizationRequirements());
519
+ res.json(module.getAuthorizationRequirements());
318
520
  })
319
521
  );
320
522
 
321
523
  router.route('/api/authorize').post(
322
524
  catchAsyncError(async (req, res) => {
525
+ const user = await authenticateUser.execute(req);
526
+ const userId = user.getId();
323
527
  const params = checkRequiredParams(req.body, [
324
528
  'entityType',
325
529
  'data',
326
530
  ]);
327
- const module = await getModuleInstance(req, params.entityType);
328
531
 
329
- res.json(
330
- await module.processAuthorizationCallback({
331
- userId: getUserId(req),
332
- data: params.data,
333
- })
532
+ const entityDetails = await processAuthorizationCallback.execute(
533
+ userId,
534
+ params.entityType,
535
+ params.data
334
536
  );
537
+
538
+ res.json(entityDetails);
335
539
  })
336
540
  );
337
541
 
338
542
  router.route('/api/entity').post(
339
543
  catchAsyncError(async (req, res) => {
544
+ const user = await authenticateUser.execute(req);
545
+ const userId = user.getId();
340
546
  const params = checkRequiredParams(req.body, [
341
547
  'entityType',
342
548
  'data',
@@ -344,20 +550,24 @@ function setEntityRoutes(router, factory, getUserId) {
344
550
  checkRequiredParams(req.body.data, ['credential_id']);
345
551
 
346
552
  // May want to pass along the user ID as well so credential ID's can't be fished???
347
- const credential = await IntegrationHelper.getCredentialById(
348
- params.data.credential_id
553
+ const credential = await getCredentialForUser.execute(
554
+ params.data.credential_id,
555
+ userId
349
556
  );
350
557
 
351
558
  if (!credential) {
352
559
  throw Boom.badRequest('Invalid credential ID');
353
560
  }
354
561
 
355
- const module = await getModuleInstance(req, params.entityType);
562
+ const module = await getModuleInstanceFromType.execute(
563
+ userId,
564
+ params.entityType
565
+ );
356
566
  const entityDetails = await module.getEntityDetails(
357
567
  module.api,
358
568
  null,
359
569
  null,
360
- getUserId(req)
570
+ userId
361
571
  );
362
572
 
363
573
  res.json(await module.findOrCreateEntity(entityDetails));
@@ -366,36 +576,38 @@ function setEntityRoutes(router, factory, getUserId) {
366
576
 
367
577
  router.route('/api/entity/options/:credentialId').get(
368
578
  catchAsyncError(async (req, res) => {
579
+ const user = await authenticateUser.execute(req);
580
+ const userId = user.getId();
369
581
  // TODO May want to pass along the user ID as well so credential ID's can't be fished???
370
582
  // TODO **flagging this for review** -MW
371
- const credential = await IntegrationHelper.getCredentialById(
372
- req.params.credentialId
583
+ const credential = await getCredentialForUser.execute(
584
+ req.params.credentialId,
585
+ userId
373
586
  );
374
- if (credential.user._id.toString() !== getUserId(req)) {
587
+ if (credential.user._id.toString() !== userId) {
375
588
  throw Boom.forbidden('Credential does not belong to user');
376
589
  }
377
590
 
378
591
  const params = checkRequiredParams(req.query, ['entityType']);
379
- const module = await getModuleInstance(req, params.entityType);
592
+ const entityOptions = await getEntityOptionsByType.execute(
593
+ userId,
594
+ params.entityType
595
+ );
380
596
 
381
- res.json(await module.getEntityOptions());
597
+ res.json(entityOptions);
382
598
  })
383
599
  );
384
600
 
385
601
  router.route('/api/entities/:entityId/test-auth').get(
386
602
  catchAsyncError(async (req, res) => {
603
+ const user = await authenticateUser.execute(req);
604
+ const userId = user.getId();
387
605
  const params = checkRequiredParams(req.params, ['entityId']);
388
- const module = await moduleFactory.getModuleInstanceFromEntityId(
606
+ const testAuthResponse = await testModuleAuth.execute(
389
607
  params.entityId,
390
- getUserId(req)
608
+ userId
391
609
  );
392
610
 
393
- if (!module) {
394
- throw Boom.notFound();
395
- }
396
-
397
- const testAuthResponse = await module.testAuth();
398
-
399
611
  if (!testAuthResponse) {
400
612
  res.status(400);
401
613
  res.json({
@@ -415,55 +627,42 @@ function setEntityRoutes(router, factory, getUserId) {
415
627
 
416
628
  router.route('/api/entities/:entityId').get(
417
629
  catchAsyncError(async (req, res) => {
630
+ const user = await authenticateUser.execute(req);
631
+ const userId = user.getId();
418
632
  const params = checkRequiredParams(req.params, ['entityId']);
419
- const module = await moduleFactory.getModuleInstanceFromEntityId(
420
- params.entityId,
421
- getUserId(req)
422
- );
423
-
424
- if (!module) {
425
- throw Boom.notFound();
426
- }
633
+ const module = await getModule.execute(params.entityId, userId);
427
634
 
428
- res.json(module.entity);
635
+ res.json(module);
429
636
  })
430
637
  );
431
638
 
432
639
  router.route('/api/entities/:entityId/options').post(
433
640
  catchAsyncError(async (req, res) => {
434
- const params = checkRequiredParams(req.params, [
435
- 'entityId',
436
- getUserId(req),
437
- ]);
438
- const module = await moduleFactory.getModuleInstanceFromEntityId(
641
+ const user = await authenticateUser.execute(req);
642
+ const userId = user.getId();
643
+ const params = checkRequiredParams(req.params, ['entityId']);
644
+
645
+ const entityOptions = await getEntityOptionsById.execute(
439
646
  params.entityId,
440
- getUserId(req)
647
+ userId
441
648
  );
442
649
 
443
- if (!module) {
444
- throw Boom.notFound();
445
- }
446
-
447
- res.json(await module.getEntityOptions());
650
+ res.json(entityOptions);
448
651
  })
449
652
  );
450
653
 
451
654
  router.route('/api/entities/:entityId/options/refresh').post(
452
655
  catchAsyncError(async (req, res) => {
453
- const params = checkRequiredParams(req.params, [
454
- 'entityId',
455
- getUserId(req),
456
- ]);
457
- const module = await moduleFactory.getModuleInstanceFromEntityId(
656
+ const user = await authenticateUser.execute(req);
657
+ const userId = user.getId();
658
+ const params = checkRequiredParams(req.params, ['entityId']);
659
+ const updatedOptions = await refreshEntityOptions.execute(
458
660
  params.entityId,
459
- getUserId(req)
661
+ userId,
662
+ req.body
460
663
  );
461
664
 
462
- if (!module) {
463
- throw Boom.notFound();
464
- }
465
-
466
- res.json(await module.refreshEntityOptions(req.body));
665
+ res.json(updatedOptions);
467
666
  })
468
667
  );
469
668
  }