@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
@@ -0,0 +1,294 @@
1
+ const {
2
+ createModuleRepository,
3
+ } = require('../../modules/repositories/module-repository-factory');
4
+ const { toCredentialId } = require('../../modules/utils/to-credential-id');
5
+
6
+ const ERROR_CODE_MAP = {
7
+ ENTITY_NOT_FOUND: 404,
8
+ INVALID_ENTITY_DATA: 400,
9
+ };
10
+
11
+ function toEntityDto(entity) {
12
+ return {
13
+ id: entity.id,
14
+ userId: entity.userId,
15
+ externalId: entity.externalId,
16
+ name: entity.name,
17
+ moduleName: entity.moduleName,
18
+ credentialId: toCredentialId(entity.credential),
19
+ };
20
+ }
21
+
22
+ function mapErrorToResponse(error) {
23
+ const status = ERROR_CODE_MAP[error?.code] || 500;
24
+ return {
25
+ error: status,
26
+ reason: error?.message,
27
+ code: error?.code,
28
+ };
29
+ }
30
+
31
+ /**
32
+ * Create entity command factory
33
+ *
34
+ * NOTE: This is an internal API. Integration developers should use createFriggCommands() instead.
35
+ *
36
+ * @returns {Object} Entity command object with CRUD operations
37
+ */
38
+ function createEntityCommands() {
39
+ const moduleRepo = createModuleRepository();
40
+
41
+ return {
42
+ /**
43
+ * Create a new entity
44
+ * @param {Object} params
45
+ * @param {string} params.userId - User ID who owns this entity
46
+ * @param {string} params.externalId - External identifier from the API module
47
+ * @param {string} params.name - Entity name
48
+ * @param {string} params.moduleName - Module name (e.g., 'husbpot', 'frontify')
49
+ * @param {string} [params.credentialId] - Associated credential ID
50
+ * @returns {Promise<Object>} Created entity object
51
+ */
52
+ async createEntity({
53
+ userId,
54
+ externalId,
55
+ name,
56
+ moduleName,
57
+ credentialId,
58
+ } = {}) {
59
+ try {
60
+ if (!userId || !externalId || !moduleName) {
61
+ const error = new Error(
62
+ 'userId, externalId, and moduleName are required'
63
+ );
64
+ error.code = 'INVALID_ENTITY_DATA';
65
+ throw error;
66
+ }
67
+
68
+ const entityData = {
69
+ user: userId,
70
+ externalId,
71
+ name,
72
+ moduleName,
73
+ };
74
+
75
+ if (credentialId) {
76
+ entityData.credential = credentialId;
77
+ }
78
+
79
+ const entity = await moduleRepo.createEntity(entityData);
80
+
81
+ return toEntityDto(entity);
82
+ } catch (error) {
83
+ return mapErrorToResponse(error);
84
+ }
85
+ },
86
+
87
+ /**
88
+ * Find an entity by filter criteria
89
+ * @param {Object} filter
90
+ * @param {string} [filter.externalId] - External ID to search for
91
+ * @param {string} [filter.userId] - User ID to search for
92
+ * @param {string} [filter.moduleName] - Module name to search for
93
+ * @returns {Promise<Object|null>} Entity object or null if not found
94
+ */
95
+ async findEntity(filter = {}) {
96
+ try {
97
+ if (
98
+ !filter.externalId &&
99
+ !filter.userId &&
100
+ !filter.moduleName
101
+ ) {
102
+ const error = new Error(
103
+ 'At least one filter criterion is required'
104
+ );
105
+ error.code = 'INVALID_ENTITY_DATA';
106
+ throw error;
107
+ }
108
+
109
+ const entity = await moduleRepo.findEntity(filter);
110
+
111
+ if (!entity) {
112
+ return null;
113
+ }
114
+
115
+ return toEntityDto(entity);
116
+ } catch (error) {
117
+ return mapErrorToResponse(error);
118
+ }
119
+ },
120
+
121
+ /**
122
+ * Find all entities for a user
123
+ * @param {string} userId - User ID to search for
124
+ * @returns {Promise<Array>} Array of entity objects
125
+ */
126
+ async findEntitiesByUserId(userId) {
127
+ try {
128
+ if (!userId) {
129
+ const error = new Error('userId is required');
130
+ error.code = 'INVALID_ENTITY_DATA';
131
+ throw error;
132
+ }
133
+
134
+ const entities = await moduleRepo.findEntitiesByUserId(userId);
135
+
136
+ return entities.map((entity) => toEntityDto(entity));
137
+ } catch (error) {
138
+ if (error.code) {
139
+ return mapErrorToResponse(error);
140
+ }
141
+ // For find operations, return empty array on error instead of error object
142
+ return [];
143
+ }
144
+ },
145
+
146
+ /**
147
+ * Find entities by user ID and module name
148
+ * @param {string} userId - User ID to search for
149
+ * @param {string} moduleName - Module name to filter by
150
+ * @returns {Promise<Array>} Array of entity objects
151
+ */
152
+ async findEntitiesByUserIdAndModuleName(userId, moduleName) {
153
+ try {
154
+ if (!userId || !moduleName) {
155
+ const error = new Error(
156
+ 'userId and moduleName are required'
157
+ );
158
+ error.code = 'INVALID_ENTITY_DATA';
159
+ throw error;
160
+ }
161
+
162
+ const entities =
163
+ await moduleRepo.findEntitiesByUserIdAndModuleName(
164
+ userId,
165
+ moduleName
166
+ );
167
+
168
+ return entities.map((entity) => toEntityDto(entity));
169
+ } catch (error) {
170
+ if (error.code) {
171
+ return mapErrorToResponse(error);
172
+ }
173
+ return [];
174
+ }
175
+ },
176
+
177
+ /**
178
+ * Find an entity by ID
179
+ * @param {string} entityId - Entity ID to search for
180
+ * @returns {Promise<Object>} Entity object
181
+ */
182
+ async findEntityById(entityId) {
183
+ try {
184
+ if (!entityId) {
185
+ const error = new Error('entityId is required');
186
+ error.code = 'INVALID_ENTITY_DATA';
187
+ throw error;
188
+ }
189
+
190
+ const entity = await moduleRepo.findEntityById(entityId);
191
+
192
+ return toEntityDto(entity);
193
+ } catch (error) {
194
+ return mapErrorToResponse(error);
195
+ }
196
+ },
197
+
198
+ /**
199
+ * Update an entity
200
+ * @param {string} entityId - Entity ID to update
201
+ * @param {Object} updates - Fields to update
202
+ * @returns {Promise<Object>} Updated entity object
203
+ */
204
+ async updateEntity(entityId, updates) {
205
+ try {
206
+ if (!entityId) {
207
+ const error = new Error('entityId is required');
208
+ error.code = 'INVALID_ENTITY_DATA';
209
+ throw error;
210
+ }
211
+
212
+ const entity = await moduleRepo.updateEntity(entityId, updates);
213
+
214
+ if (!entity) {
215
+ const error = new Error(`Entity ${entityId} not found`);
216
+ error.code = 'ENTITY_NOT_FOUND';
217
+ throw error;
218
+ }
219
+
220
+ return toEntityDto(entity);
221
+ } catch (error) {
222
+ return mapErrorToResponse(error);
223
+ }
224
+ },
225
+
226
+ /**
227
+ * Delete an entity
228
+ * @param {string} entityId - Entity ID to delete
229
+ * @returns {Promise<Object>} Result object with success flag
230
+ */
231
+ async deleteEntity(entityId) {
232
+ try {
233
+ if (!entityId) {
234
+ const error = new Error('entityId is required');
235
+ error.code = 'INVALID_ENTITY_DATA';
236
+ throw error;
237
+ }
238
+
239
+ await moduleRepo.deleteEntity(entityId);
240
+
241
+ return { success: true };
242
+ } catch (error) {
243
+ return mapErrorToResponse(error);
244
+ }
245
+ },
246
+
247
+ /**
248
+ * Delete an entity by ID (alias for deleteEntity)
249
+ * @param {string} entityId - Entity ID to delete
250
+ * @returns {Promise<Object>} Result object with success flag
251
+ */
252
+ async deleteEntityById(entityId) {
253
+ try {
254
+ if (!entityId) {
255
+ const error = new Error('entityId is required');
256
+ error.code = 'INVALID_ENTITY_DATA';
257
+ throw error;
258
+ }
259
+
260
+ await moduleRepo.deleteEntity(entityId);
261
+
262
+ return { success: true };
263
+ } catch (error) {
264
+ return mapErrorToResponse(error);
265
+ }
266
+ },
267
+
268
+ /**
269
+ * Remove credential reference from an entity
270
+ * @param {string} entityId - Entity ID to update
271
+ * @returns {Promise<Object>} Result object with success flag
272
+ */
273
+ async unsetCredential(entityId) {
274
+ try {
275
+ if (!entityId) {
276
+ const error = new Error('entityId is required');
277
+ error.code = 'INVALID_ENTITY_DATA';
278
+ throw error;
279
+ }
280
+
281
+ const acknowledged = await moduleRepo.unsetCredential(entityId);
282
+
283
+ return { success: acknowledged };
284
+ } catch (error) {
285
+ return mapErrorToResponse(error);
286
+ }
287
+ },
288
+ };
289
+ }
290
+
291
+ module.exports = {
292
+ createEntityCommands,
293
+ ERROR_CODE_MAP,
294
+ };
@@ -0,0 +1,419 @@
1
+ const {
2
+ createIntegrationRepository,
3
+ } = require('../../integrations/repositories/integration-repository-factory');
4
+ const {
5
+ createModuleRepository,
6
+ } = require('../../modules/repositories/module-repository-factory');
7
+ const { ModuleFactory } = require('../../modules/module-factory');
8
+ const {
9
+ LoadIntegrationContextUseCase,
10
+ } = require('../../integrations/use-cases/load-integration-context');
11
+ const {
12
+ FindIntegrationContextByExternalEntityIdUseCase,
13
+ } = require('../../integrations/use-cases/find-integration-context-by-external-entity-id');
14
+ const {
15
+ FindIntegrationByEntityExternalIdUseCase,
16
+ } = require('../../integrations/use-cases/find-integration-by-entity-external-id');
17
+ const {
18
+ ListIntegrationsByEntityExternalIdUseCase,
19
+ } = require('../../integrations/use-cases/list-integrations-by-entity-external-id');
20
+ const {
21
+ GetIntegrationsForUser,
22
+ } = require('../../integrations/use-cases/get-integrations-for-user');
23
+ const {
24
+ CreateIntegration,
25
+ } = require('../../integrations/use-cases/create-integration');
26
+ const {
27
+ UpdateIntegrationConfig,
28
+ } = require('../../integrations/use-cases/update-integration-config');
29
+ const {
30
+ PatchIntegrationConfig,
31
+ } = require('../../integrations/use-cases/patch-integration-config');
32
+ const {
33
+ AddEntitiesToIntegration,
34
+ } = require('../../integrations/use-cases/add-entities-to-integration');
35
+ const {
36
+ RemoveEntitiesFromIntegration,
37
+ } = require('../../integrations/use-cases/remove-entities-from-integration');
38
+ const {
39
+ getModulesDefinitionFromIntegrationClasses,
40
+ } = require('../../integrations/utils/map-integration-dto');
41
+
42
+ const ERROR_CODE_MAP = {
43
+ ENTITY_NOT_FOUND: 401,
44
+ ENTITY_USER_NOT_FOUND: 401,
45
+ INTEGRATION_NOT_FOUND: 404,
46
+ EXTERNAL_ID_REQUIRED: 400,
47
+ TYPE_REQUIRED: 400,
48
+ INTEGRATION_RECORD_NOT_FOUND: 404,
49
+ INVALID_INTEGRATION_DATA: 400,
50
+ ENTITIES_NOT_FOUND: 404,
51
+ ENTITY_USER_MISMATCH: 403,
52
+ ENTITY_MODULE_MISMATCH: 400,
53
+ LAST_ENTITY_OF_MODULE: 409,
54
+ };
55
+
56
+ function mapErrorToResponse(error) {
57
+ const status = ERROR_CODE_MAP[error?.code] || 500;
58
+ return {
59
+ error: status,
60
+ reason: error?.message,
61
+ code: error?.code,
62
+ };
63
+ }
64
+
65
+ function createIntegrationCommands({ integrationClass } = {}) {
66
+ // Always use Frigg's default repositories and use cases
67
+ const integrationRepository = createIntegrationRepository();
68
+
69
+ // Class-agnostic read commands. Available with or without an integrationClass
70
+ // so callers that operate across integration types (e.g. admin scripts) can
71
+ // look up integrations by id or list them by type/status.
72
+
73
+ /**
74
+ * Find a single integration record by id.
75
+ * @param {string} integrationId
76
+ * @returns {Promise<Object>} Integration record, or an error object.
77
+ */
78
+ async function findIntegrationById(integrationId) {
79
+ try {
80
+ return await integrationRepository.findIntegrationById(
81
+ integrationId
82
+ );
83
+ } catch (error) {
84
+ return mapErrorToResponse(error);
85
+ }
86
+ }
87
+
88
+ /**
89
+ * List integrations, optionally filtered by config type and/or status.
90
+ * @param {Object} [filter={}]
91
+ * @param {string} [filter.type] - Integration type (config.type)
92
+ * @param {string} [filter.status] - Integration status
93
+ * @returns {Promise<Array|Object>} Array of integrations, or an error object.
94
+ */
95
+ async function listIntegrations(filter = {}) {
96
+ try {
97
+ return await integrationRepository.findIntegrations(filter);
98
+ } catch (error) {
99
+ return mapErrorToResponse(error);
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Report-shaped projection (derived counters + timestamps) — the
105
+ * cross-integration read that reports (ADR-010) consume via commands.
106
+ */
107
+ async function listForReport(filter = {}) {
108
+ try {
109
+ return await integrationRepository.findAllForReport(filter);
110
+ } catch (error) {
111
+ return mapErrorToResponse(error);
112
+ }
113
+ }
114
+
115
+ // The remaining commands hydrate/modify integrations for a specific class.
116
+ if (!integrationClass) {
117
+ return { findIntegrationById, listIntegrations, listForReport };
118
+ }
119
+
120
+ const moduleRepository = createModuleRepository();
121
+
122
+ const moduleDefinitions = getModulesDefinitionFromIntegrationClasses([
123
+ integrationClass,
124
+ ]);
125
+
126
+ const moduleFactory = new ModuleFactory({
127
+ moduleRepository,
128
+ moduleDefinitions,
129
+ });
130
+
131
+ const loadIntegrationContextUseCase = new LoadIntegrationContextUseCase({
132
+ integrationRepository,
133
+ moduleRepository,
134
+ moduleFactory,
135
+ });
136
+
137
+ const findByExternalEntityIdUseCase =
138
+ new FindIntegrationContextByExternalEntityIdUseCase({
139
+ integrationRepository,
140
+ moduleRepository,
141
+ loadIntegrationContextUseCase: loadIntegrationContextUseCase,
142
+ });
143
+
144
+ const findIntegrationByEntityExternalIdUseCase =
145
+ new FindIntegrationByEntityExternalIdUseCase({
146
+ integrationRepository,
147
+ moduleRepository,
148
+ });
149
+
150
+ const listIntegrationsByEntityExternalIdUseCase =
151
+ new ListIntegrationsByEntityExternalIdUseCase({
152
+ integrationRepository,
153
+ moduleRepository,
154
+ });
155
+
156
+ const getIntegrationsForUserUseCase = new GetIntegrationsForUser({
157
+ integrationRepository,
158
+ integrationClasses: [integrationClass],
159
+ moduleFactory,
160
+ moduleRepository,
161
+ });
162
+
163
+ const createIntegrationUseCase = new CreateIntegration({
164
+ integrationRepository,
165
+ integrationClasses: [integrationClass],
166
+ moduleFactory,
167
+ });
168
+
169
+ const updateIntegrationConfigUseCase = new UpdateIntegrationConfig({
170
+ integrationRepository,
171
+ });
172
+
173
+ const patchIntegrationConfigUseCase = new PatchIntegrationConfig({
174
+ integrationRepository,
175
+ });
176
+
177
+ const addEntitiesToIntegrationUseCase = new AddEntitiesToIntegration({
178
+ integrationRepository,
179
+ moduleRepository,
180
+ });
181
+
182
+ const removeEntitiesFromIntegrationUseCase =
183
+ new RemoveEntitiesFromIntegration({
184
+ integrationRepository,
185
+ moduleRepository,
186
+ });
187
+
188
+ return {
189
+ findIntegrationById,
190
+ listIntegrations,
191
+ listForReport,
192
+
193
+ /**
194
+ * Find integration context by external entity ID and type
195
+ * @param {Object} params
196
+ * @param {string} params.externalId - External ID of the entity
197
+ * @param {string} params.type - Integration type (config.type)
198
+ * @returns {Promise<Object>} Integration context, entity, and record
199
+ */
200
+ async findIntegrationContextByExternalEntityId({ externalId, type }) {
201
+ try {
202
+ const result = await findByExternalEntityIdUseCase.execute({
203
+ externalId,
204
+ type,
205
+ });
206
+ return result;
207
+ } catch (error) {
208
+ return mapErrorToResponse(error);
209
+ }
210
+ },
211
+
212
+ /**
213
+ * Resolve an externalId (e.g. HubSpot portalId, Slack team_id) to a
214
+ * single integration ID. Throws on ambiguous resolution at either the
215
+ * entity or integration layer — cross-tenant routing is refused.
216
+ *
217
+ * @param {string|number} externalId - Provider's stable identifier.
218
+ * @param {string} [moduleName] - Disambiguates when multiple modules in
219
+ * the same app could carry colliding externalIds.
220
+ * @returns {Promise<string|null>} Integration ID, or null on no match.
221
+ * @throws {Error} On ambiguous resolution (multiple entities or
222
+ * multiple owning integrations).
223
+ */
224
+ async findIntegrationByEntityExternalId(externalId, moduleName) {
225
+ return findIntegrationByEntityExternalIdUseCase.execute({
226
+ externalId,
227
+ moduleName,
228
+ });
229
+ },
230
+
231
+ /**
232
+ * List all integration IDs whose module entities match an externalId.
233
+ * Use when one externalId is expected to map to multiple integrations
234
+ * (intentional fan-out). Does not throw on ambiguity.
235
+ *
236
+ * @param {string|number} externalId - Provider's stable identifier.
237
+ * @param {string} [moduleName] - Disambiguates across modules.
238
+ * @returns {Promise<Array<string>>} Array of integration IDs (possibly empty).
239
+ */
240
+ async listIntegrationsByEntityExternalId(externalId, moduleName) {
241
+ return listIntegrationsByEntityExternalIdUseCase.execute({
242
+ externalId,
243
+ moduleName,
244
+ });
245
+ },
246
+
247
+ async loadIntegrationContextById(integrationId) {
248
+ try {
249
+ const context = await loadIntegrationContextUseCase.execute({
250
+ integrationId,
251
+ });
252
+ return { context };
253
+ } catch (error) {
254
+ return mapErrorToResponse(error);
255
+ }
256
+ },
257
+
258
+ /**
259
+ * Find all integrations for a user
260
+ * @param {string} userId - User ID to search for
261
+ * @returns {Promise<Array>} Array of integration records
262
+ */
263
+ async findIntegrationsByUserId(userId) {
264
+ try {
265
+ const integrations =
266
+ await getIntegrationsForUserUseCase.execute(userId);
267
+ return integrations;
268
+ } catch (error) {
269
+ return mapErrorToResponse(error);
270
+ }
271
+ },
272
+
273
+ /**
274
+ * Create a new integration
275
+ * @param {Object} params
276
+ * @param {Array<string>} params.entityIds - Array of entity IDs
277
+ * @param {string} params.userId - User ID
278
+ * @param {Object} params.config - Integration configuration (must include type)
279
+ * @returns {Promise<Object>} Created integration object
280
+ */
281
+ async createIntegration({ entityIds, userId, config }) {
282
+ try {
283
+ const integration = await createIntegrationUseCase.execute(
284
+ entityIds,
285
+ userId,
286
+ config
287
+ );
288
+ return integration;
289
+ } catch (error) {
290
+ return mapErrorToResponse(error);
291
+ }
292
+ },
293
+
294
+ /**
295
+ * Update integration configuration
296
+ * @param {Object} params
297
+ * @param {string} params.integrationId - Integration ID
298
+ * @param {Object} params.config - Updated config object
299
+ * @returns {Promise<Object>} Updated integration
300
+ */
301
+ async updateIntegrationConfig({ integrationId, config }) {
302
+ try {
303
+ const integration = await updateIntegrationConfigUseCase.execute(
304
+ integrationId,
305
+ config
306
+ );
307
+ return integration;
308
+ } catch (error) {
309
+ return mapErrorToResponse(error);
310
+ }
311
+ },
312
+
313
+ /**
314
+ * Atomically merge a partial update into an integration's config
315
+ * @param {Object} params
316
+ * @param {string} params.integrationId - Integration ID
317
+ * @param {Object} params.patch - Keys to merge into the existing config
318
+ * @returns {Promise<Object>} Updated integration
319
+ */
320
+ async patchIntegrationConfig({ integrationId, patch }) {
321
+ try {
322
+ const integration = await patchIntegrationConfigUseCase.execute(
323
+ integrationId,
324
+ patch
325
+ );
326
+ return integration;
327
+ } catch (error) {
328
+ return mapErrorToResponse(error);
329
+ }
330
+ },
331
+
332
+ /**
333
+ * Attach entities to an existing integration. Every entity must
334
+ * exist, belong to the integration's user, and be of a module the
335
+ * integration already holds; entities that are already attached are
336
+ * left as they are.
337
+ * @param {Object} params
338
+ * @param {string} params.integrationId - Integration ID
339
+ * @param {Array<string>} params.entityIds - Entity IDs to attach
340
+ * @returns {Promise<Object>} Updated integration
341
+ */
342
+ async addEntitiesToIntegration({ integrationId, entityIds }) {
343
+ try {
344
+ return await addEntitiesToIntegrationUseCase.execute(
345
+ integrationId,
346
+ entityIds
347
+ );
348
+ } catch (error) {
349
+ return mapErrorToResponse(error);
350
+ }
351
+ },
352
+
353
+ /**
354
+ * Detach entities from an integration. Entities that are not
355
+ * attached are ignored; detached entities are not deleted. Each
356
+ * module must keep at least one entity.
357
+ * @param {Object} params
358
+ * @param {string} params.integrationId - Integration ID
359
+ * @param {Array<string>} params.entityIds - Entity IDs to detach
360
+ * @returns {Promise<Object>} Updated integration
361
+ */
362
+ async removeEntitiesFromIntegration({ integrationId, entityIds }) {
363
+ try {
364
+ return await removeEntitiesFromIntegrationUseCase.execute(
365
+ integrationId,
366
+ entityIds
367
+ );
368
+ } catch (error) {
369
+ return mapErrorToResponse(error);
370
+ }
371
+ },
372
+
373
+ /**
374
+ * Delete an integration by ID
375
+ * @param {string} integrationId - Integration ID to delete
376
+ * @returns {Promise<Object>} Deletion result
377
+ */
378
+ async deleteIntegrationById(integrationId) {
379
+ try {
380
+ if (!integrationId) {
381
+ const error = new Error('integrationId is required');
382
+ error.code = 'INVALID_INTEGRATION_DATA';
383
+ throw error;
384
+ }
385
+
386
+ const deleted = await integrationRepository.deleteIntegrationById(integrationId);
387
+
388
+ if (!deleted) {
389
+ const error = new Error(`Integration ${integrationId} not found`);
390
+ error.code = 'INTEGRATION_NOT_FOUND';
391
+ return mapErrorToResponse(error);
392
+ }
393
+
394
+ return {
395
+ success: true,
396
+ integrationId,
397
+ message: 'Integration deleted successfully',
398
+ };
399
+ } catch (error) {
400
+ return mapErrorToResponse(error);
401
+ }
402
+ },
403
+ };
404
+ }
405
+
406
+ async function findIntegrationContextByExternalEntityId({
407
+ integrationClass,
408
+ externalId,
409
+ type,
410
+ } = {}) {
411
+ const commands = createIntegrationCommands({ integrationClass });
412
+
413
+ return commands.findIntegrationContextByExternalEntityId({ externalId, type });
414
+ }
415
+
416
+ module.exports = {
417
+ createIntegrationCommands,
418
+ findIntegrationContextByExternalEntityId,
419
+ };