@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,355 @@
1
+ const { prisma } = require('../../database/prisma');
2
+ const {
3
+ toObjectId,
4
+ fromObjectId,
5
+ findManyDrained,
6
+ findOne,
7
+ insertOne,
8
+ updateOne,
9
+ deleteOne,
10
+ } = require('../../database/documentdb-utils');
11
+ const {
12
+ CredentialRepositoryInterface,
13
+ } = require('./credential-repository-interface');
14
+ const { tallyActiveCredentialsByType } = require('./credential-active-type');
15
+ const {
16
+ DocumentDBEncryptionService,
17
+ } = require('../../database/documentdb-encryption-service');
18
+
19
+ /**
20
+ * Credential repository for DocumentDB.
21
+ * Uses DocumentDBEncryptionService for field-level encryption.
22
+ *
23
+ * Encrypted fields:
24
+ * - Credential.data.access_token
25
+ * - Credential.data.refresh_token
26
+ * - Credential.data.id_token
27
+ *
28
+ * SECURITY CRITICAL: All OAuth credentials must be encrypted at rest.
29
+ *
30
+ * @see DocumentDBEncryptionService
31
+ * @see encryption-schema-registry.js
32
+ */
33
+ class CredentialRepositoryDocumentDB extends CredentialRepositoryInterface {
34
+ constructor() {
35
+ super();
36
+ this.prisma = prisma;
37
+ this.encryptionService = new DocumentDBEncryptionService();
38
+ }
39
+
40
+ async findCredentialById(id) {
41
+ const objectId = toObjectId(id);
42
+ if (!objectId) return null;
43
+ const doc = await findOne(this.prisma, 'Credential', { _id: objectId });
44
+ if (!doc) return null;
45
+
46
+ const decryptedCredential = await this.encryptionService.decryptFields(
47
+ 'Credential',
48
+ doc
49
+ );
50
+ return this._mapCredentialById(decryptedCredential);
51
+ }
52
+
53
+ async updateAuthenticationStatus(credentialId, authIsValid) {
54
+ const objectId = toObjectId(credentialId);
55
+ if (!objectId) return { acknowledged: false, modifiedCount: 0 };
56
+ const result = await updateOne(
57
+ this.prisma,
58
+ 'Credential',
59
+ { _id: objectId },
60
+ {
61
+ $set: { authIsValid, updatedAt: new Date() },
62
+ }
63
+ );
64
+ const modified = result?.nModified ?? result?.n ?? 0;
65
+ return { acknowledged: true, modifiedCount: modified };
66
+ }
67
+
68
+ async deleteCredentialById(credentialId) {
69
+ const objectId = toObjectId(credentialId);
70
+ if (!objectId) return { acknowledged: true, deletedCount: 0 };
71
+ const result = await deleteOne(this.prisma, 'Credential', {
72
+ _id: objectId,
73
+ });
74
+ const deleted = result?.n ?? 0;
75
+ return { acknowledged: true, deletedCount: deleted };
76
+ }
77
+
78
+ async upsertCredential(credentialDetails) {
79
+ const { identifiers, details } = credentialDetails;
80
+ if (!identifiers)
81
+ throw new Error('identifiers required to upsert credential');
82
+ if (!identifiers.userId) {
83
+ throw new Error('userId required in identifiers');
84
+ }
85
+ if (!identifiers.externalId) {
86
+ throw new Error(
87
+ 'externalId required in identifiers to prevent credential collision. When multiple credentials exist for the same user, both userId and externalId are needed to uniquely identify which credential to update.'
88
+ );
89
+ }
90
+
91
+ const filter = this._buildIdentifierFilter(identifiers);
92
+ const existing = await findOne(this.prisma, 'Credential', filter);
93
+ const now = new Date();
94
+
95
+ const { authIsValid, ...oauthData } = details || {};
96
+
97
+ if (existing) {
98
+ const decryptedExisting =
99
+ await this.encryptionService.decryptFields(
100
+ 'Credential',
101
+ existing
102
+ );
103
+ const mergedData = {
104
+ ...(decryptedExisting.data || {}),
105
+ ...oauthData,
106
+ };
107
+
108
+ const updateDocument = {
109
+ userId: existing.userId,
110
+ externalId: existing.externalId,
111
+ authIsValid: authIsValid !== undefined ? authIsValid : existing.authIsValid,
112
+ data: mergedData,
113
+ updatedAt: now,
114
+ };
115
+
116
+ const encryptedUpdate = await this.encryptionService.encryptFields(
117
+ 'Credential',
118
+ { data: updateDocument.data }
119
+ );
120
+
121
+ await updateOne(
122
+ this.prisma,
123
+ 'Credential',
124
+ { _id: existing._id },
125
+ {
126
+ $set: {
127
+ userId: updateDocument.userId,
128
+ externalId: updateDocument.externalId,
129
+ authIsValid: updateDocument.authIsValid,
130
+ data: encryptedUpdate.data,
131
+ updatedAt: updateDocument.updatedAt,
132
+ },
133
+ }
134
+ );
135
+
136
+ const updated = await findOne(this.prisma, 'Credential', {
137
+ _id: existing._id,
138
+ });
139
+ const decryptedCredential =
140
+ await this.encryptionService.decryptFields(
141
+ 'Credential',
142
+ updated
143
+ );
144
+ return this._mapCredential(decryptedCredential);
145
+ }
146
+
147
+ const plainDocument = {
148
+ userId: toObjectId(identifiers.userId),
149
+ externalId: identifiers.externalId,
150
+ authIsValid: details.authIsValid,
151
+ data: { ...oauthData },
152
+ createdAt: now,
153
+ updatedAt: now,
154
+ };
155
+
156
+ const encryptedDocument = await this.encryptionService.encryptFields(
157
+ 'Credential',
158
+ plainDocument
159
+ );
160
+
161
+ const insertedId = await insertOne(
162
+ this.prisma,
163
+ 'Credential',
164
+ encryptedDocument
165
+ );
166
+
167
+ const created = await findOne(this.prisma, 'Credential', {
168
+ _id: insertedId,
169
+ });
170
+ const decryptedCredential = await this.encryptionService.decryptFields(
171
+ 'Credential',
172
+ created
173
+ );
174
+ return this._mapCredential(decryptedCredential);
175
+ }
176
+
177
+ async findCredential(filter) {
178
+ const query = this._buildFilter(filter);
179
+ const credential = await findOne(this.prisma, 'Credential', query);
180
+ if (!credential) return null;
181
+
182
+ const decryptedCredential = await this.encryptionService.decryptFields(
183
+ 'Credential',
184
+ credential
185
+ );
186
+ return this._mapCredential(decryptedCredential);
187
+ }
188
+
189
+ async updateCredential(credentialId, updates) {
190
+ const objectId = toObjectId(credentialId);
191
+ if (!objectId) return null;
192
+ const existing = await findOne(this.prisma, 'Credential', {
193
+ _id: objectId,
194
+ });
195
+ if (!existing) return null;
196
+
197
+ const { authIsValid, ...oauthData } = updates || {};
198
+
199
+ const decryptedExisting = await this.encryptionService.decryptFields(
200
+ 'Credential',
201
+ existing
202
+ );
203
+ const mergedData = { ...(decryptedExisting.data || {}), ...oauthData };
204
+
205
+ const updateDocument = {
206
+ userId: existing.userId,
207
+ externalId: existing.externalId,
208
+ authIsValid: authIsValid,
209
+ data: mergedData,
210
+ updatedAt: new Date(),
211
+ };
212
+
213
+ const encryptedUpdate = await this.encryptionService.encryptFields(
214
+ 'Credential',
215
+ { data: updateDocument.data }
216
+ );
217
+
218
+ await updateOne(
219
+ this.prisma,
220
+ 'Credential',
221
+ { _id: objectId },
222
+ {
223
+ $set: {
224
+ userId: updateDocument.userId,
225
+ externalId: updateDocument.externalId,
226
+ authIsValid: updateDocument.authIsValid,
227
+ data: encryptedUpdate.data,
228
+ updatedAt: updateDocument.updatedAt,
229
+ },
230
+ }
231
+ );
232
+
233
+ const updated = await findOne(this.prisma, 'Credential', {
234
+ _id: objectId,
235
+ });
236
+ const decryptedCredential = await this.encryptionService.decryptFields(
237
+ 'Credential',
238
+ updated
239
+ );
240
+ return this._mapCredential(decryptedCredential);
241
+ }
242
+
243
+ /**
244
+ * Count credentials active since a timestamp, grouped by integration type.
245
+ * Projected raw reads only; the encrypted `data` is never fetched, so secrets are never decrypted for this read.
246
+ * @returns {Promise<Array<{ integrationType: string, count: number }>>}
247
+ */
248
+ async countActiveByType({ since } = {}) {
249
+ const filter = {};
250
+ // Coerce to Date: a raw string never matches the BSON date $gte (type bracketing).
251
+ if (since) filter.updatedAt = { $gte: new Date(since) };
252
+
253
+ // Drained: a deployment-wide scan must not truncate at DocumentDB's ~101-doc first batch.
254
+ const activeCredentials = await findManyDrained(
255
+ this.prisma,
256
+ 'Credential',
257
+ filter,
258
+ { projection: { _id: 1 } }
259
+ );
260
+
261
+ const credentialIds = activeCredentials
262
+ .map((doc) => toObjectId(doc._id))
263
+ .filter(Boolean);
264
+
265
+ const entities = credentialIds.length
266
+ ? await findManyDrained(
267
+ this.prisma,
268
+ 'Entity',
269
+ { credentialId: { $in: credentialIds } },
270
+ { projection: { credentialId: 1, moduleName: 1 } }
271
+ )
272
+ : [];
273
+
274
+ const entitiesByCredential = new Map();
275
+ for (const entity of entities) {
276
+ const key = fromObjectId(entity.credentialId);
277
+ if (!entitiesByCredential.has(key)) {
278
+ entitiesByCredential.set(key, []);
279
+ }
280
+ entitiesByCredential
281
+ .get(key)
282
+ .push({ moduleName: entity.moduleName });
283
+ }
284
+
285
+ const credentials = activeCredentials.map((doc) => ({
286
+ entities: entitiesByCredential.get(fromObjectId(doc._id)) || [],
287
+ }));
288
+
289
+ return tallyActiveCredentialsByType(credentials);
290
+ }
291
+
292
+ _buildIdentifierFilter(identifiers) {
293
+ const filter = {};
294
+ if (identifiers._id || identifiers.id) {
295
+ const idObj = toObjectId(identifiers._id || identifiers.id);
296
+ if (idObj) filter._id = idObj;
297
+ }
298
+ if (identifiers.userId) {
299
+ filter.userId = toObjectId(identifiers.userId);
300
+ }
301
+ if (identifiers.externalId !== undefined) {
302
+ filter.externalId = identifiers.externalId;
303
+ }
304
+ return filter;
305
+ }
306
+
307
+ _buildFilter(filter) {
308
+ const query = {};
309
+ if (!filter) return query;
310
+ if (filter.credentialId || filter.id) {
311
+ const idObj = toObjectId(filter.credentialId || filter.id);
312
+ if (idObj) query._id = idObj;
313
+ }
314
+ if (filter.userId !== undefined) {
315
+ query.userId = filter.userId;
316
+ }
317
+ if (filter.externalId !== undefined) {
318
+ query.externalId = filter.externalId;
319
+ }
320
+ return query;
321
+ }
322
+
323
+ /**
324
+ * Map credential document to application format
325
+ * Matches MongoDB repository format
326
+ * @private
327
+ */
328
+ _mapCredential(doc) {
329
+ const data = doc?.data || {};
330
+ const id = fromObjectId(doc?._id);
331
+ const userId = doc?.userId;
332
+ return {
333
+ id,
334
+ userId,
335
+ externalId: doc?.externalId ?? null,
336
+ authIsValid: doc?.authIsValid ?? null,
337
+ ...data,
338
+ };
339
+ }
340
+
341
+ _mapCredentialById(doc) {
342
+ const data = doc?.data || {};
343
+ const id = fromObjectId(doc?._id);
344
+ const userId = doc?.userId;
345
+ return {
346
+ id,
347
+ userId,
348
+ externalId: doc?.externalId ?? null,
349
+ authIsValid: doc?.authIsValid ?? null,
350
+ ...data,
351
+ };
352
+ }
353
+ }
354
+
355
+ module.exports = { CredentialRepositoryDocumentDB };
@@ -0,0 +1,54 @@
1
+ const { CredentialRepositoryMongo } = require('./credential-repository-mongo');
2
+ const {
3
+ CredentialRepositoryPostgres,
4
+ } = require('./credential-repository-postgres');
5
+ const {
6
+ CredentialRepositoryDocumentDB,
7
+ } = require('./credential-repository-documentdb');
8
+ const config = require('../../database/config');
9
+
10
+ /**
11
+ * Credential Repository Factory
12
+ * Creates the appropriate repository adapter based on database type
13
+ *
14
+ * Database-specific implementations:
15
+ * - MongoDB: Uses String IDs (ObjectId), no conversion needed
16
+ * - PostgreSQL: Uses Int IDs, converts String ↔ Int
17
+ *
18
+ * All repository methods return String IDs regardless of database type,
19
+ * ensuring application layer consistency.
20
+ *
21
+ * Usage:
22
+ * ```javascript
23
+ * const repository = createCredentialRepository();
24
+ * ```
25
+ *
26
+ * @returns {CredentialRepositoryInterface} Configured repository adapter
27
+ */
28
+ function createCredentialRepository() {
29
+ const dbType = config.DB_TYPE;
30
+
31
+ switch (dbType) {
32
+ case 'mongodb':
33
+ return new CredentialRepositoryMongo();
34
+
35
+ case 'postgresql':
36
+ return new CredentialRepositoryPostgres();
37
+
38
+ case 'documentdb':
39
+ return new CredentialRepositoryDocumentDB();
40
+
41
+ default:
42
+ throw new Error(
43
+ `Unsupported database type: ${dbType}. Supported values: 'mongodb', 'documentdb', 'postgresql'`
44
+ );
45
+ }
46
+ }
47
+
48
+ module.exports = {
49
+ createCredentialRepository,
50
+ // Export adapters for direct testing
51
+ CredentialRepositoryMongo,
52
+ CredentialRepositoryPostgres,
53
+ CredentialRepositoryDocumentDB,
54
+ };
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Credential Repository Interface
3
+ * Abstract base class defining the contract for credential persistence adapters
4
+ *
5
+ * This follows the Port in Hexagonal Architecture:
6
+ * - Domain layer depends on this abstraction
7
+ * - Concrete adapters implement this interface
8
+ * - Use cases receive repositories via dependency injection
9
+ *
10
+ * Note: Currently, Credential model has identical structure across MongoDB and PostgreSQL,
11
+ * so CredentialRepository serves both. This interface exists for consistency and
12
+ * future-proofing if database-specific implementations become needed.
13
+ *
14
+ * @abstract
15
+ */
16
+ class CredentialRepositoryInterface {
17
+ /**
18
+ * Find credential by ID
19
+ *
20
+ * @param {string|number} id - Credential ID
21
+ * @returns {Promise<Object|null>} Credential object or null
22
+ * @abstract
23
+ */
24
+ async findCredentialById(id) {
25
+ throw new Error(
26
+ 'Method findCredentialById must be implemented by subclass'
27
+ );
28
+ }
29
+
30
+ /**
31
+ * Update authentication status
32
+ *
33
+ * @param {string|number} credentialId - Credential ID
34
+ * @param {boolean} authIsValid - Authentication validity status
35
+ * @returns {Promise<Object>} Update result
36
+ * @abstract
37
+ */
38
+ async updateAuthenticationStatus(credentialId, authIsValid) {
39
+ throw new Error(
40
+ 'Method updateAuthenticationStatus must be implemented by subclass'
41
+ );
42
+ }
43
+
44
+ /**
45
+ * Permanently remove a credential document
46
+ *
47
+ * @param {string|number} credentialId - Credential ID
48
+ * @returns {Promise<Object>} Deletion result
49
+ * @abstract
50
+ */
51
+ async deleteCredentialById(credentialId) {
52
+ throw new Error(
53
+ 'Method deleteCredentialById must be implemented by subclass'
54
+ );
55
+ }
56
+
57
+ /**
58
+ * Create or update credential matching identifiers
59
+ *
60
+ * @param {{identifiers: Object, details: Object}} credentialDetails
61
+ * @returns {Promise<Object>} The persisted credential
62
+ * @abstract
63
+ */
64
+ async upsertCredential(credentialDetails) {
65
+ throw new Error(
66
+ 'Method upsertCredential must be implemented by subclass'
67
+ );
68
+ }
69
+
70
+ /**
71
+ * Find a credential by filter criteria
72
+ *
73
+ * @param {Object} filter - Filter criteria
74
+ * @returns {Promise<Object|null>} Credential object or null if not found
75
+ * @abstract
76
+ */
77
+ async findCredential(filter) {
78
+ throw new Error(
79
+ 'Method findCredential must be implemented by subclass'
80
+ );
81
+ }
82
+
83
+ /**
84
+ * Update a credential by ID
85
+ *
86
+ * @param {string|number} credentialId - Credential ID
87
+ * @param {Object} updates - Fields to update
88
+ * @returns {Promise<Object|null>} Updated credential object or null if not found
89
+ * @abstract
90
+ */
91
+ async updateCredential(credentialId, updates) {
92
+ throw new Error(
93
+ 'Method updateCredential must be implemented by subclass'
94
+ );
95
+ }
96
+
97
+ /**
98
+ * Count credentials active (updatedAt >= since) grouped by integration type.
99
+ * Reads ONLY non-encrypted fields — never the encrypted `data` JSON.
100
+ *
101
+ * @param {Object} params
102
+ * @param {Date} [params.since] - Lower bound on updatedAt
103
+ * @returns {Promise<Array<{ integrationType: string, count: number }>>}
104
+ * @abstract
105
+ */
106
+ async countActiveByType(/* { since } */) {
107
+ throw new Error(
108
+ 'Method countActiveByType must be implemented by subclass'
109
+ );
110
+ }
111
+ }
112
+
113
+ module.exports = { CredentialRepositoryInterface };