@friggframework/core 2.0.0-next.12 → 2.0.0-next.121

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