@friggframework/core 2.0.0-next.1 → 2.0.0-next.100

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