@friggframework/core 2.0.0-next.11 → 2.0.0-next.110

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (375) hide show
  1. package/CLAUDE.md +702 -0
  2. package/README.md +999 -50
  3. package/admin-scripts/index.js +52 -0
  4. package/admin-scripts/repositories/admin-script-execution-repository-documentdb.js +21 -0
  5. package/admin-scripts/repositories/admin-script-execution-repository-factory.js +51 -0
  6. package/admin-scripts/repositories/admin-script-execution-repository-interface.js +171 -0
  7. package/admin-scripts/repositories/admin-script-execution-repository-mongo.js +238 -0
  8. package/admin-scripts/repositories/admin-script-execution-repository-postgres.js +278 -0
  9. package/admin-scripts/repositories/script-schedule-repository-documentdb.js +21 -0
  10. package/admin-scripts/repositories/script-schedule-repository-factory.js +51 -0
  11. package/admin-scripts/repositories/script-schedule-repository-interface.js +108 -0
  12. package/admin-scripts/repositories/script-schedule-repository-mongo.js +179 -0
  13. package/admin-scripts/repositories/script-schedule-repository-postgres.js +210 -0
  14. package/application/commands/README.md +451 -0
  15. package/application/commands/admin-script-commands.js +359 -0
  16. package/application/commands/credential-commands.js +262 -0
  17. package/application/commands/entity-commands.js +336 -0
  18. package/application/commands/integration-commands.js +356 -0
  19. package/application/commands/integration-mapping-commands.js +25 -0
  20. package/application/commands/process-commands.js +135 -0
  21. package/application/commands/report-commands.js +188 -0
  22. package/application/commands/scheduler-commands.js +263 -0
  23. package/application/commands/usage-commands.js +56 -0
  24. package/application/commands/user-commands.js +312 -0
  25. package/application/index.js +83 -0
  26. package/artifacts/repositories/artifact-repository-factory.js +19 -0
  27. package/artifacts/repositories/artifact-repository-interface.js +27 -0
  28. package/artifacts/repositories/artifact-repository-local.js +42 -0
  29. package/artifacts/repositories/artifact-repository-s3.js +61 -0
  30. package/assertions/index.js +0 -3
  31. package/core/CLAUDE.md +700 -0
  32. package/core/Worker.js +60 -24
  33. package/core/create-handler.js +189 -5
  34. package/core/parameters-to-env.js +257 -0
  35. package/core/ssm-preload.mjs +34 -0
  36. package/credential/repositories/credential-active-type.js +32 -0
  37. package/credential/repositories/credential-repository-documentdb.js +355 -0
  38. package/credential/repositories/credential-repository-factory.js +54 -0
  39. package/credential/repositories/credential-repository-interface.js +113 -0
  40. package/credential/repositories/credential-repository-mongo.js +294 -0
  41. package/credential/repositories/credential-repository-postgres.js +312 -0
  42. package/credential/repositories/credential-repository.js +300 -0
  43. package/credential/use-cases/get-credential-for-user.js +25 -0
  44. package/credential/use-cases/update-authentication-status.js +15 -0
  45. package/database/MONGODB_TRANSACTION_FIX.md +198 -0
  46. package/database/adapters/lambda-invoker.js +97 -0
  47. package/database/config.js +154 -0
  48. package/database/documentdb-encryption-service.js +330 -0
  49. package/database/documentdb-utils.js +192 -0
  50. package/database/encryption/README.md +839 -0
  51. package/database/encryption/documentdb-encryption-service.md +3575 -0
  52. package/database/encryption/encryption-schema-registry.js +401 -0
  53. package/database/encryption/field-encryption-service.js +254 -0
  54. package/database/encryption/logger.js +79 -0
  55. package/database/encryption/prisma-encryption-extension.js +230 -0
  56. package/database/index.js +21 -21
  57. package/database/prisma.js +182 -0
  58. package/database/repositories/health-check-repository-documentdb.js +138 -0
  59. package/database/repositories/health-check-repository-factory.js +48 -0
  60. package/database/repositories/health-check-repository-interface.js +82 -0
  61. package/database/repositories/health-check-repository-mongodb.js +89 -0
  62. package/database/repositories/health-check-repository-postgres.js +82 -0
  63. package/database/repositories/migration-status-repository-s3.js +137 -0
  64. package/database/use-cases/check-database-health-use-case.js +29 -0
  65. package/database/use-cases/check-database-state-use-case.js +81 -0
  66. package/database/use-cases/check-encryption-health-use-case.js +83 -0
  67. package/database/use-cases/get-database-state-via-worker-use-case.js +61 -0
  68. package/database/use-cases/get-migration-status-use-case.js +93 -0
  69. package/database/use-cases/resolve-migration-via-worker-use-case.js +49 -0
  70. package/database/use-cases/run-database-migration-use-case.js +139 -0
  71. package/database/use-cases/test-encryption-use-case.js +253 -0
  72. package/database/use-cases/trigger-database-migration-use-case.js +157 -0
  73. package/database/utils/mongodb-collection-utils.js +94 -0
  74. package/database/utils/mongodb-schema-init.js +108 -0
  75. package/database/utils/prisma-runner.js +491 -0
  76. package/database/utils/prisma-schema-parser.js +182 -0
  77. package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +517 -0
  78. package/encrypt/Cryptor.js +34 -168
  79. package/encrypt/index.js +1 -2
  80. package/errors/client-safe-error.js +26 -0
  81. package/errors/fetch-error.js +15 -7
  82. package/errors/index.js +2 -0
  83. package/generated/prisma-mongodb/client.d.ts +1 -0
  84. package/generated/prisma-mongodb/client.js +5 -0
  85. package/generated/prisma-mongodb/default.d.ts +1 -0
  86. package/generated/prisma-mongodb/default.js +5 -0
  87. package/generated/prisma-mongodb/edge.d.ts +1 -0
  88. package/generated/prisma-mongodb/edge.js +386 -0
  89. package/generated/prisma-mongodb/index-browser.js +368 -0
  90. package/generated/prisma-mongodb/index.d.ts +27065 -0
  91. package/generated/prisma-mongodb/index.js +411 -0
  92. package/generated/prisma-mongodb/libquery_engine-debian-openssl-3.0.x.so.node +0 -0
  93. package/generated/prisma-mongodb/libquery_engine-rhel-openssl-3.0.x.so.node +0 -0
  94. package/generated/prisma-mongodb/package.json +183 -0
  95. package/generated/prisma-mongodb/runtime/edge-esm.js +35 -0
  96. package/generated/prisma-mongodb/runtime/edge.js +35 -0
  97. package/generated/prisma-mongodb/runtime/index-browser.d.ts +370 -0
  98. package/generated/prisma-mongodb/runtime/index-browser.js +17 -0
  99. package/generated/prisma-mongodb/runtime/library.d.ts +3982 -0
  100. package/generated/prisma-mongodb/runtime/library.js +147 -0
  101. package/generated/prisma-mongodb/runtime/react-native.js +84 -0
  102. package/generated/prisma-mongodb/runtime/wasm-compiler-edge.js +85 -0
  103. package/generated/prisma-mongodb/runtime/wasm-engine-edge.js +38 -0
  104. package/generated/prisma-mongodb/schema.prisma +455 -0
  105. package/generated/prisma-mongodb/wasm-edge-light-loader.mjs +5 -0
  106. package/generated/prisma-mongodb/wasm-worker-loader.mjs +5 -0
  107. package/generated/prisma-mongodb/wasm.d.ts +1 -0
  108. package/generated/prisma-mongodb/wasm.js +393 -0
  109. package/generated/prisma-postgresql/client.d.ts +1 -0
  110. package/generated/prisma-postgresql/client.js +5 -0
  111. package/generated/prisma-postgresql/default.d.ts +1 -0
  112. package/generated/prisma-postgresql/default.js +5 -0
  113. package/generated/prisma-postgresql/edge.d.ts +1 -0
  114. package/generated/prisma-postgresql/edge.js +407 -0
  115. package/generated/prisma-postgresql/index-browser.js +389 -0
  116. package/generated/prisma-postgresql/index.d.ts +29904 -0
  117. package/generated/prisma-postgresql/index.js +432 -0
  118. package/generated/prisma-postgresql/libquery_engine-debian-openssl-3.0.x.so.node +0 -0
  119. package/generated/prisma-postgresql/libquery_engine-rhel-openssl-3.0.x.so.node +0 -0
  120. package/generated/prisma-postgresql/package.json +183 -0
  121. package/generated/prisma-postgresql/query_engine_bg.js +2 -0
  122. package/generated/prisma-postgresql/query_engine_bg.wasm +0 -0
  123. package/generated/prisma-postgresql/runtime/edge-esm.js +35 -0
  124. package/generated/prisma-postgresql/runtime/edge.js +35 -0
  125. package/generated/prisma-postgresql/runtime/index-browser.d.ts +370 -0
  126. package/generated/prisma-postgresql/runtime/index-browser.js +17 -0
  127. package/generated/prisma-postgresql/runtime/library.d.ts +3982 -0
  128. package/generated/prisma-postgresql/runtime/library.js +147 -0
  129. package/generated/prisma-postgresql/runtime/react-native.js +84 -0
  130. package/generated/prisma-postgresql/runtime/wasm-compiler-edge.js +85 -0
  131. package/generated/prisma-postgresql/runtime/wasm-engine-edge.js +38 -0
  132. package/generated/prisma-postgresql/schema.prisma +436 -0
  133. package/generated/prisma-postgresql/wasm-edge-light-loader.mjs +5 -0
  134. package/generated/prisma-postgresql/wasm-worker-loader.mjs +5 -0
  135. package/generated/prisma-postgresql/wasm.d.ts +1 -0
  136. package/generated/prisma-postgresql/wasm.js +414 -0
  137. package/handlers/WEBHOOKS.md +653 -0
  138. package/handlers/app-definition-loader.js +67 -0
  139. package/handlers/app-handler-helpers.js +3 -3
  140. package/handlers/backend-utils.js +271 -42
  141. package/handlers/database-migration-handler.js +227 -0
  142. package/handlers/integration-event-dispatcher.js +68 -0
  143. package/handlers/middleware/admin-auth.js +73 -0
  144. package/handlers/routers/HEALTHCHECK.md +342 -0
  145. package/handlers/routers/auth.js +4 -15
  146. package/handlers/routers/db-migration.handler.js +29 -0
  147. package/handlers/routers/db-migration.js +329 -0
  148. package/handlers/routers/health.js +518 -0
  149. package/handlers/routers/integration-defined-routers.js +85 -10
  150. package/handlers/routers/integration-webhook-routers.js +80 -0
  151. package/handlers/routers/user.js +27 -5
  152. package/handlers/routers/websocket.js +5 -3
  153. package/handlers/use-cases/check-external-apis-health-use-case.js +81 -0
  154. package/handlers/use-cases/check-integrations-health-use-case.js +44 -0
  155. package/handlers/workers/db-migration.js +427 -0
  156. package/handlers/workers/dlq-processor.js +63 -0
  157. package/handlers/workers/integration-defined-workers.js +13 -7
  158. package/index.js +102 -46
  159. package/infrastructure/scheduler/eventbridge-scheduler-adapter.js +184 -0
  160. package/infrastructure/scheduler/index.js +33 -0
  161. package/infrastructure/scheduler/mock-scheduler-adapter.js +143 -0
  162. package/infrastructure/scheduler/scheduler-service-factory.js +73 -0
  163. package/infrastructure/scheduler/scheduler-service-interface.js +47 -0
  164. package/integrations/EXTENSIONS.md +240 -0
  165. package/integrations/WEBHOOK-QUICKSTART.md +151 -0
  166. package/integrations/extension.js +254 -0
  167. package/integrations/index.js +20 -10
  168. package/integrations/integration-base.js +730 -74
  169. package/integrations/integration-router.js +398 -180
  170. package/integrations/options.js +1 -1
  171. package/integrations/repositories/config-patch-shared.js +43 -0
  172. package/integrations/repositories/integration-mapping-repository-documentdb.js +303 -0
  173. package/integrations/repositories/integration-mapping-repository-factory.js +57 -0
  174. package/integrations/repositories/integration-mapping-repository-interface.js +120 -0
  175. package/integrations/repositories/integration-mapping-repository-mongo.js +183 -0
  176. package/integrations/repositories/integration-mapping-repository-postgres.js +255 -0
  177. package/integrations/repositories/integration-mapping-repository.js +156 -0
  178. package/integrations/repositories/integration-repository-documentdb.js +322 -0
  179. package/integrations/repositories/integration-repository-factory.js +51 -0
  180. package/integrations/repositories/integration-repository-interface.js +189 -0
  181. package/integrations/repositories/integration-repository-mongo.js +450 -0
  182. package/integrations/repositories/integration-repository-postgres.js +492 -0
  183. package/integrations/repositories/process-repository-documentdb.js +311 -0
  184. package/integrations/repositories/process-repository-factory.js +53 -0
  185. package/integrations/repositories/process-repository-interface.js +136 -0
  186. package/integrations/repositories/process-repository-mongo.js +262 -0
  187. package/integrations/repositories/process-repository-postgres.js +380 -0
  188. package/integrations/repositories/process-update-ops-shared.js +112 -0
  189. package/integrations/repositories/report-id.js +13 -0
  190. package/integrations/tests/doubles/config-capturing-integration.js +81 -0
  191. package/integrations/tests/doubles/dummy-integration-class.js +113 -0
  192. package/integrations/tests/doubles/test-integration-repository.js +146 -0
  193. package/integrations/use-cases/create-integration.js +215 -0
  194. package/integrations/use-cases/create-process.js +130 -0
  195. package/integrations/use-cases/delete-integration-for-user.js +119 -0
  196. package/integrations/use-cases/find-integration-by-entity-external-id.js +74 -0
  197. package/integrations/use-cases/find-integration-context-by-external-entity-id.js +76 -0
  198. package/integrations/use-cases/get-integration-for-user.js +78 -0
  199. package/integrations/use-cases/get-integration-instance-by-definition.js +67 -0
  200. package/integrations/use-cases/get-integration-instance.js +83 -0
  201. package/integrations/use-cases/get-integrations-for-user.js +88 -0
  202. package/integrations/use-cases/get-possible-integrations.js +27 -0
  203. package/integrations/use-cases/get-process.js +89 -0
  204. package/integrations/use-cases/index.js +19 -0
  205. package/integrations/use-cases/list-integrations-by-entity-external-id.js +46 -0
  206. package/integrations/use-cases/load-integration-context.js +71 -0
  207. package/integrations/use-cases/patch-integration-config.js +39 -0
  208. package/integrations/use-cases/process-errors.js +28 -0
  209. package/integrations/use-cases/update-integration-config.js +32 -0
  210. package/integrations/use-cases/update-integration-messages.js +44 -0
  211. package/integrations/use-cases/update-integration-status.js +32 -0
  212. package/integrations/use-cases/update-integration.js +92 -0
  213. package/integrations/use-cases/update-process-metrics.js +222 -0
  214. package/integrations/use-cases/update-process-state.js +163 -0
  215. package/integrations/utils/map-integration-dto.js +37 -0
  216. package/jest-global-setup-noop.js +3 -0
  217. package/jest-global-teardown-noop.js +3 -0
  218. package/logs/logger.js +0 -4
  219. package/{module-plugin → modules}/index.js +0 -10
  220. package/modules/module-factory.js +56 -0
  221. package/modules/module.js +307 -0
  222. package/modules/repositories/module-repository-documentdb.js +350 -0
  223. package/modules/repositories/module-repository-factory.js +40 -0
  224. package/modules/repositories/module-repository-interface.js +145 -0
  225. package/modules/repositories/module-repository-mongo.js +436 -0
  226. package/modules/repositories/module-repository-postgres.js +481 -0
  227. package/modules/repositories/module-repository.js +369 -0
  228. package/modules/requester/api-key.js +52 -0
  229. package/modules/requester/oauth-2.js +555 -0
  230. package/modules/requester/requester.js +542 -0
  231. package/{module-plugin → modules}/test/mock-api/api.js +8 -3
  232. package/{module-plugin → modules}/test/mock-api/definition.js +14 -10
  233. package/modules/tests/doubles/test-module-factory.js +16 -0
  234. package/modules/tests/doubles/test-module-repository.js +39 -0
  235. package/modules/use-cases/get-entities-for-user.js +32 -0
  236. package/modules/use-cases/get-entity-options-by-id.js +71 -0
  237. package/modules/use-cases/get-entity-options-by-type.js +34 -0
  238. package/modules/use-cases/get-module-instance-from-type.js +34 -0
  239. package/modules/use-cases/get-module.js +74 -0
  240. package/modules/use-cases/process-authorization-callback.js +243 -0
  241. package/modules/use-cases/refresh-entity-options.js +72 -0
  242. package/modules/use-cases/test-module-auth.js +72 -0
  243. package/modules/utils/map-module-dto.js +18 -0
  244. package/package.json +92 -50
  245. package/prisma-mongodb/schema.prisma +455 -0
  246. package/prisma-postgresql/migrations/20250930193005_init/migration.sql +315 -0
  247. package/prisma-postgresql/migrations/20251006135218_init/migration.sql +9 -0
  248. package/prisma-postgresql/migrations/20251010000000_remove_unused_entity_reference_map/migration.sql +3 -0
  249. package/prisma-postgresql/migrations/20251112195422_update_user_unique_constraints/migration.sql +25 -0
  250. package/prisma-postgresql/migrations/20260422120000_add_entity_data_column/migration.sql +10 -0
  251. package/prisma-postgresql/migrations/20260422120001_create_process_table/migration.sql +48 -0
  252. package/prisma-postgresql/migrations/20260625000000_add_user_organization_id_index/migration.sql +2 -0
  253. package/prisma-postgresql/migrations/20260703000000_add_integration_status_in_creation_in_deletion/migration.sql +11 -0
  254. package/prisma-postgresql/migrations/20260703000001_integration_status_default_in_creation/migration.sql +8 -0
  255. package/prisma-postgresql/migrations/20260705000000_create_usage_counter/migration.sql +26 -0
  256. package/prisma-postgresql/migrations/20260706000000_add_admin_script_execution_and_schedule/migration.sql +61 -0
  257. package/prisma-postgresql/migrations/migration_lock.toml +3 -0
  258. package/prisma-postgresql/schema.prisma +436 -0
  259. package/queues/queuer-util.js +103 -21
  260. package/reporting/README.md +154 -0
  261. package/reporting/builtin-reports.js +6 -0
  262. package/reporting/index.js +13 -0
  263. package/reporting/report-base.js +49 -0
  264. package/reporting/reports/integrations-report.js +221 -0
  265. package/syncs/manager.js +468 -443
  266. package/syncs/repositories/sync-repository-documentdb.js +240 -0
  267. package/syncs/repositories/sync-repository-factory.js +43 -0
  268. package/syncs/repositories/sync-repository-interface.js +109 -0
  269. package/syncs/repositories/sync-repository-mongo.js +239 -0
  270. package/syncs/repositories/sync-repository-postgres.js +319 -0
  271. package/syncs/sync.js +0 -1
  272. package/telemetry/README.md +331 -0
  273. package/telemetry/bind-telemetry-context.js +73 -0
  274. package/telemetry/canonical-counters.js +52 -0
  275. package/telemetry/exporters.js +85 -0
  276. package/telemetry/index.js +26 -0
  277. package/telemetry/instrument-handler.js +87 -0
  278. package/telemetry/no-op-telemetry.js +67 -0
  279. package/telemetry/north-star.js +103 -0
  280. package/telemetry/otel-telemetry.js +213 -0
  281. package/telemetry/plugin-subscribers.js +77 -0
  282. package/telemetry/telemetry-config.js +120 -0
  283. package/telemetry/telemetry-context.js +40 -0
  284. package/telemetry/telemetry-event-bus.js +58 -0
  285. package/telemetry/telemetry-runtime.js +147 -0
  286. package/telemetry/telemetry-service.js +51 -0
  287. package/telemetry/usage-rollup-subscriber.js +116 -0
  288. package/token/repositories/token-repository-documentdb.js +137 -0
  289. package/token/repositories/token-repository-factory.js +40 -0
  290. package/token/repositories/token-repository-interface.js +131 -0
  291. package/token/repositories/token-repository-mongo.js +219 -0
  292. package/token/repositories/token-repository-postgres.js +264 -0
  293. package/token/repositories/token-repository.js +219 -0
  294. package/types/associations/index.d.ts +0 -17
  295. package/types/core/index.d.ts +12 -4
  296. package/types/database/index.d.ts +10 -2
  297. package/types/encrypt/index.d.ts +5 -3
  298. package/types/integrations/index.d.ts +3 -8
  299. package/types/module-plugin/index.d.ts +20 -69
  300. package/types/syncs/index.d.ts +0 -17
  301. package/usage/README.md +54 -0
  302. package/usage/index.js +17 -0
  303. package/usage/repositories/usage-repository-documentdb.js +194 -0
  304. package/usage/repositories/usage-repository-factory.js +25 -0
  305. package/usage/repositories/usage-repository-interface.js +37 -0
  306. package/usage/repositories/usage-repository-prisma.js +146 -0
  307. package/usage/tracked-metrics.js +38 -0
  308. package/usage/usage-windows.js +24 -0
  309. package/user/repositories/user-repository-documentdb.js +458 -0
  310. package/user/repositories/user-repository-factory.js +52 -0
  311. package/user/repositories/user-repository-interface.js +214 -0
  312. package/user/repositories/user-repository-mongo.js +323 -0
  313. package/user/repositories/user-repository-postgres.js +377 -0
  314. package/user/tests/doubles/test-user-repository.js +72 -0
  315. package/user/use-cases/authenticate-user.js +127 -0
  316. package/user/use-cases/authenticate-with-shared-secret.js +48 -0
  317. package/user/use-cases/create-individual-user.js +61 -0
  318. package/user/use-cases/create-organization-user.js +47 -0
  319. package/user/use-cases/create-token-for-user-id.js +30 -0
  320. package/user/use-cases/get-user-from-adopter-jwt.js +149 -0
  321. package/user/use-cases/get-user-from-bearer-token.js +77 -0
  322. package/user/use-cases/get-user-from-x-frigg-headers.js +132 -0
  323. package/user/use-cases/login-user.js +122 -0
  324. package/user/user.js +125 -0
  325. package/utils/backend-path.js +38 -0
  326. package/utils/index.js +6 -0
  327. package/websocket/repositories/websocket-connection-repository-documentdb.js +119 -0
  328. package/websocket/repositories/websocket-connection-repository-factory.js +44 -0
  329. package/websocket/repositories/websocket-connection-repository-interface.js +106 -0
  330. package/websocket/repositories/websocket-connection-repository-mongo.js +156 -0
  331. package/websocket/repositories/websocket-connection-repository-postgres.js +196 -0
  332. package/websocket/repositories/websocket-connection-repository.js +161 -0
  333. package/assertions/is-equal.js +0 -17
  334. package/associations/model.js +0 -54
  335. package/database/models/IndividualUser.js +0 -76
  336. package/database/models/OrganizationUser.js +0 -29
  337. package/database/models/State.js +0 -9
  338. package/database/models/Token.js +0 -70
  339. package/database/models/UserModel.js +0 -7
  340. package/database/models/WebsocketConnection.js +0 -49
  341. package/database/mongo.js +0 -45
  342. package/database/mongoose.js +0 -5
  343. package/encrypt/Cryptor.test.js +0 -32
  344. package/encrypt/encrypt.js +0 -132
  345. package/encrypt/encrypt.test.js +0 -1069
  346. package/encrypt/test-encrypt.js +0 -107
  347. package/errors/base-error.test.js +0 -32
  348. package/errors/fetch-error.test.js +0 -79
  349. package/errors/halt-error.test.js +0 -11
  350. package/errors/validation-errors.test.js +0 -120
  351. package/handlers/routers/middleware/loadUser.js +0 -15
  352. package/handlers/routers/middleware/requireLoggedInUser.js +0 -12
  353. package/integrations/create-frigg-backend.js +0 -31
  354. package/integrations/integration-factory.js +0 -251
  355. package/integrations/integration-mapping.js +0 -43
  356. package/integrations/integration-model.js +0 -46
  357. package/integrations/integration-user.js +0 -144
  358. package/integrations/test/integration-base.test.js +0 -144
  359. package/lambda/TimeoutCatcher.test.js +0 -68
  360. package/logs/logger.test.js +0 -76
  361. package/module-plugin/auther.js +0 -393
  362. package/module-plugin/credential.js +0 -22
  363. package/module-plugin/entity-manager.js +0 -70
  364. package/module-plugin/entity.js +0 -46
  365. package/module-plugin/manager.js +0 -169
  366. package/module-plugin/module-factory.js +0 -61
  367. package/module-plugin/requester/api-key.js +0 -36
  368. package/module-plugin/requester/oauth-2.js +0 -219
  369. package/module-plugin/requester/requester.js +0 -165
  370. package/module-plugin/requester/requester.test.js +0 -28
  371. package/module-plugin/test/auther.test.js +0 -97
  372. package/syncs/model.js +0 -62
  373. /package/{module-plugin → modules}/ModuleConstants.js +0 -0
  374. /package/{module-plugin → modules}/requester/basic.js +0 -0
  375. /package/{module-plugin → modules}/test/mock-api/mocks/hubspot.js +0 -0
package/core/CLAUDE.md ADDED
@@ -0,0 +1,700 @@
1
+ # CLAUDE.md - Frigg Core Runtime System
2
+
3
+ This file provides guidance to Claude Code when working with the Frigg Framework's core runtime system in `packages/core/core/`.
4
+
5
+ ## Critical Context (Read First)
6
+
7
+ - **Package Purpose**: Core runtime system and foundational classes for Frigg Lambda execution
8
+ - **Main Components**: Handler factory, Worker base class, Delegate pattern, Module loading
9
+ - **Core Architecture**: Lambda-optimized runtime with connection pooling, error handling, secrets management
10
+ - **Key Integration**: AWS Lambda, SQS job processing, MongoDB connections, AWS Secrets Manager
11
+ - **Security Model**: Automatic secrets injection, database connection management, user-facing error sanitization
12
+ - **DO NOT**: Expose internal errors to users, bypass connection pooling, skip database initialization
13
+
14
+ ## Core Components Architecture
15
+
16
+ ### Handler Creation System (`create-handler.js:9-67`)
17
+
18
+ **Purpose**: Factory for creating Lambda handlers with consistent infrastructure setup
19
+
20
+ **Key Features**:
21
+ - **Database Connection Management**: Automatic MongoDB connection with pooling
22
+ - **Secrets Management**: AWS Secrets Manager integration via `SECRET_ARN` env var
23
+ - **Error Sanitization**: Prevents internal details from leaking to end users
24
+ - **Debug Logging**: Request/response logging with structured debug info
25
+ - **Connection Optimization**: `context.callbackWaitsForEmptyEventLoop = false` for reuse
26
+
27
+ **Handler Configuration Options**:
28
+ ```javascript
29
+ const handler = createHandler({
30
+ eventName: 'MyIntegration', // For logging/debugging
31
+ isUserFacingResponse: true, // true = sanitize errors, false = pass through
32
+ method: async (event, context) => {}, // Your Lambda function logic
33
+ shouldUseDatabase: true // false = skip MongoDB connection
34
+ });
35
+ ```
36
+
37
+ **Error Handling Patterns**:
38
+ - **User-Facing**: Returns 500 with generic "Internal Error Occurred" message
39
+ - **Server-to-Server**: Re-throws errors for AWS to handle
40
+ - **Halt Errors**: `error.isHaltError = true` logs but returns success (no retry)
41
+
42
+ ### Worker Base Class (`Worker.js:9-83`)
43
+
44
+ **Purpose**: Base class for SQS job processing with standardized patterns
45
+
46
+ **Core Responsibilities**:
47
+ - **Queue Management**: Get SQS queue URLs and send messages
48
+ - **Batch Processing**: Process multiple SQS records in sequence
49
+ - **Message Validation**: Extensible parameter validation system
50
+ - **Error Handling**: Structured error handling for async job processing
51
+
52
+ **Usage Pattern**:
53
+ ```javascript
54
+ class MyWorker extends Worker {
55
+ async _run(params, context = {}) {
56
+ // Your job processing logic here
57
+ // params are already JSON.parsed from SQS message body
58
+ }
59
+
60
+ _validateParams(params) {
61
+ // Validate required parameters
62
+ this._verifyParamExists(params, 'requiredField');
63
+ }
64
+ }
65
+
66
+ // In your Lambda handler
67
+ const worker = new MyWorker();
68
+ await worker.run(event, context); // Process SQS Records
69
+ ```
70
+
71
+ **Message Sending**:
72
+ ```javascript
73
+ await worker.send({
74
+ QueueUrl: 'https://sqs.region.amazonaws.com/account/queue',
75
+ jobType: 'processAttachment',
76
+ integrationId: 'abc123',
77
+ // ... other job parameters
78
+ }, delaySeconds);
79
+ ```
80
+
81
+ ### Delegate Pattern System (`Delegate.js:3-27`)
82
+
83
+ **Purpose**: Observer/delegation pattern for decoupled component communication
84
+
85
+ **Core Concepts**:
86
+ - **Notification System**: Components notify delegates of events/state changes
87
+ - **Type Safety**: `delegateTypes` array defines valid notification strings
88
+ - **Bidirectional**: Supports both sending and receiving notifications
89
+ - **Null Safety**: Gracefully handles missing delegates
90
+
91
+ **Implementation Pattern**:
92
+ ```javascript
93
+ class MyIntegration extends Delegate {
94
+ constructor(params) {
95
+ super(params);
96
+ this.delegateTypes = ['processComplete', 'errorOccurred', 'statusUpdate'];
97
+ }
98
+
99
+ async processData(data) {
100
+ // Do work
101
+ await this.notify('statusUpdate', { progress: 50 });
102
+ // More work
103
+ await this.notify('processComplete', { result: data });
104
+ }
105
+
106
+ async receiveNotification(notifier, delegateString, object) {
107
+ // Handle notifications from other components
108
+ switch(delegateString) {
109
+ case 'dataReady':
110
+ await this.processData(object);
111
+ break;
112
+ }
113
+ }
114
+ }
115
+ ```
116
+
117
+ ### Module Loading System (`load-installed-modules.js:1-1085`)
118
+
119
+ **Purpose**: Dynamic loading and registration of integration modules
120
+
121
+ **Key Features**:
122
+ - **Package Discovery**: Automatically find `@friggframework/api-module-*` packages
123
+ - **Module Registration**: Load and register integration classes
124
+ - **Configuration Management**: Handle module-specific configuration
125
+ - **Dependency Resolution**: Manage inter-module dependencies
126
+
127
+ ## Runtime Lifecycle & Patterns
128
+
129
+ ### Lambda Handler Lifecycle
130
+ 1. **Pre-Execution Setup**:
131
+ ```javascript
132
+ initDebugLog(eventName, event); // Debug logging setup
133
+ await secretsToEnv(); // Secrets Manager injection
134
+ await parametersToEnv(); // SSM Parameter Store fetch (only when SSM_PARAMETER_PREFIX + FRIGG_SSM_OFFLOADED_KEYS are set)
135
+ context.callbackWaitsForEmptyEventLoop = false; // Connection pooling
136
+ ```
137
+
138
+ 2. **Database Connection**:
139
+ ```javascript
140
+ if (shouldUseDatabase) {
141
+ await connectToDatabase(); // MongoDB connection with pooling
142
+ }
143
+ ```
144
+
145
+ 3. **Method Execution**:
146
+ ```javascript
147
+ return await method(event, context); // Your integration logic
148
+ ```
149
+
150
+ 4. **Error Handling & Cleanup**:
151
+ ```javascript
152
+ flushDebugLog(error); // Debug info flush on error
153
+ // Sanitized error response for user-facing endpoints
154
+ ```
155
+
156
+ ### SQS Job Processing Lifecycle
157
+ 1. **Batch Processing**: Process all records in `event.Records` sequentially
158
+ 2. **Message Parsing**: JSON.parse message body for parameters
159
+ 3. **Validation**: Run custom validation on parsed parameters
160
+ 4. **Execution**: Call `_run()` method with validated parameters
161
+ 5. **Error Propagation**: Let AWS handle retries/DLQ for failed jobs
162
+
163
+ ### Secrets Management Integration
164
+ - **Automatic Injection**: If `SECRET_ARN` environment variable is set
165
+ - **Environment Variables**: Secrets automatically set as `process.env` variables
166
+ - **Security**: No secrets logging or exposure in error messages
167
+ - **Caching**: Secrets cached for Lambda container lifetime
168
+
169
+ ### SSM Parameter Store Loader (`parameters-to-env.js`)
170
+ Offloads env vars that would otherwise exceed Lambda's 4KB env limit. Runs right after `secretsToEnv()` and is a no-op unless both `SSM_PARAMETER_PREFIX` and `FRIGG_SSM_OFFLOADED_KEYS` (comma-separated env var names) are set.
171
+
172
+ - **Precedence**: real `process.env` > Secrets Manager > SSM. A key already present in `process.env` at load time is never fetched or overwritten (a documented local-debugging escape hatch); only keys the loader itself set are refreshed.
173
+ - **Fetch**: `GetParametersCommand` with `WithDecryption: true`, batched in groups of 10 (the GetParameters max). Parameter name for key `K` is `${SSM_PARAMETER_PREFIX}/${K}`.
174
+ - **TTL cache**: successful loads cache for `FRIGG_SSM_CACHE_TTL` seconds (default 300; `0` = forever). Concurrent callers share one in-flight promise. A failed initial load is never cached, so the next invocation retries; a failed TTL *refresh* keeps serving the stale values (warn + 30s backoff) instead of erroring a warm container. `ThrottlingException` is retried with short exponential backoff.
175
+ - **Fail-fast**: throws listing every missing parameter name (and the prefix) if a required key is absent from SSM. Keys already satisfied by real `process.env` never trigger a failure.
176
+ - **Security**: logs parameter names and versions only, never values.
177
+
178
+ ## Database Connection Patterns
179
+
180
+ ### Connection Pooling Strategy
181
+ ```javascript
182
+ // Mongoose connection reuse across Lambda invocations
183
+ context.callbackWaitsForEmptyEventLoop = false;
184
+ await connectToDatabase(); // Reuses existing connection if available
185
+ ```
186
+
187
+ ### Database Usage Patterns
188
+ ```javascript
189
+ // Conditional database connection
190
+ const handler = createHandler({
191
+ shouldUseDatabase: false, // Skip for database-free operations
192
+ method: async (event) => {
193
+ // No DB operations needed
194
+ return { statusCode: 200, body: 'OK' };
195
+ }
196
+ });
197
+ ```
198
+
199
+ ## Error Handling Architecture
200
+
201
+ ### Error Classification
202
+ 1. **User-Facing Errors**: `isUserFacingResponse: true`
203
+ - Returns generic 500 error message
204
+ - Prevents information disclosure
205
+ - Logs full error details internally
206
+
207
+ 2. **Server-to-Server Errors**: `isUserFacingResponse: false`
208
+ - Re-throws original error for AWS handling
209
+ - Used for SQS, SNS, and internal API calls
210
+ - Enables proper retry mechanisms
211
+
212
+ 3. **Halt Errors**: `error.isHaltError = true`
213
+ - Logs error but returns success
214
+ - Prevents infinite retries for known issues
215
+ - Used for graceful degradation scenarios
216
+
217
+ ### Debug Logging Strategy
218
+ ```javascript
219
+ initDebugLog(eventName, event); // Start logging context
220
+ // ... your code ...
221
+ flushDebugLog(error); // Flush on error (includes full context)
222
+ ```
223
+
224
+ ## Integration Development Patterns
225
+
226
+ ### Extending Worker for Job Processing
227
+ ```javascript
228
+ class AttachmentWorker extends Worker {
229
+ _validateParams(params) {
230
+ this._verifyParamExists(params, 'integrationId');
231
+ this._verifyParamExists(params, 'attachmentUrl');
232
+ this._verifyParamExists(params, 'destination');
233
+ }
234
+
235
+ async _run(params, context) {
236
+ const { integrationId, attachmentUrl, destination } = params;
237
+ // Process attachment upload/download
238
+ // Handle errors gracefully
239
+ // Update job status
240
+ }
241
+ }
242
+ ```
243
+
244
+ ### Creating Custom Handlers
245
+ ```javascript
246
+ const myIntegrationHandler = createHandler({
247
+ eventName: 'MyIntegration',
248
+ isUserFacingResponse: true, // Sanitize errors for users
249
+ shouldUseDatabase: true, // Need database access
250
+ method: async (event, context) => {
251
+ // Your integration logic here
252
+ // Database is already connected
253
+ // Secrets are in process.env
254
+
255
+ return {
256
+ statusCode: 200,
257
+ body: JSON.stringify({ success: true })
258
+ };
259
+ }
260
+ });
261
+ ```
262
+
263
+ ### Delegate Pattern for Integration Communication
264
+ ```javascript
265
+ class IntegrationManager extends Delegate {
266
+ constructor() {
267
+ super();
268
+ this.delegateTypes = [
269
+ 'authenticationComplete',
270
+ 'syncStarted',
271
+ 'syncComplete',
272
+ 'errorOccurred'
273
+ ];
274
+ }
275
+
276
+ async startSync(integrationId) {
277
+ await this.notify('syncStarted', { integrationId });
278
+ // ... sync logic ...
279
+ await this.notify('syncComplete', { integrationId, recordCount: 100 });
280
+ }
281
+ }
282
+ ```
283
+
284
+ ## Performance Optimization Patterns
285
+
286
+ ### Connection Reuse
287
+ ```javascript
288
+ // ALWAYS set this in handlers for performance
289
+ context.callbackWaitsForEmptyEventLoop = false;
290
+ ```
291
+
292
+ ### Conditional Database Usage
293
+ ```javascript
294
+ // Skip database for lightweight operations
295
+ const handler = createHandler({
296
+ shouldUseDatabase: false, // Faster cold starts
297
+ method: healthCheckMethod
298
+ });
299
+ ```
300
+
301
+ ### SQS Batch Processing Optimization
302
+ ```javascript
303
+ // Process records sequentially (not parallel) for resource control
304
+ for (const record of records) {
305
+ await this._run(JSON.parse(record.body), context);
306
+ }
307
+ ```
308
+
309
+ ## Repository & Use Case Architecture
310
+
311
+ The Frigg Framework follows DDD/Hexagonal Architecture with clear separation between handlers, use cases, and repositories.
312
+
313
+ ### Repository Pattern in Core
314
+
315
+ **Purpose**: Abstract database and external system access into dedicated repository classes.
316
+
317
+ **Structure**:
318
+ ```javascript
319
+ // Example: packages/core/database/websocket-connection-repository.js
320
+ class WebsocketConnectionRepository {
321
+ /**
322
+ * Create a new WebSocket connection record
323
+ * Pure database operation - no business logic
324
+ */
325
+ async createConnection(connectionId) {
326
+ return await WebsocketConnection.create({ connectionId });
327
+ }
328
+
329
+ /**
330
+ * Delete a WebSocket connection record
331
+ * Returns raw deletion result
332
+ */
333
+ async deleteConnection(connectionId) {
334
+ return await WebsocketConnection.deleteOne({ connectionId });
335
+ }
336
+
337
+ /**
338
+ * Get all active connections
339
+ * Returns raw data from database
340
+ */
341
+ async getActiveConnections() {
342
+ return await WebsocketConnection.getActiveConnections();
343
+ }
344
+ }
345
+ ```
346
+
347
+ **Repository Responsibilities**:
348
+ - ✅ **CRUD operations** - Create, Read, Update, Delete database records
349
+ - ✅ **Query execution** - Run database queries and return results
350
+ - ✅ **Data access only** - No interpretation or decision-making
351
+ - ✅ **Atomic operations** - Each method performs one database operation
352
+ - ❌ **NO business logic** - Don't decide what data means or what to do with it
353
+ - ❌ **NO orchestration** - Don't coordinate multiple operations
354
+
355
+ **Real Repository Examples**:
356
+ - `WebsocketConnectionRepository` - WebSocket persistence (packages/core/database/websocket-connection-repository.js)
357
+ - `SyncRepository` - Sync object management (packages/core/syncs/sync-repository.js)
358
+ - `IntegrationMappingRepository` - Integration mappings (packages/core/integrations/integration-mapping-repository.js)
359
+ - `TokenRepository` - Token operations (packages/core/database/token-repository.js)
360
+ - `HealthCheckRepository` - Health check data access (packages/core/database/health-check-repository.js)
361
+
362
+ ### Use Case Pattern in Core
363
+
364
+ **Purpose**: Contain business logic, orchestration, and workflow coordination.
365
+
366
+ **Structure**:
367
+ ```javascript
368
+ // Example: packages/core/database/use-cases/check-database-health-use-case.js
369
+ class CheckDatabaseHealthUseCase {
370
+ constructor({ healthCheckRepository }) {
371
+ // Dependency injection - receive repository via constructor
372
+ this.repository = healthCheckRepository;
373
+ }
374
+
375
+ async execute() {
376
+ // 1. Get raw data from repository
377
+ const { stateName, isConnected } = this.repository.getDatabaseConnectionState();
378
+
379
+ // 2. Apply business logic - determine health status
380
+ const result = {
381
+ status: isConnected ? 'healthy' : 'unhealthy',
382
+ state: stateName,
383
+ };
384
+
385
+ // 3. Orchestration - conditionally perform additional checks
386
+ if (isConnected) {
387
+ result.responseTime = await this.repository.pingDatabase(2000);
388
+ }
389
+
390
+ return result;
391
+ }
392
+ }
393
+ ```
394
+
395
+ **Use Case Responsibilities**:
396
+ - ✅ **Business logic** - Make decisions based on data
397
+ - ✅ **Orchestration** - Coordinate multiple repository calls
398
+ - ✅ **Validation** - Enforce business rules
399
+ - ✅ **Workflow** - Determine what happens next
400
+ - ✅ **Error handling** - Handle domain-specific errors
401
+ - ❌ **NO direct database access** - Always use repositories
402
+ - ❌ **NO HTTP concerns** - Don't know about status codes or headers
403
+
404
+ **Real Use Case Examples**:
405
+ - `CheckDatabaseHealthUseCase` - Database health business logic (packages/core/database/use-cases/check-database-health-use-case.js)
406
+ - `TestEncryptionUseCase` - Encryption testing workflow (packages/core/database/use-cases/test-encryption-use-case.js)
407
+
408
+ ### Handler Pattern in Core
409
+
410
+ **Purpose**: Translate Lambda/HTTP/SQS events into use case calls.
411
+
412
+ **Handler Should ONLY**:
413
+ - Define routes and event handlers
414
+ - Call use cases (NOT repositories)
415
+ - Map use case results to HTTP/Lambda responses
416
+ - Handle protocol-specific concerns (status codes, headers)
417
+
418
+ **❌ WRONG - Handler contains business logic**:
419
+ ```javascript
420
+ // BAD: Business logic in handler
421
+ router.get('/health', async (req, res) => {
422
+ const state = mongoose.connection.readyState;
423
+ const isHealthy = state === 1; // ❌ Business logic in handler
424
+
425
+ if (isHealthy) { // ❌ Orchestration in handler
426
+ const pingStart = Date.now();
427
+ await mongoose.connection.db.admin().ping(); // ❌ Direct DB access
428
+ const responseTime = Date.now() - pingStart;
429
+ res.json({ status: 'healthy', responseTime });
430
+ }
431
+ });
432
+ ```
433
+
434
+ **✅ CORRECT - Handler delegates to use case**:
435
+ ```javascript
436
+ // GOOD: Handler calls use case
437
+ const healthCheckRepository = new HealthCheckRepository();
438
+ const checkDatabaseHealthUseCase = new CheckDatabaseHealthUseCase({
439
+ healthCheckRepository
440
+ });
441
+
442
+ router.get('/health', async (req, res) => {
443
+ // Call use case - all business logic is there
444
+ const health = await checkDatabaseHealthUseCase.execute();
445
+
446
+ // Handler only maps to HTTP response
447
+ const statusCode = health.status === 'healthy' ? 200 : 503;
448
+ res.status(statusCode).json(health);
449
+ });
450
+ ```
451
+
452
+ ### Dependency Direction
453
+
454
+ **The Golden Rule**:
455
+ > "Handlers ONLY call Use Cases, NEVER Repositories or Business Logic directly"
456
+
457
+ **Correct Flow**:
458
+ ```
459
+ Handler/Router (createHandler)
460
+ ↓ calls
461
+ Use Case (execute)
462
+ ↓ calls
463
+ Repository (CRUD methods)
464
+ ↓ accesses
465
+ Database/External System
466
+ ```
467
+
468
+ **Why This Matters**:
469
+ - **Testability**: Use cases can be tested with mocked repositories
470
+ - **Reusability**: Use cases can be called from handlers, CLI, background jobs
471
+ - **Maintainability**: Business logic is centralized, not scattered across handlers
472
+ - **Flexibility**: Swap repository implementations without changing use cases
473
+
474
+ ### Migration from Old Patterns
475
+
476
+ **Old Pattern (Mongoose models everywhere)**:
477
+ ```javascript
478
+ // BAD: Direct model access in handlers
479
+ const handler = createHandler({
480
+ method: async (event) => {
481
+ const user = await User.findById(event.userId); // ❌ Direct model access
482
+ if (!user.isActive) { // ❌ Business logic in handler
483
+ throw new Error('User not active');
484
+ }
485
+ await Sync.create({ userId: user.id }); // ❌ Direct model access
486
+ }
487
+ });
488
+ ```
489
+
490
+ **New Pattern (Repository + Use Case)**:
491
+ ```javascript
492
+ // GOOD: Repository abstracts data access
493
+ class UserRepository {
494
+ async findById(userId) {
495
+ return await User.findById(userId);
496
+ }
497
+ }
498
+
499
+ class SyncRepository {
500
+ async createSync(data) {
501
+ return await Sync.create(data);
502
+ }
503
+ }
504
+
505
+ // GOOD: Use case contains business logic
506
+ class ActivateUserSyncUseCase {
507
+ constructor({ userRepository, syncRepository }) {
508
+ this.userRepo = userRepository;
509
+ this.syncRepo = syncRepository;
510
+ }
511
+
512
+ async execute(userId) {
513
+ const user = await this.userRepo.findById(userId);
514
+
515
+ if (!user.isActive) { // ✅ Business logic in use case
516
+ throw new Error('User not active');
517
+ }
518
+
519
+ return await this.syncRepo.createSync({ userId: user.id });
520
+ }
521
+ }
522
+
523
+ // GOOD: Handler delegates to use case
524
+ const handler = createHandler({
525
+ method: async (event) => {
526
+ const useCase = new ActivateUserSyncUseCase({
527
+ userRepository: new UserRepository(),
528
+ syncRepository: new SyncRepository()
529
+ });
530
+ return await useCase.execute(event.userId);
531
+ }
532
+ });
533
+ ```
534
+
535
+ ### Integration with Worker Pattern
536
+
537
+ **Workers should also follow this pattern**:
538
+
539
+ ```javascript
540
+ class ProcessAttachmentWorker extends Worker {
541
+ constructor() {
542
+ super();
543
+ // Inject repositories into use case
544
+ this.useCase = new ProcessAttachmentUseCase({
545
+ asanaRepository: new AsanaRepository(),
546
+ frontifyRepository: new FrontifyRepository()
547
+ });
548
+ }
549
+
550
+ _validateParams(params) {
551
+ this._verifyParamExists(params, 'attachmentId');
552
+ }
553
+
554
+ async _run(params, context) {
555
+ // Worker delegates to use case
556
+ return await this.useCase.execute(params.attachmentId);
557
+ }
558
+ }
559
+ ```
560
+
561
+ ### When to Extract to Repository/Use Case
562
+
563
+ **Extract to Repository when you see**:
564
+ - Direct Mongoose model calls (`User.findById()`, `Sync.create()`)
565
+ - Database queries in handlers or business logic
566
+ - External API calls scattered across codebase
567
+ - File system or AWS SDK operations in handlers
568
+
569
+ **Extract to Use Case when you see**:
570
+ - Business logic in handlers (if/else based on data)
571
+ - Orchestration of multiple operations
572
+ - Validation and error handling logic
573
+ - Workflow coordination
574
+
575
+ ### Testing with Repository/Use Case Pattern
576
+
577
+ **Repository Tests** (Integration tests with real DB):
578
+ ```javascript
579
+ describe('WebsocketConnectionRepository', () => {
580
+ it('creates connection record', async () => {
581
+ const repo = new WebsocketConnectionRepository();
582
+ const result = await repo.createConnection('conn-123');
583
+ expect(result.connectionId).toBe('conn-123');
584
+ });
585
+ });
586
+ ```
587
+
588
+ **Use Case Tests** (Unit tests with mocked repositories):
589
+ ```javascript
590
+ describe('CheckDatabaseHealthUseCase', () => {
591
+ it('returns unhealthy when disconnected', async () => {
592
+ const mockRepo = {
593
+ getDatabaseConnectionState: () => ({
594
+ stateName: 'disconnected',
595
+ isConnected: false
596
+ })
597
+ };
598
+ const useCase = new CheckDatabaseHealthUseCase({
599
+ healthCheckRepository: mockRepo
600
+ });
601
+ const result = await useCase.execute();
602
+ expect(result.status).toBe('unhealthy');
603
+ });
604
+ });
605
+ ```
606
+
607
+ **Handler Tests** (HTTP/Lambda response tests):
608
+ ```javascript
609
+ describe('Health Handler', () => {
610
+ it('returns 503 when unhealthy', async () => {
611
+ // Mock use case
612
+ const mockUseCase = {
613
+ execute: async () => ({ status: 'unhealthy' })
614
+ };
615
+ // Test HTTP response
616
+ const response = await handler(mockEvent, mockContext);
617
+ expect(response.statusCode).toBe(503);
618
+ });
619
+ });
620
+ ```
621
+
622
+ ## Anti-Patterns to Avoid
623
+
624
+ ### Core Runtime Anti-Patterns
625
+ ❌ **Don't expose internal errors** to user-facing endpoints - use `isUserFacingResponse: true`
626
+ ❌ **Don't skip connection optimization** - always set `callbackWaitsForEmptyEventLoop = false`
627
+ ❌ **Don't parallel process SQS records** - sequential processing prevents resource exhaustion
628
+ ❌ **Don't hardcode queue URLs** - use the Worker's `getQueueURL()` method
629
+ ❌ **Don't bypass parameter validation** - always implement `_validateParams()` in Workers
630
+ ❌ **Don't leak secrets in logs** - the system handles this, don't override
631
+ ❌ **Don't ignore delegate types** - define valid `delegateTypes` array for type safety
632
+
633
+ ### DDD/Hexagonal Architecture Anti-Patterns
634
+ ❌ **Don't access models directly in handlers** - create repositories to abstract data access
635
+ ❌ **Don't put business logic in handlers** - extract to use cases
636
+ ❌ **Don't call repositories from handlers** - always go through use cases
637
+ ❌ **Don't put orchestration in repositories** - repositories should be atomic CRUD operations
638
+ ❌ **Don't skip dependency injection** - inject repositories into use cases via constructor
639
+ ❌ **Don't create "god" use cases** - keep use cases focused on single business operations
640
+ ❌ **Don't mix database queries with business logic** - separate into repository + use case
641
+
642
+ ## Testing Patterns
643
+
644
+ ### Handler Testing
645
+ ```javascript
646
+ const { createHandler } = require('@friggframework/core/core');
647
+
648
+ const testHandler = createHandler({
649
+ isUserFacingResponse: false, // Get full errors in tests
650
+ shouldUseDatabase: false, // Mock/skip DB in tests
651
+ method: yourTestMethod
652
+ });
653
+
654
+ // Test with mock event/context
655
+ const result = await testHandler(mockEvent, mockContext);
656
+ ```
657
+
658
+ ### Worker Testing
659
+ ```javascript
660
+ class TestWorker extends Worker {
661
+ _validateParams(params) {
662
+ this._verifyParamExists(params, 'testField');
663
+ }
664
+
665
+ async _run(params, context) {
666
+ // Your test logic
667
+ return { processed: true };
668
+ }
669
+ }
670
+
671
+ // Test SQS record processing
672
+ const worker = new TestWorker();
673
+ await worker.run({
674
+ Records: [{
675
+ body: JSON.stringify({ testField: 'value' })
676
+ }]
677
+ });
678
+ ```
679
+
680
+ ## Environment Variables
681
+
682
+ ### Required Variables
683
+ - `AWS_REGION`: AWS region for SQS operations
684
+ - `SECRET_ARN`: (Optional) AWS Secrets Manager secret ARN for automatic injection
685
+
686
+ ### Database Variables
687
+ - MongoDB connection variables (handled by `../database/mongo`)
688
+ - See database module documentation for complete list
689
+
690
+ ### Queue Variables
691
+ - Queue URLs typically passed as parameters, not environment variables
692
+ - Use Worker's `getQueueURL()` method for dynamic queue discovery
693
+
694
+ ## Security Considerations
695
+
696
+ - **Secrets**: Never log or expose secrets in error messages
697
+ - **Error Messages**: Always sanitize errors for user-facing responses
698
+ - **Database**: Connection pooling reuses connections securely
699
+ - **SQS**: Message validation prevents injection attacks
700
+ - **Logging**: Debug logs include sensitive data - handle carefully in production