@friggframework/core 2.0.0-next.12 → 2.0.0-next.120

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (410) hide show
  1. package/.eslintrc.json +18 -1
  2. package/CLAUDE.md +830 -0
  3. package/README.md +996 -50
  4. package/admin-scripts/index.js +52 -0
  5. package/admin-scripts/repositories/admin-script-execution-repository-documentdb.js +21 -0
  6. package/admin-scripts/repositories/admin-script-execution-repository-factory.js +51 -0
  7. package/admin-scripts/repositories/admin-script-execution-repository-interface.js +171 -0
  8. package/admin-scripts/repositories/admin-script-execution-repository-mongo.js +238 -0
  9. package/admin-scripts/repositories/admin-script-execution-repository-postgres.js +278 -0
  10. package/admin-scripts/repositories/script-schedule-repository-documentdb.js +21 -0
  11. package/admin-scripts/repositories/script-schedule-repository-factory.js +51 -0
  12. package/admin-scripts/repositories/script-schedule-repository-interface.js +108 -0
  13. package/admin-scripts/repositories/script-schedule-repository-mongo.js +179 -0
  14. package/admin-scripts/repositories/script-schedule-repository-postgres.js +210 -0
  15. package/application/commands/README.md +451 -0
  16. package/application/commands/admin-script-commands.js +359 -0
  17. package/application/commands/credential-commands.js +262 -0
  18. package/application/commands/entity-commands.js +294 -0
  19. package/application/commands/integration-commands.js +419 -0
  20. package/application/commands/integration-mapping-commands.js +25 -0
  21. package/application/commands/process-commands.js +135 -0
  22. package/application/commands/report-commands.js +188 -0
  23. package/application/commands/scheduler-commands.js +263 -0
  24. package/application/commands/usage-commands.js +56 -0
  25. package/application/commands/user-commands.js +312 -0
  26. package/application/index.js +83 -0
  27. package/artifacts/repositories/artifact-repository-factory.js +19 -0
  28. package/artifacts/repositories/artifact-repository-interface.js +27 -0
  29. package/artifacts/repositories/artifact-repository-local.js +42 -0
  30. package/artifacts/repositories/artifact-repository-s3.js +61 -0
  31. package/assertions/index.js +0 -3
  32. package/core/CLAUDE.md +715 -0
  33. package/core/Worker.js +55 -24
  34. package/core/create-handler.js +121 -38
  35. package/core/index.js +8 -1
  36. package/core/invocation-scope.js +225 -0
  37. package/core/parameters-to-env.js +257 -0
  38. package/core/secrets-to-env.js +7 -6
  39. package/core/ssm-preload.mjs +34 -0
  40. package/credential/repositories/credential-active-type.js +32 -0
  41. package/credential/repositories/credential-repository-documentdb.js +355 -0
  42. package/credential/repositories/credential-repository-factory.js +54 -0
  43. package/credential/repositories/credential-repository-interface.js +113 -0
  44. package/credential/repositories/credential-repository-mongo.js +294 -0
  45. package/credential/repositories/credential-repository-postgres.js +312 -0
  46. package/credential/repositories/credential-repository.js +300 -0
  47. package/credential/use-cases/get-credential-for-user.js +25 -0
  48. package/credential/use-cases/update-authentication-status.js +15 -0
  49. package/database/MONGODB_TRANSACTION_FIX.md +198 -0
  50. package/database/adapters/lambda-invoker.js +97 -0
  51. package/database/config.js +147 -0
  52. package/database/documentdb-encryption-service.js +334 -0
  53. package/database/documentdb-utils.js +196 -0
  54. package/database/encryption/README.md +863 -0
  55. package/database/encryption/documentdb-encryption-service.md +3575 -0
  56. package/database/encryption/encryption-schema-registry.js +404 -0
  57. package/database/encryption/field-encryption-service.js +254 -0
  58. package/database/encryption/integration-mapping-encryption.js +97 -0
  59. package/database/encryption/logger.js +82 -0
  60. package/database/encryption/prisma-encryption-extension.js +241 -0
  61. package/database/index.js +21 -21
  62. package/database/prisma.js +182 -0
  63. package/database/repositories/health-check-repository-documentdb.js +138 -0
  64. package/database/repositories/health-check-repository-factory.js +48 -0
  65. package/database/repositories/health-check-repository-interface.js +82 -0
  66. package/database/repositories/health-check-repository-mongodb.js +89 -0
  67. package/database/repositories/health-check-repository-postgres.js +82 -0
  68. package/database/repositories/migration-status-repository-s3.js +137 -0
  69. package/database/use-cases/check-database-health-use-case.js +29 -0
  70. package/database/use-cases/check-database-state-use-case.js +81 -0
  71. package/database/use-cases/check-encryption-health-use-case.js +83 -0
  72. package/database/use-cases/get-database-state-via-worker-use-case.js +61 -0
  73. package/database/use-cases/get-migration-status-use-case.js +93 -0
  74. package/database/use-cases/resolve-migration-via-worker-use-case.js +49 -0
  75. package/database/use-cases/run-database-migration-use-case.js +139 -0
  76. package/database/use-cases/test-encryption-use-case.js +253 -0
  77. package/database/use-cases/trigger-database-migration-use-case.js +157 -0
  78. package/database/utils/mongodb-collection-utils.js +94 -0
  79. package/database/utils/mongodb-schema-init.js +108 -0
  80. package/database/utils/prisma-runner.js +491 -0
  81. package/database/utils/prisma-schema-parser.js +182 -0
  82. package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +517 -0
  83. package/encrypt/Cryptor.js +34 -168
  84. package/encrypt/index.js +1 -2
  85. package/errors/client-safe-error.js +26 -0
  86. package/errors/fetch-error.js +59 -57
  87. package/errors/index.js +6 -0
  88. package/errors/mapping-already-exists-error.js +14 -0
  89. package/generated/prisma-mongodb/client.d.ts +1 -0
  90. package/generated/prisma-mongodb/client.js +5 -0
  91. package/generated/prisma-mongodb/default.d.ts +1 -0
  92. package/generated/prisma-mongodb/default.js +5 -0
  93. package/generated/prisma-mongodb/edge.d.ts +1 -0
  94. package/generated/prisma-mongodb/edge.js +386 -0
  95. package/generated/prisma-mongodb/index-browser.js +368 -0
  96. package/generated/prisma-mongodb/index.d.ts +27065 -0
  97. package/generated/prisma-mongodb/index.js +411 -0
  98. package/generated/prisma-mongodb/libquery_engine-debian-openssl-3.0.x.so.node +0 -0
  99. package/generated/prisma-mongodb/libquery_engine-rhel-openssl-3.0.x.so.node +0 -0
  100. package/generated/prisma-mongodb/package.json +183 -0
  101. package/generated/prisma-mongodb/runtime/edge-esm.js +35 -0
  102. package/generated/prisma-mongodb/runtime/edge.js +35 -0
  103. package/generated/prisma-mongodb/runtime/index-browser.d.ts +370 -0
  104. package/generated/prisma-mongodb/runtime/index-browser.js +17 -0
  105. package/generated/prisma-mongodb/runtime/library.d.ts +3982 -0
  106. package/generated/prisma-mongodb/runtime/library.js +147 -0
  107. package/generated/prisma-mongodb/runtime/react-native.js +84 -0
  108. package/generated/prisma-mongodb/runtime/wasm-compiler-edge.js +85 -0
  109. package/generated/prisma-mongodb/runtime/wasm-engine-edge.js +38 -0
  110. package/generated/prisma-mongodb/schema.prisma +455 -0
  111. package/generated/prisma-mongodb/wasm-edge-light-loader.mjs +5 -0
  112. package/generated/prisma-mongodb/wasm-worker-loader.mjs +5 -0
  113. package/generated/prisma-mongodb/wasm.d.ts +1 -0
  114. package/generated/prisma-mongodb/wasm.js +393 -0
  115. package/generated/prisma-postgresql/client.d.ts +1 -0
  116. package/generated/prisma-postgresql/client.js +5 -0
  117. package/generated/prisma-postgresql/default.d.ts +1 -0
  118. package/generated/prisma-postgresql/default.js +5 -0
  119. package/generated/prisma-postgresql/edge.d.ts +1 -0
  120. package/generated/prisma-postgresql/edge.js +407 -0
  121. package/generated/prisma-postgresql/index-browser.js +389 -0
  122. package/generated/prisma-postgresql/index.d.ts +29904 -0
  123. package/generated/prisma-postgresql/index.js +432 -0
  124. package/generated/prisma-postgresql/libquery_engine-debian-openssl-3.0.x.so.node +0 -0
  125. package/generated/prisma-postgresql/libquery_engine-rhel-openssl-3.0.x.so.node +0 -0
  126. package/generated/prisma-postgresql/package.json +183 -0
  127. package/generated/prisma-postgresql/query_engine_bg.js +2 -0
  128. package/generated/prisma-postgresql/query_engine_bg.wasm +0 -0
  129. package/generated/prisma-postgresql/runtime/edge-esm.js +35 -0
  130. package/generated/prisma-postgresql/runtime/edge.js +35 -0
  131. package/generated/prisma-postgresql/runtime/index-browser.d.ts +370 -0
  132. package/generated/prisma-postgresql/runtime/index-browser.js +17 -0
  133. package/generated/prisma-postgresql/runtime/library.d.ts +3982 -0
  134. package/generated/prisma-postgresql/runtime/library.js +147 -0
  135. package/generated/prisma-postgresql/runtime/react-native.js +84 -0
  136. package/generated/prisma-postgresql/runtime/wasm-compiler-edge.js +85 -0
  137. package/generated/prisma-postgresql/runtime/wasm-engine-edge.js +38 -0
  138. package/generated/prisma-postgresql/schema.prisma +436 -0
  139. package/generated/prisma-postgresql/wasm-edge-light-loader.mjs +5 -0
  140. package/generated/prisma-postgresql/wasm-worker-loader.mjs +5 -0
  141. package/generated/prisma-postgresql/wasm.d.ts +1 -0
  142. package/generated/prisma-postgresql/wasm.js +414 -0
  143. package/handlers/WEBHOOKS.md +682 -0
  144. package/handlers/app-definition-loader.js +103 -0
  145. package/handlers/app-handler-helpers.js +20 -6
  146. package/handlers/backend-utils.js +272 -46
  147. package/handlers/database-migration-handler.js +236 -0
  148. package/handlers/integration-event-dispatcher.js +68 -0
  149. package/handlers/middleware/admin-auth.js +73 -0
  150. package/handlers/routers/HEALTHCHECK.md +342 -0
  151. package/handlers/routers/auth.js +4 -15
  152. package/handlers/routers/db-migration.handler.js +29 -0
  153. package/handlers/routers/db-migration.js +329 -0
  154. package/handlers/routers/health.js +518 -0
  155. package/handlers/routers/integration-defined-routers.js +85 -10
  156. package/handlers/routers/integration-webhook-routers.js +87 -0
  157. package/handlers/routers/user.js +27 -5
  158. package/handlers/routers/websocket.js +31 -9
  159. package/handlers/use-cases/check-external-apis-health-use-case.js +81 -0
  160. package/handlers/use-cases/check-integrations-health-use-case.js +44 -0
  161. package/handlers/workers/db-migration.js +438 -0
  162. package/handlers/workers/dlq-processor.js +89 -0
  163. package/handlers/workers/integration-defined-workers.js +13 -7
  164. package/index.js +123 -47
  165. package/infrastructure/scheduler/eventbridge-scheduler-adapter.js +184 -0
  166. package/infrastructure/scheduler/index.js +33 -0
  167. package/infrastructure/scheduler/mock-scheduler-adapter.js +143 -0
  168. package/infrastructure/scheduler/scheduler-service-factory.js +73 -0
  169. package/infrastructure/scheduler/scheduler-service-interface.js +47 -0
  170. package/integrations/EXTENSIONS.md +240 -0
  171. package/integrations/WEBHOOK-QUICKSTART.md +151 -0
  172. package/integrations/extension.js +254 -0
  173. package/integrations/index.js +20 -10
  174. package/integrations/integration-base.js +777 -74
  175. package/integrations/integration-router.js +399 -180
  176. package/integrations/options.js +1 -1
  177. package/integrations/repositories/config-patch-shared.js +43 -0
  178. package/integrations/repositories/integration-mapping-query-pipeline.js +152 -0
  179. package/integrations/repositories/integration-mapping-query.js +193 -0
  180. package/integrations/repositories/integration-mapping-repository-documentdb.js +406 -0
  181. package/integrations/repositories/integration-mapping-repository-factory.js +57 -0
  182. package/integrations/repositories/integration-mapping-repository-interface.js +183 -0
  183. package/integrations/repositories/integration-mapping-repository-mongo.js +284 -0
  184. package/integrations/repositories/integration-mapping-repository-postgres.js +403 -0
  185. package/integrations/repositories/integration-mapping-repository.js +185 -0
  186. package/integrations/repositories/integration-repository-documentdb.js +354 -0
  187. package/integrations/repositories/integration-repository-factory.js +51 -0
  188. package/integrations/repositories/integration-repository-interface.js +219 -0
  189. package/integrations/repositories/integration-repository-mongo.js +502 -0
  190. package/integrations/repositories/integration-repository-postgres.js +550 -0
  191. package/integrations/repositories/process-repository-documentdb.js +311 -0
  192. package/integrations/repositories/process-repository-factory.js +53 -0
  193. package/integrations/repositories/process-repository-interface.js +136 -0
  194. package/integrations/repositories/process-repository-mongo.js +262 -0
  195. package/integrations/repositories/process-repository-postgres.js +380 -0
  196. package/integrations/repositories/process-update-ops-shared.js +112 -0
  197. package/integrations/repositories/report-id.js +13 -0
  198. package/integrations/tests/doubles/config-capturing-integration.js +81 -0
  199. package/integrations/tests/doubles/dummy-integration-class.js +113 -0
  200. package/integrations/tests/doubles/test-integration-repository.js +146 -0
  201. package/integrations/use-cases/add-entities-to-integration.js +92 -0
  202. package/integrations/use-cases/create-integration.js +253 -0
  203. package/integrations/use-cases/create-process.js +130 -0
  204. package/integrations/use-cases/delete-integration-for-user.js +130 -0
  205. package/integrations/use-cases/find-integration-by-entity-external-id.js +74 -0
  206. package/integrations/use-cases/find-integration-context-by-external-entity-id.js +76 -0
  207. package/integrations/use-cases/get-integration-for-user.js +78 -0
  208. package/integrations/use-cases/get-integration-instance-by-definition.js +67 -0
  209. package/integrations/use-cases/get-integration-instance.js +83 -0
  210. package/integrations/use-cases/get-integrations-for-user.js +88 -0
  211. package/integrations/use-cases/get-possible-integrations.js +27 -0
  212. package/integrations/use-cases/get-process.js +89 -0
  213. package/integrations/use-cases/index.js +19 -0
  214. package/integrations/use-cases/list-integrations-by-entity-external-id.js +46 -0
  215. package/integrations/use-cases/load-integration-context.js +71 -0
  216. package/integrations/use-cases/patch-integration-config.js +39 -0
  217. package/integrations/use-cases/process-errors.js +28 -0
  218. package/integrations/use-cases/remove-entities-from-integration.js +70 -0
  219. package/integrations/use-cases/update-integration-config.js +32 -0
  220. package/integrations/use-cases/update-integration-messages.js +44 -0
  221. package/integrations/use-cases/update-integration-status.js +32 -0
  222. package/integrations/use-cases/update-integration.js +92 -0
  223. package/integrations/use-cases/update-process-metrics.js +222 -0
  224. package/integrations/use-cases/update-process-state.js +163 -0
  225. package/integrations/utils/assert-entity-ids-input.js +42 -0
  226. package/integrations/utils/map-integration-dto.js +37 -0
  227. package/jest-global-setup-noop.js +3 -0
  228. package/jest-global-teardown-noop.js +3 -0
  229. package/jest.config.js +2 -0
  230. package/logs/.eslintrc.json +26 -1
  231. package/logs/__fixtures__/events.js +82 -0
  232. package/logs/__fixtures__/matchers.js +45 -0
  233. package/logs/__fixtures__/secrets.js +59 -0
  234. package/logs/__fixtures__/vectors.js +329 -0
  235. package/logs/__fixtures__/with-env.js +45 -0
  236. package/logs/context.js +109 -0
  237. package/logs/contract-keys.js +67 -0
  238. package/logs/debug-shims.js +46 -0
  239. package/logs/denied-keys.js +21 -0
  240. package/logs/index.js +14 -3
  241. package/logs/jest-logger-setup.js +25 -0
  242. package/logs/levels.js +71 -0
  243. package/logs/logger-runtime.js +137 -0
  244. package/logs/logger.js +134 -46
  245. package/logs/record.js +276 -0
  246. package/logs/redact.js +328 -0
  247. package/logs/serialize.js +329 -0
  248. package/logs/sinks.js +93 -0
  249. package/logs/summarize-event.js +163 -0
  250. package/{module-plugin → modules}/index.js +0 -10
  251. package/modules/module-factory.js +56 -0
  252. package/modules/module.js +320 -0
  253. package/modules/repositories/module-repository-documentdb.js +350 -0
  254. package/modules/repositories/module-repository-factory.js +40 -0
  255. package/modules/repositories/module-repository-interface.js +145 -0
  256. package/modules/repositories/module-repository-mongo.js +436 -0
  257. package/modules/repositories/module-repository-postgres.js +481 -0
  258. package/modules/repositories/module-repository.js +369 -0
  259. package/modules/requester/api-key.js +52 -0
  260. package/modules/requester/oauth-2.js +561 -0
  261. package/modules/requester/requester.js +605 -0
  262. package/{module-plugin → modules}/test/mock-api/api.js +8 -3
  263. package/{module-plugin → modules}/test/mock-api/definition.js +14 -10
  264. package/modules/tests/doubles/test-module-factory.js +16 -0
  265. package/modules/tests/doubles/test-module-repository.js +39 -0
  266. package/modules/use-cases/get-entities-for-user.js +32 -0
  267. package/modules/use-cases/get-entity-options-by-id.js +71 -0
  268. package/modules/use-cases/get-entity-options-by-type.js +34 -0
  269. package/modules/use-cases/get-module-instance-from-type.js +34 -0
  270. package/modules/use-cases/get-module.js +74 -0
  271. package/modules/use-cases/process-authorization-callback.js +294 -0
  272. package/modules/use-cases/refresh-entity-options.js +72 -0
  273. package/modules/use-cases/test-module-auth.js +72 -0
  274. package/modules/utils/map-module-dto.js +20 -0
  275. package/modules/utils/to-credential-id.js +14 -0
  276. package/package.json +91 -52
  277. package/prisma-mongodb/schema.prisma +455 -0
  278. package/prisma-postgresql/migrations/20250930193005_init/migration.sql +315 -0
  279. package/prisma-postgresql/migrations/20251006135218_init/migration.sql +9 -0
  280. package/prisma-postgresql/migrations/20251010000000_remove_unused_entity_reference_map/migration.sql +3 -0
  281. package/prisma-postgresql/migrations/20251112195422_update_user_unique_constraints/migration.sql +25 -0
  282. package/prisma-postgresql/migrations/20260422120000_add_entity_data_column/migration.sql +10 -0
  283. package/prisma-postgresql/migrations/20260422120001_create_process_table/migration.sql +48 -0
  284. package/prisma-postgresql/migrations/20260625000000_add_user_organization_id_index/migration.sql +2 -0
  285. package/prisma-postgresql/migrations/20260703000000_add_integration_status_in_creation_in_deletion/migration.sql +11 -0
  286. package/prisma-postgresql/migrations/20260703000001_integration_status_default_in_creation/migration.sql +8 -0
  287. package/prisma-postgresql/migrations/20260705000000_create_usage_counter/migration.sql +26 -0
  288. package/prisma-postgresql/migrations/20260706000000_add_admin_script_execution_and_schedule/migration.sql +61 -0
  289. package/prisma-postgresql/migrations/migration_lock.toml +3 -0
  290. package/prisma-postgresql/schema.prisma +436 -0
  291. package/queues/queue-delivery.js +41 -0
  292. package/queues/queuer-util.js +89 -21
  293. package/reporting/README.md +154 -0
  294. package/reporting/builtin-reports.js +6 -0
  295. package/reporting/index.js +13 -0
  296. package/reporting/report-base.js +49 -0
  297. package/reporting/reports/integrations-report.js +221 -0
  298. package/syncs/manager.js +468 -443
  299. package/syncs/repositories/sync-repository-documentdb.js +240 -0
  300. package/syncs/repositories/sync-repository-factory.js +43 -0
  301. package/syncs/repositories/sync-repository-interface.js +109 -0
  302. package/syncs/repositories/sync-repository-mongo.js +239 -0
  303. package/syncs/repositories/sync-repository-postgres.js +319 -0
  304. package/syncs/sync.js +0 -1
  305. package/telemetry/README.md +331 -0
  306. package/telemetry/bind-telemetry-context.js +77 -0
  307. package/telemetry/canonical-counters.js +52 -0
  308. package/telemetry/exporters.js +85 -0
  309. package/telemetry/index.js +26 -0
  310. package/telemetry/instrument-handler.js +104 -0
  311. package/telemetry/no-op-telemetry.js +71 -0
  312. package/telemetry/north-star.js +103 -0
  313. package/telemetry/otel-telemetry.js +232 -0
  314. package/telemetry/plugin-subscribers.js +77 -0
  315. package/telemetry/telemetry-config.js +120 -0
  316. package/telemetry/telemetry-context.js +51 -0
  317. package/telemetry/telemetry-event-bus.js +58 -0
  318. package/telemetry/telemetry-runtime.js +164 -0
  319. package/telemetry/telemetry-service.js +52 -0
  320. package/telemetry/usage-rollup-subscriber.js +116 -0
  321. package/token/repositories/token-repository-documentdb.js +137 -0
  322. package/token/repositories/token-repository-factory.js +40 -0
  323. package/token/repositories/token-repository-interface.js +131 -0
  324. package/token/repositories/token-repository-mongo.js +219 -0
  325. package/token/repositories/token-repository-postgres.js +264 -0
  326. package/token/repositories/token-repository.js +219 -0
  327. package/types/associations/index.d.ts +0 -17
  328. package/types/core/index.d.ts +12 -4
  329. package/types/database/index.d.ts +10 -2
  330. package/types/encrypt/index.d.ts +5 -3
  331. package/types/errors/index.d.ts +24 -10
  332. package/types/integrations/index.d.ts +3 -8
  333. package/types/logs/index.d.ts +61 -2
  334. package/types/module-plugin/index.d.ts +20 -69
  335. package/types/syncs/index.d.ts +0 -17
  336. package/usage/README.md +54 -0
  337. package/usage/index.js +17 -0
  338. package/usage/repositories/usage-repository-documentdb.js +194 -0
  339. package/usage/repositories/usage-repository-factory.js +25 -0
  340. package/usage/repositories/usage-repository-interface.js +37 -0
  341. package/usage/repositories/usage-repository-prisma.js +146 -0
  342. package/usage/tracked-metrics.js +38 -0
  343. package/usage/usage-windows.js +24 -0
  344. package/user/repositories/user-repository-documentdb.js +426 -0
  345. package/user/repositories/user-repository-factory.js +52 -0
  346. package/user/repositories/user-repository-interface.js +214 -0
  347. package/user/repositories/user-repository-mongo.js +323 -0
  348. package/user/repositories/user-repository-postgres.js +377 -0
  349. package/user/tests/doubles/test-user-repository.js +72 -0
  350. package/user/use-cases/authenticate-user.js +143 -0
  351. package/user/use-cases/authenticate-with-shared-secret.js +48 -0
  352. package/user/use-cases/create-individual-user.js +61 -0
  353. package/user/use-cases/create-organization-user.js +47 -0
  354. package/user/use-cases/create-token-for-user-id.js +30 -0
  355. package/user/use-cases/get-user-from-adopter-jwt.js +149 -0
  356. package/user/use-cases/get-user-from-bearer-token.js +82 -0
  357. package/user/use-cases/get-user-from-x-frigg-headers.js +132 -0
  358. package/user/use-cases/login-user.js +122 -0
  359. package/user/user.js +125 -0
  360. package/utils/backend-path.js +38 -0
  361. package/utils/index.js +6 -0
  362. package/websocket/repositories/websocket-connection-repository-documentdb.js +119 -0
  363. package/websocket/repositories/websocket-connection-repository-factory.js +44 -0
  364. package/websocket/repositories/websocket-connection-repository-interface.js +106 -0
  365. package/websocket/repositories/websocket-connection-repository-mongo.js +156 -0
  366. package/websocket/repositories/websocket-connection-repository-postgres.js +196 -0
  367. package/websocket/repositories/websocket-connection-repository.js +161 -0
  368. package/assertions/is-equal.js +0 -17
  369. package/associations/model.js +0 -54
  370. package/database/models/IndividualUser.js +0 -76
  371. package/database/models/OrganizationUser.js +0 -29
  372. package/database/models/State.js +0 -9
  373. package/database/models/Token.js +0 -70
  374. package/database/models/UserModel.js +0 -7
  375. package/database/models/WebsocketConnection.js +0 -49
  376. package/database/mongo.js +0 -45
  377. package/database/mongoose.js +0 -5
  378. package/encrypt/Cryptor.test.js +0 -32
  379. package/encrypt/encrypt.js +0 -132
  380. package/encrypt/encrypt.test.js +0 -1069
  381. package/encrypt/test-encrypt.js +0 -107
  382. package/errors/base-error.test.js +0 -32
  383. package/errors/fetch-error.test.js +0 -79
  384. package/errors/halt-error.test.js +0 -11
  385. package/errors/validation-errors.test.js +0 -120
  386. package/handlers/routers/middleware/loadUser.js +0 -15
  387. package/handlers/routers/middleware/requireLoggedInUser.js +0 -12
  388. package/integrations/create-frigg-backend.js +0 -31
  389. package/integrations/integration-factory.js +0 -251
  390. package/integrations/integration-mapping.js +0 -43
  391. package/integrations/integration-model.js +0 -46
  392. package/integrations/integration-user.js +0 -144
  393. package/integrations/test/integration-base.test.js +0 -144
  394. package/lambda/TimeoutCatcher.test.js +0 -68
  395. package/logs/logger.test.js +0 -76
  396. package/module-plugin/auther.js +0 -393
  397. package/module-plugin/credential.js +0 -22
  398. package/module-plugin/entity-manager.js +0 -70
  399. package/module-plugin/entity.js +0 -46
  400. package/module-plugin/manager.js +0 -169
  401. package/module-plugin/module-factory.js +0 -61
  402. package/module-plugin/requester/api-key.js +0 -36
  403. package/module-plugin/requester/oauth-2.js +0 -219
  404. package/module-plugin/requester/requester.js +0 -165
  405. package/module-plugin/requester/requester.test.js +0 -28
  406. package/module-plugin/test/auther.test.js +0 -97
  407. package/syncs/model.js +0 -62
  408. /package/{module-plugin → modules}/ModuleConstants.js +0 -0
  409. /package/{module-plugin → modules}/requester/basic.js +0 -0
  410. /package/{module-plugin → modules}/test/mock-api/mocks/hubspot.js +0 -0
@@ -0,0 +1,138 @@
1
+ const {
2
+ HealthCheckRepositoryInterface,
3
+ } = require('./health-check-repository-interface');
4
+ const {
5
+ toObjectId,
6
+ fromObjectId,
7
+ findOne,
8
+ insertOne,
9
+ deleteOne,
10
+ } = require('../documentdb-utils');
11
+ const { DocumentDBEncryptionService } = require('../documentdb-encryption-service');
12
+
13
+ class HealthCheckRepositoryDocumentDB extends HealthCheckRepositoryInterface {
14
+ /**
15
+ * @param {Object} params
16
+ * @param {Object} params.prismaClient - Prisma client instance
17
+ */
18
+ constructor({ prismaClient }) {
19
+ super();
20
+ this.prisma = prismaClient;
21
+ this.encryptionService = new DocumentDBEncryptionService();
22
+ }
23
+
24
+ /**
25
+ * @returns {Promise<{readyState: number, stateName: string, isConnected: boolean}>}
26
+ */
27
+ async getDatabaseConnectionState() {
28
+ let isConnected = false;
29
+ let stateName = 'unknown';
30
+
31
+ try {
32
+ await this.prisma.$runCommandRaw({ ping: 1 });
33
+ isConnected = true;
34
+ stateName = 'connected';
35
+ } catch (error) {
36
+ stateName = 'disconnected';
37
+ }
38
+
39
+ return {
40
+ readyState: isConnected ? 1 : 0,
41
+ stateName,
42
+ isConnected,
43
+ };
44
+ }
45
+
46
+ /**
47
+ * @param {number} maxTimeMS
48
+ * @returns {Promise<number>} Response time in milliseconds
49
+ */
50
+ async pingDatabase(maxTimeMS = 2000) {
51
+ const pingStart = Date.now();
52
+ let timeoutId;
53
+
54
+ const timeoutPromise = new Promise((_, reject) => {
55
+ timeoutId = setTimeout(() => reject(new Error('Database ping timeout')), maxTimeMS);
56
+ });
57
+
58
+ try {
59
+ await Promise.race([
60
+ this.prisma.$runCommandRaw({ ping: 1 }),
61
+ timeoutPromise,
62
+ ]);
63
+ return Date.now() - pingStart;
64
+ } finally {
65
+ clearTimeout(timeoutId);
66
+ }
67
+ }
68
+
69
+ async createCredential(credentialData) {
70
+ const now = new Date();
71
+ const document = {
72
+ ...credentialData,
73
+ createdAt: now,
74
+ updatedAt: now,
75
+ };
76
+
77
+ // Encrypt sensitive fields before insert
78
+ const encryptedDocument = await this.encryptionService.encryptFields(
79
+ 'Credential',
80
+ document
81
+ );
82
+ const insertedId = await insertOne(this.prisma, 'Credential', encryptedDocument);
83
+ const created = await findOne(this.prisma, 'Credential', { _id: insertedId });
84
+
85
+ // Decrypt after read
86
+ const decrypted = await this.encryptionService.decryptFields(
87
+ 'Credential',
88
+ created
89
+ );
90
+
91
+ return {
92
+ id: fromObjectId(decrypted._id),
93
+ ...decrypted,
94
+ };
95
+ }
96
+
97
+ async findCredentialById(id) {
98
+ const doc = await findOne(this.prisma, 'Credential', {
99
+ _id: toObjectId(id),
100
+ });
101
+
102
+ if (!doc) return null;
103
+
104
+ // Decrypt sensitive fields
105
+ const decrypted = await this.encryptionService.decryptFields('Credential', doc);
106
+
107
+ return {
108
+ id: fromObjectId(decrypted._id),
109
+ ...decrypted,
110
+ };
111
+ }
112
+
113
+ async getRawCredentialById(id) {
114
+ const objectId = toObjectId(id);
115
+ if (!objectId) return null;
116
+
117
+ const result = await this.prisma.$runCommandRaw({
118
+ find: 'Credential',
119
+ filter: { _id: objectId },
120
+ });
121
+
122
+ // Return raw document WITHOUT decryption
123
+ // This allows the test to verify that fields are actually encrypted in the database
124
+ return result?.cursor?.firstBatch?.[0] ?? null;
125
+ }
126
+
127
+ async deleteCredential(id) {
128
+ const objectId = toObjectId(id);
129
+ if (!objectId) return false;
130
+
131
+ const result = await deleteOne(this.prisma, 'Credential', { _id: objectId });
132
+ const deleted = result?.n ?? 0;
133
+ return deleted > 0;
134
+ }
135
+ }
136
+
137
+ module.exports = { HealthCheckRepositoryDocumentDB };
138
+
@@ -0,0 +1,48 @@
1
+ const { HealthCheckRepositoryMongoDB } = require('./health-check-repository-mongodb');
2
+ const { HealthCheckRepositoryPostgreSQL } = require('./health-check-repository-postgres');
3
+ const { HealthCheckRepositoryDocumentDB } = require('./health-check-repository-documentdb');
4
+ const config = require('../config');
5
+
6
+ /**
7
+ * Factory function to create a health check repository for the configured database type.
8
+ * Requires explicit prismaClient injection to support IoC container patterns.
9
+ *
10
+ * @param {Object} options
11
+ * @param {Object} options.prismaClient - Prisma client instance (required for dependency injection)
12
+ * @returns {HealthCheckRepositoryInterface} Database-specific health check repository
13
+ * @throws {Error} If prismaClient is not provided
14
+ *
15
+ * @example
16
+ * const { prisma } = require('../prisma');
17
+ * const repository = createHealthCheckRepository({ prismaClient: prisma });
18
+ */
19
+ function createHealthCheckRepository({ prismaClient } = {}) {
20
+ if (!prismaClient) {
21
+ throw new Error('prismaClient is required');
22
+ }
23
+
24
+ const dbType = config.DB_TYPE;
25
+
26
+ switch (dbType) {
27
+ case 'mongodb':
28
+ return new HealthCheckRepositoryMongoDB({ prismaClient });
29
+
30
+ case 'postgresql':
31
+ return new HealthCheckRepositoryPostgreSQL({ prismaClient });
32
+
33
+ case 'documentdb':
34
+ return new HealthCheckRepositoryDocumentDB({ prismaClient });
35
+
36
+ default:
37
+ throw new Error(
38
+ `Unsupported database type: ${dbType}. Supported values: 'mongodb', 'documentdb', 'postgresql'`
39
+ );
40
+ }
41
+ }
42
+
43
+ module.exports = {
44
+ createHealthCheckRepository,
45
+ HealthCheckRepositoryMongoDB,
46
+ HealthCheckRepositoryPostgreSQL,
47
+ HealthCheckRepositoryDocumentDB,
48
+ };
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Health Check Repository Interface
3
+ * Abstract base class defining the contract for health check 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, HealthCheckRepository has identical structure across MongoDB and PostgreSQL,
11
+ * so HealthCheckRepository serves both. This interface exists for consistency and
12
+ * future-proofing if database-specific implementations become needed.
13
+ *
14
+ * @abstract
15
+ */
16
+ class HealthCheckRepositoryInterface {
17
+ /**
18
+ * @returns {Promise<{readyState: number, stateName: string, isConnected: boolean}>}
19
+ * @abstract
20
+ */
21
+ async getDatabaseConnectionState() {
22
+ throw new Error('Method getDatabaseConnectionState must be implemented by subclass');
23
+ }
24
+
25
+ /**
26
+ * Ping database to verify connectivity
27
+ *
28
+ * @param {number} maxTimeMS - Maximum time in milliseconds
29
+ * @returns {Promise<number>} Response time in milliseconds
30
+ * @abstract
31
+ */
32
+ async pingDatabase(maxTimeMS) {
33
+ throw new Error('Method pingDatabase must be implemented by subclass');
34
+ }
35
+
36
+ /**
37
+ * Persist an encrypted credential for health verification.
38
+ * Implementations should rely on Prisma so encryption middleware runs.
39
+ *
40
+ * @param {Object} credentialData
41
+ * @returns {Promise<Object>} Persisted credential
42
+ * @abstract
43
+ */
44
+ async createCredential(credentialData) {
45
+ throw new Error('Method createCredential must be implemented by subclass');
46
+ }
47
+
48
+ /**
49
+ * Retrieve credential by ID using Prisma (decrypted).
50
+ *
51
+ * @param {string} id
52
+ * @returns {Promise<Object|null>}
53
+ * @abstract
54
+ */
55
+ async findCredentialById(id) {
56
+ throw new Error('Method findCredentialById must be implemented by subclass');
57
+ }
58
+
59
+ /**
60
+ * Fetch raw credential document from the database (without decryption).
61
+ *
62
+ * @param {string} id
63
+ * @returns {Promise<Object|null>}
64
+ * @abstract
65
+ */
66
+ async getRawCredentialById(id) {
67
+ throw new Error('Method getRawCredentialById must be implemented by subclass');
68
+ }
69
+
70
+ /**
71
+ * Delete credential by ID.
72
+ *
73
+ * @param {string} id
74
+ * @returns {Promise<void>}
75
+ * @abstract
76
+ */
77
+ async deleteCredential(id) {
78
+ throw new Error('Method deleteCredential must be implemented by subclass');
79
+ }
80
+ }
81
+
82
+ module.exports = { HealthCheckRepositoryInterface };
@@ -0,0 +1,89 @@
1
+ const {
2
+ HealthCheckRepositoryInterface,
3
+ } = require('./health-check-repository-interface');
4
+
5
+ class HealthCheckRepositoryMongoDB extends HealthCheckRepositoryInterface {
6
+ /**
7
+ * @param {Object} params
8
+ * @param {Object} params.prismaClient - Prisma client instance
9
+ */
10
+ constructor({ prismaClient }) {
11
+ super();
12
+ this.prisma = prismaClient;
13
+ }
14
+
15
+ /**
16
+ * @returns {Promise<{readyState: number, stateName: string, isConnected: boolean}>}
17
+ */
18
+ async getDatabaseConnectionState() {
19
+ let isConnected = false;
20
+ let stateName = 'unknown';
21
+
22
+ try {
23
+ await this.prisma.$runCommandRaw({ ping: 1 });
24
+ isConnected = true;
25
+ stateName = 'connected';
26
+ } catch (error) {
27
+ stateName = 'disconnected';
28
+ }
29
+
30
+ return {
31
+ readyState: isConnected ? 1 : 0,
32
+ stateName,
33
+ isConnected,
34
+ };
35
+ }
36
+
37
+ async pingDatabase(maxTimeMS = 2000) {
38
+ const pingStart = Date.now();
39
+ let timeoutId;
40
+
41
+ const timeoutPromise = new Promise((_, reject) => {
42
+ timeoutId = setTimeout(() => reject(new Error('Database ping timeout')), maxTimeMS);
43
+ });
44
+
45
+ try {
46
+ await Promise.race([
47
+ this.prisma.$runCommandRaw({ ping: 1 }),
48
+ timeoutPromise
49
+ ]);
50
+ return Date.now() - pingStart;
51
+ } finally {
52
+ clearTimeout(timeoutId);
53
+ }
54
+ }
55
+
56
+ async createCredential(credentialData) {
57
+ return await this.prisma.credential.create({
58
+ data: credentialData,
59
+ });
60
+ }
61
+
62
+ async findCredentialById(id) {
63
+ return await this.prisma.credential.findUnique({
64
+ where: { id },
65
+ });
66
+ }
67
+
68
+ /**
69
+ * Get raw credential from database bypassing Prisma encryption extension.
70
+ * Uses findRaw() to query MongoDB directly.
71
+ * @param {string} id
72
+ * @returns {Promise<Object|null>}
73
+ */
74
+ async getRawCredentialById(id) {
75
+ if (!id) return null;
76
+ const results = await this.prisma.credential.findRaw({
77
+ filter: { _id: { $oid: id } },
78
+ });
79
+ return results[0] || null;
80
+ }
81
+
82
+ async deleteCredential(id) {
83
+ await this.prisma.credential.delete({
84
+ where: { id },
85
+ });
86
+ }
87
+ }
88
+
89
+ module.exports = { HealthCheckRepositoryMongoDB };
@@ -0,0 +1,82 @@
1
+ const {
2
+ HealthCheckRepositoryInterface,
3
+ } = require('./health-check-repository-interface');
4
+
5
+ class HealthCheckRepositoryPostgreSQL extends HealthCheckRepositoryInterface {
6
+ /**
7
+ * @param {Object} params
8
+ * @param {Object} params.prismaClient - Prisma client instance
9
+ */
10
+ constructor({ prismaClient }) {
11
+ super();
12
+ this.prisma = prismaClient;
13
+ }
14
+
15
+ /**
16
+ * @returns {Promise<{readyState: number, stateName: string, isConnected: boolean}>}
17
+ */
18
+ async getDatabaseConnectionState() {
19
+ let isConnected = false;
20
+ let stateName = 'unknown';
21
+
22
+ try {
23
+ await this.prisma.$queryRaw`SELECT 1`;
24
+ isConnected = true;
25
+ stateName = 'connected';
26
+ } catch (error) {
27
+ stateName = 'disconnected';
28
+ }
29
+
30
+ return {
31
+ readyState: isConnected ? 1 : 0,
32
+ stateName,
33
+ isConnected,
34
+ };
35
+ }
36
+
37
+ /**
38
+ * @param {number} maxTimeMS
39
+ * @returns {Promise<number>} Response time in milliseconds
40
+ */
41
+ async pingDatabase(maxTimeMS = 2000) {
42
+ const pingStart = Date.now();
43
+ await this.prisma.$queryRaw`SELECT 1`;
44
+ return Date.now() - pingStart;
45
+ }
46
+
47
+ async createCredential(credentialData) {
48
+ return await this.prisma.credential.create({
49
+ data: credentialData,
50
+ });
51
+ }
52
+
53
+ async findCredentialById(id) {
54
+ return await this.prisma.credential.findUnique({
55
+ where: { id },
56
+ });
57
+ }
58
+
59
+ /**
60
+ * @param {string} id
61
+ * @returns {Promise<Object|null>}
62
+ */
63
+ async getRawCredentialById(id) {
64
+ const results = await this.prisma.$queryRaw`
65
+ SELECT * FROM "Credential" WHERE id = ${id}
66
+ `;
67
+
68
+ if (!results || results.length === 0) {
69
+ return null;
70
+ }
71
+
72
+ return results[0];
73
+ }
74
+
75
+ async deleteCredential(id) {
76
+ await this.prisma.credential.delete({
77
+ where: { id },
78
+ });
79
+ }
80
+ }
81
+
82
+ module.exports = { HealthCheckRepositoryPostgreSQL };
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Migration Status Repository - S3 Storage
3
+ *
4
+ * Infrastructure Layer - Hexagonal Architecture
5
+ *
6
+ * Stores migration status in S3 to avoid chicken-and-egg dependency on User/Process tables.
7
+ * Initial database migrations can't use Process table (requires User FK which doesn't exist yet).
8
+ */
9
+
10
+ const { S3Client, PutObjectCommand, GetObjectCommand } = require('@aws-sdk/client-s3');
11
+ const { randomUUID } = require('crypto');
12
+
13
+ class MigrationStatusRepositoryS3 {
14
+ /**
15
+ * @param {string} bucketName - S3 bucket name for migration status storage
16
+ * @param {S3Client} s3Client - Optional S3 client (for testing)
17
+ */
18
+ constructor(bucketName, s3Client = null) {
19
+ this.bucketName = bucketName;
20
+ this.s3Client = s3Client || new S3Client({ region: process.env.AWS_REGION || 'us-east-1' });
21
+ }
22
+
23
+ /**
24
+ * Build S3 key for migration status
25
+ * @param {string} migrationId - Migration identifier
26
+ * @param {string} stage - Deployment stage
27
+ * @returns {string} S3 key
28
+ */
29
+ _buildS3Key(migrationId, stage) {
30
+ return `migrations/${stage}/${migrationId}.json`;
31
+ }
32
+
33
+ /**
34
+ * Create new migration status record
35
+ * @param {Object} data - Migration data
36
+ * @param {string} [data.migrationId] - Migration ID (generates UUID if not provided)
37
+ * @param {string} data.stage - Deployment stage
38
+ * @param {string} [data.triggeredBy] - User or system that triggered migration
39
+ * @param {string} [data.triggeredAt] - ISO timestamp
40
+ * @returns {Promise<Object>} Created migration status
41
+ */
42
+ async create(data) {
43
+ const migrationId = data.migrationId || randomUUID();
44
+ const timestamp = data.triggeredAt || new Date().toISOString();
45
+
46
+ const status = {
47
+ migrationId,
48
+ stage: data.stage,
49
+ state: 'INITIALIZING',
50
+ progress: 0,
51
+ triggeredBy: data.triggeredBy || 'system',
52
+ triggeredAt: timestamp,
53
+ createdAt: timestamp,
54
+ updatedAt: timestamp,
55
+ };
56
+
57
+ const key = this._buildS3Key(migrationId, data.stage);
58
+
59
+ await this.s3Client.send(
60
+ new PutObjectCommand({
61
+ Bucket: this.bucketName,
62
+ Key: key,
63
+ Body: JSON.stringify(status, null, 2),
64
+ ContentType: 'application/json',
65
+ })
66
+ );
67
+
68
+ return status;
69
+ }
70
+
71
+ /**
72
+ * Update existing migration status
73
+ * @param {Object} data - Update data
74
+ * @param {string} data.migrationId - Migration ID
75
+ * @param {string} data.stage - Deployment stage
76
+ * @param {string} [data.state] - New state
77
+ * @param {number} [data.progress] - Progress percentage (0-100)
78
+ * @param {string} [data.error] - Error message if failed
79
+ * @param {string} [data.completedAt] - Completion timestamp
80
+ * @returns {Promise<Object>} Updated migration status
81
+ */
82
+ async update(data) {
83
+ const key = this._buildS3Key(data.migrationId, data.stage);
84
+
85
+ // Get existing status
86
+ const existing = await this.get(data.migrationId, data.stage);
87
+
88
+ // Merge updates
89
+ const updated = {
90
+ ...existing,
91
+ ...data,
92
+ updatedAt: new Date().toISOString(),
93
+ };
94
+
95
+ await this.s3Client.send(
96
+ new PutObjectCommand({
97
+ Bucket: this.bucketName,
98
+ Key: key,
99
+ Body: JSON.stringify(updated, null, 2),
100
+ ContentType: 'application/json',
101
+ })
102
+ );
103
+
104
+ return updated;
105
+ }
106
+
107
+ /**
108
+ * Get migration status by ID
109
+ * @param {string} migrationId - Migration ID
110
+ * @param {string} stage - Deployment stage
111
+ * @returns {Promise<Object>} Migration status
112
+ * @throws {Error} If migration not found
113
+ */
114
+ async get(migrationId, stage) {
115
+ const key = this._buildS3Key(migrationId, stage);
116
+
117
+ try {
118
+ const response = await this.s3Client.send(
119
+ new GetObjectCommand({
120
+ Bucket: this.bucketName,
121
+ Key: key,
122
+ })
123
+ );
124
+
125
+ const body = await response.Body.transformToString();
126
+ return JSON.parse(body);
127
+ } catch (error) {
128
+ if (error.name === 'NoSuchKey') {
129
+ throw new Error(`Migration not found: ${migrationId}`);
130
+ }
131
+ throw error;
132
+ }
133
+ }
134
+ }
135
+
136
+ module.exports = { MigrationStatusRepositoryS3 };
137
+
@@ -0,0 +1,29 @@
1
+ class CheckDatabaseHealthUseCase {
2
+ /**
3
+ * @param {Object} params
4
+ * @param {import('../repositories/health-check-repository-interface').HealthCheckRepositoryInterface} params.healthCheckRepository
5
+ */
6
+ constructor({ healthCheckRepository }) {
7
+ this.repository = healthCheckRepository;
8
+ }
9
+
10
+ /**
11
+ * @returns {Promise<{status: string, state: string, responseTime?: number}>}
12
+ */
13
+ async execute() {
14
+ const { stateName, isConnected } = await this.repository.getDatabaseConnectionState();
15
+
16
+ const result = {
17
+ status: isConnected ? 'healthy' : 'unhealthy',
18
+ state: stateName,
19
+ };
20
+
21
+ if (isConnected) {
22
+ result.responseTime = await this.repository.pingDatabase(2000);
23
+ }
24
+
25
+ return result;
26
+ }
27
+ }
28
+
29
+ module.exports = { CheckDatabaseHealthUseCase };
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Check Database State Use Case
3
+ *
4
+ * Domain logic for checking database state (pending migrations, errors, etc).
5
+ * Does NOT trigger migrations, just reports current state.
6
+ *
7
+ * Architecture: Hexagonal/Clean
8
+ * - Use Case (Domain Layer)
9
+ * - Depends on prismaRunner (Infrastructure abstraction)
10
+ * - Called by Router or other Use Cases (Adapter Layer)
11
+ */
12
+
13
+ class ValidationError extends Error {
14
+ constructor(message) {
15
+ super(message);
16
+ this.name = 'ValidationError';
17
+ }
18
+ }
19
+
20
+ class CheckDatabaseStateUseCase {
21
+ /**
22
+ * @param {Object} dependencies
23
+ * @param {Object} dependencies.prismaRunner - Prisma runner utility
24
+ */
25
+ constructor({ prismaRunner }) {
26
+ if (!prismaRunner) {
27
+ throw new Error('prismaRunner dependency is required');
28
+ }
29
+ this.prismaRunner = prismaRunner;
30
+ }
31
+
32
+ /**
33
+ * Execute check migration status
34
+ *
35
+ * @param {string} dbType - Database type (postgresql, mongodb, or documentdb)
36
+ * @param {string} stage - Deployment stage (default: 'production')
37
+ * @returns {Promise<Object>} Migration status
38
+ */
39
+ async execute(dbType, stage = 'production') {
40
+ // Validate inputs
41
+ if (!dbType) {
42
+ throw new ValidationError('dbType is required');
43
+ }
44
+
45
+ if (!['postgresql', 'mongodb', 'documentdb'].includes(dbType)) {
46
+ throw new ValidationError('dbType must be postgresql, mongodb, or documentdb');
47
+ }
48
+
49
+ console.log(`Checking migration status for ${dbType} in ${stage}`);
50
+
51
+ // Check database state using Prisma
52
+ const state = await this.prismaRunner.checkDatabaseState(dbType);
53
+
54
+ // Build response
55
+ const response = {
56
+ upToDate: state.upToDate,
57
+ pendingMigrations: state.pendingMigrations || 0,
58
+ dbType,
59
+ stage,
60
+ };
61
+
62
+ // Add error if present
63
+ if (state.error) {
64
+ response.error = state.error;
65
+ response.recommendation = 'Run POST /admin/db-migrate to initialize database';
66
+ }
67
+
68
+ // Add recommendation if migrations pending
69
+ if (!state.upToDate && state.pendingMigrations > 0) {
70
+ response.recommendation = `Run POST /admin/db-migrate to apply ${state.pendingMigrations} pending migration(s)`;
71
+ }
72
+
73
+ return response;
74
+ }
75
+ }
76
+
77
+ module.exports = {
78
+ CheckDatabaseStateUseCase,
79
+ ValidationError,
80
+ };
81
+