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

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 +238 -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 +92 -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,350 @@
1
+ const { prisma } = require('../../database/prisma');
2
+ const {
3
+ toObjectId,
4
+ fromObjectId,
5
+ findMany,
6
+ findOne,
7
+ insertOne,
8
+ updateOne,
9
+ deleteOne,
10
+ } = require('../../database/documentdb-utils');
11
+ const { ModuleRepositoryInterface } = require('./module-repository-interface');
12
+ const { DocumentDBEncryptionService } = require('../../database/documentdb-encryption-service');
13
+
14
+ /**
15
+ * Module/Entity repository for DocumentDB.
16
+ * Uses DocumentDBEncryptionService for credential decryption.
17
+ *
18
+ * Encrypted fields: Credential.data.*
19
+ *
20
+ * Note: This repository only reads credentials. CredentialRepository
21
+ * handles credential creation/updates with encryption.
22
+ *
23
+ * @see DocumentDBEncryptionService
24
+ * @see CredentialRepositoryDocumentDB
25
+ */
26
+ class ModuleRepositoryDocumentDB extends ModuleRepositoryInterface {
27
+ constructor() {
28
+ super();
29
+ this.prisma = prisma;
30
+ this.encryptionService = new DocumentDBEncryptionService();
31
+ }
32
+
33
+ async findEntityById(entityId) {
34
+ const objectId = toObjectId(entityId);
35
+ if (!objectId) {
36
+ throw new Error(`Entity ${entityId} not found`);
37
+ }
38
+ const doc = await findOne(this.prisma, 'Entity', { _id: objectId });
39
+ if (!doc) {
40
+ throw new Error(`Entity ${entityId} not found`);
41
+ }
42
+ const credential = await this._fetchCredential(doc.credentialId);
43
+ return this._mapEntity(doc, credential);
44
+ }
45
+
46
+ async findEntitiesByUserId(userId) {
47
+ const objectId = toObjectId(userId);
48
+ if (!objectId) {
49
+ throw new Error(`Invalid userId: ${userId}`);
50
+ }
51
+ const filter = { userId: objectId };
52
+ const docs = await findMany(this.prisma, 'Entity', filter);
53
+ const credentialMap = await this._fetchCredentialsBulk(docs.map((doc) => doc.credentialId));
54
+ return docs.map((doc) => this._mapEntity(doc, credentialMap.get(fromObjectId(doc.credentialId)) || null));
55
+ }
56
+
57
+ async findEntitiesByIds(entitiesIds) {
58
+ const ids = (entitiesIds || []).map((id) => toObjectId(id)).filter(Boolean);
59
+ if (ids.length === 0) return [];
60
+ const docs = await findMany(this.prisma, 'Entity', { _id: { $in: ids } });
61
+ const credentialMap = await this._fetchCredentialsBulk(docs.map((doc) => doc.credentialId));
62
+ return docs.map((doc) => this._mapEntity(doc, credentialMap.get(fromObjectId(doc.credentialId)) || null));
63
+ }
64
+
65
+ async findEntitiesByUserIdAndModuleName(userId, moduleName) {
66
+ const objectId = toObjectId(userId);
67
+ if (!objectId) {
68
+ throw new Error(`Invalid userId: ${userId}`);
69
+ }
70
+ const filter = {
71
+ userId: objectId,
72
+ moduleName,
73
+ };
74
+ const docs = await findMany(this.prisma, 'Entity', filter);
75
+ const credentialMap = await this._fetchCredentialsBulk(docs.map((doc) => doc.credentialId));
76
+ return docs.map((doc) => this._mapEntity(doc, credentialMap.get(fromObjectId(doc.credentialId)) || null));
77
+ }
78
+
79
+ async unsetCredential(entityId) {
80
+ const objectId = toObjectId(entityId);
81
+ if (!objectId) return false;
82
+ await updateOne(
83
+ this.prisma,
84
+ 'Entity',
85
+ { _id: objectId },
86
+ {
87
+ $set: {
88
+ credentialId: null,
89
+ },
90
+ }
91
+ );
92
+ return true;
93
+ }
94
+
95
+ async findEntity(filter) {
96
+ const query = this._buildFilter(filter);
97
+ const doc = await findOne(this.prisma, 'Entity', query);
98
+ if (!doc) return null;
99
+ const credential = await this._fetchCredential(doc.credentialId);
100
+ return this._mapEntity(doc, credential);
101
+ }
102
+
103
+ async findEntities(filter) {
104
+ const query = this._buildFilter(filter);
105
+ const docs = await findMany(this.prisma, 'Entity', query);
106
+ if (!docs || docs.length === 0) return [];
107
+ const credentialMap = await this._fetchCredentialsBulk(
108
+ docs.map((doc) => doc.credentialId)
109
+ );
110
+ return docs.map((doc) =>
111
+ this._mapEntity(
112
+ doc,
113
+ credentialMap.get(fromObjectId(doc.credentialId)) || null
114
+ )
115
+ );
116
+ }
117
+
118
+ async createEntity(entityData) {
119
+ const {
120
+ user,
121
+ userId,
122
+ credential,
123
+ credentialId,
124
+ name,
125
+ moduleName,
126
+ externalId,
127
+ ...dynamicData
128
+ } = entityData;
129
+
130
+ const document = {
131
+ userId: toObjectId(userId || user),
132
+ credentialId: toObjectId(credentialId || credential) || null,
133
+ name: name ?? null,
134
+ moduleName: moduleName ?? null,
135
+ externalId: externalId ?? null,
136
+ data: dynamicData,
137
+ };
138
+ const insertedId = await insertOne(this.prisma, 'Entity', document);
139
+ const created = await findOne(this.prisma, 'Entity', { _id: insertedId });
140
+ const credentialObj = await this._fetchCredential(created?.credentialId);
141
+ return this._mapEntity(created, credentialObj);
142
+ }
143
+
144
+ async updateEntity(entityId, updates) {
145
+ const objectId = toObjectId(entityId);
146
+ if (!objectId) return null;
147
+
148
+ const existing = await findOne(this.prisma, 'Entity', { _id: objectId });
149
+ if (!existing) return null;
150
+
151
+ const {
152
+ user,
153
+ userId,
154
+ credential,
155
+ credentialId,
156
+ name,
157
+ moduleName,
158
+ externalId,
159
+ ...dynamicData
160
+ } = updates;
161
+
162
+ const updatePayload = {};
163
+ if (user !== undefined || userId !== undefined) {
164
+ updatePayload.userId = toObjectId(userId || user) || null;
165
+ }
166
+ if (credential !== undefined || credentialId !== undefined) {
167
+ updatePayload.credentialId = toObjectId(credentialId || credential) || null;
168
+ }
169
+ if (name !== undefined) updatePayload.name = name;
170
+ if (moduleName !== undefined) updatePayload.moduleName = moduleName;
171
+ if (externalId !== undefined) updatePayload.externalId = externalId;
172
+
173
+ if (Object.keys(dynamicData).length > 0) {
174
+ updatePayload.data = { ...(existing.data || {}), ...dynamicData };
175
+ }
176
+
177
+ await updateOne(
178
+ this.prisma,
179
+ 'Entity',
180
+ { _id: objectId },
181
+ { $set: updatePayload }
182
+ );
183
+ const updated = await findOne(this.prisma, 'Entity', { _id: objectId });
184
+ if (!updated) return null;
185
+ const credentialObj = await this._fetchCredential(updated?.credentialId);
186
+ return this._mapEntity(updated, credentialObj);
187
+ }
188
+
189
+ async deleteEntity(entityId) {
190
+ const objectId = toObjectId(entityId);
191
+ if (!objectId) return false;
192
+ const result = await deleteOne(this.prisma, 'Entity', { _id: objectId });
193
+ const deleted = result?.n ?? 0;
194
+ return deleted > 0;
195
+ }
196
+
197
+ async _fetchCredential(credentialId) {
198
+ const id = fromObjectId(credentialId);
199
+ if (!id) return null;
200
+
201
+ try {
202
+ // Convert to ObjectId for raw query
203
+ const objectId = toObjectId(id);
204
+ if (!objectId) return null;
205
+
206
+ // Use raw findOne to bypass Prisma encryption extension
207
+ const rawCredential = await findOne(this.prisma, 'Credential', {
208
+ _id: objectId
209
+ });
210
+
211
+ if (!rawCredential) return null;
212
+
213
+ // Decrypt sensitive fields using service
214
+ const decryptedCredential = await this.encryptionService.decryptFields('Credential', rawCredential);
215
+
216
+ // Return in same format
217
+ const credential = {
218
+ id: fromObjectId(decryptedCredential._id),
219
+ userId: fromObjectId(decryptedCredential.userId),
220
+ externalId: decryptedCredential.externalId ?? null,
221
+ authIsValid: decryptedCredential.authIsValid ?? null,
222
+ createdAt: decryptedCredential.createdAt,
223
+ updatedAt: decryptedCredential.updatedAt,
224
+ data: decryptedCredential.data
225
+ };
226
+
227
+ return this._convertCredentialIds(credential);
228
+ } catch (error) {
229
+ console.error(`Failed to fetch/decrypt credential ${id}:`, error.message);
230
+ // Return null instead of throwing to allow graceful degradation
231
+ // This repository is read-only (doesn't create/update credentials)
232
+ // Entities can still be loaded even if their credential is corrupted/unreadable
233
+ // The entity will have null credential, which calling code must handle
234
+ // This is intentional behavior: prefer partial data over complete failure
235
+ return null;
236
+ }
237
+ }
238
+
239
+ async _fetchCredentialsBulk(credentialIds) {
240
+ const ids = (credentialIds || [])
241
+ .map((value) => fromObjectId(value))
242
+ .filter((value) => value !== null && value !== undefined);
243
+ if (ids.length === 0) return new Map();
244
+
245
+ try {
246
+ // Convert string IDs to ObjectIds for bulk query
247
+ const objectIds = ids.map(id => toObjectId(id)).filter(Boolean);
248
+ if (objectIds.length === 0) return new Map();
249
+
250
+ // Use raw findMany to bypass Prisma encryption extension
251
+ const rawCredentials = await findMany(this.prisma, 'Credential', {
252
+ _id: { $in: objectIds }
253
+ });
254
+
255
+ // Decrypt all credentials in parallel
256
+ const decryptionPromises = rawCredentials.map(async (rawCredential) => {
257
+ try {
258
+ // Decrypt sensitive fields using service
259
+ const decryptedCredential = await this.encryptionService.decryptFields('Credential', rawCredential);
260
+
261
+ // Build credential object in same format as Prisma would return
262
+ const credential = {
263
+ id: fromObjectId(decryptedCredential._id),
264
+ userId: fromObjectId(decryptedCredential.userId),
265
+ externalId: decryptedCredential.externalId ?? null,
266
+ authIsValid: decryptedCredential.authIsValid ?? null,
267
+ createdAt: decryptedCredential.createdAt,
268
+ updatedAt: decryptedCredential.updatedAt,
269
+ data: decryptedCredential.data
270
+ };
271
+
272
+ return this._convertCredentialIds(credential);
273
+ } catch (error) {
274
+ const credId = fromObjectId(rawCredential._id);
275
+ console.error(`Failed to decrypt credential ${credId}:`, error.message);
276
+ return null;
277
+ }
278
+ });
279
+
280
+ // Wait for all decryptions to complete
281
+ const decryptedCredentials = await Promise.all(decryptionPromises);
282
+
283
+ // Build Map from results, filtering out nulls
284
+ const map = new Map();
285
+ decryptedCredentials.forEach(credential => {
286
+ if (credential) {
287
+ map.set(credential.id, credential);
288
+ }
289
+ });
290
+
291
+ return map;
292
+ } catch (error) {
293
+ console.error('Failed to fetch credentials bulk:', error.message);
294
+ return new Map();
295
+ }
296
+ }
297
+
298
+ /**
299
+ * Convert credential object IDs to strings for application layer
300
+ * Ensures consistent credential format across database adapters
301
+ * @private
302
+ * @param {Object|null} credential - Credential object from database
303
+ * @returns {Object|null} Credential with properly formatted IDs
304
+ */
305
+ _convertCredentialIds(credential) {
306
+ if (!credential) return credential;
307
+ return {
308
+ ...credential,
309
+ id: credential.id ? String(credential.id) : null,
310
+ userId: credential.userId ? String(credential.userId) : null,
311
+ };
312
+ }
313
+
314
+ _buildFilter(filter) {
315
+ const query = {};
316
+ if (!filter) return query;
317
+ if (filter._id || filter.id) {
318
+ const idObj = toObjectId(filter._id || filter.id);
319
+ if (idObj) query._id = idObj;
320
+ }
321
+ if (filter.user || filter.userId) {
322
+ const userObj = toObjectId(filter.user || filter.userId);
323
+ if (userObj) query.userId = userObj;
324
+ }
325
+ if (filter.credential || filter.credentialId) {
326
+ const credObj = toObjectId(filter.credential || filter.credentialId);
327
+ if (credObj) query.credentialId = credObj;
328
+ }
329
+ if (filter.name) query.name = filter.name;
330
+ if (filter.moduleName) query.moduleName = filter.moduleName;
331
+ if (filter.externalId) query.externalId = filter.externalId;
332
+ return query;
333
+ }
334
+
335
+ _mapEntity(doc, credential) {
336
+ const dynamicData = doc?.data || {};
337
+ return {
338
+ id: fromObjectId(doc?._id),
339
+ credential,
340
+ userId: fromObjectId(doc?.userId),
341
+ name: doc?.name ?? null,
342
+ externalId: doc?.externalId ?? null,
343
+ moduleName: doc?.moduleName ?? null,
344
+ ...dynamicData,
345
+ };
346
+ }
347
+ }
348
+
349
+ module.exports = { ModuleRepositoryDocumentDB };
350
+
@@ -0,0 +1,40 @@
1
+ const { ModuleRepositoryMongo } = require('./module-repository-mongo');
2
+ const { ModuleRepositoryPostgres } = require('./module-repository-postgres');
3
+ const {
4
+ ModuleRepositoryDocumentDB,
5
+ } = require('./module-repository-documentdb');
6
+ const config = require('../../database/config');
7
+
8
+ /**
9
+ * Module Repository Factory
10
+ * Creates the appropriate repository adapter based on database type
11
+ *
12
+ * @returns {ModuleRepositoryInterface} Configured repository adapter
13
+ */
14
+ function createModuleRepository() {
15
+ const dbType = config.DB_TYPE;
16
+
17
+ switch (dbType) {
18
+ case 'mongodb':
19
+ return new ModuleRepositoryMongo();
20
+
21
+ case 'postgresql':
22
+ return new ModuleRepositoryPostgres();
23
+
24
+ case 'documentdb':
25
+ return new ModuleRepositoryDocumentDB();
26
+
27
+ default:
28
+ throw new Error(
29
+ `Unsupported database type: ${dbType}. Supported values: 'mongodb', 'documentdb', 'postgresql'`
30
+ );
31
+ }
32
+ }
33
+
34
+ module.exports = {
35
+ createModuleRepository,
36
+ // Export adapters for direct testing
37
+ ModuleRepositoryMongo,
38
+ ModuleRepositoryPostgres,
39
+ ModuleRepositoryDocumentDB,
40
+ };
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Module Repository Interface
3
+ * Abstract base class defining the contract for Entity (module) 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, Entity model has identical structure across MongoDB and PostgreSQL,
11
+ * so ModuleRepository serves both. This interface exists for consistency and
12
+ * future-proofing if database-specific implementations become needed.
13
+ *
14
+ * @abstract
15
+ */
16
+ class ModuleRepositoryInterface {
17
+ /**
18
+ * Find entity by ID with credential
19
+ *
20
+ * @param {string|number} entityId - Entity ID
21
+ * @returns {Promise<Object>} Entity object
22
+ * @abstract
23
+ */
24
+ async findEntityById(entityId) {
25
+ throw new Error(
26
+ 'Method findEntityById must be implemented by subclass'
27
+ );
28
+ }
29
+
30
+ /**
31
+ * Find all entities for a user
32
+ *
33
+ * @param {string|number} userId - User ID
34
+ * @returns {Promise<Array>} Array of entity objects
35
+ * @abstract
36
+ */
37
+ async findEntitiesByUserId(userId) {
38
+ throw new Error(
39
+ 'Method findEntitiesByUserId must be implemented by subclass'
40
+ );
41
+ }
42
+
43
+ /**
44
+ * Find entities by IDs
45
+ *
46
+ * @param {Array<string|number>} entitiesIds - Array of entity IDs
47
+ * @returns {Promise<Array>} Array of entity objects
48
+ * @abstract
49
+ */
50
+ async findEntitiesByIds(entitiesIds) {
51
+ throw new Error(
52
+ 'Method findEntitiesByIds must be implemented by subclass'
53
+ );
54
+ }
55
+
56
+ /**
57
+ * Find entities by user ID and module name
58
+ *
59
+ * @param {string|number} userId - User ID
60
+ * @param {string} moduleName - Module name
61
+ * @returns {Promise<Array>} Array of entity objects
62
+ * @abstract
63
+ */
64
+ async findEntitiesByUserIdAndModuleName(userId, moduleName) {
65
+ throw new Error(
66
+ 'Method findEntitiesByUserIdAndModuleName must be implemented by subclass'
67
+ );
68
+ }
69
+
70
+ /**
71
+ * Unset credential from entity
72
+ *
73
+ * @param {string|number} entityId - Entity ID
74
+ * @returns {Promise<Object>} Update result
75
+ * @abstract
76
+ */
77
+ async unsetCredential(entityId) {
78
+ throw new Error(
79
+ 'Method unsetCredential must be implemented by subclass'
80
+ );
81
+ }
82
+
83
+ /**
84
+ * Find entity by filter
85
+ *
86
+ * @param {Object} filter - Filter criteria
87
+ * @returns {Promise<Object|null>} Entity object or null
88
+ * @abstract
89
+ */
90
+ async findEntity(filter) {
91
+ throw new Error('Method findEntity must be implemented by subclass');
92
+ }
93
+
94
+ /**
95
+ * Find all entities matching a filter.
96
+ *
97
+ * Symmetric with findEntity but returns the full match set. Use this when
98
+ * a single externalId may correspond to more than one Entity row
99
+ * (e.g. shared upstream account across tenants) and the caller needs to
100
+ * detect/handle the multi-match case explicitly.
101
+ *
102
+ * @param {Object} filter - Filter criteria
103
+ * @returns {Promise<Array>} Array of entity objects (empty if no match)
104
+ * @abstract
105
+ */
106
+ async findEntities(filter) {
107
+ throw new Error('Method findEntities must be implemented by subclass');
108
+ }
109
+
110
+ /**
111
+ * Create a new entity
112
+ *
113
+ * @param {Object} entityData - Entity data
114
+ * @returns {Promise<Object>} Created entity object
115
+ * @abstract
116
+ */
117
+ async createEntity(entityData) {
118
+ throw new Error('Method createEntity must be implemented by subclass');
119
+ }
120
+
121
+ /**
122
+ * Update entity by ID
123
+ *
124
+ * @param {string|number} entityId - Entity ID to update
125
+ * @param {Object} updates - Fields to update
126
+ * @returns {Promise<Object>} Updated entity object
127
+ * @abstract
128
+ */
129
+ async updateEntity(entityId, updates) {
130
+ throw new Error('Method updateEntity must be implemented by subclass');
131
+ }
132
+
133
+ /**
134
+ * Delete entity by ID
135
+ *
136
+ * @param {string|number} entityId - Entity ID to delete
137
+ * @returns {Promise<Object>} Deletion result
138
+ * @abstract
139
+ */
140
+ async deleteEntity(entityId) {
141
+ throw new Error('Method deleteEntity must be implemented by subclass');
142
+ }
143
+ }
144
+
145
+ module.exports = { ModuleRepositoryInterface };