@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,294 @@
1
+ const { prisma } = require('../../database/prisma');
2
+ const {
3
+ CredentialRepositoryInterface,
4
+ } = require('./credential-repository-interface');
5
+ const { tallyActiveCredentialsByType } = require('./credential-active-type');
6
+
7
+ /**
8
+ * MongoDB Credential Repository Adapter
9
+ * Handles OAuth credentials and API tokens persistence with MongoDB
10
+ *
11
+ * MongoDB-specific characteristics:
12
+ * - Uses String IDs (ObjectId)
13
+ * - No ID conversion needed (IDs are already strings)
14
+ * - Dynamic schema support via JSON field
15
+ */
16
+ class CredentialRepositoryMongo extends CredentialRepositoryInterface {
17
+ constructor() {
18
+ super();
19
+ this.prisma = prisma;
20
+ }
21
+
22
+ /**
23
+ * Find credential by ID
24
+ * Replaces: Credential.findById(id)
25
+ *
26
+ * @param {string} id - Credential ID
27
+ * @returns {Promise<Object|null>} Credential object or null
28
+ */
29
+ async findCredentialById(id) {
30
+ const credential = await this.prisma.credential.findUnique({
31
+ where: { id },
32
+ });
33
+
34
+ if (!credential) {
35
+ return null;
36
+ }
37
+
38
+ // Extract data from JSON field
39
+ const data = credential.data || {};
40
+
41
+ return {
42
+ id: credential.id,
43
+ userId: credential.userId,
44
+ externalId: credential.externalId,
45
+ authIsValid: credential.authIsValid,
46
+ ...data, // Spread OAuth tokens from JSON field
47
+ };
48
+ }
49
+
50
+ /**
51
+ * Update authentication status
52
+ * Replaces: Credential.updateOne({ _id: credentialId }, { $set: { authIsValid } })
53
+ *
54
+ * @param {string} credentialId - Credential ID
55
+ * @param {boolean} authIsValid - Authentication validity status
56
+ * @returns {Promise<Object>} Update result
57
+ */
58
+ async updateAuthenticationStatus(credentialId, authIsValid) {
59
+ await this.prisma.credential.update({
60
+ where: { id: credentialId },
61
+ data: { authIsValid },
62
+ });
63
+
64
+ return { acknowledged: true, modifiedCount: 1 };
65
+ }
66
+
67
+ /**
68
+ * Permanently remove a credential document
69
+ * Replaces: Credential.deleteOne({ _id: credentialId })
70
+ *
71
+ * @param {string} credentialId - Credential ID
72
+ * @returns {Promise<Object>} Deletion result
73
+ */
74
+ async deleteCredentialById(credentialId) {
75
+ try {
76
+ await this.prisma.credential.delete({
77
+ where: { id: credentialId },
78
+ });
79
+ return { acknowledged: true, deletedCount: 1 };
80
+ } catch (error) {
81
+ if (error.code === 'P2025') {
82
+ return { acknowledged: true, deletedCount: 0 };
83
+ }
84
+ throw error;
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Create or update credential matching identifiers
90
+ * Replaces: Credential.findOneAndUpdate(query, update, { upsert: true })
91
+ *
92
+ * @param {{identifiers: Object, details: Object}} credentialDetails
93
+ * @returns {Promise<Object>} The persisted credential
94
+ */
95
+ async upsertCredential(credentialDetails) {
96
+ const { identifiers, details } = credentialDetails;
97
+ if (!identifiers)
98
+ throw new Error('identifiers required to upsert credential');
99
+
100
+ if (!identifiers.userId) {
101
+ throw new Error('userId required in identifiers');
102
+ }
103
+ if (!identifiers.externalId) {
104
+ throw new Error(
105
+ 'externalId required in identifiers to prevent credential collision. ' +
106
+ 'When multiple credentials exist for the same user, both userId and externalId ' +
107
+ 'are needed to uniquely identify which credential to update.'
108
+ );
109
+ }
110
+
111
+ const where = this._convertIdentifiersToWhere(identifiers);
112
+
113
+ const { authIsValid, ...oauthData } = details;
114
+
115
+ const existing = await this.prisma.credential.findFirst({ where });
116
+
117
+ if (existing) {
118
+ const mergedData = { ...(existing.data || {}), ...oauthData };
119
+
120
+ const updated = await this.prisma.credential.update({
121
+ where: { id: existing.id },
122
+ data: {
123
+ userId: existing.userId,
124
+ externalId: existing.externalId,
125
+ authIsValid: authIsValid !== undefined ? authIsValid : existing.authIsValid,
126
+ data: mergedData,
127
+ },
128
+ });
129
+
130
+ return {
131
+ id: updated.id,
132
+ externalId: updated.externalId,
133
+ userId: updated.userId,
134
+ authIsValid: updated.authIsValid,
135
+ ...(updated.data || {}),
136
+ };
137
+ }
138
+
139
+ const created = await this.prisma.credential.create({
140
+ data: {
141
+ userId: identifiers.userId,
142
+ externalId: identifiers.externalId,
143
+ authIsValid: authIsValid,
144
+ data: oauthData,
145
+ },
146
+ });
147
+
148
+ return {
149
+ id: created.id,
150
+ externalId: created.externalId,
151
+ userId: created.userId,
152
+ authIsValid: created.authIsValid,
153
+ ...(created.data || {}),
154
+ };
155
+ }
156
+
157
+ /**
158
+ * Find a credential by filter criteria
159
+ * Replaces: Credential.findOne(query)
160
+ *
161
+ * @param {Object} filter
162
+ * @param {string} [filter.userId] - User ID
163
+ * @param {string} [filter.externalId] - External ID
164
+ * @param {string} [filter.credentialId] - Credential ID
165
+ * @returns {Promise<Object|null>} Credential object or null if not found
166
+ */
167
+ async findCredential(filter) {
168
+ const where = this._convertFilterToWhere(filter);
169
+
170
+ const credential = await this.prisma.credential.findFirst({
171
+ where,
172
+ });
173
+
174
+ if (!credential) {
175
+ return null;
176
+ }
177
+
178
+ const data = credential.data || {};
179
+
180
+ return {
181
+ id: credential.id,
182
+ userId: credential.userId,
183
+ externalId: credential.externalId,
184
+ authIsValid: credential.authIsValid,
185
+ access_token: data.access_token,
186
+ refresh_token: data.refresh_token,
187
+ ...data,
188
+ };
189
+ }
190
+
191
+ /**
192
+ * Update a credential by ID
193
+ * Replaces: Credential.findByIdAndUpdate(credentialId, { $set: updates })
194
+ *
195
+ * @param {string} credentialId - Credential ID
196
+ * @param {Object} updates - Fields to update
197
+ * @returns {Promise<Object|null>} Updated credential object or null if not found
198
+ */
199
+ async updateCredential(credentialId, updates) {
200
+ const existing = await this.prisma.credential.findUnique({
201
+ where: { id: credentialId },
202
+ });
203
+
204
+ if (!existing) {
205
+ return null;
206
+ }
207
+
208
+ const { authIsValid, ...oauthData } = updates;
209
+
210
+ const mergedData = { ...(existing.data || {}), ...oauthData };
211
+
212
+ const updated = await this.prisma.credential.update({
213
+ where: { id: credentialId },
214
+ data: {
215
+ userId: existing.userId,
216
+ externalId: existing.externalId,
217
+ authIsValid: authIsValid,
218
+ data: mergedData,
219
+ },
220
+ });
221
+
222
+ const data = updated.data || {};
223
+
224
+ return {
225
+ id: updated.id,
226
+ userId: updated.userId,
227
+ externalId: updated.externalId,
228
+ authIsValid: updated.authIsValid,
229
+ access_token: data.access_token,
230
+ refresh_token: data.refresh_token,
231
+ ...data,
232
+ };
233
+ }
234
+
235
+ /**
236
+ * Count credentials active since a timestamp, grouped by integration type.
237
+ *
238
+ * @param {Object} params
239
+ * @param {Date} [params.since] - Lower bound on updatedAt
240
+ * @returns {Promise<Array<{ integrationType: string, count: number }>>}
241
+ */
242
+ async countActiveByType({ since } = {}) {
243
+ const where = {};
244
+ if (since) where.updatedAt = { gte: since };
245
+
246
+ // Type lives on the related Entity.moduleName, not on Credential. Select
247
+ // only that field (+ id) so the encrypted `data` JSON is never decrypted.
248
+ const credentials = await this.prisma.credential.findMany({
249
+ where,
250
+ select: {
251
+ id: true,
252
+ entities: { select: { moduleName: true } },
253
+ },
254
+ });
255
+
256
+ return tallyActiveCredentialsByType(credentials);
257
+ }
258
+
259
+ /**
260
+ * Convert identifiers to Prisma where clause
261
+ * @private
262
+ * @param {Object} identifiers - Identifier fields
263
+ * @returns {Object} Prisma where clause
264
+ */
265
+ _convertIdentifiersToWhere(identifiers) {
266
+ const where = {};
267
+
268
+ if (identifiers._id) where.id = identifiers._id;
269
+ if (identifiers.id) where.id = identifiers.id;
270
+ if (identifiers.userId) where.userId = identifiers.userId;
271
+ if (identifiers.externalId) where.externalId = identifiers.externalId;
272
+
273
+ return where;
274
+ }
275
+
276
+ /**
277
+ * Convert filter to Prisma where clause
278
+ * @private
279
+ * @param {Object} filter - Filter criteria
280
+ * @returns {Object} Prisma where clause
281
+ */
282
+ _convertFilterToWhere(filter) {
283
+ const where = {};
284
+
285
+ if (filter.credentialId) where.id = filter.credentialId;
286
+ if (filter.id) where.id = filter.id;
287
+ if (filter.userId) where.userId = filter.userId;
288
+ if (filter.externalId) where.externalId = filter.externalId;
289
+
290
+ return where;
291
+ }
292
+ }
293
+
294
+ module.exports = { CredentialRepositoryMongo };
@@ -0,0 +1,312 @@
1
+ const { prisma } = require('../../database/prisma');
2
+ const {
3
+ CredentialRepositoryInterface,
4
+ } = require('./credential-repository-interface');
5
+ const { tallyActiveCredentialsByType } = require('./credential-active-type');
6
+
7
+ /**
8
+ * PostgreSQL Credential Repository Adapter
9
+ * Handles OAuth credentials and API tokens persistence with PostgreSQL
10
+ *
11
+ * PostgreSQL-specific characteristics:
12
+ * - Uses Int IDs with autoincrement
13
+ * - Requires ID conversion: String (app layer) ↔ Int (database)
14
+ * - All returned IDs are converted to strings for application layer consistency
15
+ */
16
+ class CredentialRepositoryPostgres extends CredentialRepositoryInterface {
17
+ constructor() {
18
+ super();
19
+ this.prisma = prisma;
20
+ }
21
+
22
+ /**
23
+ * Convert string ID to integer for PostgreSQL queries
24
+ * @private
25
+ * @param {string|number|null|undefined} id - ID to convert
26
+ * @returns {number|null|undefined} Integer ID or null/undefined
27
+ * @throws {Error} If ID cannot be converted to integer
28
+ */
29
+ _convertId(id) {
30
+ if (id === null || id === undefined) return id;
31
+ const parsed = parseInt(id, 10);
32
+ if (isNaN(parsed)) {
33
+ throw new Error(`Invalid ID: ${id} cannot be converted to integer`);
34
+ }
35
+ return parsed;
36
+ }
37
+
38
+ /**
39
+ * Find credential by ID
40
+ *
41
+ * @param {string} id - Credential ID (string from application layer)
42
+ * @returns {Promise<Object|null>} Credential object with string IDs or null
43
+ */
44
+ async findCredentialById(id) {
45
+ const intId = this._convertId(id);
46
+ const credential = await this.prisma.credential.findUnique({
47
+ where: { id: intId },
48
+ });
49
+
50
+ if (!credential) {
51
+ return null;
52
+ }
53
+
54
+ const data = credential.data || {};
55
+
56
+ return {
57
+ id: credential.id.toString(),
58
+ userId: credential.userId.toString(),
59
+ externalId: credential.externalId,
60
+ authIsValid: credential.authIsValid,
61
+ ...data, // Spread OAuth tokens from JSON field
62
+ };
63
+ }
64
+
65
+ /**
66
+ * Update authentication status
67
+ *
68
+ * @param {string} credentialId - Credential ID (string from application layer)
69
+ * @param {boolean} authIsValid - Authentication validity status
70
+ * @returns {Promise<Object>} Update result
71
+ */
72
+ async updateAuthenticationStatus(credentialId, authIsValid) {
73
+ const intId = this._convertId(credentialId);
74
+ await this.prisma.credential.update({
75
+ where: { id: intId },
76
+ data: { authIsValid },
77
+ });
78
+
79
+ return { acknowledged: true, modifiedCount: 1 };
80
+ }
81
+
82
+ /**
83
+ * Permanently remove a credential document
84
+ *
85
+ * @param {string} credentialId - Credential ID (string from application layer)
86
+ * @returns {Promise<Object>} Deletion result
87
+ */
88
+ async deleteCredentialById(credentialId) {
89
+ try {
90
+ const intId = this._convertId(credentialId);
91
+ await this.prisma.credential.delete({
92
+ where: { id: intId },
93
+ });
94
+ return { acknowledged: true, deletedCount: 1 };
95
+ } catch (error) {
96
+ if (error.code === 'P2025') {
97
+ // Record not found
98
+ return { acknowledged: true, deletedCount: 0 };
99
+ }
100
+ throw error;
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Create or update credential matching identifiers
106
+ *
107
+ * @param {{identifiers: Object, details: Object}} credentialDetails
108
+ * @returns {Promise<Object>} The persisted credential with string IDs
109
+ */
110
+ async upsertCredential(credentialDetails) {
111
+ const { identifiers, details } = credentialDetails;
112
+ if (!identifiers)
113
+ throw new Error('identifiers required to upsert credential');
114
+
115
+ if (!identifiers.userId) {
116
+ throw new Error('userId required in identifiers');
117
+ }
118
+ if (!identifiers.externalId) {
119
+ throw new Error(
120
+ 'externalId required in identifiers to prevent credential collision. ' +
121
+ 'When multiple credentials exist for the same user, both userId and externalId ' +
122
+ 'are needed to uniquely identify which credential to update.'
123
+ );
124
+ }
125
+
126
+ const where = this._convertIdentifiersToWhere(identifiers);
127
+
128
+ const { externalId } = identifiers;
129
+
130
+ const { authIsValid, ...oauthData } = details;
131
+
132
+ const existing = await this.prisma.credential.findFirst({ where });
133
+
134
+ if (existing) {
135
+ const mergedData = { ...(existing.data || {}), ...oauthData };
136
+
137
+ const updated = await this.prisma.credential.update({
138
+ where: { id: existing.id },
139
+ data: {
140
+ userId: this._convertId(existing.userId),
141
+ externalId: existing.externalId,
142
+ authIsValid: authIsValid !== undefined ? authIsValid : existing.authIsValid,
143
+ data: mergedData,
144
+ },
145
+ });
146
+
147
+ return {
148
+ id: updated.id.toString(),
149
+ externalId: updated.externalId,
150
+ userId: updated.userId?.toString(),
151
+ authIsValid: updated.authIsValid,
152
+ ...(updated.data || {}),
153
+ };
154
+ }
155
+
156
+ const created = await this.prisma.credential.create({
157
+ data: {
158
+ // Use userId from where clause
159
+ userId: where.userId,
160
+ externalId,
161
+ authIsValid: authIsValid,
162
+ data: oauthData,
163
+ },
164
+ });
165
+
166
+ return {
167
+ id: created.id.toString(),
168
+ externalId: created.externalId,
169
+ userId: created.userId?.toString(),
170
+ authIsValid: created.authIsValid,
171
+ ...(created.data || {}),
172
+ };
173
+ }
174
+
175
+ /**
176
+ * Find a credential by filter criteria
177
+ *
178
+ * @param {Object} filter
179
+ * @param {string} [filter.userId] - User ID (string from application layer)
180
+ * @param {string} [filter.externalId] - External ID
181
+ * @param {string} [filter.credentialId] - Credential ID (string from application layer)
182
+ * @returns {Promise<Object|null>} Credential object with string IDs or null if not found
183
+ */
184
+ async findCredential(filter) {
185
+ const where = this._convertFilterToWhere(filter);
186
+
187
+ const credential = await this.prisma.credential.findFirst({
188
+ where,
189
+ });
190
+
191
+ if (!credential) {
192
+ return null;
193
+ }
194
+
195
+ const data = credential.data || {};
196
+
197
+ return {
198
+ id: credential.id.toString(),
199
+ userId: credential.userId?.toString(),
200
+ externalId: credential.externalId,
201
+ authIsValid: credential.authIsValid,
202
+ access_token: data.access_token,
203
+ refresh_token: data.refresh_token,
204
+ ...data,
205
+ };
206
+ }
207
+
208
+ /**
209
+ * Update a credential by ID
210
+ *
211
+ * @param {string} credentialId - Credential ID (string from application layer)
212
+ * @param {Object} updates - Fields to update
213
+ * @returns {Promise<Object|null>} Updated credential object with string IDs or null if not found
214
+ */
215
+ async updateCredential(credentialId, updates) {
216
+ const intId = this._convertId(credentialId);
217
+ const existing = await this.prisma.credential.findUnique({
218
+ where: { id: intId },
219
+ });
220
+
221
+ if (!existing) {
222
+ return null;
223
+ }
224
+
225
+ const { authIsValid, ...oauthData } = updates;
226
+
227
+ const mergedData = { ...(existing.data || {}), ...oauthData };
228
+
229
+ const updated = await this.prisma.credential.update({
230
+ where: { id: intId },
231
+ data: {
232
+ userId: this._convertId(existing.userId),
233
+ externalId: existing.externalId,
234
+ authIsValid: authIsValid,
235
+ data: mergedData,
236
+ },
237
+ });
238
+
239
+ const data = updated.data || {};
240
+
241
+ return {
242
+ id: updated.id.toString(),
243
+ userId: updated.userId?.toString(),
244
+ externalId: updated.externalId,
245
+ authIsValid: updated.authIsValid,
246
+ access_token: data.access_token,
247
+ refresh_token: data.refresh_token,
248
+ ...data,
249
+ };
250
+ }
251
+
252
+ /**
253
+ * Count credentials active since a timestamp, grouped by integration type.
254
+ *
255
+ * @param {Object} params
256
+ * @param {Date} [params.since] - Lower bound on updatedAt
257
+ * @returns {Promise<Array<{ integrationType: string, count: number }>>}
258
+ */
259
+ async countActiveByType({ since } = {}) {
260
+ const where = {};
261
+ if (since) where.updatedAt = { gte: since };
262
+
263
+ // Select only the entity moduleName (+ id) so the encrypted `data` JSON
264
+ // is never read and the encryption extension has nothing to decrypt.
265
+ const credentials = await this.prisma.credential.findMany({
266
+ where,
267
+ select: {
268
+ id: true,
269
+ entities: { select: { moduleName: true } },
270
+ },
271
+ });
272
+
273
+ return tallyActiveCredentialsByType(credentials);
274
+ }
275
+
276
+ /**
277
+ * Convert identifiers to Prisma where clause (converting IDs to Int)
278
+ * @private
279
+ * @param {Object} identifiers - Identifier fields
280
+ * @returns {Object} Prisma where clause with Int IDs
281
+ */
282
+ _convertIdentifiersToWhere(identifiers) {
283
+ const where = {};
284
+
285
+ if (identifiers.id) where.id = this._convertId(identifiers.id);
286
+ if (identifiers.userId)
287
+ where.userId = this._convertId(identifiers.userId);
288
+ if (identifiers.externalId) where.externalId = identifiers.externalId;
289
+
290
+ return where;
291
+ }
292
+
293
+ /**
294
+ * Convert filter to Prisma where clause (converting IDs to Int)
295
+ * @private
296
+ * @param {Object} filter - Filter criteria
297
+ * @returns {Object} Prisma where clause with Int IDs
298
+ */
299
+ _convertFilterToWhere(filter) {
300
+ const where = {};
301
+
302
+ if (filter.credentialId)
303
+ where.id = this._convertId(filter.credentialId);
304
+ if (filter.id) where.id = this._convertId(filter.id);
305
+ if (filter.userId) where.userId = this._convertId(filter.userId);
306
+ if (filter.externalId) where.externalId = filter.externalId;
307
+
308
+ return where;
309
+ }
310
+ }
311
+
312
+ module.exports = { CredentialRepositoryPostgres };