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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (410) hide show
  1. package/.eslintrc.json +18 -1
  2. package/CLAUDE.md +830 -0
  3. package/README.md +996 -50
  4. package/admin-scripts/index.js +52 -0
  5. package/admin-scripts/repositories/admin-script-execution-repository-documentdb.js +21 -0
  6. package/admin-scripts/repositories/admin-script-execution-repository-factory.js +51 -0
  7. package/admin-scripts/repositories/admin-script-execution-repository-interface.js +171 -0
  8. package/admin-scripts/repositories/admin-script-execution-repository-mongo.js +238 -0
  9. package/admin-scripts/repositories/admin-script-execution-repository-postgres.js +278 -0
  10. package/admin-scripts/repositories/script-schedule-repository-documentdb.js +21 -0
  11. package/admin-scripts/repositories/script-schedule-repository-factory.js +51 -0
  12. package/admin-scripts/repositories/script-schedule-repository-interface.js +108 -0
  13. package/admin-scripts/repositories/script-schedule-repository-mongo.js +179 -0
  14. package/admin-scripts/repositories/script-schedule-repository-postgres.js +210 -0
  15. package/application/commands/README.md +451 -0
  16. package/application/commands/admin-script-commands.js +359 -0
  17. package/application/commands/credential-commands.js +262 -0
  18. package/application/commands/entity-commands.js +294 -0
  19. package/application/commands/integration-commands.js +419 -0
  20. package/application/commands/integration-mapping-commands.js +25 -0
  21. package/application/commands/process-commands.js +135 -0
  22. package/application/commands/report-commands.js +188 -0
  23. package/application/commands/scheduler-commands.js +263 -0
  24. package/application/commands/usage-commands.js +56 -0
  25. package/application/commands/user-commands.js +312 -0
  26. package/application/index.js +83 -0
  27. package/artifacts/repositories/artifact-repository-factory.js +19 -0
  28. package/artifacts/repositories/artifact-repository-interface.js +27 -0
  29. package/artifacts/repositories/artifact-repository-local.js +42 -0
  30. package/artifacts/repositories/artifact-repository-s3.js +61 -0
  31. package/assertions/index.js +0 -3
  32. package/core/CLAUDE.md +715 -0
  33. package/core/Worker.js +55 -24
  34. package/core/create-handler.js +121 -38
  35. package/core/index.js +8 -1
  36. package/core/invocation-scope.js +225 -0
  37. package/core/parameters-to-env.js +257 -0
  38. package/core/secrets-to-env.js +7 -6
  39. package/core/ssm-preload.mjs +34 -0
  40. package/credential/repositories/credential-active-type.js +32 -0
  41. package/credential/repositories/credential-repository-documentdb.js +355 -0
  42. package/credential/repositories/credential-repository-factory.js +54 -0
  43. package/credential/repositories/credential-repository-interface.js +113 -0
  44. package/credential/repositories/credential-repository-mongo.js +294 -0
  45. package/credential/repositories/credential-repository-postgres.js +312 -0
  46. package/credential/repositories/credential-repository.js +300 -0
  47. package/credential/use-cases/get-credential-for-user.js +25 -0
  48. package/credential/use-cases/update-authentication-status.js +15 -0
  49. package/database/MONGODB_TRANSACTION_FIX.md +198 -0
  50. package/database/adapters/lambda-invoker.js +97 -0
  51. package/database/config.js +147 -0
  52. package/database/documentdb-encryption-service.js +334 -0
  53. package/database/documentdb-utils.js +196 -0
  54. package/database/encryption/README.md +863 -0
  55. package/database/encryption/documentdb-encryption-service.md +3575 -0
  56. package/database/encryption/encryption-schema-registry.js +404 -0
  57. package/database/encryption/field-encryption-service.js +254 -0
  58. package/database/encryption/integration-mapping-encryption.js +97 -0
  59. package/database/encryption/logger.js +82 -0
  60. package/database/encryption/prisma-encryption-extension.js +241 -0
  61. package/database/index.js +21 -21
  62. package/database/prisma.js +182 -0
  63. package/database/repositories/health-check-repository-documentdb.js +138 -0
  64. package/database/repositories/health-check-repository-factory.js +48 -0
  65. package/database/repositories/health-check-repository-interface.js +82 -0
  66. package/database/repositories/health-check-repository-mongodb.js +89 -0
  67. package/database/repositories/health-check-repository-postgres.js +82 -0
  68. package/database/repositories/migration-status-repository-s3.js +137 -0
  69. package/database/use-cases/check-database-health-use-case.js +29 -0
  70. package/database/use-cases/check-database-state-use-case.js +81 -0
  71. package/database/use-cases/check-encryption-health-use-case.js +83 -0
  72. package/database/use-cases/get-database-state-via-worker-use-case.js +61 -0
  73. package/database/use-cases/get-migration-status-use-case.js +93 -0
  74. package/database/use-cases/resolve-migration-via-worker-use-case.js +49 -0
  75. package/database/use-cases/run-database-migration-use-case.js +139 -0
  76. package/database/use-cases/test-encryption-use-case.js +253 -0
  77. package/database/use-cases/trigger-database-migration-use-case.js +157 -0
  78. package/database/utils/mongodb-collection-utils.js +94 -0
  79. package/database/utils/mongodb-schema-init.js +108 -0
  80. package/database/utils/prisma-runner.js +491 -0
  81. package/database/utils/prisma-schema-parser.js +182 -0
  82. package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +517 -0
  83. package/encrypt/Cryptor.js +34 -168
  84. package/encrypt/index.js +1 -2
  85. package/errors/client-safe-error.js +26 -0
  86. package/errors/fetch-error.js +59 -57
  87. package/errors/index.js +6 -0
  88. package/errors/mapping-already-exists-error.js +14 -0
  89. package/generated/prisma-mongodb/client.d.ts +1 -0
  90. package/generated/prisma-mongodb/client.js +5 -0
  91. package/generated/prisma-mongodb/default.d.ts +1 -0
  92. package/generated/prisma-mongodb/default.js +5 -0
  93. package/generated/prisma-mongodb/edge.d.ts +1 -0
  94. package/generated/prisma-mongodb/edge.js +386 -0
  95. package/generated/prisma-mongodb/index-browser.js +368 -0
  96. package/generated/prisma-mongodb/index.d.ts +27065 -0
  97. package/generated/prisma-mongodb/index.js +411 -0
  98. package/generated/prisma-mongodb/libquery_engine-debian-openssl-3.0.x.so.node +0 -0
  99. package/generated/prisma-mongodb/libquery_engine-rhel-openssl-3.0.x.so.node +0 -0
  100. package/generated/prisma-mongodb/package.json +183 -0
  101. package/generated/prisma-mongodb/runtime/edge-esm.js +35 -0
  102. package/generated/prisma-mongodb/runtime/edge.js +35 -0
  103. package/generated/prisma-mongodb/runtime/index-browser.d.ts +370 -0
  104. package/generated/prisma-mongodb/runtime/index-browser.js +17 -0
  105. package/generated/prisma-mongodb/runtime/library.d.ts +3982 -0
  106. package/generated/prisma-mongodb/runtime/library.js +147 -0
  107. package/generated/prisma-mongodb/runtime/react-native.js +84 -0
  108. package/generated/prisma-mongodb/runtime/wasm-compiler-edge.js +85 -0
  109. package/generated/prisma-mongodb/runtime/wasm-engine-edge.js +38 -0
  110. package/generated/prisma-mongodb/schema.prisma +455 -0
  111. package/generated/prisma-mongodb/wasm-edge-light-loader.mjs +5 -0
  112. package/generated/prisma-mongodb/wasm-worker-loader.mjs +5 -0
  113. package/generated/prisma-mongodb/wasm.d.ts +1 -0
  114. package/generated/prisma-mongodb/wasm.js +393 -0
  115. package/generated/prisma-postgresql/client.d.ts +1 -0
  116. package/generated/prisma-postgresql/client.js +5 -0
  117. package/generated/prisma-postgresql/default.d.ts +1 -0
  118. package/generated/prisma-postgresql/default.js +5 -0
  119. package/generated/prisma-postgresql/edge.d.ts +1 -0
  120. package/generated/prisma-postgresql/edge.js +407 -0
  121. package/generated/prisma-postgresql/index-browser.js +389 -0
  122. package/generated/prisma-postgresql/index.d.ts +29904 -0
  123. package/generated/prisma-postgresql/index.js +432 -0
  124. package/generated/prisma-postgresql/libquery_engine-debian-openssl-3.0.x.so.node +0 -0
  125. package/generated/prisma-postgresql/libquery_engine-rhel-openssl-3.0.x.so.node +0 -0
  126. package/generated/prisma-postgresql/package.json +183 -0
  127. package/generated/prisma-postgresql/query_engine_bg.js +2 -0
  128. package/generated/prisma-postgresql/query_engine_bg.wasm +0 -0
  129. package/generated/prisma-postgresql/runtime/edge-esm.js +35 -0
  130. package/generated/prisma-postgresql/runtime/edge.js +35 -0
  131. package/generated/prisma-postgresql/runtime/index-browser.d.ts +370 -0
  132. package/generated/prisma-postgresql/runtime/index-browser.js +17 -0
  133. package/generated/prisma-postgresql/runtime/library.d.ts +3982 -0
  134. package/generated/prisma-postgresql/runtime/library.js +147 -0
  135. package/generated/prisma-postgresql/runtime/react-native.js +84 -0
  136. package/generated/prisma-postgresql/runtime/wasm-compiler-edge.js +85 -0
  137. package/generated/prisma-postgresql/runtime/wasm-engine-edge.js +38 -0
  138. package/generated/prisma-postgresql/schema.prisma +436 -0
  139. package/generated/prisma-postgresql/wasm-edge-light-loader.mjs +5 -0
  140. package/generated/prisma-postgresql/wasm-worker-loader.mjs +5 -0
  141. package/generated/prisma-postgresql/wasm.d.ts +1 -0
  142. package/generated/prisma-postgresql/wasm.js +414 -0
  143. package/handlers/WEBHOOKS.md +682 -0
  144. package/handlers/app-definition-loader.js +103 -0
  145. package/handlers/app-handler-helpers.js +20 -6
  146. package/handlers/backend-utils.js +272 -46
  147. package/handlers/database-migration-handler.js +236 -0
  148. package/handlers/integration-event-dispatcher.js +68 -0
  149. package/handlers/middleware/admin-auth.js +73 -0
  150. package/handlers/routers/HEALTHCHECK.md +342 -0
  151. package/handlers/routers/auth.js +4 -15
  152. package/handlers/routers/db-migration.handler.js +29 -0
  153. package/handlers/routers/db-migration.js +329 -0
  154. package/handlers/routers/health.js +518 -0
  155. package/handlers/routers/integration-defined-routers.js +85 -10
  156. package/handlers/routers/integration-webhook-routers.js +87 -0
  157. package/handlers/routers/user.js +27 -5
  158. package/handlers/routers/websocket.js +31 -9
  159. package/handlers/use-cases/check-external-apis-health-use-case.js +81 -0
  160. package/handlers/use-cases/check-integrations-health-use-case.js +44 -0
  161. package/handlers/workers/db-migration.js +438 -0
  162. package/handlers/workers/dlq-processor.js +89 -0
  163. package/handlers/workers/integration-defined-workers.js +13 -7
  164. package/index.js +123 -47
  165. package/infrastructure/scheduler/eventbridge-scheduler-adapter.js +238 -0
  166. package/infrastructure/scheduler/index.js +33 -0
  167. package/infrastructure/scheduler/mock-scheduler-adapter.js +143 -0
  168. package/infrastructure/scheduler/scheduler-service-factory.js +73 -0
  169. package/infrastructure/scheduler/scheduler-service-interface.js +47 -0
  170. package/integrations/EXTENSIONS.md +240 -0
  171. package/integrations/WEBHOOK-QUICKSTART.md +151 -0
  172. package/integrations/extension.js +254 -0
  173. package/integrations/index.js +20 -10
  174. package/integrations/integration-base.js +777 -74
  175. package/integrations/integration-router.js +399 -180
  176. package/integrations/options.js +1 -1
  177. package/integrations/repositories/config-patch-shared.js +43 -0
  178. package/integrations/repositories/integration-mapping-query-pipeline.js +152 -0
  179. package/integrations/repositories/integration-mapping-query.js +193 -0
  180. package/integrations/repositories/integration-mapping-repository-documentdb.js +406 -0
  181. package/integrations/repositories/integration-mapping-repository-factory.js +57 -0
  182. package/integrations/repositories/integration-mapping-repository-interface.js +183 -0
  183. package/integrations/repositories/integration-mapping-repository-mongo.js +284 -0
  184. package/integrations/repositories/integration-mapping-repository-postgres.js +403 -0
  185. package/integrations/repositories/integration-mapping-repository.js +185 -0
  186. package/integrations/repositories/integration-repository-documentdb.js +354 -0
  187. package/integrations/repositories/integration-repository-factory.js +51 -0
  188. package/integrations/repositories/integration-repository-interface.js +219 -0
  189. package/integrations/repositories/integration-repository-mongo.js +502 -0
  190. package/integrations/repositories/integration-repository-postgres.js +550 -0
  191. package/integrations/repositories/process-repository-documentdb.js +311 -0
  192. package/integrations/repositories/process-repository-factory.js +53 -0
  193. package/integrations/repositories/process-repository-interface.js +136 -0
  194. package/integrations/repositories/process-repository-mongo.js +262 -0
  195. package/integrations/repositories/process-repository-postgres.js +380 -0
  196. package/integrations/repositories/process-update-ops-shared.js +112 -0
  197. package/integrations/repositories/report-id.js +13 -0
  198. package/integrations/tests/doubles/config-capturing-integration.js +81 -0
  199. package/integrations/tests/doubles/dummy-integration-class.js +113 -0
  200. package/integrations/tests/doubles/test-integration-repository.js +146 -0
  201. package/integrations/use-cases/add-entities-to-integration.js +92 -0
  202. package/integrations/use-cases/create-integration.js +253 -0
  203. package/integrations/use-cases/create-process.js +130 -0
  204. package/integrations/use-cases/delete-integration-for-user.js +130 -0
  205. package/integrations/use-cases/find-integration-by-entity-external-id.js +74 -0
  206. package/integrations/use-cases/find-integration-context-by-external-entity-id.js +76 -0
  207. package/integrations/use-cases/get-integration-for-user.js +78 -0
  208. package/integrations/use-cases/get-integration-instance-by-definition.js +67 -0
  209. package/integrations/use-cases/get-integration-instance.js +83 -0
  210. package/integrations/use-cases/get-integrations-for-user.js +88 -0
  211. package/integrations/use-cases/get-possible-integrations.js +27 -0
  212. package/integrations/use-cases/get-process.js +89 -0
  213. package/integrations/use-cases/index.js +19 -0
  214. package/integrations/use-cases/list-integrations-by-entity-external-id.js +46 -0
  215. package/integrations/use-cases/load-integration-context.js +71 -0
  216. package/integrations/use-cases/patch-integration-config.js +39 -0
  217. package/integrations/use-cases/process-errors.js +28 -0
  218. package/integrations/use-cases/remove-entities-from-integration.js +70 -0
  219. package/integrations/use-cases/update-integration-config.js +32 -0
  220. package/integrations/use-cases/update-integration-messages.js +44 -0
  221. package/integrations/use-cases/update-integration-status.js +32 -0
  222. package/integrations/use-cases/update-integration.js +92 -0
  223. package/integrations/use-cases/update-process-metrics.js +222 -0
  224. package/integrations/use-cases/update-process-state.js +163 -0
  225. package/integrations/utils/assert-entity-ids-input.js +42 -0
  226. package/integrations/utils/map-integration-dto.js +37 -0
  227. package/jest-global-setup-noop.js +3 -0
  228. package/jest-global-teardown-noop.js +3 -0
  229. package/jest.config.js +2 -0
  230. package/logs/.eslintrc.json +26 -1
  231. package/logs/__fixtures__/events.js +82 -0
  232. package/logs/__fixtures__/matchers.js +45 -0
  233. package/logs/__fixtures__/secrets.js +59 -0
  234. package/logs/__fixtures__/vectors.js +329 -0
  235. package/logs/__fixtures__/with-env.js +45 -0
  236. package/logs/context.js +109 -0
  237. package/logs/contract-keys.js +67 -0
  238. package/logs/debug-shims.js +46 -0
  239. package/logs/denied-keys.js +21 -0
  240. package/logs/index.js +14 -3
  241. package/logs/jest-logger-setup.js +25 -0
  242. package/logs/levels.js +71 -0
  243. package/logs/logger-runtime.js +137 -0
  244. package/logs/logger.js +134 -46
  245. package/logs/record.js +276 -0
  246. package/logs/redact.js +328 -0
  247. package/logs/serialize.js +329 -0
  248. package/logs/sinks.js +93 -0
  249. package/logs/summarize-event.js +163 -0
  250. package/{module-plugin → modules}/index.js +0 -10
  251. package/modules/module-factory.js +56 -0
  252. package/modules/module.js +320 -0
  253. package/modules/repositories/module-repository-documentdb.js +350 -0
  254. package/modules/repositories/module-repository-factory.js +40 -0
  255. package/modules/repositories/module-repository-interface.js +145 -0
  256. package/modules/repositories/module-repository-mongo.js +436 -0
  257. package/modules/repositories/module-repository-postgres.js +481 -0
  258. package/modules/repositories/module-repository.js +369 -0
  259. package/modules/requester/api-key.js +52 -0
  260. package/modules/requester/oauth-2.js +561 -0
  261. package/modules/requester/requester.js +605 -0
  262. package/{module-plugin → modules}/test/mock-api/api.js +8 -3
  263. package/{module-plugin → modules}/test/mock-api/definition.js +14 -10
  264. package/modules/tests/doubles/test-module-factory.js +16 -0
  265. package/modules/tests/doubles/test-module-repository.js +39 -0
  266. package/modules/use-cases/get-entities-for-user.js +32 -0
  267. package/modules/use-cases/get-entity-options-by-id.js +71 -0
  268. package/modules/use-cases/get-entity-options-by-type.js +34 -0
  269. package/modules/use-cases/get-module-instance-from-type.js +34 -0
  270. package/modules/use-cases/get-module.js +74 -0
  271. package/modules/use-cases/process-authorization-callback.js +294 -0
  272. package/modules/use-cases/refresh-entity-options.js +72 -0
  273. package/modules/use-cases/test-module-auth.js +72 -0
  274. package/modules/utils/map-module-dto.js +20 -0
  275. package/modules/utils/to-credential-id.js +14 -0
  276. package/package.json +92 -52
  277. package/prisma-mongodb/schema.prisma +455 -0
  278. package/prisma-postgresql/migrations/20250930193005_init/migration.sql +315 -0
  279. package/prisma-postgresql/migrations/20251006135218_init/migration.sql +9 -0
  280. package/prisma-postgresql/migrations/20251010000000_remove_unused_entity_reference_map/migration.sql +3 -0
  281. package/prisma-postgresql/migrations/20251112195422_update_user_unique_constraints/migration.sql +25 -0
  282. package/prisma-postgresql/migrations/20260422120000_add_entity_data_column/migration.sql +10 -0
  283. package/prisma-postgresql/migrations/20260422120001_create_process_table/migration.sql +48 -0
  284. package/prisma-postgresql/migrations/20260625000000_add_user_organization_id_index/migration.sql +2 -0
  285. package/prisma-postgresql/migrations/20260703000000_add_integration_status_in_creation_in_deletion/migration.sql +11 -0
  286. package/prisma-postgresql/migrations/20260703000001_integration_status_default_in_creation/migration.sql +8 -0
  287. package/prisma-postgresql/migrations/20260705000000_create_usage_counter/migration.sql +26 -0
  288. package/prisma-postgresql/migrations/20260706000000_add_admin_script_execution_and_schedule/migration.sql +61 -0
  289. package/prisma-postgresql/migrations/migration_lock.toml +3 -0
  290. package/prisma-postgresql/schema.prisma +436 -0
  291. package/queues/queue-delivery.js +41 -0
  292. package/queues/queuer-util.js +89 -21
  293. package/reporting/README.md +154 -0
  294. package/reporting/builtin-reports.js +6 -0
  295. package/reporting/index.js +13 -0
  296. package/reporting/report-base.js +49 -0
  297. package/reporting/reports/integrations-report.js +221 -0
  298. package/syncs/manager.js +468 -443
  299. package/syncs/repositories/sync-repository-documentdb.js +240 -0
  300. package/syncs/repositories/sync-repository-factory.js +43 -0
  301. package/syncs/repositories/sync-repository-interface.js +109 -0
  302. package/syncs/repositories/sync-repository-mongo.js +239 -0
  303. package/syncs/repositories/sync-repository-postgres.js +319 -0
  304. package/syncs/sync.js +0 -1
  305. package/telemetry/README.md +331 -0
  306. package/telemetry/bind-telemetry-context.js +77 -0
  307. package/telemetry/canonical-counters.js +52 -0
  308. package/telemetry/exporters.js +85 -0
  309. package/telemetry/index.js +26 -0
  310. package/telemetry/instrument-handler.js +104 -0
  311. package/telemetry/no-op-telemetry.js +71 -0
  312. package/telemetry/north-star.js +103 -0
  313. package/telemetry/otel-telemetry.js +232 -0
  314. package/telemetry/plugin-subscribers.js +77 -0
  315. package/telemetry/telemetry-config.js +120 -0
  316. package/telemetry/telemetry-context.js +51 -0
  317. package/telemetry/telemetry-event-bus.js +58 -0
  318. package/telemetry/telemetry-runtime.js +164 -0
  319. package/telemetry/telemetry-service.js +52 -0
  320. package/telemetry/usage-rollup-subscriber.js +116 -0
  321. package/token/repositories/token-repository-documentdb.js +137 -0
  322. package/token/repositories/token-repository-factory.js +40 -0
  323. package/token/repositories/token-repository-interface.js +131 -0
  324. package/token/repositories/token-repository-mongo.js +219 -0
  325. package/token/repositories/token-repository-postgres.js +264 -0
  326. package/token/repositories/token-repository.js +219 -0
  327. package/types/associations/index.d.ts +0 -17
  328. package/types/core/index.d.ts +12 -4
  329. package/types/database/index.d.ts +10 -2
  330. package/types/encrypt/index.d.ts +5 -3
  331. package/types/errors/index.d.ts +24 -10
  332. package/types/integrations/index.d.ts +3 -8
  333. package/types/logs/index.d.ts +61 -2
  334. package/types/module-plugin/index.d.ts +20 -69
  335. package/types/syncs/index.d.ts +0 -17
  336. package/usage/README.md +54 -0
  337. package/usage/index.js +17 -0
  338. package/usage/repositories/usage-repository-documentdb.js +194 -0
  339. package/usage/repositories/usage-repository-factory.js +25 -0
  340. package/usage/repositories/usage-repository-interface.js +37 -0
  341. package/usage/repositories/usage-repository-prisma.js +146 -0
  342. package/usage/tracked-metrics.js +38 -0
  343. package/usage/usage-windows.js +24 -0
  344. package/user/repositories/user-repository-documentdb.js +426 -0
  345. package/user/repositories/user-repository-factory.js +52 -0
  346. package/user/repositories/user-repository-interface.js +214 -0
  347. package/user/repositories/user-repository-mongo.js +323 -0
  348. package/user/repositories/user-repository-postgres.js +377 -0
  349. package/user/tests/doubles/test-user-repository.js +72 -0
  350. package/user/use-cases/authenticate-user.js +143 -0
  351. package/user/use-cases/authenticate-with-shared-secret.js +48 -0
  352. package/user/use-cases/create-individual-user.js +61 -0
  353. package/user/use-cases/create-organization-user.js +47 -0
  354. package/user/use-cases/create-token-for-user-id.js +30 -0
  355. package/user/use-cases/get-user-from-adopter-jwt.js +149 -0
  356. package/user/use-cases/get-user-from-bearer-token.js +82 -0
  357. package/user/use-cases/get-user-from-x-frigg-headers.js +132 -0
  358. package/user/use-cases/login-user.js +122 -0
  359. package/user/user.js +125 -0
  360. package/utils/backend-path.js +38 -0
  361. package/utils/index.js +6 -0
  362. package/websocket/repositories/websocket-connection-repository-documentdb.js +119 -0
  363. package/websocket/repositories/websocket-connection-repository-factory.js +44 -0
  364. package/websocket/repositories/websocket-connection-repository-interface.js +106 -0
  365. package/websocket/repositories/websocket-connection-repository-mongo.js +156 -0
  366. package/websocket/repositories/websocket-connection-repository-postgres.js +196 -0
  367. package/websocket/repositories/websocket-connection-repository.js +161 -0
  368. package/assertions/is-equal.js +0 -17
  369. package/associations/model.js +0 -54
  370. package/database/models/IndividualUser.js +0 -76
  371. package/database/models/OrganizationUser.js +0 -29
  372. package/database/models/State.js +0 -9
  373. package/database/models/Token.js +0 -70
  374. package/database/models/UserModel.js +0 -7
  375. package/database/models/WebsocketConnection.js +0 -49
  376. package/database/mongo.js +0 -45
  377. package/database/mongoose.js +0 -5
  378. package/encrypt/Cryptor.test.js +0 -32
  379. package/encrypt/encrypt.js +0 -132
  380. package/encrypt/encrypt.test.js +0 -1069
  381. package/encrypt/test-encrypt.js +0 -107
  382. package/errors/base-error.test.js +0 -32
  383. package/errors/fetch-error.test.js +0 -79
  384. package/errors/halt-error.test.js +0 -11
  385. package/errors/validation-errors.test.js +0 -120
  386. package/handlers/routers/middleware/loadUser.js +0 -15
  387. package/handlers/routers/middleware/requireLoggedInUser.js +0 -12
  388. package/integrations/create-frigg-backend.js +0 -31
  389. package/integrations/integration-factory.js +0 -251
  390. package/integrations/integration-mapping.js +0 -43
  391. package/integrations/integration-model.js +0 -46
  392. package/integrations/integration-user.js +0 -144
  393. package/integrations/test/integration-base.test.js +0 -144
  394. package/lambda/TimeoutCatcher.test.js +0 -68
  395. package/logs/logger.test.js +0 -76
  396. package/module-plugin/auther.js +0 -393
  397. package/module-plugin/credential.js +0 -22
  398. package/module-plugin/entity-manager.js +0 -70
  399. package/module-plugin/entity.js +0 -46
  400. package/module-plugin/manager.js +0 -169
  401. package/module-plugin/module-factory.js +0 -61
  402. package/module-plugin/requester/api-key.js +0 -36
  403. package/module-plugin/requester/oauth-2.js +0 -219
  404. package/module-plugin/requester/requester.js +0 -165
  405. package/module-plugin/requester/requester.test.js +0 -28
  406. package/module-plugin/test/auther.test.js +0 -97
  407. package/syncs/model.js +0 -62
  408. /package/{module-plugin → modules}/ModuleConstants.js +0 -0
  409. /package/{module-plugin → modules}/requester/basic.js +0 -0
  410. /package/{module-plugin → modules}/test/mock-api/mocks/hubspot.js +0 -0
package/core/Worker.js CHANGED
@@ -1,10 +1,13 @@
1
- const AWS = require('aws-sdk');
1
+ const { SQSClient, GetQueueUrlCommand, SendMessageCommand } = require('@aws-sdk/client-sqs');
2
2
  const _ = require('lodash');
3
3
  const { RequiredPropertyError } = require('../errors');
4
4
  const { get } = require('../assertions');
5
+ const { readQueueDelivery } = require('../queues/queue-delivery');
6
+ const { runMessageScope } = require('./invocation-scope');
7
+ const { getLogger } = require('../logs');
5
8
 
6
- AWS.config.update({ region: process.env.AWS_REGION });
7
- const sqs = new AWS.SQS({ apiVersion: '2012-11-05' });
9
+ const sqs = new SQSClient({ region: process.env.AWS_REGION });
10
+ const log = getLogger('frigg.worker');
8
11
 
9
12
  class Worker {
10
13
  async getQueueURL(params) {
@@ -12,25 +15,59 @@ class Worker {
12
15
  // let params = {
13
16
  // QueueName: process.env.QueueName
14
17
  // };
15
- return new Promise((resolve, reject) => {
16
- sqs.getQueueUrl(params, (err, data) => {
17
- if (err) {
18
- reject(err);
19
- } else {
20
- resolve(data.QueueUrl);
21
- }
22
- });
23
- });
18
+ const command = new GetQueueUrlCommand(params);
19
+ const data = await sqs.send(command);
20
+ return data.QueueUrl;
24
21
  }
25
22
 
26
23
  async run(params, context = {}) {
27
24
  const records = get(params, 'Records');
25
+ const batchItemFailures = [];
26
+
27
+ console.log(
28
+ `[Worker] run: processing ${records.length} record(s)`
29
+ );
28
30
 
29
31
  for (const record of records) {
30
- const runParams = JSON.parse(record.body);
31
- this._validateParams(runParams);
32
- await this._run(runParams, context);
32
+ await runMessageScope(record, async () => {
33
+ // messageId, receiveCount and the event come from the scope.
34
+ log.debug('Record started', { eventName: 'frigg.worker.record_started' });
35
+
36
+ try {
37
+ const runParams = JSON.parse(record.body);
38
+ this._validateParams(runParams);
39
+ await this._run(runParams, context, readQueueDelivery(record));
40
+ log.debug('Record succeeded', { eventName: 'frigg.worker.record_succeeded' });
41
+ } catch (error) {
42
+ if (error.isHaltError) {
43
+ // HaltError means "discard this message, don't retry".
44
+ // Treat as success so SQS deletes it from the queue.
45
+ // Logged explicitly — silent discards made prod debugging
46
+ // extremely hard; keep this visible.
47
+ log.error('Record halted (discarded, no retry)', {
48
+ eventName: 'frigg.worker.record_halted',
49
+ statusCode: error.statusCode,
50
+ error,
51
+ });
52
+ return;
53
+ }
54
+ // The message goes back to SQS, so WARN (ADR-048 §4).
55
+ log.warn('Record failed, returned for retry', {
56
+ eventName: 'frigg.worker.record_failed',
57
+ error,
58
+ });
59
+ batchItemFailures.push({ itemIdentifier: record.messageId });
60
+ }
61
+ });
33
62
  }
63
+
64
+ if (batchItemFailures.length > 0) {
65
+ console.warn(
66
+ `[Worker] run: returning ${batchItemFailures.length} batchItemFailure(s) of ${records.length}`
67
+ );
68
+ }
69
+
70
+ return { batchItemFailures };
34
71
  }
35
72
 
36
73
  async _run(params, context = {}) {
@@ -54,15 +91,9 @@ class Worker {
54
91
  }
55
92
 
56
93
  async sendAsyncSQSMessage(params) {
57
- return new Promise((resolve, reject) => {
58
- sqs.sendMessage(params, (err, data) => {
59
- if (err) {
60
- reject(err);
61
- } else {
62
- resolve(data.MessageId);
63
- }
64
- });
65
- });
94
+ const command = new SendMessageCommand(params);
95
+ const data = await sqs.send(command);
96
+ return data.MessageId;
66
97
  }
67
98
 
68
99
  // Throw an exception if the params do not validate
@@ -2,9 +2,25 @@
2
2
  // REMOVING FOR NOW UNTIL WE ADD WEBPACK BACK IN
3
3
  // require('source-map-support').install();
4
4
 
5
- const { connectToDatabase } = require('../database/mongo');
6
- const { initDebugLog, flushDebugLog } = require('../logs');
5
+ const { getLogger, toSanitizedSurrogate } = require('../logs');
6
+ const {
7
+ summarizeLambdaEvent,
8
+ toScopeInvocation,
9
+ toRequestDetails,
10
+ } = require('../logs/summarize-event');
11
+ const {
12
+ runInvocationScope,
13
+ DEFAULT_FLUSH_TIMEOUT_MS,
14
+ } = require('./invocation-scope');
7
15
  const { secretsToEnv } = require('./secrets-to-env');
16
+ const { parametersToEnv } = require('./parameters-to-env');
17
+ const {
18
+ getTelemetry,
19
+ getUsageRollupSubscriber,
20
+ getPluginTelemetrySubscribers,
21
+ } = require('../telemetry/telemetry-runtime');
22
+
23
+ const log = getLogger('frigg.handler');
8
24
 
9
25
  const createHandler = (optionByName = {}) => {
10
26
  const {
@@ -12,6 +28,9 @@ const createHandler = (optionByName = {}) => {
12
28
  isUserFacingResponse = true,
13
29
  method,
14
30
  shouldUseDatabase = true,
31
+ telemetry,
32
+ flushTimeoutMs = DEFAULT_FLUSH_TIMEOUT_MS,
33
+ usageRollup,
15
34
  } = optionByName;
16
35
 
17
36
  if (!method) {
@@ -19,50 +38,114 @@ const createHandler = (optionByName = {}) => {
19
38
  }
20
39
 
21
40
  return async (event, context) => {
22
- try {
23
- initDebugLog(eventName, event);
41
+ const eventSummary = summarizeLambdaEvent(event);
42
+ const activeTelemetry = telemetry || getTelemetry();
43
+ const activeUsageRollup =
44
+ usageRollup !== undefined
45
+ ? usageRollup
46
+ : getUsageRollupSubscriber();
24
47
 
25
- const requestMethod = event.httpMethod;
26
- const requestPath = event.path;
27
- if (requestMethod && requestPath) {
28
- console.info(`${requestMethod} ${requestPath}`);
29
- }
48
+ // Wire adopter-declared telemetry subscribers once per cold start.
49
+ // Memoized in the singleton, so this is a cheap
50
+ // no-op after the first invocation.
51
+ getPluginTelemetrySubscribers();
30
52
 
31
- // If enabled (i.e. if SECRET_ARN is set in process.env) Fetch secrets from AWS Secrets Manager, and set them as environment variables.
32
- await secretsToEnv();
53
+ const scopeFields = {
54
+ requestId: context?.awsRequestId,
55
+ handlerName: eventName,
56
+ method: eventSummary.method,
57
+ route: eventSummary.route,
58
+ routeKey: eventSummary.routeKey,
59
+ invocation: toScopeInvocation(eventSummary),
60
+ };
61
+ // Path, query keys and header names go only on the entry and failure
62
+ // records; the logger adds them to the scope's invocation.
63
+ const requestDetails = toRequestDetails(eventSummary);
33
64
 
34
- // Helps mongoose reuse the connection. Lowers response times.
35
- context.callbackWaitsForEmptyEventLoop = false;
65
+ return runInvocationScope(
66
+ scopeFields,
67
+ async () => {
68
+ try {
69
+ log.info('Handler invoked', {
70
+ eventName: 'frigg.handler.invoked',
71
+ invocation: requestDetails,
72
+ });
36
73
 
37
- if (shouldUseDatabase) {
38
- await connectToDatabase();
39
- }
74
+ // If enabled (i.e. if SECRET_ARN is set in process.env) Fetch secrets from AWS Secrets Manager, and set them as environment variables.
75
+ await secretsToEnv();
40
76
 
41
- // Run the Lambda
42
- return await method(event, context);
43
- } catch (error) {
44
- flushDebugLog(error);
45
-
46
- // Don't leak implementation details to end users.
47
- if (isUserFacingResponse) {
48
- return {
49
- statusCode: 500,
50
- body: JSON.stringify({
51
- error: 'An Internal Error Occurred',
52
- }),
53
- };
54
- }
77
+ // If enabled (i.e. if SSM_PARAMETER_PREFIX and FRIGG_SSM_OFFLOADED_KEYS are set) fetch offloaded params from SSM Parameter Store into process.env.
78
+ await parametersToEnv();
55
79
 
56
- // Handle server-to-server responses.
80
+ // Lazy-required so DB-free handlers never load the Prisma client.
81
+ if (shouldUseDatabase) {
82
+ const { connectPrisma } = require('../database/prisma');
83
+ await connectPrisma();
84
+ }
57
85
 
58
- // Halt errors are logged but suceed and won't be retried.
59
- if (error.isHaltError === true) {
60
- return;
61
- }
86
+ // Helps reuse the database connection. Lowers response times.
87
+ context.callbackWaitsForEmptyEventLoop = false;
62
88
 
63
- // Here we can just rethrow and let AWS build the response.
64
- throw error;
65
- }
89
+ // Run the Lambda
90
+ return await method(event, context);
91
+ } catch (error) {
92
+ // Allow client-safe errors to pass through with their actual message
93
+ if (isUserFacingResponse && error.isClientSafe === true) {
94
+ const statusCode = error.statusCode || 400;
95
+ log.warn('Request rejected', {
96
+ eventName: 'frigg.handler.rejected',
97
+ statusCode,
98
+ error,
99
+ });
100
+ return {
101
+ statusCode,
102
+ body: JSON.stringify({
103
+ error: error.message,
104
+ }),
105
+ };
106
+ }
107
+
108
+ // Server-to-server: halt errors succeed and won't be
109
+ // retried, so the halt itself is the failure record.
110
+ if (!isUserFacingResponse && error.isHaltError === true) {
111
+ log.error('Handler halted', {
112
+ eventName: 'frigg.handler.halted',
113
+ invocation: requestDetails,
114
+ error,
115
+ });
116
+ return;
117
+ }
118
+
119
+ log.error('Handler failed', {
120
+ eventName: 'frigg.handler.failed',
121
+ invocation: requestDetails,
122
+ error,
123
+ });
124
+
125
+ // Don't leak implementation details to end users.
126
+ if (isUserFacingResponse) {
127
+ return {
128
+ statusCode: 500,
129
+ body: JSON.stringify({
130
+ error: 'An Internal Error Occurred',
131
+ }),
132
+ };
133
+ }
134
+
135
+ // The Lambda runtime writes a rethrown error itself, so
136
+ // rethrow a sanitized copy (ADR-048 §6 item 11).
137
+ throw toSanitizedSurrogate(error);
138
+ }
139
+ },
140
+ {
141
+ telemetry: activeTelemetry,
142
+ usageRollup: activeUsageRollup,
143
+ eventSummary,
144
+ shouldUseDatabase,
145
+ flushTimeoutMs,
146
+ context,
147
+ }
148
+ );
66
149
  };
67
150
  };
68
151
 
package/core/index.js CHANGED
@@ -2,5 +2,12 @@ const { Delegate } = require('./Delegate');
2
2
  const { Worker } = require('./Worker');
3
3
  const { loadInstalledModules } = require('./load-installed-modules');
4
4
  const { createHandler } = require('./create-handler');
5
+ const { runInvocationScope } = require('./invocation-scope');
5
6
 
6
- module.exports = { Delegate, Worker, loadInstalledModules, createHandler };
7
+ module.exports = {
8
+ Delegate,
9
+ Worker,
10
+ loadInstalledModules,
11
+ createHandler,
12
+ runInvocationScope,
13
+ };
@@ -0,0 +1,225 @@
1
+ const { runInContext, LOGGER_SCOPE_KEY } = require('../logs/context');
2
+ const { summarizeMessageBody } = require('../logs/summarize-event');
3
+ const { flushSinks, hasFlushableSinks } = require('../logs/logger-runtime');
4
+
5
+ // Bounds the tail latency telemetry adds to every warm invocation. Kept low so
6
+ // an unreachable OTLP endpoint (e.g. a VPC Lambda with no NAT/egress) costs at
7
+ // most this, not multiple seconds. Override with OTEL_FLUSH_TIMEOUT_MS.
8
+ const DEFAULT_FLUSH_TIMEOUT_MS =
9
+ Number(process.env.OTEL_FLUSH_TIMEOUT_MS) || 500;
10
+
11
+ // Time kept back from the Lambda deadline, so a slow flush never becomes a
12
+ // Lambda timeout.
13
+ const FLUSH_MARGIN_MS = 50;
14
+
15
+ // setTimeout fires at once for a delay above this.
16
+ const MAX_TIMER_MS = 2 ** 31 - 1;
17
+
18
+ /**
19
+ * Fold the invocation's buffered usage counters into the durable store, then
20
+ * clear the buffer. On an SQS redelivery (ApproximateReceiveCount > 1) we
21
+ * DISCARD rather than flush — the prior delivery already counted, and the usage
22
+ * accuracy contract is "approximate, skip obvious redeliveries". Fully guarded.
23
+ */
24
+ async function flushUsageRollup(subscriber, eventSummary, shouldUseDatabase) {
25
+ if (!subscriber) return;
26
+ try {
27
+ // Persisting usage requires a DB connection. DB-free handlers (e.g. the
28
+ // webhook-receipt route) never called connectPrisma, so drop the buffer
29
+ // instead of issuing a connectionless Prisma write.
30
+ if (!shouldUseDatabase) {
31
+ subscriber.discard();
32
+ return;
33
+ }
34
+ // Discard only when EVERY record in the batch is a redelivery. The buffer
35
+ // is invocation-scoped (not per-message), so discarding on *any*
36
+ // redelivery would drop the fresh records' counts too (silent
37
+ // under-count). For a mixed batch we flush: preserving fresh counts and
38
+ // at worst re-counting the one redelivered record is strictly better than
39
+ // losing fresh data for an approximate store. (Integration queue workers
40
+ // are batchSize:1 today, so a batch is all-or-nothing; this keeps it
41
+ // correct if batchSize is ever raised.)
42
+ const records = Array.isArray(eventSummary?.records)
43
+ ? eventSummary.records
44
+ : [];
45
+ const allRedelivered =
46
+ records.length > 0 &&
47
+ records.every((r) => Number(r.receiveCount) > 1);
48
+ if (allRedelivered) {
49
+ subscriber.discard();
50
+ } else {
51
+ await subscriber.flush();
52
+ }
53
+ } catch (_) {
54
+ // Usage rollup must never break the handler.
55
+ }
56
+ }
57
+
58
+ function isTelemetryEnabled(telemetry) {
59
+ try {
60
+ return Boolean(
61
+ telemetry &&
62
+ typeof telemetry.isEnabled === 'function' &&
63
+ telemetry.isEnabled()
64
+ );
65
+ } catch (_) {
66
+ return false;
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Flush telemetry before the Lambda container freezes. Because
72
+ * `callbackWaitsForEmptyEventLoop=false` stops the event loop the moment the
73
+ * handler returns, OTel's timer-driven batch processors would never fire — so
74
+ * spans/metrics must be flushed here. No timer of its own: the caller bounds it
75
+ * with `withDeadline`. Fully guarded, so a flush failure never breaks the
76
+ * handler.
77
+ */
78
+ async function flushTelemetry(telemetry, { signal } = {}) {
79
+ if (!isTelemetryEnabled(telemetry) || signal?.aborted) return;
80
+ try {
81
+ await telemetry.forceFlush();
82
+ } catch (_) {
83
+ // Telemetry flush must never break the handler.
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Run `fn(signal)` for at most `ms`. Owns the only timer and clears it when the
89
+ * work settles. Aborts the signal at the deadline. Never rejects, and a late
90
+ * rejection of the work is swallowed.
91
+ */
92
+ function withDeadline(ms, fn) {
93
+ const controller = new AbortController();
94
+ return new Promise((resolve) => {
95
+ let timer;
96
+ const finish = () => {
97
+ clearTimeout(timer);
98
+ resolve();
99
+ };
100
+ timer = setTimeout(() => {
101
+ controller.abort();
102
+ finish();
103
+ }, Math.min(ms, MAX_TIMER_MS));
104
+ let work;
105
+ try {
106
+ work = Promise.resolve(fn(controller.signal));
107
+ } catch (_) {
108
+ work = Promise.resolve();
109
+ }
110
+ work.then(finish, finish);
111
+ });
112
+ }
113
+
114
+ function remainingTimeMs(context) {
115
+ try {
116
+ const remaining = context?.getRemainingTimeInMillis?.();
117
+ return typeof remaining === 'number' ? remaining : Infinity;
118
+ } catch (_) {
119
+ return Infinity;
120
+ }
121
+ }
122
+
123
+ async function flushInvocation({
124
+ telemetry,
125
+ usageRollup,
126
+ eventSummary,
127
+ shouldUseDatabase,
128
+ flushTimeoutMs,
129
+ context,
130
+ }) {
131
+ // ADR-048 §11: the deadline is fixed at flush start. The usage rollup
132
+ // emits no telemetry, so it runs in parallel with no bound of its own.
133
+ const deadline = Math.min(
134
+ flushTimeoutMs,
135
+ remainingTimeMs(context) - FLUSH_MARGIN_MS
136
+ );
137
+ await Promise.all([
138
+ flushUsageRollup(usageRollup, eventSummary, shouldUseDatabase),
139
+ flushBounded(telemetry, deadline),
140
+ ]);
141
+ }
142
+
143
+ function flushBounded(telemetry, deadline) {
144
+ const flushes = [];
145
+ if (isTelemetryEnabled(telemetry)) {
146
+ flushes.push((signal) => flushTelemetry(telemetry, { signal }));
147
+ }
148
+ if (hasFlushableSinks()) {
149
+ flushes.push((signal) => flushSinks({ signal }));
150
+ }
151
+ if (!flushes.length || !(deadline > 0)) return undefined;
152
+ return withDeadline(deadline, (signal) =>
153
+ Promise.allSettled(flushes.map((flush) => flush(signal)))
154
+ );
155
+ }
156
+
157
+ /**
158
+ * Open the logger scope for one invocation, run `fn` inside it, then flush.
159
+ * `fields` (requestId, handlerName, method, route, routeKey, invocation, ...)
160
+ * go into the scope's logger sub-object and never reach the telemetry bus.
161
+ */
162
+ async function runInvocationScope(fields, fn, opts = {}) {
163
+ const {
164
+ telemetry,
165
+ usageRollup,
166
+ eventSummary,
167
+ shouldUseDatabase = true,
168
+ flushTimeoutMs = DEFAULT_FLUSH_TIMEOUT_MS,
169
+ context,
170
+ } = opts;
171
+ return runInContext({ [LOGGER_SCOPE_KEY]: { ...(fields || {}) } }, async () => {
172
+ try {
173
+ return await fn();
174
+ } finally {
175
+ // Every step is guarded, so a flush never changes the result.
176
+ await flushInvocation({
177
+ telemetry,
178
+ usageRollup,
179
+ eventSummary,
180
+ shouldUseDatabase,
181
+ flushTimeoutMs,
182
+ context,
183
+ });
184
+ }
185
+ });
186
+ }
187
+
188
+ function toCount(value) {
189
+ const count = Number(value);
190
+ return value !== undefined && value !== null && Number.isFinite(count)
191
+ ? count
192
+ : undefined;
193
+ }
194
+
195
+ /**
196
+ * Open the logger scope for one SQS message: messageId, receiveCount and the
197
+ * Frigg ids the body carries. No flush; the invocation scope owns that.
198
+ */
199
+ function runMessageScope(record, fn) {
200
+ const { event, processId, integrationId } = summarizeMessageBody(
201
+ record?.body
202
+ );
203
+ return runInContext(
204
+ {
205
+ [LOGGER_SCOPE_KEY]: {
206
+ messageId: record?.messageId,
207
+ receiveCount: toCount(record?.attributes?.ApproximateReceiveCount),
208
+ integrationEvent: event,
209
+ processId,
210
+ integrationId,
211
+ },
212
+ },
213
+ fn
214
+ );
215
+ }
216
+
217
+ module.exports = {
218
+ runInvocationScope,
219
+ runMessageScope,
220
+ withDeadline,
221
+ flushTelemetry,
222
+ flushUsageRollup,
223
+ FLUSH_MARGIN_MS,
224
+ DEFAULT_FLUSH_TIMEOUT_MS,
225
+ };