@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,438 @@
1
+ /**
2
+ * Database Migration Lambda Handler
3
+ *
4
+ * Lambda function that runs Prisma database migrations from within the VPC,
5
+ * enabling CI/CD pipelines to migrate databases without requiring public access.
6
+ *
7
+ * This handler uses the prisma-runner utilities from @friggframework/core,
8
+ * ensuring consistency with the `frigg db:setup` command.
9
+ *
10
+ * Environment Variables Required:
11
+ * - DATABASE_URL: Database connection string (automatically set from Secrets Manager)
12
+ * - DB_TYPE: Database type ('postgresql', 'mongodb', or 'documentdb')
13
+ * - STAGE: Deployment stage (determines migration command: 'dev' or 'deploy')
14
+ *
15
+ * Invocation:
16
+ * aws lambda invoke \
17
+ * --function-name my-app-production-dbMigrate \
18
+ * --region us-east-1 \
19
+ * response.json
20
+ *
21
+ * Success Response:
22
+ * {
23
+ * "statusCode": 200,
24
+ * "body": {
25
+ * "success": true,
26
+ * "message": "Database migration completed successfully",
27
+ * "dbType": "postgresql",
28
+ * "stage": "production",
29
+ * "migrationCommand": "deploy"
30
+ * }
31
+ * }
32
+ *
33
+ * Error Response:
34
+ * {
35
+ * "statusCode": 500,
36
+ * "body": {
37
+ * "success": false,
38
+ * "error": "Migration failed: ...",
39
+ * "stack": "Error: ..."
40
+ * }
41
+ * }
42
+ */
43
+
44
+ const {
45
+ RunDatabaseMigrationUseCase,
46
+ MigrationError,
47
+ ValidationError,
48
+ } = require('../../database/use-cases/run-database-migration-use-case');
49
+ const {
50
+ CheckDatabaseStateUseCase,
51
+ } = require('../../database/use-cases/check-database-state-use-case');
52
+ const {
53
+ MigrationStatusRepositoryS3,
54
+ } = require('../../database/repositories/migration-status-repository-s3');
55
+
56
+ // Inject prisma-runner as dependency
57
+ const prismaRunner = require('../../database/utils/prisma-runner');
58
+ const { getLogger } = require('../../logs');
59
+
60
+ const log = getLogger('frigg.database.migration');
61
+
62
+ // Use S3 repository for migration status tracking (no User table dependency)
63
+ const bucketName = process.env.S3_BUCKET_NAME || process.env.MIGRATION_STATUS_BUCKET;
64
+ const migrationStatusRepository = new MigrationStatusRepositoryS3(bucketName);
65
+
66
+ /**
67
+ * Sanitizes error messages to prevent credential leaks
68
+ * @param {string} errorMessage - Error message that might contain credentials
69
+ * @returns {string} Sanitized error message
70
+ */
71
+ function sanitizeError(errorMessage) {
72
+ if (!errorMessage) return 'Unknown error';
73
+
74
+ return String(errorMessage)
75
+ // Remove PostgreSQL connection strings
76
+ .replace(/postgresql:\/\/[^@\s]+@[^\s/]+/gi, 'postgresql://***:***@***')
77
+ // Remove MongoDB connection strings
78
+ .replace(/mongodb(\+srv)?:\/\/[^@\s]+@[^\s/]+/gi, 'mongodb$1://***:***@***')
79
+ // Remove password parameters
80
+ .replace(/password[=:]\s*[^\s,;)]+/gi, 'password=***')
81
+ // Remove API keys
82
+ .replace(/apikey[=:]\s*[^\s,;)]+/gi, 'apikey=***')
83
+ .replace(/api[_-]?key[=:]\s*[^\s,;)]+/gi, 'api_key=***')
84
+ // Remove tokens
85
+ .replace(/token[=:]\s*[^\s,;)]+/gi, 'token=***')
86
+ .replace(/bearer\s+[^\s,;)]+/gi, 'bearer ***');
87
+ }
88
+
89
+ /**
90
+ * Sanitizes DATABASE_URL for safe logging
91
+ * @param {string} url - Database URL
92
+ * @returns {string} Sanitized URL
93
+ */
94
+ function sanitizeDatabaseUrl(url) {
95
+ if (!url) return '';
96
+
97
+ // Replace credentials in connection string
98
+ return url.replace(/(:\/\/)([^:]+):([^@]+)@/, '$1***:***@');
99
+ }
100
+
101
+ /**
102
+ * Extract migration parameters from SQS event or direct invocation
103
+ * @param {Object} event - Lambda event (SQS or direct)
104
+ * @returns {Object} Extracted parameters { migrationId, dbType, stage }
105
+ */
106
+ function extractMigrationParams(event) {
107
+ let migrationId = null;
108
+ let stage = null;
109
+ let dbType = process.env.DB_TYPE || 'postgresql';
110
+
111
+ // Check if this is an SQS event
112
+ if (event.Records && event.Records.length > 0) {
113
+ // SQS event - extract from message body
114
+ const message = JSON.parse(event.Records[0].body);
115
+ migrationId = message.migrationId;
116
+ stage = message.stage || process.env.STAGE || 'production';
117
+ dbType = message.dbType || dbType;
118
+
119
+ console.log('SQS event detected');
120
+ console.log(` Migration ID: ${migrationId}`);
121
+ console.log(` DB Type: ${dbType}`);
122
+ console.log(` Stage: ${stage}`);
123
+ } else {
124
+ // Direct invocation - use event properties or environment variables
125
+ migrationId = event.migrationId || null;
126
+ stage = event.stage || process.env.STAGE || 'production';
127
+ dbType = event.dbType || dbType;
128
+
129
+ console.log('Direct invocation detected');
130
+ if (migrationId) {
131
+ console.log(` Migration ID: ${migrationId}`);
132
+ }
133
+ console.log(` DB Type: ${dbType}`);
134
+ console.log(` Stage: ${stage}`);
135
+ }
136
+
137
+ return { migrationId, dbType, stage };
138
+ }
139
+
140
+ /**
141
+ * Lambda handler entry point
142
+ * @param {Object} event - Lambda event (SQS message or direct invocation)
143
+ * @param {Object} context - Lambda context (contains AWS request ID, timeout info)
144
+ * @returns {Promise<Object>} Response with statusCode and body
145
+ */
146
+ exports.handler = async (event, context) => {
147
+ console.log('========================================');
148
+ console.log('Database Migration Lambda Started');
149
+ console.log('========================================');
150
+ console.log('Context:', JSON.stringify({
151
+ requestId: context.requestId,
152
+ functionName: context.functionName,
153
+ remainingTimeInMillis: context.getRemainingTimeInMillis(),
154
+ }, null, 2));
155
+
156
+ // Extract migration parameters from event
157
+ const { migrationId, dbType, stage } = extractMigrationParams(event);
158
+
159
+ // Check for action parameter (direct invocation for status checks)
160
+ const action = event.action || 'migrate'; // Default to migration
161
+
162
+ // targetStage, not stage: the record's own stage field would win.
163
+ log.info('Database migration invoked', {
164
+ eventName: 'frigg.database.migration.invoked',
165
+ migrationId,
166
+ dbType,
167
+ targetStage: stage,
168
+ action,
169
+ });
170
+
171
+ // Handle checkStatus action
172
+ if (action === 'checkStatus') {
173
+ console.log(`\n========================================`);
174
+ console.log(`Action: checkStatus (dbType=${dbType}, stage=${stage})`);
175
+ console.log(`========================================`);
176
+
177
+ try {
178
+ const checkDbStateUseCase = new CheckDatabaseStateUseCase({ prismaRunner });
179
+ const status = await checkDbStateUseCase.execute(dbType, stage);
180
+
181
+ console.log('✓ Database state check completed');
182
+ console.log(` Up to date: ${status.upToDate}`);
183
+ console.log(` Pending migrations: ${status.pendingMigrations}`);
184
+
185
+ return {
186
+ statusCode: 200,
187
+ body: status,
188
+ };
189
+ } catch (error) {
190
+ console.error('❌ Database state check failed:', error.message);
191
+ return {
192
+ statusCode: 500,
193
+ body: {
194
+ success: false,
195
+ error: sanitizeError(error.message),
196
+ upToDate: false,
197
+ },
198
+ };
199
+ }
200
+ }
201
+
202
+ if (action === 'resolve') {
203
+ const { migrationName, resolveAction = 'applied' } = event;
204
+ console.log(`\n========================================`);
205
+ console.log(
206
+ `Action: resolve (migration=${migrationName}, mode=${resolveAction})`
207
+ );
208
+ console.log(`========================================`);
209
+
210
+ if (!migrationName) {
211
+ return {
212
+ statusCode: 400,
213
+ body: { success: false, error: 'migrationName is required' },
214
+ };
215
+ }
216
+ if (!/^\d{14}_[a-z0-9_]+$/i.test(migrationName)) {
217
+ return {
218
+ statusCode: 400,
219
+ body: {
220
+ success: false,
221
+ error: 'migrationName is not a valid migration identifier',
222
+ },
223
+ };
224
+ }
225
+ if (!['applied', 'rolled-back'].includes(resolveAction)) {
226
+ return {
227
+ statusCode: 400,
228
+ body: {
229
+ success: false,
230
+ error: 'resolveAction must be "applied" or "rolled-back"',
231
+ },
232
+ };
233
+ }
234
+ if (dbType !== 'postgresql') {
235
+ return {
236
+ statusCode: 400,
237
+ body: {
238
+ success: false,
239
+ error: `Migration resolve is only supported for postgresql, not "${dbType}"`,
240
+ },
241
+ };
242
+ }
243
+
244
+ try {
245
+ const result = await prismaRunner.runPrismaMigrateResolve(
246
+ migrationName,
247
+ resolveAction,
248
+ true
249
+ );
250
+ if (!result.success) {
251
+ return {
252
+ statusCode: 500,
253
+ body: {
254
+ success: false,
255
+ error: sanitizeError(result.error),
256
+ },
257
+ };
258
+ }
259
+ return {
260
+ statusCode: 200,
261
+ body: {
262
+ success: true,
263
+ message: `Migration ${migrationName} marked as ${resolveAction}`,
264
+ migrationName,
265
+ action: resolveAction,
266
+ },
267
+ };
268
+ } catch (error) {
269
+ console.error('❌ Migration resolve failed:', error.message);
270
+ return {
271
+ statusCode: 500,
272
+ body: { success: false, error: sanitizeError(error.message) },
273
+ };
274
+ }
275
+ }
276
+
277
+ // Otherwise, handle migration (existing code)
278
+ console.log(`\n========================================`);
279
+ console.log(`Action: migrate (migrationId=${migrationId || 'new'})`);
280
+ console.log(`========================================`);
281
+
282
+ // Get environment variables
283
+ const databaseUrl = process.env.DATABASE_URL;
284
+
285
+ try {
286
+ // Validate DATABASE_URL is set
287
+ if (!databaseUrl) {
288
+ const error = 'DATABASE_URL environment variable is not set';
289
+ console.error('❌ Validation failed:', error);
290
+ return {
291
+ statusCode: 500,
292
+ body: JSON.stringify({
293
+ success: false,
294
+ error,
295
+ }),
296
+ };
297
+ }
298
+
299
+ console.log('✓ Environment validated');
300
+ console.log(` Database Type: ${dbType}`);
301
+ console.log(` Stage: ${stage}`);
302
+ console.log(` Database URL: ${sanitizeDatabaseUrl(databaseUrl)}`);
303
+
304
+ // Update migration status to RUNNING (if migrationId provided)
305
+ if (migrationId) {
306
+ console.log(`\n✓ Updating migration status to RUNNING: ${migrationId}`);
307
+ await migrationStatusRepository.update({
308
+ migrationId,
309
+ stage,
310
+ state: 'RUNNING',
311
+ progress: 10,
312
+ startedAt: new Date().toISOString(),
313
+ });
314
+ }
315
+
316
+ // Create use case with dependencies (Dependency Injection)
317
+ const runDatabaseMigrationUseCase = new RunDatabaseMigrationUseCase({
318
+ prismaRunner,
319
+ });
320
+
321
+ console.log('\n========================================');
322
+ console.log('Executing Database Migration');
323
+ console.log('========================================');
324
+
325
+ // Execute use case (business logic layer)
326
+ const result = await runDatabaseMigrationUseCase.execute({
327
+ dbType,
328
+ stage,
329
+ verbose: true, // Enable verbose output for Lambda CloudWatch logs
330
+ });
331
+
332
+ console.log('✓ Database migration completed successfully');
333
+ console.log('\n========================================');
334
+ console.log('Migration Summary');
335
+ console.log('========================================');
336
+ console.log(` Status: Success`);
337
+ console.log(` Database: ${result.dbType}`);
338
+ console.log(` Stage: ${result.stage}`);
339
+ console.log(` Command: ${result.command}`);
340
+ console.log('========================================');
341
+
342
+ // Update migration status to COMPLETED (if migrationId provided)
343
+ if (migrationId) {
344
+ console.log(`\n✓ Updating migration status to COMPLETED: ${migrationId}`);
345
+ await migrationStatusRepository.update({
346
+ migrationId,
347
+ stage,
348
+ state: 'COMPLETED',
349
+ progress: 100,
350
+ completedAt: new Date().toISOString(),
351
+ migrationCommand: result.command,
352
+ });
353
+ }
354
+
355
+ // Return success response (adapter layer - HTTP mapping)
356
+ const responseBody = {
357
+ success: true,
358
+ message: result.message,
359
+ dbType: result.dbType,
360
+ stage: result.stage,
361
+ migrationCommand: result.command,
362
+ timestamp: new Date().toISOString(),
363
+ };
364
+
365
+ if (migrationId) {
366
+ responseBody.migrationId = migrationId;
367
+ }
368
+
369
+ return {
370
+ statusCode: 200,
371
+ body: JSON.stringify(responseBody),
372
+ };
373
+
374
+ } catch (error) {
375
+ console.error('\n========================================');
376
+ console.error('Migration Failed');
377
+ console.error('========================================');
378
+ console.error('Error:', error.name, error.message);
379
+
380
+ // Log full stack trace to CloudWatch (only visible to developers)
381
+ if (error.stack) {
382
+ console.error('Stack:', error.stack);
383
+ }
384
+
385
+ // Log context if available (from MigrationError)
386
+ if (error.context) {
387
+ console.error('Context:', JSON.stringify(error.context, null, 2));
388
+ }
389
+
390
+ // Map domain errors to HTTP status codes (adapter layer)
391
+ let statusCode = 500;
392
+ let errorMessage = error.message || 'Unknown error occurred';
393
+
394
+ if (error instanceof ValidationError) {
395
+ statusCode = 400; // Bad Request for validation errors
396
+ } else if (error instanceof MigrationError) {
397
+ statusCode = 500; // Internal Server Error for migration failures
398
+ }
399
+
400
+ // Sanitize error message before returning
401
+ const sanitizedError = sanitizeError(errorMessage);
402
+
403
+ // Update migration status to FAILED (if migrationId provided)
404
+ if (migrationId) {
405
+ try {
406
+ console.log(`\n✓ Updating migration status to FAILED: ${migrationId}`);
407
+ await migrationStatusRepository.update({
408
+ migrationId,
409
+ stage,
410
+ state: 'FAILED',
411
+ progress: 0,
412
+ error: sanitizedError,
413
+ failedAt: new Date().toISOString(),
414
+ });
415
+ } catch (updateError) {
416
+ console.error('Failed to update migration status:', updateError.message);
417
+ // Continue - don't let status update failure block error response
418
+ }
419
+ }
420
+
421
+ const errorBody = {
422
+ success: false,
423
+ error: sanitizedError,
424
+ errorType: error.name || 'Error',
425
+ // Only include stack traces in development environments
426
+ ...(stage === 'dev' || stage === 'local' || stage === 'test' ? { stack: error.stack } : {}),
427
+ };
428
+
429
+ if (migrationId) {
430
+ errorBody.migrationId = migrationId;
431
+ }
432
+
433
+ return {
434
+ statusCode,
435
+ body: JSON.stringify(errorBody),
436
+ };
437
+ }
438
+ };
@@ -0,0 +1,89 @@
1
+ /**
2
+ * DLQ Processor — logs failed messages from the InternalErrorQueue
3
+ * with structured context for monitoring and debugging.
4
+ *
5
+ * This handler MUST NOT throw. If it throws, the message goes back to
6
+ * the DLQ and creates an infinite loop. All errors are caught and logged.
7
+ */
8
+ const crypto = require('node:crypto');
9
+ const { getLogger } = require('../../logs');
10
+ const {
11
+ summarizeLambdaEvent,
12
+ toScopeInvocation,
13
+ } = require('../../logs/summarize-event');
14
+ const {
15
+ runInvocationScope,
16
+ runMessageScope,
17
+ } = require('../../core/invocation-scope');
18
+
19
+ const log = getLogger('frigg.queue.dlq');
20
+
21
+ function extractQueueName(eventSourceARN) {
22
+ if (!eventSourceARN) return 'UNKNOWN';
23
+ const parts = eventSourceARN.split(':');
24
+ return parts[parts.length - 1] || 'UNKNOWN';
25
+ }
26
+
27
+ // The body can hold credentials, so only its size and digest are logged.
28
+ function describeBody(body) {
29
+ const text = typeof body === 'string' ? body : String(body ?? '');
30
+ let parsed = true;
31
+ try {
32
+ JSON.parse(text);
33
+ } catch {
34
+ parsed = false;
35
+ }
36
+ return {
37
+ parsed,
38
+ bodyLength: Buffer.byteLength(text),
39
+ bodySha256: crypto.createHash('sha256').update(text).digest('hex'),
40
+ };
41
+ }
42
+
43
+ function logRecord(record) {
44
+ const { parsed, ...body } = describeBody(record.body);
45
+ if (!parsed) {
46
+ log.warn('DLQ message body is not JSON', {
47
+ eventName: 'frigg.queue.dlq.body_unparsed',
48
+ ...body,
49
+ });
50
+ }
51
+ // messageId, receiveCount and the body ids come from the message scope.
52
+ log.error('Message reached the DLQ', {
53
+ eventName: 'frigg.queue.dlq.message_failed',
54
+ sentTimestamp: record.attributes?.SentTimestamp,
55
+ sourceQueue: extractQueueName(record.eventSourceARN),
56
+ ...body,
57
+ });
58
+ }
59
+
60
+ async function dlqProcessor(event, context) {
61
+ if (!event?.Records?.length) return { batchItemFailures: [] };
62
+
63
+ await runInvocationScope(
64
+ {
65
+ requestId: context?.awsRequestId,
66
+ handlerName: 'dlqProcessor',
67
+ invocation: toScopeInvocation(summarizeLambdaEvent(event)),
68
+ },
69
+ async () => {
70
+ for (const record of event.Records) {
71
+ await runMessageScope(record, async () => {
72
+ try {
73
+ logRecord(record);
74
+ } catch (error) {
75
+ log.error('DLQ record failed', {
76
+ eventName: 'frigg.queue.dlq.record_failed',
77
+ error,
78
+ });
79
+ }
80
+ });
81
+ }
82
+ },
83
+ { shouldUseDatabase: false, context }
84
+ );
85
+
86
+ return { batchItemFailures: [] };
87
+ }
88
+
89
+ module.exports = { dlqProcessor };
@@ -1,8 +1,18 @@
1
1
  const { createHandler } = require('@friggframework/core');
2
- const { integrationFactory, createQueueWorker } = require('../backend-utils');
2
+ const { loadAppDefinition } = require('../app-definition-loader');
3
+ const { createQueueWorker } = require('../backend-utils');
4
+ // TODO(Phase 2): mount extension-declared workers in addition to the per-integration
5
+ // default queue worker. Today, getExtensionWorkers(IntegrationClass) returns the
6
+ // declared workers but they are not yet bound to dedicated SQS sources. Extension-
7
+ // contributed *events* still flow through the default queue worker below because
8
+ // _mergeExtensions() registers them in instance.events, so end-to-end webhook
9
+ // delivery for Tier 3 extensions works without this Phase 2 work.
10
+ // const { getExtensionWorkers } = require('../../integrations/extension');
3
11
 
4
12
  const handlers = {};
5
- integrationFactory.integrationClasses.forEach((IntegrationClass) => {
13
+ const { integrations: integrationClasses } = loadAppDefinition();
14
+
15
+ integrationClasses.forEach((IntegrationClass) => {
6
16
  const defaultQueueWorker = createQueueWorker(IntegrationClass);
7
17
 
8
18
  handlers[`${IntegrationClass.Definition.name}`] = {
@@ -11,11 +21,7 @@ integrationFactory.integrationClasses.forEach((IntegrationClass) => {
11
21
  isUserFacingResponse: false,
12
22
  method: async (event, context) => {
13
23
  const worker = new defaultQueueWorker();
14
- await worker.run(event, context);
15
- return {
16
- message: 'Successfully processed the Generic Queue Worker',
17
- input: event,
18
- };
24
+ return await worker.run(event, context);
19
25
  },
20
26
  }),
21
27
  };