@friggframework/core 2.0.0-next.11 → 2.0.0-next.110

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 (375) hide show
  1. package/CLAUDE.md +702 -0
  2. package/README.md +999 -50
  3. package/admin-scripts/index.js +52 -0
  4. package/admin-scripts/repositories/admin-script-execution-repository-documentdb.js +21 -0
  5. package/admin-scripts/repositories/admin-script-execution-repository-factory.js +51 -0
  6. package/admin-scripts/repositories/admin-script-execution-repository-interface.js +171 -0
  7. package/admin-scripts/repositories/admin-script-execution-repository-mongo.js +238 -0
  8. package/admin-scripts/repositories/admin-script-execution-repository-postgres.js +278 -0
  9. package/admin-scripts/repositories/script-schedule-repository-documentdb.js +21 -0
  10. package/admin-scripts/repositories/script-schedule-repository-factory.js +51 -0
  11. package/admin-scripts/repositories/script-schedule-repository-interface.js +108 -0
  12. package/admin-scripts/repositories/script-schedule-repository-mongo.js +179 -0
  13. package/admin-scripts/repositories/script-schedule-repository-postgres.js +210 -0
  14. package/application/commands/README.md +451 -0
  15. package/application/commands/admin-script-commands.js +359 -0
  16. package/application/commands/credential-commands.js +262 -0
  17. package/application/commands/entity-commands.js +336 -0
  18. package/application/commands/integration-commands.js +356 -0
  19. package/application/commands/integration-mapping-commands.js +25 -0
  20. package/application/commands/process-commands.js +135 -0
  21. package/application/commands/report-commands.js +188 -0
  22. package/application/commands/scheduler-commands.js +263 -0
  23. package/application/commands/usage-commands.js +56 -0
  24. package/application/commands/user-commands.js +312 -0
  25. package/application/index.js +83 -0
  26. package/artifacts/repositories/artifact-repository-factory.js +19 -0
  27. package/artifacts/repositories/artifact-repository-interface.js +27 -0
  28. package/artifacts/repositories/artifact-repository-local.js +42 -0
  29. package/artifacts/repositories/artifact-repository-s3.js +61 -0
  30. package/assertions/index.js +0 -3
  31. package/core/CLAUDE.md +700 -0
  32. package/core/Worker.js +60 -24
  33. package/core/create-handler.js +189 -5
  34. package/core/parameters-to-env.js +257 -0
  35. package/core/ssm-preload.mjs +34 -0
  36. package/credential/repositories/credential-active-type.js +32 -0
  37. package/credential/repositories/credential-repository-documentdb.js +355 -0
  38. package/credential/repositories/credential-repository-factory.js +54 -0
  39. package/credential/repositories/credential-repository-interface.js +113 -0
  40. package/credential/repositories/credential-repository-mongo.js +294 -0
  41. package/credential/repositories/credential-repository-postgres.js +312 -0
  42. package/credential/repositories/credential-repository.js +300 -0
  43. package/credential/use-cases/get-credential-for-user.js +25 -0
  44. package/credential/use-cases/update-authentication-status.js +15 -0
  45. package/database/MONGODB_TRANSACTION_FIX.md +198 -0
  46. package/database/adapters/lambda-invoker.js +97 -0
  47. package/database/config.js +154 -0
  48. package/database/documentdb-encryption-service.js +330 -0
  49. package/database/documentdb-utils.js +192 -0
  50. package/database/encryption/README.md +839 -0
  51. package/database/encryption/documentdb-encryption-service.md +3575 -0
  52. package/database/encryption/encryption-schema-registry.js +401 -0
  53. package/database/encryption/field-encryption-service.js +254 -0
  54. package/database/encryption/logger.js +79 -0
  55. package/database/encryption/prisma-encryption-extension.js +230 -0
  56. package/database/index.js +21 -21
  57. package/database/prisma.js +182 -0
  58. package/database/repositories/health-check-repository-documentdb.js +138 -0
  59. package/database/repositories/health-check-repository-factory.js +48 -0
  60. package/database/repositories/health-check-repository-interface.js +82 -0
  61. package/database/repositories/health-check-repository-mongodb.js +89 -0
  62. package/database/repositories/health-check-repository-postgres.js +82 -0
  63. package/database/repositories/migration-status-repository-s3.js +137 -0
  64. package/database/use-cases/check-database-health-use-case.js +29 -0
  65. package/database/use-cases/check-database-state-use-case.js +81 -0
  66. package/database/use-cases/check-encryption-health-use-case.js +83 -0
  67. package/database/use-cases/get-database-state-via-worker-use-case.js +61 -0
  68. package/database/use-cases/get-migration-status-use-case.js +93 -0
  69. package/database/use-cases/resolve-migration-via-worker-use-case.js +49 -0
  70. package/database/use-cases/run-database-migration-use-case.js +139 -0
  71. package/database/use-cases/test-encryption-use-case.js +253 -0
  72. package/database/use-cases/trigger-database-migration-use-case.js +157 -0
  73. package/database/utils/mongodb-collection-utils.js +94 -0
  74. package/database/utils/mongodb-schema-init.js +108 -0
  75. package/database/utils/prisma-runner.js +491 -0
  76. package/database/utils/prisma-schema-parser.js +182 -0
  77. package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +517 -0
  78. package/encrypt/Cryptor.js +34 -168
  79. package/encrypt/index.js +1 -2
  80. package/errors/client-safe-error.js +26 -0
  81. package/errors/fetch-error.js +15 -7
  82. package/errors/index.js +2 -0
  83. package/generated/prisma-mongodb/client.d.ts +1 -0
  84. package/generated/prisma-mongodb/client.js +5 -0
  85. package/generated/prisma-mongodb/default.d.ts +1 -0
  86. package/generated/prisma-mongodb/default.js +5 -0
  87. package/generated/prisma-mongodb/edge.d.ts +1 -0
  88. package/generated/prisma-mongodb/edge.js +386 -0
  89. package/generated/prisma-mongodb/index-browser.js +368 -0
  90. package/generated/prisma-mongodb/index.d.ts +27065 -0
  91. package/generated/prisma-mongodb/index.js +411 -0
  92. package/generated/prisma-mongodb/libquery_engine-debian-openssl-3.0.x.so.node +0 -0
  93. package/generated/prisma-mongodb/libquery_engine-rhel-openssl-3.0.x.so.node +0 -0
  94. package/generated/prisma-mongodb/package.json +183 -0
  95. package/generated/prisma-mongodb/runtime/edge-esm.js +35 -0
  96. package/generated/prisma-mongodb/runtime/edge.js +35 -0
  97. package/generated/prisma-mongodb/runtime/index-browser.d.ts +370 -0
  98. package/generated/prisma-mongodb/runtime/index-browser.js +17 -0
  99. package/generated/prisma-mongodb/runtime/library.d.ts +3982 -0
  100. package/generated/prisma-mongodb/runtime/library.js +147 -0
  101. package/generated/prisma-mongodb/runtime/react-native.js +84 -0
  102. package/generated/prisma-mongodb/runtime/wasm-compiler-edge.js +85 -0
  103. package/generated/prisma-mongodb/runtime/wasm-engine-edge.js +38 -0
  104. package/generated/prisma-mongodb/schema.prisma +455 -0
  105. package/generated/prisma-mongodb/wasm-edge-light-loader.mjs +5 -0
  106. package/generated/prisma-mongodb/wasm-worker-loader.mjs +5 -0
  107. package/generated/prisma-mongodb/wasm.d.ts +1 -0
  108. package/generated/prisma-mongodb/wasm.js +393 -0
  109. package/generated/prisma-postgresql/client.d.ts +1 -0
  110. package/generated/prisma-postgresql/client.js +5 -0
  111. package/generated/prisma-postgresql/default.d.ts +1 -0
  112. package/generated/prisma-postgresql/default.js +5 -0
  113. package/generated/prisma-postgresql/edge.d.ts +1 -0
  114. package/generated/prisma-postgresql/edge.js +407 -0
  115. package/generated/prisma-postgresql/index-browser.js +389 -0
  116. package/generated/prisma-postgresql/index.d.ts +29904 -0
  117. package/generated/prisma-postgresql/index.js +432 -0
  118. package/generated/prisma-postgresql/libquery_engine-debian-openssl-3.0.x.so.node +0 -0
  119. package/generated/prisma-postgresql/libquery_engine-rhel-openssl-3.0.x.so.node +0 -0
  120. package/generated/prisma-postgresql/package.json +183 -0
  121. package/generated/prisma-postgresql/query_engine_bg.js +2 -0
  122. package/generated/prisma-postgresql/query_engine_bg.wasm +0 -0
  123. package/generated/prisma-postgresql/runtime/edge-esm.js +35 -0
  124. package/generated/prisma-postgresql/runtime/edge.js +35 -0
  125. package/generated/prisma-postgresql/runtime/index-browser.d.ts +370 -0
  126. package/generated/prisma-postgresql/runtime/index-browser.js +17 -0
  127. package/generated/prisma-postgresql/runtime/library.d.ts +3982 -0
  128. package/generated/prisma-postgresql/runtime/library.js +147 -0
  129. package/generated/prisma-postgresql/runtime/react-native.js +84 -0
  130. package/generated/prisma-postgresql/runtime/wasm-compiler-edge.js +85 -0
  131. package/generated/prisma-postgresql/runtime/wasm-engine-edge.js +38 -0
  132. package/generated/prisma-postgresql/schema.prisma +436 -0
  133. package/generated/prisma-postgresql/wasm-edge-light-loader.mjs +5 -0
  134. package/generated/prisma-postgresql/wasm-worker-loader.mjs +5 -0
  135. package/generated/prisma-postgresql/wasm.d.ts +1 -0
  136. package/generated/prisma-postgresql/wasm.js +414 -0
  137. package/handlers/WEBHOOKS.md +653 -0
  138. package/handlers/app-definition-loader.js +67 -0
  139. package/handlers/app-handler-helpers.js +3 -3
  140. package/handlers/backend-utils.js +271 -42
  141. package/handlers/database-migration-handler.js +227 -0
  142. package/handlers/integration-event-dispatcher.js +68 -0
  143. package/handlers/middleware/admin-auth.js +73 -0
  144. package/handlers/routers/HEALTHCHECK.md +342 -0
  145. package/handlers/routers/auth.js +4 -15
  146. package/handlers/routers/db-migration.handler.js +29 -0
  147. package/handlers/routers/db-migration.js +329 -0
  148. package/handlers/routers/health.js +518 -0
  149. package/handlers/routers/integration-defined-routers.js +85 -10
  150. package/handlers/routers/integration-webhook-routers.js +80 -0
  151. package/handlers/routers/user.js +27 -5
  152. package/handlers/routers/websocket.js +5 -3
  153. package/handlers/use-cases/check-external-apis-health-use-case.js +81 -0
  154. package/handlers/use-cases/check-integrations-health-use-case.js +44 -0
  155. package/handlers/workers/db-migration.js +427 -0
  156. package/handlers/workers/dlq-processor.js +63 -0
  157. package/handlers/workers/integration-defined-workers.js +13 -7
  158. package/index.js +102 -46
  159. package/infrastructure/scheduler/eventbridge-scheduler-adapter.js +184 -0
  160. package/infrastructure/scheduler/index.js +33 -0
  161. package/infrastructure/scheduler/mock-scheduler-adapter.js +143 -0
  162. package/infrastructure/scheduler/scheduler-service-factory.js +73 -0
  163. package/infrastructure/scheduler/scheduler-service-interface.js +47 -0
  164. package/integrations/EXTENSIONS.md +240 -0
  165. package/integrations/WEBHOOK-QUICKSTART.md +151 -0
  166. package/integrations/extension.js +254 -0
  167. package/integrations/index.js +20 -10
  168. package/integrations/integration-base.js +730 -74
  169. package/integrations/integration-router.js +398 -180
  170. package/integrations/options.js +1 -1
  171. package/integrations/repositories/config-patch-shared.js +43 -0
  172. package/integrations/repositories/integration-mapping-repository-documentdb.js +303 -0
  173. package/integrations/repositories/integration-mapping-repository-factory.js +57 -0
  174. package/integrations/repositories/integration-mapping-repository-interface.js +120 -0
  175. package/integrations/repositories/integration-mapping-repository-mongo.js +183 -0
  176. package/integrations/repositories/integration-mapping-repository-postgres.js +255 -0
  177. package/integrations/repositories/integration-mapping-repository.js +156 -0
  178. package/integrations/repositories/integration-repository-documentdb.js +322 -0
  179. package/integrations/repositories/integration-repository-factory.js +51 -0
  180. package/integrations/repositories/integration-repository-interface.js +189 -0
  181. package/integrations/repositories/integration-repository-mongo.js +450 -0
  182. package/integrations/repositories/integration-repository-postgres.js +492 -0
  183. package/integrations/repositories/process-repository-documentdb.js +311 -0
  184. package/integrations/repositories/process-repository-factory.js +53 -0
  185. package/integrations/repositories/process-repository-interface.js +136 -0
  186. package/integrations/repositories/process-repository-mongo.js +262 -0
  187. package/integrations/repositories/process-repository-postgres.js +380 -0
  188. package/integrations/repositories/process-update-ops-shared.js +112 -0
  189. package/integrations/repositories/report-id.js +13 -0
  190. package/integrations/tests/doubles/config-capturing-integration.js +81 -0
  191. package/integrations/tests/doubles/dummy-integration-class.js +113 -0
  192. package/integrations/tests/doubles/test-integration-repository.js +146 -0
  193. package/integrations/use-cases/create-integration.js +215 -0
  194. package/integrations/use-cases/create-process.js +130 -0
  195. package/integrations/use-cases/delete-integration-for-user.js +119 -0
  196. package/integrations/use-cases/find-integration-by-entity-external-id.js +74 -0
  197. package/integrations/use-cases/find-integration-context-by-external-entity-id.js +76 -0
  198. package/integrations/use-cases/get-integration-for-user.js +78 -0
  199. package/integrations/use-cases/get-integration-instance-by-definition.js +67 -0
  200. package/integrations/use-cases/get-integration-instance.js +83 -0
  201. package/integrations/use-cases/get-integrations-for-user.js +88 -0
  202. package/integrations/use-cases/get-possible-integrations.js +27 -0
  203. package/integrations/use-cases/get-process.js +89 -0
  204. package/integrations/use-cases/index.js +19 -0
  205. package/integrations/use-cases/list-integrations-by-entity-external-id.js +46 -0
  206. package/integrations/use-cases/load-integration-context.js +71 -0
  207. package/integrations/use-cases/patch-integration-config.js +39 -0
  208. package/integrations/use-cases/process-errors.js +28 -0
  209. package/integrations/use-cases/update-integration-config.js +32 -0
  210. package/integrations/use-cases/update-integration-messages.js +44 -0
  211. package/integrations/use-cases/update-integration-status.js +32 -0
  212. package/integrations/use-cases/update-integration.js +92 -0
  213. package/integrations/use-cases/update-process-metrics.js +222 -0
  214. package/integrations/use-cases/update-process-state.js +163 -0
  215. package/integrations/utils/map-integration-dto.js +37 -0
  216. package/jest-global-setup-noop.js +3 -0
  217. package/jest-global-teardown-noop.js +3 -0
  218. package/logs/logger.js +0 -4
  219. package/{module-plugin → modules}/index.js +0 -10
  220. package/modules/module-factory.js +56 -0
  221. package/modules/module.js +307 -0
  222. package/modules/repositories/module-repository-documentdb.js +350 -0
  223. package/modules/repositories/module-repository-factory.js +40 -0
  224. package/modules/repositories/module-repository-interface.js +145 -0
  225. package/modules/repositories/module-repository-mongo.js +436 -0
  226. package/modules/repositories/module-repository-postgres.js +481 -0
  227. package/modules/repositories/module-repository.js +369 -0
  228. package/modules/requester/api-key.js +52 -0
  229. package/modules/requester/oauth-2.js +555 -0
  230. package/modules/requester/requester.js +542 -0
  231. package/{module-plugin → modules}/test/mock-api/api.js +8 -3
  232. package/{module-plugin → modules}/test/mock-api/definition.js +14 -10
  233. package/modules/tests/doubles/test-module-factory.js +16 -0
  234. package/modules/tests/doubles/test-module-repository.js +39 -0
  235. package/modules/use-cases/get-entities-for-user.js +32 -0
  236. package/modules/use-cases/get-entity-options-by-id.js +71 -0
  237. package/modules/use-cases/get-entity-options-by-type.js +34 -0
  238. package/modules/use-cases/get-module-instance-from-type.js +34 -0
  239. package/modules/use-cases/get-module.js +74 -0
  240. package/modules/use-cases/process-authorization-callback.js +243 -0
  241. package/modules/use-cases/refresh-entity-options.js +72 -0
  242. package/modules/use-cases/test-module-auth.js +72 -0
  243. package/modules/utils/map-module-dto.js +18 -0
  244. package/package.json +92 -50
  245. package/prisma-mongodb/schema.prisma +455 -0
  246. package/prisma-postgresql/migrations/20250930193005_init/migration.sql +315 -0
  247. package/prisma-postgresql/migrations/20251006135218_init/migration.sql +9 -0
  248. package/prisma-postgresql/migrations/20251010000000_remove_unused_entity_reference_map/migration.sql +3 -0
  249. package/prisma-postgresql/migrations/20251112195422_update_user_unique_constraints/migration.sql +25 -0
  250. package/prisma-postgresql/migrations/20260422120000_add_entity_data_column/migration.sql +10 -0
  251. package/prisma-postgresql/migrations/20260422120001_create_process_table/migration.sql +48 -0
  252. package/prisma-postgresql/migrations/20260625000000_add_user_organization_id_index/migration.sql +2 -0
  253. package/prisma-postgresql/migrations/20260703000000_add_integration_status_in_creation_in_deletion/migration.sql +11 -0
  254. package/prisma-postgresql/migrations/20260703000001_integration_status_default_in_creation/migration.sql +8 -0
  255. package/prisma-postgresql/migrations/20260705000000_create_usage_counter/migration.sql +26 -0
  256. package/prisma-postgresql/migrations/20260706000000_add_admin_script_execution_and_schedule/migration.sql +61 -0
  257. package/prisma-postgresql/migrations/migration_lock.toml +3 -0
  258. package/prisma-postgresql/schema.prisma +436 -0
  259. package/queues/queuer-util.js +103 -21
  260. package/reporting/README.md +154 -0
  261. package/reporting/builtin-reports.js +6 -0
  262. package/reporting/index.js +13 -0
  263. package/reporting/report-base.js +49 -0
  264. package/reporting/reports/integrations-report.js +221 -0
  265. package/syncs/manager.js +468 -443
  266. package/syncs/repositories/sync-repository-documentdb.js +240 -0
  267. package/syncs/repositories/sync-repository-factory.js +43 -0
  268. package/syncs/repositories/sync-repository-interface.js +109 -0
  269. package/syncs/repositories/sync-repository-mongo.js +239 -0
  270. package/syncs/repositories/sync-repository-postgres.js +319 -0
  271. package/syncs/sync.js +0 -1
  272. package/telemetry/README.md +331 -0
  273. package/telemetry/bind-telemetry-context.js +73 -0
  274. package/telemetry/canonical-counters.js +52 -0
  275. package/telemetry/exporters.js +85 -0
  276. package/telemetry/index.js +26 -0
  277. package/telemetry/instrument-handler.js +87 -0
  278. package/telemetry/no-op-telemetry.js +67 -0
  279. package/telemetry/north-star.js +103 -0
  280. package/telemetry/otel-telemetry.js +213 -0
  281. package/telemetry/plugin-subscribers.js +77 -0
  282. package/telemetry/telemetry-config.js +120 -0
  283. package/telemetry/telemetry-context.js +40 -0
  284. package/telemetry/telemetry-event-bus.js +58 -0
  285. package/telemetry/telemetry-runtime.js +147 -0
  286. package/telemetry/telemetry-service.js +51 -0
  287. package/telemetry/usage-rollup-subscriber.js +116 -0
  288. package/token/repositories/token-repository-documentdb.js +137 -0
  289. package/token/repositories/token-repository-factory.js +40 -0
  290. package/token/repositories/token-repository-interface.js +131 -0
  291. package/token/repositories/token-repository-mongo.js +219 -0
  292. package/token/repositories/token-repository-postgres.js +264 -0
  293. package/token/repositories/token-repository.js +219 -0
  294. package/types/associations/index.d.ts +0 -17
  295. package/types/core/index.d.ts +12 -4
  296. package/types/database/index.d.ts +10 -2
  297. package/types/encrypt/index.d.ts +5 -3
  298. package/types/integrations/index.d.ts +3 -8
  299. package/types/module-plugin/index.d.ts +20 -69
  300. package/types/syncs/index.d.ts +0 -17
  301. package/usage/README.md +54 -0
  302. package/usage/index.js +17 -0
  303. package/usage/repositories/usage-repository-documentdb.js +194 -0
  304. package/usage/repositories/usage-repository-factory.js +25 -0
  305. package/usage/repositories/usage-repository-interface.js +37 -0
  306. package/usage/repositories/usage-repository-prisma.js +146 -0
  307. package/usage/tracked-metrics.js +38 -0
  308. package/usage/usage-windows.js +24 -0
  309. package/user/repositories/user-repository-documentdb.js +458 -0
  310. package/user/repositories/user-repository-factory.js +52 -0
  311. package/user/repositories/user-repository-interface.js +214 -0
  312. package/user/repositories/user-repository-mongo.js +323 -0
  313. package/user/repositories/user-repository-postgres.js +377 -0
  314. package/user/tests/doubles/test-user-repository.js +72 -0
  315. package/user/use-cases/authenticate-user.js +127 -0
  316. package/user/use-cases/authenticate-with-shared-secret.js +48 -0
  317. package/user/use-cases/create-individual-user.js +61 -0
  318. package/user/use-cases/create-organization-user.js +47 -0
  319. package/user/use-cases/create-token-for-user-id.js +30 -0
  320. package/user/use-cases/get-user-from-adopter-jwt.js +149 -0
  321. package/user/use-cases/get-user-from-bearer-token.js +77 -0
  322. package/user/use-cases/get-user-from-x-frigg-headers.js +132 -0
  323. package/user/use-cases/login-user.js +122 -0
  324. package/user/user.js +125 -0
  325. package/utils/backend-path.js +38 -0
  326. package/utils/index.js +6 -0
  327. package/websocket/repositories/websocket-connection-repository-documentdb.js +119 -0
  328. package/websocket/repositories/websocket-connection-repository-factory.js +44 -0
  329. package/websocket/repositories/websocket-connection-repository-interface.js +106 -0
  330. package/websocket/repositories/websocket-connection-repository-mongo.js +156 -0
  331. package/websocket/repositories/websocket-connection-repository-postgres.js +196 -0
  332. package/websocket/repositories/websocket-connection-repository.js +161 -0
  333. package/assertions/is-equal.js +0 -17
  334. package/associations/model.js +0 -54
  335. package/database/models/IndividualUser.js +0 -76
  336. package/database/models/OrganizationUser.js +0 -29
  337. package/database/models/State.js +0 -9
  338. package/database/models/Token.js +0 -70
  339. package/database/models/UserModel.js +0 -7
  340. package/database/models/WebsocketConnection.js +0 -49
  341. package/database/mongo.js +0 -45
  342. package/database/mongoose.js +0 -5
  343. package/encrypt/Cryptor.test.js +0 -32
  344. package/encrypt/encrypt.js +0 -132
  345. package/encrypt/encrypt.test.js +0 -1069
  346. package/encrypt/test-encrypt.js +0 -107
  347. package/errors/base-error.test.js +0 -32
  348. package/errors/fetch-error.test.js +0 -79
  349. package/errors/halt-error.test.js +0 -11
  350. package/errors/validation-errors.test.js +0 -120
  351. package/handlers/routers/middleware/loadUser.js +0 -15
  352. package/handlers/routers/middleware/requireLoggedInUser.js +0 -12
  353. package/integrations/create-frigg-backend.js +0 -31
  354. package/integrations/integration-factory.js +0 -251
  355. package/integrations/integration-mapping.js +0 -43
  356. package/integrations/integration-model.js +0 -46
  357. package/integrations/integration-user.js +0 -144
  358. package/integrations/test/integration-base.test.js +0 -144
  359. package/lambda/TimeoutCatcher.test.js +0 -68
  360. package/logs/logger.test.js +0 -76
  361. package/module-plugin/auther.js +0 -393
  362. package/module-plugin/credential.js +0 -22
  363. package/module-plugin/entity-manager.js +0 -70
  364. package/module-plugin/entity.js +0 -46
  365. package/module-plugin/manager.js +0 -169
  366. package/module-plugin/module-factory.js +0 -61
  367. package/module-plugin/requester/api-key.js +0 -36
  368. package/module-plugin/requester/oauth-2.js +0 -219
  369. package/module-plugin/requester/requester.js +0 -165
  370. package/module-plugin/requester/requester.test.js +0 -28
  371. package/module-plugin/test/auther.test.js +0 -97
  372. package/syncs/model.js +0 -62
  373. /package/{module-plugin → modules}/ModuleConstants.js +0 -0
  374. /package/{module-plugin → modules}/requester/basic.js +0 -0
  375. /package/{module-plugin → modules}/test/mock-api/mocks/hubspot.js +0 -0
@@ -0,0 +1,322 @@
1
+ const { prisma } = require('../../database/prisma');
2
+ const {
3
+ toObjectId,
4
+ toObjectIdArray,
5
+ fromObjectId,
6
+ findMany,
7
+ findManyDrained,
8
+ findOne,
9
+ insertOne,
10
+ updateOne,
11
+ deleteOne,
12
+ } = require('../../database/documentdb-utils');
13
+ const {
14
+ IntegrationRepositoryInterface,
15
+ } = require('./integration-repository-interface');
16
+ const { validateConfigPatch } = require('./config-patch-shared');
17
+
18
+ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
19
+ constructor() {
20
+ super();
21
+ this.prisma = prisma;
22
+ }
23
+
24
+ async findIntegrationsByUserId(userId) {
25
+ const objectId = toObjectId(userId);
26
+ const filter = objectId ? { userId: objectId } : {};
27
+ const records = await findMany(this.prisma, 'Integration', filter);
28
+ return records.map((doc) => this._mapIntegration(doc));
29
+ }
30
+
31
+ async findIntegrations({ type, status } = {}) {
32
+ const filter = {};
33
+ if (type) {
34
+ filter['config.type'] = type;
35
+ }
36
+ if (status) {
37
+ filter.status = status;
38
+ }
39
+ const records = await findMany(this.prisma, 'Integration', filter);
40
+ return records.map((doc) => this._mapIntegration(doc));
41
+ }
42
+
43
+ async findIntegrationsByEntityId(entityId) {
44
+ const objectId = toObjectId(entityId);
45
+ if (!objectId) return [];
46
+ const records = await findMany(this.prisma, 'Integration', {
47
+ entityIds: objectId,
48
+ });
49
+ return records.map((doc) => this._mapIntegration(doc));
50
+ }
51
+
52
+ async deleteIntegrationById(integrationId) {
53
+ const objectId = toObjectId(integrationId);
54
+ if (!objectId) return { acknowledged: true, deletedCount: 0 };
55
+ const result = await deleteOne(this.prisma, 'Integration', { _id: objectId });
56
+ const deleted = result?.n ?? 0;
57
+ return { acknowledged: true, deletedCount: deleted };
58
+ }
59
+
60
+ async findIntegrationByName(name) {
61
+ const doc = await findOne(this.prisma, 'Integration', { 'config.type': name });
62
+ if (!doc) {
63
+ throw new Error(`Integration with name ${name} not found`);
64
+ }
65
+ return this._mapIntegration(doc);
66
+ }
67
+
68
+ async findIntegrationById(id) {
69
+ const objectId = toObjectId(id);
70
+ if (!objectId) {
71
+ throw new Error(`Integration with id ${id} not found`);
72
+ }
73
+ const doc = await findOne(this.prisma, 'Integration', { _id: objectId });
74
+ if (!doc) {
75
+ throw new Error(`Integration with id ${id} not found`);
76
+ }
77
+ return this._mapIntegration(doc);
78
+ }
79
+
80
+ async updateIntegrationStatus(integrationId, status) {
81
+ const objectId = toObjectId(integrationId);
82
+ if (!objectId) return false;
83
+ await updateOne(
84
+ this.prisma,
85
+ 'Integration',
86
+ { _id: objectId },
87
+ {
88
+ $set: { status, updatedAt: new Date() },
89
+ }
90
+ );
91
+ return true;
92
+ }
93
+
94
+ async updateIntegrationMessages(
95
+ integrationId,
96
+ messageType,
97
+ messageTitle,
98
+ messageBody,
99
+ messageTimestamp
100
+ ) {
101
+ const objectId = toObjectId(integrationId);
102
+ if (!objectId) {
103
+ throw new Error(`Integration ${integrationId} not found`);
104
+ }
105
+ const existing = await findOne(this.prisma, 'Integration', { _id: objectId });
106
+ if (!existing) {
107
+ throw new Error(`Integration ${integrationId} not found`);
108
+ }
109
+ const messages = this._extractMessages(existing);
110
+ const list = Array.isArray(messages[messageType]) ? [...messages[messageType]] : [];
111
+ list.push({
112
+ title: messageTitle ?? null,
113
+ message: messageBody,
114
+ timestamp: messageTimestamp,
115
+ });
116
+ const updatedMessages = { ...messages, [messageType]: list };
117
+ await updateOne(
118
+ this.prisma,
119
+ 'Integration',
120
+ { _id: objectId },
121
+ {
122
+ $set: {
123
+ messages: updatedMessages,
124
+ errors: updatedMessages.errors ?? [],
125
+ warnings: updatedMessages.warnings ?? [],
126
+ info: updatedMessages.info ?? [],
127
+ logs: updatedMessages.logs ?? [],
128
+ updatedAt: new Date(),
129
+ },
130
+ }
131
+ );
132
+ return true;
133
+ }
134
+
135
+ async createIntegration(entities, userId, config) {
136
+ const now = new Date();
137
+ const document = {
138
+ userId: toObjectId(userId) || null,
139
+ config,
140
+ version: '0.0.0',
141
+ status: 'IN_CREATION',
142
+ entityIds: toObjectIdArray(entities),
143
+ messages: { errors: [], warnings: [], info: [], logs: [] },
144
+ errors: [],
145
+ warnings: [],
146
+ info: [],
147
+ logs: [],
148
+ createdAt: now,
149
+ updatedAt: now,
150
+ };
151
+ const insertedId = await insertOne(this.prisma, 'Integration', document);
152
+ const created = await findOne(this.prisma, 'Integration', { _id: insertedId });
153
+ if (!created) {
154
+ console.error('[IntegrationRepositoryDocumentDB] Integration not found after insert', {
155
+ insertedId: fromObjectId(insertedId),
156
+ userId,
157
+ config,
158
+ });
159
+ throw new Error(
160
+ 'Failed to create integration: Document not found after insert. ' +
161
+ 'This indicates a database consistency issue.'
162
+ );
163
+ }
164
+ return this._mapIntegration(created);
165
+ }
166
+
167
+ async findIntegrationByUserId(userId) {
168
+ const objectId = toObjectId(userId);
169
+ if (!objectId) return null;
170
+ const doc = await findOne(this.prisma, 'Integration', { userId: objectId });
171
+ return doc ? this._mapIntegration(doc) : null;
172
+ }
173
+
174
+ async updateIntegrationConfig(integrationId, config) {
175
+ if (config === null || config === undefined) {
176
+ throw new Error('Config parameter is required');
177
+ }
178
+ const objectId = toObjectId(integrationId);
179
+ if (!objectId) {
180
+ throw new Error(`Integration with id ${integrationId} not found`);
181
+ }
182
+ await updateOne(
183
+ this.prisma,
184
+ 'Integration',
185
+ { _id: objectId },
186
+ {
187
+ $set: {
188
+ config,
189
+ updatedAt: new Date(),
190
+ },
191
+ }
192
+ );
193
+ const updated = await findOne(this.prisma, 'Integration', { _id: objectId });
194
+ if (!updated) {
195
+ console.error('[IntegrationRepositoryDocumentDB] Integration not found after update', {
196
+ integrationId: fromObjectId(objectId),
197
+ config,
198
+ });
199
+ throw new Error(
200
+ 'Failed to update integration: Document not found after update. ' +
201
+ 'This indicates a database consistency issue.'
202
+ );
203
+ }
204
+ return this._mapIntegration(updated);
205
+ }
206
+
207
+ /**
208
+ * Atomically merge a patch into the existing config with a per-key
209
+ * $set (config.<k> for each patch key), then re-read to shape the
210
+ * return value — DocumentDB's raw update command doesn't return the
211
+ * post-update document directly.
212
+ *
213
+ * @param {string} integrationId - Integration ID
214
+ * @param {Object} patch - Keys to merge into the existing config
215
+ * @returns {Promise<Object>} Updated integration object
216
+ */
217
+ async patchIntegrationConfig(integrationId, patch) {
218
+ validateConfigPatch(patch);
219
+ const objectId = toObjectId(integrationId);
220
+ if (!objectId) {
221
+ throw new Error(`Integration with id ${integrationId} not found`);
222
+ }
223
+
224
+ const $set = { updatedAt: new Date() };
225
+ for (const [key, value] of Object.entries(patch)) {
226
+ $set[`config.${key}`] = value;
227
+ }
228
+
229
+ const result = await updateOne(
230
+ this.prisma,
231
+ 'Integration',
232
+ { _id: objectId },
233
+ { $set }
234
+ );
235
+ if (result.writeErrors?.length) {
236
+ throw new Error(
237
+ `Failed to patch integration config: ${result.writeErrors[0].errmsg}`
238
+ );
239
+ }
240
+ if (!result.n) {
241
+ throw new Error(`Integration with id ${integrationId} not found`);
242
+ }
243
+
244
+ const updated = await findOne(this.prisma, 'Integration', { _id: objectId });
245
+ if (!updated) {
246
+ console.error('[IntegrationRepositoryDocumentDB] Integration not found after update', {
247
+ integrationId: fromObjectId(objectId),
248
+ patch,
249
+ });
250
+ throw new Error(
251
+ 'Failed to update integration: Document not found after update. ' +
252
+ 'This indicates a database consistency issue.'
253
+ );
254
+ }
255
+ return this._mapIntegration(updated);
256
+ }
257
+
258
+ // Drain the full cursor so a deployment-wide report is never truncated.
259
+ async findAllForReport({ status, userId } = {}) {
260
+ const filter = {};
261
+ if (status) filter.status = status;
262
+ if (userId !== undefined && userId !== null) {
263
+ const objectId = toObjectId(userId);
264
+ // Invalid userId means no matches — don't fall through to an unfiltered whole-deployment query.
265
+ if (!objectId) return [];
266
+ filter.userId = objectId;
267
+ }
268
+
269
+ const docs = await findManyDrained(this.prisma, 'Integration', filter);
270
+
271
+ return docs.map((doc) => {
272
+ const errors = this._extractReportErrors(doc);
273
+ return {
274
+ id: fromObjectId(doc?._id),
275
+ type: doc?.config?.type ?? null,
276
+ status: doc?.status ?? null,
277
+ userId: fromObjectId(doc?.userId) ?? null,
278
+ version: doc?.version ?? null,
279
+ errorCount: Array.isArray(errors) ? errors.length : 0,
280
+ moduleCount: Array.isArray(doc?.entityIds)
281
+ ? doc.entityIds.length
282
+ : 0,
283
+ createdAt: doc?.createdAt ?? null,
284
+ updatedAt: doc?.updatedAt ?? null,
285
+ };
286
+ });
287
+ }
288
+
289
+ _extractReportErrors(doc) {
290
+ if (Array.isArray(doc?.errors)) return doc.errors;
291
+ if (Array.isArray(doc?.messages?.errors)) return doc.messages.errors;
292
+ return [];
293
+ }
294
+
295
+ _mapIntegration(doc) {
296
+ const messages = this._extractMessages(doc);
297
+ return {
298
+ id: fromObjectId(doc?._id),
299
+ entitiesIds: (doc?.entityIds || []).map((value) => fromObjectId(value)),
300
+ userId: fromObjectId(doc?.userId),
301
+ config: doc?.config ?? null,
302
+ version: doc?.version ?? null,
303
+ status: doc?.status ?? null,
304
+ messages,
305
+ createdAt: doc?.createdAt ?? null,
306
+ };
307
+ }
308
+
309
+ _extractMessages(doc) {
310
+ const base = doc?.messages && typeof doc.messages === 'object' ? doc.messages : {};
311
+ return {
312
+ errors: base.errors ?? doc?.errors ?? [],
313
+ warnings: base.warnings ?? doc?.warnings ?? [],
314
+ info: base.info ?? doc?.info ?? [],
315
+ logs: base.logs ?? doc?.logs ?? [],
316
+ };
317
+ }
318
+ }
319
+
320
+ module.exports = { IntegrationRepositoryDocumentDB };
321
+
322
+
@@ -0,0 +1,51 @@
1
+ const { IntegrationRepositoryMongo } = require('./integration-repository-mongo');
2
+ const { IntegrationRepositoryPostgres } = require('./integration-repository-postgres');
3
+ const {
4
+ IntegrationRepositoryDocumentDB,
5
+ } = require('./integration-repository-documentdb');
6
+ const config = require('../../database/config');
7
+
8
+ /**
9
+ * Integration Repository Factory
10
+ * Creates the appropriate repository adapter based on database type
11
+ *
12
+ * This implements the Factory pattern for Hexagonal Architecture:
13
+ * - Reads database type from app definition (backend/index.js)
14
+ * - Returns correct adapter (MongoDB or PostgreSQL)
15
+ * - Provides clear error for unsupported databases
16
+ *
17
+ * Usage:
18
+ * ```javascript
19
+ * const repository = createIntegrationRepository();
20
+ * ```
21
+ *
22
+ * @returns {IntegrationRepositoryInterface} Configured repository adapter
23
+ * @throws {Error} If database type is not supported
24
+ */
25
+ function createIntegrationRepository() {
26
+ const dbType = config.DB_TYPE;
27
+
28
+ switch (dbType) {
29
+ case 'mongodb':
30
+ return new IntegrationRepositoryMongo();
31
+
32
+ case 'postgresql':
33
+ return new IntegrationRepositoryPostgres();
34
+
35
+ case 'documentdb':
36
+ return new IntegrationRepositoryDocumentDB();
37
+
38
+ default:
39
+ throw new Error(
40
+ `Unsupported database type: ${dbType}. Supported values: 'mongodb', 'documentdb', 'postgresql'`
41
+ );
42
+ }
43
+ }
44
+
45
+ module.exports = {
46
+ createIntegrationRepository,
47
+ // Export adapters for direct testing
48
+ IntegrationRepositoryMongo,
49
+ IntegrationRepositoryPostgres,
50
+ IntegrationRepositoryDocumentDB,
51
+ };
@@ -0,0 +1,189 @@
1
+ /**
2
+ * Integration Repository Interface
3
+ * Abstract base class defining the contract for integration persistence adapters
4
+ *
5
+ * This follows the Port in Hexagonal Architecture:
6
+ * - Domain layer depends on this abstraction
7
+ * - Concrete adapters (MongoDB, PostgreSQL) implement this interface
8
+ * - Use cases receive repositories via dependency injection
9
+ *
10
+ * @abstract
11
+ */
12
+ class IntegrationRepositoryInterface {
13
+ /**
14
+ * Find all integrations for a user
15
+ *
16
+ * @param {string|number} userId - User ID
17
+ * @returns {Promise<Array>} Array of integration objects
18
+ * @abstract
19
+ */
20
+ async findIntegrationsByUserId(userId) {
21
+ throw new Error('Method findIntegrationsByUserId must be implemented by subclass');
22
+ }
23
+
24
+ /**
25
+ * Find integrations, optionally filtered by config type and/or status.
26
+ * With no filter, returns every integration.
27
+ *
28
+ * @param {Object} [filter={}]
29
+ * @param {string} [filter.type] - Integration type (config.type)
30
+ * @param {string} [filter.status] - Integration status
31
+ * @returns {Promise<Array>} Array of integration objects (possibly empty)
32
+ * @abstract
33
+ */
34
+ async findIntegrations(filter = {}) {
35
+ throw new Error('Method findIntegrations must be implemented by subclass');
36
+ }
37
+
38
+ /**
39
+ * Find every integration in a report-shaped projection, optionally
40
+ * filtered by status and/or owning user. Adapters must drain the full
41
+ * result set (no first-batch truncation) since this powers a
42
+ * deployment-wide scan.
43
+ *
44
+ * @param {Object} [filter={}]
45
+ * @param {string} [filter.status] - Integration status
46
+ * @param {string|number} [filter.userId] - Owning user ID
47
+ * @returns {Promise<Array<{id, type, status, userId, version, errorCount, moduleCount, createdAt, updatedAt}>>}
48
+ * @abstract
49
+ */
50
+ async findAllForReport(filter = {}) {
51
+ throw new Error('Method findAllForReport must be implemented by subclass');
52
+ }
53
+
54
+ /**
55
+ * Delete integration by ID
56
+ *
57
+ * @param {string|number} integrationId - Integration ID
58
+ * @returns {Promise<Object>} Deletion result
59
+ * @abstract
60
+ */
61
+ async deleteIntegrationById(integrationId) {
62
+ throw new Error('Method deleteIntegrationById must be implemented by subclass');
63
+ }
64
+
65
+ /**
66
+ * Find integration by name
67
+ *
68
+ * @param {string} name - Integration type name
69
+ * @returns {Promise<Object>} Integration object
70
+ * @abstract
71
+ */
72
+ async findIntegrationByName(name) {
73
+ throw new Error('Method findIntegrationByName must be implemented by subclass');
74
+ }
75
+
76
+ /**
77
+ * Find integration by ID
78
+ *
79
+ * @param {string|number} id - Integration ID
80
+ * @returns {Promise<Object>} Integration object
81
+ * @abstract
82
+ */
83
+ async findIntegrationById(id) {
84
+ throw new Error('Method findIntegrationById must be implemented by subclass');
85
+ }
86
+
87
+ /**
88
+ * Update integration status
89
+ *
90
+ * @param {string|number} integrationId - Integration ID
91
+ * @param {string} status - New status
92
+ * @returns {Promise<boolean>} Success indicator
93
+ * @abstract
94
+ */
95
+ async updateIntegrationStatus(integrationId, status) {
96
+ throw new Error('Method updateIntegrationStatus must be implemented by subclass');
97
+ }
98
+
99
+ /**
100
+ * Update integration messages
101
+ *
102
+ * @param {string|number} integrationId - Integration ID
103
+ * @param {string} messageType - Type of message (errors, warnings, info, logs)
104
+ * @param {string} messageTitle - Message title
105
+ * @param {string} messageBody - Message body
106
+ * @param {Date} messageTimestamp - Message timestamp
107
+ * @returns {Promise<boolean>} Success indicator
108
+ * @abstract
109
+ */
110
+ async updateIntegrationMessages(
111
+ integrationId,
112
+ messageType,
113
+ messageTitle,
114
+ messageBody,
115
+ messageTimestamp
116
+ ) {
117
+ throw new Error('Method updateIntegrationMessages must be implemented by subclass');
118
+ }
119
+
120
+ /**
121
+ * Create a new integration
122
+ *
123
+ * @param {Array<string|number>} entities - Array of entity IDs
124
+ * @param {string|number} userId - User ID
125
+ * @param {Object} config - Integration configuration
126
+ * @returns {Promise<Object>} Created integration object
127
+ * @abstract
128
+ */
129
+ async createIntegration(entities, userId, config) {
130
+ throw new Error('Method createIntegration must be implemented by subclass');
131
+ }
132
+
133
+ /**
134
+ * Find integration by user ID (returns single integration)
135
+ *
136
+ * @param {string|number} userId - User ID
137
+ * @returns {Promise<Object|null>} Integration object or null
138
+ * @abstract
139
+ */
140
+ async findIntegrationByUserId(userId) {
141
+ throw new Error('Method findIntegrationByUserId must be implemented by subclass');
142
+ }
143
+
144
+ /**
145
+ * Update integration configuration
146
+ *
147
+ * @param {string|number} integrationId - Integration ID
148
+ * @param {Object} config - Updated configuration object
149
+ * @returns {Promise<Object>} Updated integration object
150
+ * @abstract
151
+ */
152
+ async updateIntegrationConfig(integrationId, config) {
153
+ throw new Error('Method updateIntegrationConfig must be implemented by subclass');
154
+ }
155
+
156
+ /**
157
+ * Atomically merge a partial update into an integration's config. Keys
158
+ * not present in the patch are left untouched; concurrent patches with
159
+ * disjoint keys must both persist. Patch values may not be null or
160
+ * undefined — key deletion is only supported via updateIntegrationConfig.
161
+ *
162
+ * @param {string|number} integrationId - Integration ID
163
+ * @param {Object} patch - Keys to merge into the existing config
164
+ * @returns {Promise<Object>} Updated integration object
165
+ * @abstract
166
+ */
167
+ async patchIntegrationConfig(integrationId, patch) {
168
+ throw new Error('Method patchIntegrationConfig must be implemented by subclass');
169
+ }
170
+
171
+ /**
172
+ * Find all integrations whose entity set includes the given entity ID.
173
+ *
174
+ * Used by the authorization callback flow to walk up from a re-authorized
175
+ * entity to its parent integrations so that any in a broken state (ERROR,
176
+ * DISABLED) can be restored to ENABLED.
177
+ *
178
+ * @param {string|number} entityId - Entity ID
179
+ * @returns {Promise<Array>} Array of integration objects (possibly empty)
180
+ * @abstract
181
+ */
182
+ async findIntegrationsByEntityId(entityId) {
183
+ throw new Error(
184
+ 'Method findIntegrationsByEntityId must be implemented by subclass'
185
+ );
186
+ }
187
+ }
188
+
189
+ module.exports = { IntegrationRepositoryInterface };