@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,492 @@
1
+ const { prisma } = require('../../database/prisma');
2
+ const {
3
+ IntegrationRepositoryInterface,
4
+ } = require('./integration-repository-interface');
5
+ const { validateConfigPatch } = require('./config-patch-shared');
6
+ const { strictIntId } = require('./report-id');
7
+
8
+ /**
9
+ * PostgreSQL Integration Repository Adapter
10
+ * Handles integration persistence using Prisma with PostgreSQL
11
+ *
12
+ * PostgreSQL-specific characteristics:
13
+ * - Uses nested relations for foreign keys (user, entities)
14
+ * - Uses Int IDs with autoincrement
15
+ * - Requires ID conversion: String (app layer) ↔ Int (database)
16
+ * - All returned IDs are converted to strings for application layer consistency
17
+ * - Implicit join tables for many-to-many relationships (_EntityToIntegration)
18
+ * - Uses connect/disconnect syntax for relations
19
+ */
20
+ class IntegrationRepositoryPostgres extends IntegrationRepositoryInterface {
21
+ constructor() {
22
+ super();
23
+ this.prisma = prisma;
24
+ }
25
+
26
+ /**
27
+ * Convert string ID to integer for PostgreSQL queries
28
+ * @private
29
+ * @param {string|number|null|undefined} id - ID to convert
30
+ * @returns {number|null|undefined} Integer ID or null/undefined
31
+ * @throws {Error} If ID cannot be converted to integer
32
+ */
33
+ _convertId(id) {
34
+ if (id === null || id === undefined) return id;
35
+ const parsed = parseInt(id, 10);
36
+ if (isNaN(parsed)) {
37
+ throw new Error(`Invalid ID: ${id} cannot be converted to integer`);
38
+ }
39
+ return parsed;
40
+ }
41
+
42
+ /**
43
+ * Convert integration object IDs to strings
44
+ * @private
45
+ * @param {Object|null} integration - Integration object from database
46
+ * @returns {Object|null} Integration with string IDs
47
+ */
48
+ _convertIntegrationIds(integration) {
49
+ if (!integration) return integration;
50
+ return {
51
+ ...integration,
52
+ id: integration.id?.toString(),
53
+ userId: integration.userId?.toString(),
54
+ entities: integration.entities?.map(e => ({
55
+ ...e,
56
+ id: e.id?.toString(),
57
+ userId: e.userId?.toString(),
58
+ credentialId: e.credentialId?.toString()
59
+ }))
60
+ };
61
+ }
62
+
63
+ /**
64
+ * Find all integrations for a user
65
+ *
66
+ * @param {string} userId - User ID (string from application layer)
67
+ * @returns {Promise<Array>} Array of integration objects with string IDs
68
+ */
69
+ async findIntegrationsByUserId(userId) {
70
+ const intUserId = this._convertId(userId);
71
+ const integrations = await this.prisma.integration.findMany({
72
+ where: { userId: intUserId },
73
+ include: {
74
+ entities: true,
75
+ },
76
+ });
77
+
78
+ // Map to domain objects with string IDs
79
+ return integrations.map((integration) => {
80
+ const converted = this._convertIntegrationIds(integration);
81
+ return {
82
+ id: converted.id,
83
+ entitiesIds: converted.entities.map((e) => e.id),
84
+ userId: converted.userId,
85
+ config: converted.config,
86
+ version: converted.version,
87
+ status: converted.status,
88
+ messages: converted.messages,
89
+ createdAt: converted.createdAt,
90
+ };
91
+ });
92
+ }
93
+
94
+ /**
95
+ * Find integrations, optionally filtered by config type and/or status.
96
+ *
97
+ * @param {Object} [filter={}]
98
+ * @param {string} [filter.type] - Integration type (config.type)
99
+ * @param {string} [filter.status] - Integration status
100
+ * @returns {Promise<Array>} Array of integration objects (possibly empty)
101
+ */
102
+ async findIntegrations({ type, status } = {}) {
103
+ const where = {};
104
+ if (type) {
105
+ where.config = { path: ['type'], equals: type };
106
+ }
107
+ if (status) {
108
+ where.status = status;
109
+ }
110
+
111
+ const integrations = await this.prisma.integration.findMany({
112
+ where,
113
+ include: {
114
+ entities: true,
115
+ },
116
+ });
117
+
118
+ return integrations.map((integration) => {
119
+ const converted = this._convertIntegrationIds(integration);
120
+ return {
121
+ id: converted.id,
122
+ entitiesIds: converted.entities.map((e) => e.id),
123
+ userId: converted.userId,
124
+ config: converted.config,
125
+ version: converted.version,
126
+ status: converted.status,
127
+ messages: converted.messages,
128
+ createdAt: converted.createdAt,
129
+ };
130
+ });
131
+ }
132
+
133
+ /**
134
+ * Find every integration in a report-shaped projection.
135
+ *
136
+ * type lives in config.type (a JSON path not portably groupable across
137
+ * DBs); it is left in the row for the caller to bucket.
138
+ *
139
+ * @param {Object} [filter={}]
140
+ * @param {string} [filter.status] - Integration status
141
+ * @param {string|number} [filter.userId] - Owning user ID
142
+ * @returns {Promise<Array>} Report-shaped integration rows
143
+ */
144
+ async findAllForReport({ status, userId } = {}) {
145
+ const where = {};
146
+ if (status) where.status = status;
147
+ if (userId !== undefined && userId !== null) {
148
+ // Strict: parseInt would coerce '12abc'/'12.9' to 12 and read the wrong user.
149
+ where.userId = strictIntId(userId);
150
+ }
151
+
152
+ const integrations = await this.prisma.integration.findMany({
153
+ where,
154
+ include: { entities: { select: { id: true } } },
155
+ });
156
+
157
+ return integrations.map((integration) => ({
158
+ id: integration.id?.toString(),
159
+ type: integration.config?.type ?? null,
160
+ status: integration.status ?? null,
161
+ userId: integration.userId?.toString() ?? null,
162
+ version: integration.version ?? null,
163
+ errorCount: Array.isArray(integration.errors)
164
+ ? integration.errors.length
165
+ : 0,
166
+ moduleCount: integration.entities?.length ?? 0,
167
+ createdAt: integration.createdAt ?? null,
168
+ updatedAt: integration.updatedAt ?? null,
169
+ }));
170
+ }
171
+
172
+ /**
173
+ * Delete integration by ID
174
+ *
175
+ * @param {string} integrationId - Integration ID (string from application layer)
176
+ * @returns {Promise<Object>} Deletion result
177
+ */
178
+ async deleteIntegrationById(integrationId) {
179
+ const intId = this._convertId(integrationId);
180
+ await this.prisma.integration.delete({
181
+ where: { id: intId },
182
+ });
183
+
184
+ // Return Mongoose-compatible result
185
+ return { acknowledged: true, deletedCount: 1 };
186
+ }
187
+
188
+ /**
189
+ * Find integration by name
190
+ *
191
+ * @param {string} name - Integration type name
192
+ * @returns {Promise<Object>} Integration object with string IDs
193
+ */
194
+ async findIntegrationByName(name) {
195
+ const integration = await this.prisma.integration.findFirst({
196
+ where: {
197
+ config: {
198
+ path: ['type'],
199
+ equals: name,
200
+ },
201
+ },
202
+ include: {
203
+ entities: true,
204
+ },
205
+ });
206
+
207
+ if (!integration) {
208
+ throw new Error(`Integration with name ${name} not found`);
209
+ }
210
+
211
+ const converted = this._convertIntegrationIds(integration);
212
+ return {
213
+ id: converted.id,
214
+ entitiesIds: converted.entities.map((e) => e.id),
215
+ userId: converted.userId,
216
+ config: converted.config,
217
+ version: converted.version,
218
+ status: converted.status,
219
+ messages: converted.messages,
220
+ };
221
+ }
222
+
223
+ /**
224
+ * Find integration by ID
225
+ *
226
+ * @param {string} id - Integration ID (string from application layer)
227
+ * @returns {Promise<Object>} Integration object with string IDs
228
+ */
229
+ async findIntegrationById(id) {
230
+ const intId = this._convertId(id);
231
+ const integration = await this.prisma.integration.findUnique({
232
+ where: { id: intId },
233
+ include: {
234
+ entities: true,
235
+ },
236
+ });
237
+
238
+ if (!integration) {
239
+ throw new Error(`Integration with id ${id} not found`);
240
+ }
241
+
242
+ const converted = this._convertIntegrationIds(integration);
243
+ return {
244
+ id: converted.id,
245
+ entitiesIds: converted.entities.map((e) => e.id),
246
+ userId: converted.userId,
247
+ config: converted.config,
248
+ version: converted.version,
249
+ status: converted.status,
250
+ messages: converted.messages,
251
+ };
252
+ }
253
+
254
+ /**
255
+ * Update integration status
256
+ *
257
+ * @param {string} integrationId - Integration ID (string from application layer)
258
+ * @param {string} status - New status
259
+ * @returns {Promise<boolean>} Success indicator
260
+ */
261
+ async updateIntegrationStatus(integrationId, status) {
262
+ const intId = this._convertId(integrationId);
263
+ await this.prisma.integration.update({
264
+ where: { id: intId },
265
+ data: { status },
266
+ });
267
+
268
+ return true; // Mongoose compatibility
269
+ }
270
+
271
+ /**
272
+ * Update integration messages
273
+ *
274
+ * @param {string} integrationId - Integration ID (string from application layer)
275
+ * @param {string} messageType - Type of message (errors, warnings, info, logs)
276
+ * @param {string} messageTitle - Message title
277
+ * @param {string} messageBody - Message body
278
+ * @param {Date} messageTimestamp - Message timestamp
279
+ * @returns {Promise<boolean>} Success indicator
280
+ */
281
+ async updateIntegrationMessages(
282
+ integrationId,
283
+ messageType,
284
+ messageTitle,
285
+ messageBody,
286
+ messageTimestamp
287
+ ) {
288
+ const intId = this._convertId(integrationId);
289
+
290
+ // Get current integration
291
+ const integration = await this.prisma.integration.findUnique({
292
+ where: { id: intId },
293
+ });
294
+
295
+ if (!integration) {
296
+ throw new Error(`Integration ${integrationId} not found`);
297
+ }
298
+
299
+ // Parse existing messages (JSON field)
300
+ const messages = integration.messages || {};
301
+ const messageArray = Array.isArray(messages[messageType])
302
+ ? messages[messageType]
303
+ : [];
304
+
305
+ // Add new message
306
+ messageArray.push({
307
+ title: messageTitle,
308
+ message: messageBody,
309
+ timestamp: messageTimestamp,
310
+ });
311
+
312
+ // Update messages
313
+ await this.prisma.integration.update({
314
+ where: { id: intId },
315
+ data: {
316
+ [messageType]: messageArray,
317
+ },
318
+ });
319
+
320
+ return true; // Mongoose compatibility
321
+ }
322
+
323
+ /**
324
+ * Create a new integration
325
+ *
326
+ * PostgreSQL-specific: Uses nested relations with connect syntax
327
+ *
328
+ * @param {Array<string>} entities - Array of entity IDs (strings from application layer)
329
+ * @param {string} userId - User ID (string from application layer)
330
+ * @param {Object} config - Integration configuration
331
+ * @returns {Promise<Object>} Created integration object with string IDs
332
+ */
333
+ async createIntegration(entities, userId, config) {
334
+ const data = {
335
+ config,
336
+ version: '0.0.0',
337
+ };
338
+
339
+ // PostgreSQL: use nested relations with ID conversion
340
+ if (userId) {
341
+ data.user = { connect: { id: this._convertId(userId) } };
342
+ }
343
+ if (entities && entities.length > 0) {
344
+ data.entities = {
345
+ connect: entities.map((id) => ({ id: this._convertId(id) })),
346
+ };
347
+ }
348
+
349
+ const integration = await this.prisma.integration.create({
350
+ data,
351
+ include: {
352
+ entities: true,
353
+ },
354
+ });
355
+
356
+ const converted = this._convertIntegrationIds(integration);
357
+ return {
358
+ id: converted.id,
359
+ entitiesIds: converted.entities.map((e) => e.id),
360
+ userId: converted.userId,
361
+ config: converted.config,
362
+ version: converted.version,
363
+ status: converted.status,
364
+ messages: converted.messages,
365
+ };
366
+ }
367
+
368
+ /**
369
+ * Find integration by user ID (returns single integration)
370
+ *
371
+ * @param {string} userId - User ID (string from application layer)
372
+ * @returns {Promise<Object|null>} Integration object with string IDs or null
373
+ */
374
+ async findIntegrationByUserId(userId) {
375
+ const intUserId = this._convertId(userId);
376
+ const integration = await this.prisma.integration.findFirst({
377
+ where: { userId: intUserId },
378
+ include: {
379
+ entities: true,
380
+ },
381
+ });
382
+
383
+ if (!integration) {
384
+ return null;
385
+ }
386
+
387
+ const converted = this._convertIntegrationIds(integration);
388
+ return {
389
+ id: converted.id,
390
+ entitiesIds: converted.entities.map((e) => e.id),
391
+ userId: converted.userId,
392
+ config: converted.config,
393
+ version: converted.version,
394
+ status: converted.status,
395
+ messages: converted.messages,
396
+ };
397
+ }
398
+
399
+ /**
400
+ * Update integration configuration
401
+ *
402
+ * @param {string} integrationId - Integration ID (string from application layer)
403
+ * @param {Object} config - Updated configuration object
404
+ * @returns {Promise<Object>} Updated integration object with string IDs
405
+ */
406
+ async updateIntegrationConfig(integrationId, config) {
407
+ if (config === null || config === undefined) {
408
+ throw new Error('Config parameter is required');
409
+ }
410
+
411
+ const intId = this._convertId(integrationId);
412
+ const integration = await this.prisma.integration.update({
413
+ where: { id: intId },
414
+ data: { config },
415
+ include: {
416
+ entities: true,
417
+ },
418
+ });
419
+
420
+ const converted = this._convertIntegrationIds(integration);
421
+ return {
422
+ id: converted.id,
423
+ entitiesIds: converted.entities.map((e) => e.id),
424
+ userId: converted.userId,
425
+ config: converted.config,
426
+ version: converted.version,
427
+ status: converted.status,
428
+ messages: converted.messages,
429
+ };
430
+ }
431
+
432
+ /**
433
+ * Atomically merge a patch into the existing config with a single
434
+ * jsonb concatenation — the database does the merge, so there is no
435
+ * JS-side read-modify-write for concurrent callers to race on.
436
+ *
437
+ * @param {string} integrationId - Integration ID (string from application layer)
438
+ * @param {Object} patch - Keys to merge into the existing config
439
+ * @returns {Promise<Object>} Updated integration object with string IDs
440
+ */
441
+ async patchIntegrationConfig(integrationId, patch) {
442
+ validateConfigPatch(patch);
443
+
444
+ const intId = this._convertId(integrationId);
445
+ const affectedCount = await this.prisma.$executeRawUnsafe(
446
+ 'UPDATE "Integration" SET "config" = COALESCE("config", \'{}\'::jsonb) || $1::jsonb, "updatedAt" = NOW() WHERE "id" = $2',
447
+ JSON.stringify(patch),
448
+ intId
449
+ );
450
+
451
+ if (!affectedCount) {
452
+ throw new Error(`Integration with id ${integrationId} not found`);
453
+ }
454
+
455
+ return this.findIntegrationById(integrationId);
456
+ }
457
+
458
+ /**
459
+ * Find all integrations whose entity set includes the given entity ID.
460
+ *
461
+ * @param {string|number} entityId - Entity ID (string from application layer)
462
+ * @returns {Promise<Array>} Array of integration objects with string IDs (possibly empty)
463
+ */
464
+ async findIntegrationsByEntityId(entityId) {
465
+ const intEntityId = this._convertId(entityId);
466
+ const integrations = await this.prisma.integration.findMany({
467
+ where: {
468
+ entities: {
469
+ some: { id: intEntityId },
470
+ },
471
+ },
472
+ include: {
473
+ entities: true,
474
+ },
475
+ });
476
+
477
+ return integrations.map((integration) => {
478
+ const converted = this._convertIntegrationIds(integration);
479
+ return {
480
+ id: converted.id,
481
+ entitiesIds: converted.entities.map((e) => e.id),
482
+ userId: converted.userId,
483
+ config: converted.config,
484
+ version: converted.version,
485
+ status: converted.status,
486
+ messages: converted.messages,
487
+ };
488
+ });
489
+ }
490
+ }
491
+
492
+ module.exports = { IntegrationRepositoryPostgres };