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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (410) hide show
  1. package/.eslintrc.json +18 -1
  2. package/CLAUDE.md +830 -0
  3. package/README.md +996 -50
  4. package/admin-scripts/index.js +52 -0
  5. package/admin-scripts/repositories/admin-script-execution-repository-documentdb.js +21 -0
  6. package/admin-scripts/repositories/admin-script-execution-repository-factory.js +51 -0
  7. package/admin-scripts/repositories/admin-script-execution-repository-interface.js +171 -0
  8. package/admin-scripts/repositories/admin-script-execution-repository-mongo.js +238 -0
  9. package/admin-scripts/repositories/admin-script-execution-repository-postgres.js +278 -0
  10. package/admin-scripts/repositories/script-schedule-repository-documentdb.js +21 -0
  11. package/admin-scripts/repositories/script-schedule-repository-factory.js +51 -0
  12. package/admin-scripts/repositories/script-schedule-repository-interface.js +108 -0
  13. package/admin-scripts/repositories/script-schedule-repository-mongo.js +179 -0
  14. package/admin-scripts/repositories/script-schedule-repository-postgres.js +210 -0
  15. package/application/commands/README.md +451 -0
  16. package/application/commands/admin-script-commands.js +359 -0
  17. package/application/commands/credential-commands.js +262 -0
  18. package/application/commands/entity-commands.js +294 -0
  19. package/application/commands/integration-commands.js +419 -0
  20. package/application/commands/integration-mapping-commands.js +25 -0
  21. package/application/commands/process-commands.js +135 -0
  22. package/application/commands/report-commands.js +188 -0
  23. package/application/commands/scheduler-commands.js +263 -0
  24. package/application/commands/usage-commands.js +56 -0
  25. package/application/commands/user-commands.js +312 -0
  26. package/application/index.js +83 -0
  27. package/artifacts/repositories/artifact-repository-factory.js +19 -0
  28. package/artifacts/repositories/artifact-repository-interface.js +27 -0
  29. package/artifacts/repositories/artifact-repository-local.js +42 -0
  30. package/artifacts/repositories/artifact-repository-s3.js +61 -0
  31. package/assertions/index.js +0 -3
  32. package/core/CLAUDE.md +715 -0
  33. package/core/Worker.js +55 -24
  34. package/core/create-handler.js +121 -38
  35. package/core/index.js +8 -1
  36. package/core/invocation-scope.js +225 -0
  37. package/core/parameters-to-env.js +257 -0
  38. package/core/secrets-to-env.js +7 -6
  39. package/core/ssm-preload.mjs +34 -0
  40. package/credential/repositories/credential-active-type.js +32 -0
  41. package/credential/repositories/credential-repository-documentdb.js +355 -0
  42. package/credential/repositories/credential-repository-factory.js +54 -0
  43. package/credential/repositories/credential-repository-interface.js +113 -0
  44. package/credential/repositories/credential-repository-mongo.js +294 -0
  45. package/credential/repositories/credential-repository-postgres.js +312 -0
  46. package/credential/repositories/credential-repository.js +300 -0
  47. package/credential/use-cases/get-credential-for-user.js +25 -0
  48. package/credential/use-cases/update-authentication-status.js +15 -0
  49. package/database/MONGODB_TRANSACTION_FIX.md +198 -0
  50. package/database/adapters/lambda-invoker.js +97 -0
  51. package/database/config.js +147 -0
  52. package/database/documentdb-encryption-service.js +334 -0
  53. package/database/documentdb-utils.js +196 -0
  54. package/database/encryption/README.md +863 -0
  55. package/database/encryption/documentdb-encryption-service.md +3575 -0
  56. package/database/encryption/encryption-schema-registry.js +404 -0
  57. package/database/encryption/field-encryption-service.js +254 -0
  58. package/database/encryption/integration-mapping-encryption.js +97 -0
  59. package/database/encryption/logger.js +82 -0
  60. package/database/encryption/prisma-encryption-extension.js +241 -0
  61. package/database/index.js +21 -21
  62. package/database/prisma.js +182 -0
  63. package/database/repositories/health-check-repository-documentdb.js +138 -0
  64. package/database/repositories/health-check-repository-factory.js +48 -0
  65. package/database/repositories/health-check-repository-interface.js +82 -0
  66. package/database/repositories/health-check-repository-mongodb.js +89 -0
  67. package/database/repositories/health-check-repository-postgres.js +82 -0
  68. package/database/repositories/migration-status-repository-s3.js +137 -0
  69. package/database/use-cases/check-database-health-use-case.js +29 -0
  70. package/database/use-cases/check-database-state-use-case.js +81 -0
  71. package/database/use-cases/check-encryption-health-use-case.js +83 -0
  72. package/database/use-cases/get-database-state-via-worker-use-case.js +61 -0
  73. package/database/use-cases/get-migration-status-use-case.js +93 -0
  74. package/database/use-cases/resolve-migration-via-worker-use-case.js +49 -0
  75. package/database/use-cases/run-database-migration-use-case.js +139 -0
  76. package/database/use-cases/test-encryption-use-case.js +253 -0
  77. package/database/use-cases/trigger-database-migration-use-case.js +157 -0
  78. package/database/utils/mongodb-collection-utils.js +94 -0
  79. package/database/utils/mongodb-schema-init.js +108 -0
  80. package/database/utils/prisma-runner.js +491 -0
  81. package/database/utils/prisma-schema-parser.js +182 -0
  82. package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +517 -0
  83. package/encrypt/Cryptor.js +34 -168
  84. package/encrypt/index.js +1 -2
  85. package/errors/client-safe-error.js +26 -0
  86. package/errors/fetch-error.js +59 -57
  87. package/errors/index.js +6 -0
  88. package/errors/mapping-already-exists-error.js +14 -0
  89. package/generated/prisma-mongodb/client.d.ts +1 -0
  90. package/generated/prisma-mongodb/client.js +5 -0
  91. package/generated/prisma-mongodb/default.d.ts +1 -0
  92. package/generated/prisma-mongodb/default.js +5 -0
  93. package/generated/prisma-mongodb/edge.d.ts +1 -0
  94. package/generated/prisma-mongodb/edge.js +386 -0
  95. package/generated/prisma-mongodb/index-browser.js +368 -0
  96. package/generated/prisma-mongodb/index.d.ts +27065 -0
  97. package/generated/prisma-mongodb/index.js +411 -0
  98. package/generated/prisma-mongodb/libquery_engine-debian-openssl-3.0.x.so.node +0 -0
  99. package/generated/prisma-mongodb/libquery_engine-rhel-openssl-3.0.x.so.node +0 -0
  100. package/generated/prisma-mongodb/package.json +183 -0
  101. package/generated/prisma-mongodb/runtime/edge-esm.js +35 -0
  102. package/generated/prisma-mongodb/runtime/edge.js +35 -0
  103. package/generated/prisma-mongodb/runtime/index-browser.d.ts +370 -0
  104. package/generated/prisma-mongodb/runtime/index-browser.js +17 -0
  105. package/generated/prisma-mongodb/runtime/library.d.ts +3982 -0
  106. package/generated/prisma-mongodb/runtime/library.js +147 -0
  107. package/generated/prisma-mongodb/runtime/react-native.js +84 -0
  108. package/generated/prisma-mongodb/runtime/wasm-compiler-edge.js +85 -0
  109. package/generated/prisma-mongodb/runtime/wasm-engine-edge.js +38 -0
  110. package/generated/prisma-mongodb/schema.prisma +455 -0
  111. package/generated/prisma-mongodb/wasm-edge-light-loader.mjs +5 -0
  112. package/generated/prisma-mongodb/wasm-worker-loader.mjs +5 -0
  113. package/generated/prisma-mongodb/wasm.d.ts +1 -0
  114. package/generated/prisma-mongodb/wasm.js +393 -0
  115. package/generated/prisma-postgresql/client.d.ts +1 -0
  116. package/generated/prisma-postgresql/client.js +5 -0
  117. package/generated/prisma-postgresql/default.d.ts +1 -0
  118. package/generated/prisma-postgresql/default.js +5 -0
  119. package/generated/prisma-postgresql/edge.d.ts +1 -0
  120. package/generated/prisma-postgresql/edge.js +407 -0
  121. package/generated/prisma-postgresql/index-browser.js +389 -0
  122. package/generated/prisma-postgresql/index.d.ts +29904 -0
  123. package/generated/prisma-postgresql/index.js +432 -0
  124. package/generated/prisma-postgresql/libquery_engine-debian-openssl-3.0.x.so.node +0 -0
  125. package/generated/prisma-postgresql/libquery_engine-rhel-openssl-3.0.x.so.node +0 -0
  126. package/generated/prisma-postgresql/package.json +183 -0
  127. package/generated/prisma-postgresql/query_engine_bg.js +2 -0
  128. package/generated/prisma-postgresql/query_engine_bg.wasm +0 -0
  129. package/generated/prisma-postgresql/runtime/edge-esm.js +35 -0
  130. package/generated/prisma-postgresql/runtime/edge.js +35 -0
  131. package/generated/prisma-postgresql/runtime/index-browser.d.ts +370 -0
  132. package/generated/prisma-postgresql/runtime/index-browser.js +17 -0
  133. package/generated/prisma-postgresql/runtime/library.d.ts +3982 -0
  134. package/generated/prisma-postgresql/runtime/library.js +147 -0
  135. package/generated/prisma-postgresql/runtime/react-native.js +84 -0
  136. package/generated/prisma-postgresql/runtime/wasm-compiler-edge.js +85 -0
  137. package/generated/prisma-postgresql/runtime/wasm-engine-edge.js +38 -0
  138. package/generated/prisma-postgresql/schema.prisma +436 -0
  139. package/generated/prisma-postgresql/wasm-edge-light-loader.mjs +5 -0
  140. package/generated/prisma-postgresql/wasm-worker-loader.mjs +5 -0
  141. package/generated/prisma-postgresql/wasm.d.ts +1 -0
  142. package/generated/prisma-postgresql/wasm.js +414 -0
  143. package/handlers/WEBHOOKS.md +682 -0
  144. package/handlers/app-definition-loader.js +103 -0
  145. package/handlers/app-handler-helpers.js +20 -6
  146. package/handlers/backend-utils.js +272 -46
  147. package/handlers/database-migration-handler.js +236 -0
  148. package/handlers/integration-event-dispatcher.js +68 -0
  149. package/handlers/middleware/admin-auth.js +73 -0
  150. package/handlers/routers/HEALTHCHECK.md +342 -0
  151. package/handlers/routers/auth.js +4 -15
  152. package/handlers/routers/db-migration.handler.js +29 -0
  153. package/handlers/routers/db-migration.js +329 -0
  154. package/handlers/routers/health.js +518 -0
  155. package/handlers/routers/integration-defined-routers.js +85 -10
  156. package/handlers/routers/integration-webhook-routers.js +87 -0
  157. package/handlers/routers/user.js +27 -5
  158. package/handlers/routers/websocket.js +31 -9
  159. package/handlers/use-cases/check-external-apis-health-use-case.js +81 -0
  160. package/handlers/use-cases/check-integrations-health-use-case.js +44 -0
  161. package/handlers/workers/db-migration.js +438 -0
  162. package/handlers/workers/dlq-processor.js +89 -0
  163. package/handlers/workers/integration-defined-workers.js +13 -7
  164. package/index.js +123 -47
  165. package/infrastructure/scheduler/eventbridge-scheduler-adapter.js +184 -0
  166. package/infrastructure/scheduler/index.js +33 -0
  167. package/infrastructure/scheduler/mock-scheduler-adapter.js +143 -0
  168. package/infrastructure/scheduler/scheduler-service-factory.js +73 -0
  169. package/infrastructure/scheduler/scheduler-service-interface.js +47 -0
  170. package/integrations/EXTENSIONS.md +240 -0
  171. package/integrations/WEBHOOK-QUICKSTART.md +151 -0
  172. package/integrations/extension.js +254 -0
  173. package/integrations/index.js +20 -10
  174. package/integrations/integration-base.js +777 -74
  175. package/integrations/integration-router.js +399 -180
  176. package/integrations/options.js +1 -1
  177. package/integrations/repositories/config-patch-shared.js +43 -0
  178. package/integrations/repositories/integration-mapping-query-pipeline.js +152 -0
  179. package/integrations/repositories/integration-mapping-query.js +193 -0
  180. package/integrations/repositories/integration-mapping-repository-documentdb.js +406 -0
  181. package/integrations/repositories/integration-mapping-repository-factory.js +57 -0
  182. package/integrations/repositories/integration-mapping-repository-interface.js +183 -0
  183. package/integrations/repositories/integration-mapping-repository-mongo.js +284 -0
  184. package/integrations/repositories/integration-mapping-repository-postgres.js +403 -0
  185. package/integrations/repositories/integration-mapping-repository.js +185 -0
  186. package/integrations/repositories/integration-repository-documentdb.js +354 -0
  187. package/integrations/repositories/integration-repository-factory.js +51 -0
  188. package/integrations/repositories/integration-repository-interface.js +219 -0
  189. package/integrations/repositories/integration-repository-mongo.js +502 -0
  190. package/integrations/repositories/integration-repository-postgres.js +550 -0
  191. package/integrations/repositories/process-repository-documentdb.js +311 -0
  192. package/integrations/repositories/process-repository-factory.js +53 -0
  193. package/integrations/repositories/process-repository-interface.js +136 -0
  194. package/integrations/repositories/process-repository-mongo.js +262 -0
  195. package/integrations/repositories/process-repository-postgres.js +380 -0
  196. package/integrations/repositories/process-update-ops-shared.js +112 -0
  197. package/integrations/repositories/report-id.js +13 -0
  198. package/integrations/tests/doubles/config-capturing-integration.js +81 -0
  199. package/integrations/tests/doubles/dummy-integration-class.js +113 -0
  200. package/integrations/tests/doubles/test-integration-repository.js +146 -0
  201. package/integrations/use-cases/add-entities-to-integration.js +92 -0
  202. package/integrations/use-cases/create-integration.js +253 -0
  203. package/integrations/use-cases/create-process.js +130 -0
  204. package/integrations/use-cases/delete-integration-for-user.js +130 -0
  205. package/integrations/use-cases/find-integration-by-entity-external-id.js +74 -0
  206. package/integrations/use-cases/find-integration-context-by-external-entity-id.js +76 -0
  207. package/integrations/use-cases/get-integration-for-user.js +78 -0
  208. package/integrations/use-cases/get-integration-instance-by-definition.js +67 -0
  209. package/integrations/use-cases/get-integration-instance.js +83 -0
  210. package/integrations/use-cases/get-integrations-for-user.js +88 -0
  211. package/integrations/use-cases/get-possible-integrations.js +27 -0
  212. package/integrations/use-cases/get-process.js +89 -0
  213. package/integrations/use-cases/index.js +19 -0
  214. package/integrations/use-cases/list-integrations-by-entity-external-id.js +46 -0
  215. package/integrations/use-cases/load-integration-context.js +71 -0
  216. package/integrations/use-cases/patch-integration-config.js +39 -0
  217. package/integrations/use-cases/process-errors.js +28 -0
  218. package/integrations/use-cases/remove-entities-from-integration.js +70 -0
  219. package/integrations/use-cases/update-integration-config.js +32 -0
  220. package/integrations/use-cases/update-integration-messages.js +44 -0
  221. package/integrations/use-cases/update-integration-status.js +32 -0
  222. package/integrations/use-cases/update-integration.js +92 -0
  223. package/integrations/use-cases/update-process-metrics.js +222 -0
  224. package/integrations/use-cases/update-process-state.js +163 -0
  225. package/integrations/utils/assert-entity-ids-input.js +42 -0
  226. package/integrations/utils/map-integration-dto.js +37 -0
  227. package/jest-global-setup-noop.js +3 -0
  228. package/jest-global-teardown-noop.js +3 -0
  229. package/jest.config.js +2 -0
  230. package/logs/.eslintrc.json +26 -1
  231. package/logs/__fixtures__/events.js +82 -0
  232. package/logs/__fixtures__/matchers.js +45 -0
  233. package/logs/__fixtures__/secrets.js +59 -0
  234. package/logs/__fixtures__/vectors.js +329 -0
  235. package/logs/__fixtures__/with-env.js +45 -0
  236. package/logs/context.js +109 -0
  237. package/logs/contract-keys.js +67 -0
  238. package/logs/debug-shims.js +46 -0
  239. package/logs/denied-keys.js +21 -0
  240. package/logs/index.js +14 -3
  241. package/logs/jest-logger-setup.js +25 -0
  242. package/logs/levels.js +71 -0
  243. package/logs/logger-runtime.js +137 -0
  244. package/logs/logger.js +134 -46
  245. package/logs/record.js +276 -0
  246. package/logs/redact.js +328 -0
  247. package/logs/serialize.js +329 -0
  248. package/logs/sinks.js +93 -0
  249. package/logs/summarize-event.js +163 -0
  250. package/{module-plugin → modules}/index.js +0 -10
  251. package/modules/module-factory.js +56 -0
  252. package/modules/module.js +320 -0
  253. package/modules/repositories/module-repository-documentdb.js +350 -0
  254. package/modules/repositories/module-repository-factory.js +40 -0
  255. package/modules/repositories/module-repository-interface.js +145 -0
  256. package/modules/repositories/module-repository-mongo.js +436 -0
  257. package/modules/repositories/module-repository-postgres.js +481 -0
  258. package/modules/repositories/module-repository.js +369 -0
  259. package/modules/requester/api-key.js +52 -0
  260. package/modules/requester/oauth-2.js +561 -0
  261. package/modules/requester/requester.js +605 -0
  262. package/{module-plugin → modules}/test/mock-api/api.js +8 -3
  263. package/{module-plugin → modules}/test/mock-api/definition.js +14 -10
  264. package/modules/tests/doubles/test-module-factory.js +16 -0
  265. package/modules/tests/doubles/test-module-repository.js +39 -0
  266. package/modules/use-cases/get-entities-for-user.js +32 -0
  267. package/modules/use-cases/get-entity-options-by-id.js +71 -0
  268. package/modules/use-cases/get-entity-options-by-type.js +34 -0
  269. package/modules/use-cases/get-module-instance-from-type.js +34 -0
  270. package/modules/use-cases/get-module.js +74 -0
  271. package/modules/use-cases/process-authorization-callback.js +294 -0
  272. package/modules/use-cases/refresh-entity-options.js +72 -0
  273. package/modules/use-cases/test-module-auth.js +72 -0
  274. package/modules/utils/map-module-dto.js +20 -0
  275. package/modules/utils/to-credential-id.js +14 -0
  276. package/package.json +91 -52
  277. package/prisma-mongodb/schema.prisma +455 -0
  278. package/prisma-postgresql/migrations/20250930193005_init/migration.sql +315 -0
  279. package/prisma-postgresql/migrations/20251006135218_init/migration.sql +9 -0
  280. package/prisma-postgresql/migrations/20251010000000_remove_unused_entity_reference_map/migration.sql +3 -0
  281. package/prisma-postgresql/migrations/20251112195422_update_user_unique_constraints/migration.sql +25 -0
  282. package/prisma-postgresql/migrations/20260422120000_add_entity_data_column/migration.sql +10 -0
  283. package/prisma-postgresql/migrations/20260422120001_create_process_table/migration.sql +48 -0
  284. package/prisma-postgresql/migrations/20260625000000_add_user_organization_id_index/migration.sql +2 -0
  285. package/prisma-postgresql/migrations/20260703000000_add_integration_status_in_creation_in_deletion/migration.sql +11 -0
  286. package/prisma-postgresql/migrations/20260703000001_integration_status_default_in_creation/migration.sql +8 -0
  287. package/prisma-postgresql/migrations/20260705000000_create_usage_counter/migration.sql +26 -0
  288. package/prisma-postgresql/migrations/20260706000000_add_admin_script_execution_and_schedule/migration.sql +61 -0
  289. package/prisma-postgresql/migrations/migration_lock.toml +3 -0
  290. package/prisma-postgresql/schema.prisma +436 -0
  291. package/queues/queue-delivery.js +41 -0
  292. package/queues/queuer-util.js +89 -21
  293. package/reporting/README.md +154 -0
  294. package/reporting/builtin-reports.js +6 -0
  295. package/reporting/index.js +13 -0
  296. package/reporting/report-base.js +49 -0
  297. package/reporting/reports/integrations-report.js +221 -0
  298. package/syncs/manager.js +468 -443
  299. package/syncs/repositories/sync-repository-documentdb.js +240 -0
  300. package/syncs/repositories/sync-repository-factory.js +43 -0
  301. package/syncs/repositories/sync-repository-interface.js +109 -0
  302. package/syncs/repositories/sync-repository-mongo.js +239 -0
  303. package/syncs/repositories/sync-repository-postgres.js +319 -0
  304. package/syncs/sync.js +0 -1
  305. package/telemetry/README.md +331 -0
  306. package/telemetry/bind-telemetry-context.js +77 -0
  307. package/telemetry/canonical-counters.js +52 -0
  308. package/telemetry/exporters.js +85 -0
  309. package/telemetry/index.js +26 -0
  310. package/telemetry/instrument-handler.js +104 -0
  311. package/telemetry/no-op-telemetry.js +71 -0
  312. package/telemetry/north-star.js +103 -0
  313. package/telemetry/otel-telemetry.js +232 -0
  314. package/telemetry/plugin-subscribers.js +77 -0
  315. package/telemetry/telemetry-config.js +120 -0
  316. package/telemetry/telemetry-context.js +51 -0
  317. package/telemetry/telemetry-event-bus.js +58 -0
  318. package/telemetry/telemetry-runtime.js +164 -0
  319. package/telemetry/telemetry-service.js +52 -0
  320. package/telemetry/usage-rollup-subscriber.js +116 -0
  321. package/token/repositories/token-repository-documentdb.js +137 -0
  322. package/token/repositories/token-repository-factory.js +40 -0
  323. package/token/repositories/token-repository-interface.js +131 -0
  324. package/token/repositories/token-repository-mongo.js +219 -0
  325. package/token/repositories/token-repository-postgres.js +264 -0
  326. package/token/repositories/token-repository.js +219 -0
  327. package/types/associations/index.d.ts +0 -17
  328. package/types/core/index.d.ts +12 -4
  329. package/types/database/index.d.ts +10 -2
  330. package/types/encrypt/index.d.ts +5 -3
  331. package/types/errors/index.d.ts +24 -10
  332. package/types/integrations/index.d.ts +3 -8
  333. package/types/logs/index.d.ts +61 -2
  334. package/types/module-plugin/index.d.ts +20 -69
  335. package/types/syncs/index.d.ts +0 -17
  336. package/usage/README.md +54 -0
  337. package/usage/index.js +17 -0
  338. package/usage/repositories/usage-repository-documentdb.js +194 -0
  339. package/usage/repositories/usage-repository-factory.js +25 -0
  340. package/usage/repositories/usage-repository-interface.js +37 -0
  341. package/usage/repositories/usage-repository-prisma.js +146 -0
  342. package/usage/tracked-metrics.js +38 -0
  343. package/usage/usage-windows.js +24 -0
  344. package/user/repositories/user-repository-documentdb.js +426 -0
  345. package/user/repositories/user-repository-factory.js +52 -0
  346. package/user/repositories/user-repository-interface.js +214 -0
  347. package/user/repositories/user-repository-mongo.js +323 -0
  348. package/user/repositories/user-repository-postgres.js +377 -0
  349. package/user/tests/doubles/test-user-repository.js +72 -0
  350. package/user/use-cases/authenticate-user.js +143 -0
  351. package/user/use-cases/authenticate-with-shared-secret.js +48 -0
  352. package/user/use-cases/create-individual-user.js +61 -0
  353. package/user/use-cases/create-organization-user.js +47 -0
  354. package/user/use-cases/create-token-for-user-id.js +30 -0
  355. package/user/use-cases/get-user-from-adopter-jwt.js +149 -0
  356. package/user/use-cases/get-user-from-bearer-token.js +82 -0
  357. package/user/use-cases/get-user-from-x-frigg-headers.js +132 -0
  358. package/user/use-cases/login-user.js +122 -0
  359. package/user/user.js +125 -0
  360. package/utils/backend-path.js +38 -0
  361. package/utils/index.js +6 -0
  362. package/websocket/repositories/websocket-connection-repository-documentdb.js +119 -0
  363. package/websocket/repositories/websocket-connection-repository-factory.js +44 -0
  364. package/websocket/repositories/websocket-connection-repository-interface.js +106 -0
  365. package/websocket/repositories/websocket-connection-repository-mongo.js +156 -0
  366. package/websocket/repositories/websocket-connection-repository-postgres.js +196 -0
  367. package/websocket/repositories/websocket-connection-repository.js +161 -0
  368. package/assertions/is-equal.js +0 -17
  369. package/associations/model.js +0 -54
  370. package/database/models/IndividualUser.js +0 -76
  371. package/database/models/OrganizationUser.js +0 -29
  372. package/database/models/State.js +0 -9
  373. package/database/models/Token.js +0 -70
  374. package/database/models/UserModel.js +0 -7
  375. package/database/models/WebsocketConnection.js +0 -49
  376. package/database/mongo.js +0 -45
  377. package/database/mongoose.js +0 -5
  378. package/encrypt/Cryptor.test.js +0 -32
  379. package/encrypt/encrypt.js +0 -132
  380. package/encrypt/encrypt.test.js +0 -1069
  381. package/encrypt/test-encrypt.js +0 -107
  382. package/errors/base-error.test.js +0 -32
  383. package/errors/fetch-error.test.js +0 -79
  384. package/errors/halt-error.test.js +0 -11
  385. package/errors/validation-errors.test.js +0 -120
  386. package/handlers/routers/middleware/loadUser.js +0 -15
  387. package/handlers/routers/middleware/requireLoggedInUser.js +0 -12
  388. package/integrations/create-frigg-backend.js +0 -31
  389. package/integrations/integration-factory.js +0 -251
  390. package/integrations/integration-mapping.js +0 -43
  391. package/integrations/integration-model.js +0 -46
  392. package/integrations/integration-user.js +0 -144
  393. package/integrations/test/integration-base.test.js +0 -144
  394. package/lambda/TimeoutCatcher.test.js +0 -68
  395. package/logs/logger.test.js +0 -76
  396. package/module-plugin/auther.js +0 -393
  397. package/module-plugin/credential.js +0 -22
  398. package/module-plugin/entity-manager.js +0 -70
  399. package/module-plugin/entity.js +0 -46
  400. package/module-plugin/manager.js +0 -169
  401. package/module-plugin/module-factory.js +0 -61
  402. package/module-plugin/requester/api-key.js +0 -36
  403. package/module-plugin/requester/oauth-2.js +0 -219
  404. package/module-plugin/requester/requester.js +0 -165
  405. package/module-plugin/requester/requester.test.js +0 -28
  406. package/module-plugin/test/auther.test.js +0 -97
  407. package/syncs/model.js +0 -62
  408. /package/{module-plugin → modules}/ModuleConstants.js +0 -0
  409. /package/{module-plugin → modules}/requester/basic.js +0 -0
  410. /package/{module-plugin → modules}/test/mock-api/mocks/hubspot.js +0 -0
@@ -0,0 +1,232 @@
1
+ const otelApi = require('@opentelemetry/api');
2
+ const {
3
+ BasicTracerProvider,
4
+ BatchSpanProcessor,
5
+ ParentBasedSampler,
6
+ TraceIdRatioBasedSampler,
7
+ AlwaysOnSampler,
8
+ } = require('@opentelemetry/sdk-trace-base');
9
+ const {
10
+ MeterProvider,
11
+ PeriodicExportingMetricReader,
12
+ } = require('@opentelemetry/sdk-metrics');
13
+ const { resourceFromAttributes } = require('@opentelemetry/resources');
14
+ const { resolveExporter } = require('./exporters');
15
+ const { createTelemetryEventBus } = require('./telemetry-event-bus');
16
+ const {
17
+ runWithTelemetryContext,
18
+ mergeTelemetryContext,
19
+ } = require('./telemetry-context');
20
+ const { serializeError } = require('../logs/serialize');
21
+ const { LOGGER_SCOPE_KEY } = require('../logs/context');
22
+
23
+ const BAGGAGE_TYPES = new Set(['string', 'number', 'boolean', 'bigint']);
24
+ const isBaggageValue = (value) => BAGGAGE_TYPES.has(typeof value);
25
+
26
+ const TRACER_NAME = 'frigg';
27
+ const METRIC_EXPORT_INTERVAL_MS =
28
+ Number(process.env.OTEL_METRIC_EXPORT_INTERVAL_MS) || 60000;
29
+
30
+ /**
31
+ * Register an AsyncLocalStorage-backed OTel context manager once per process.
32
+ * Without it `BasicTracerProvider` uses the Noop context manager, so
33
+ * `startActiveSpan` never sets an active context — spans would be unparented
34
+ * roots, `getActiveSpan()` always undefined, and baggage inert. Guarded so
35
+ * repeated telemetry construction (tests) doesn't re-register.
36
+ */
37
+ let contextManagerRegistered = false;
38
+ function ensureContextManager() {
39
+ if (contextManagerRegistered) return;
40
+ contextManagerRegistered = true;
41
+ try {
42
+ const {
43
+ AsyncLocalStorageContextManager,
44
+ } = require('@opentelemetry/context-async-hooks');
45
+ const manager = new AsyncLocalStorageContextManager();
46
+ manager.enable();
47
+ otelApi.context.setGlobalContextManager(manager);
48
+ } catch (_) {
49
+ // If registration fails, traces are flat but usage attribution (which
50
+ // rides the separate telemetry-context ALS) is unaffected.
51
+ }
52
+ }
53
+
54
+ /**
55
+ * OpenTelemetry-backed telemetry adapter. Constructed only when a real exporter
56
+ * is configured (`createTelemetry` returns the no-op otherwise). `BatchSpanProcessor`
57
+ * is used uniformly — spans are delivered by the bounded `forceFlush()` the Lambda
58
+ * handler awaits before the container freezes (`callbackWaitsForEmptyEventLoop=false`),
59
+ * never by background timers.
60
+ */
61
+ class OtelTelemetry {
62
+ constructor({
63
+ exporter,
64
+ resource = {},
65
+ sampleRatio,
66
+ bus = createTelemetryEventBus(),
67
+ } = {}) {
68
+ ensureContextManager();
69
+ const { traceExporter, metricExporter } = resolveExporter(exporter);
70
+
71
+ const resourceAttrs = { 'service.name': resource.service || 'frigg' };
72
+ if (resource.stage) {
73
+ resourceAttrs['deployment.environment'] = resource.stage;
74
+ resourceAttrs.stage = resource.stage;
75
+ }
76
+ if (resource.appName) resourceAttrs.appName = resource.appName;
77
+ const res = resourceFromAttributes(resourceAttrs);
78
+
79
+ const sampler =
80
+ typeof sampleRatio === 'number' && sampleRatio < 1
81
+ ? new ParentBasedSampler({
82
+ root: new TraceIdRatioBasedSampler(sampleRatio),
83
+ })
84
+ : new AlwaysOnSampler();
85
+
86
+ this._tracerProvider = new BasicTracerProvider({
87
+ resource: res,
88
+ sampler,
89
+ spanProcessors: traceExporter
90
+ ? [new BatchSpanProcessor(traceExporter)]
91
+ : [],
92
+ });
93
+
94
+ const metricReader = metricExporter
95
+ ? new PeriodicExportingMetricReader({
96
+ exporter: metricExporter,
97
+ exportIntervalMillis: METRIC_EXPORT_INTERVAL_MS,
98
+ })
99
+ : null;
100
+ this._meterProvider = new MeterProvider({
101
+ resource: res,
102
+ readers: metricReader ? [metricReader] : [],
103
+ });
104
+
105
+ this._bus = bus;
106
+ this._tracer = this._tracerProvider.getTracer(TRACER_NAME);
107
+ this._meter = this._meterProvider.getMeter(TRACER_NAME);
108
+ // One instrument instance per metric name — OTel requires it, and
109
+ // re-creating a counter would drop data points.
110
+ this._counters = new Map();
111
+ }
112
+
113
+ _getCounter(name) {
114
+ if (!this._counters.has(name)) {
115
+ this._counters.set(name, this._meter.createCounter(name));
116
+ }
117
+ return this._counters.get(name);
118
+ }
119
+
120
+ count(name, value = 1, attributes = {}, context) {
121
+ try {
122
+ this._getCounter(name).add(value, attributes);
123
+ } catch (_) {
124
+ // Telemetry must never break the wrapped path.
125
+ }
126
+ // Mirror onto the internal stream for the usage rollup + plugin taps; the
127
+ // bus context (incl. high-cardinality ids) rides the bus only, never the
128
+ // OTel metric attributes.
129
+ const merged = mergeTelemetryContext(context);
130
+ const payload = { name, value, attributes };
131
+ if (merged) payload.context = merged;
132
+ this._bus.emit('metric', payload);
133
+ }
134
+
135
+ event(name, attributes = {}, context) {
136
+ try {
137
+ const active = otelApi.trace.getActiveSpan();
138
+ if (active) active.addEvent(name, attributes);
139
+ } catch (_) {}
140
+ const merged = mergeTelemetryContext(context);
141
+ const payload = { name, attributes };
142
+ if (merged) payload.context = merged;
143
+ this._bus.emit('event', payload);
144
+ }
145
+
146
+ getActiveSpanContext() {
147
+ const spanContext = otelApi.trace.getActiveSpan()?.spanContext();
148
+ if (!spanContext || !otelApi.isSpanContextValid(spanContext)) {
149
+ return null;
150
+ }
151
+ const { traceId, spanId, traceFlags } = spanContext;
152
+ return { traceId, spanId, traceFlags };
153
+ }
154
+
155
+ startSpan(name, options) {
156
+ return this._tracer.startSpan(name, options);
157
+ }
158
+
159
+ async span(name, fn, options = {}) {
160
+ return this._tracer.startActiveSpan(name, options, async (span) => {
161
+ try {
162
+ const result =
163
+ typeof fn === 'function' ? await fn(span) : undefined;
164
+ span.setStatus({ code: otelApi.SpanStatusCode.OK });
165
+ return result;
166
+ } catch (err) {
167
+ const serialized = serializeError(err);
168
+ span.recordException({
169
+ name: serialized.type,
170
+ message: serialized.message,
171
+ stack: serialized.stack,
172
+ code: serialized.code,
173
+ });
174
+ span.setStatus({
175
+ code: otelApi.SpanStatusCode.ERROR,
176
+ message: serialized.message,
177
+ });
178
+ throw err;
179
+ } finally {
180
+ span.end();
181
+ }
182
+ });
183
+ }
184
+
185
+ /**
186
+ * Run `fn` with the given identifiers on (a) the AsyncLocalStorage telemetry
187
+ * context — which the usage rollup reads to attribute emissions per-integration
188
+ * on ANY path — and (b) OTel baggage for trace propagation. High-cardinality
189
+ * ids ride here, never on metric labels.
190
+ */
191
+ async withContext(attributes = {}, fn) {
192
+ const entries = {};
193
+ for (const [key, value] of Object.entries(attributes || {})) {
194
+ if (key === LOGGER_SCOPE_KEY || !isBaggageValue(value)) continue;
195
+ entries[key] = { value: String(value) };
196
+ }
197
+ const baggage = otelApi.propagation.createBaggage(entries);
198
+ const ctx = otelApi.propagation.setBaggage(
199
+ otelApi.context.active(),
200
+ baggage
201
+ );
202
+ return runWithTelemetryContext(attributes, () =>
203
+ otelApi.context.with(ctx, () =>
204
+ typeof fn === 'function' ? fn() : undefined
205
+ )
206
+ );
207
+ }
208
+
209
+ on(eventType, callback) {
210
+ return this._bus.on(eventType, callback);
211
+ }
212
+
213
+ async forceFlush() {
214
+ await Promise.allSettled([
215
+ this._tracerProvider.forceFlush(),
216
+ this._meterProvider.forceFlush(),
217
+ ]);
218
+ }
219
+
220
+ async shutdown() {
221
+ await Promise.allSettled([
222
+ this._tracerProvider.shutdown(),
223
+ this._meterProvider.shutdown(),
224
+ ]);
225
+ }
226
+
227
+ isEnabled() {
228
+ return true;
229
+ }
230
+ }
231
+
232
+ module.exports = { OtelTelemetry };
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Declarative plugin/extension telemetry taps.
3
+ *
4
+ * The built-in usage rollup and North Star derivation subscribe to the telemetry
5
+ * bus in framework code; this lets an ADOPTER subscribe declaratively from the
6
+ * app definition (`Definition.telemetry.subscribers: [...]`) — forward to a
7
+ * custom sink, compute aggregates, persist counters — without writing wiring code.
8
+ *
9
+ * A subscriber is one of:
10
+ * - a **factory** `fn(telemetry)` that registers itself (e.g. calls
11
+ * `telemetry.on('metric', ...)`) and MAY return an unsubscribe function; or
12
+ * - a **declarative object** `{ event?: 'metric'|'event', handler(payload, eventType) }`
13
+ * — when `event` is omitted the handler receives both metric and event payloads.
14
+ *
15
+ * Every attach and every handler invocation is guarded so a misbehaving
16
+ * subscriber can never break emission, its siblings, or a handler (mirrors the
17
+ * bus's own per-subscriber isolation).
18
+ *
19
+ * @param {object} params
20
+ * @param {object} params.telemetry Telemetry service exposing `on(eventType, cb)`.
21
+ * @param {Array<Function|{event?: string, handler: Function}>} [params.subscribers]
22
+ * @returns {Array<Function>} unsubscribe functions for the wired subscribers.
23
+ */
24
+ const EVENT_TYPES = ['metric', 'event'];
25
+
26
+ function wireTelemetrySubscribers({ telemetry, subscribers = [] } = {}) {
27
+ if (
28
+ !telemetry ||
29
+ typeof telemetry.on !== 'function' ||
30
+ !Array.isArray(subscribers)
31
+ ) {
32
+ return [];
33
+ }
34
+
35
+ const unsubscribes = [];
36
+
37
+ for (const subscriber of subscribers) {
38
+ try {
39
+ if (typeof subscriber === 'function') {
40
+ const off = subscriber(telemetry);
41
+ if (typeof off === 'function') unsubscribes.push(off);
42
+ continue;
43
+ }
44
+
45
+ if (subscriber && typeof subscriber.handler === 'function') {
46
+ const events = subscriber.event
47
+ ? [subscriber.event]
48
+ : EVENT_TYPES;
49
+ for (const eventType of events) {
50
+ const off = telemetry.on(eventType, (payload) => {
51
+ try {
52
+ subscriber.handler(payload, eventType);
53
+ } catch (error) {
54
+ console.warn(
55
+ `[Frigg][telemetry] subscriber handler for "${eventType}" threw: ${
56
+ error && error.message
57
+ }`
58
+ );
59
+ }
60
+ });
61
+ if (typeof off === 'function') unsubscribes.push(off);
62
+ }
63
+ }
64
+ } catch (error) {
65
+ // A single bad subscriber must never break wiring of the others.
66
+ console.warn(
67
+ `[Frigg][telemetry] failed to wire a telemetry subscriber: ${
68
+ error && error.message
69
+ }`
70
+ );
71
+ }
72
+ }
73
+
74
+ return unsubscribes;
75
+ }
76
+
77
+ module.exports = { wireTelemetrySubscribers };
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Resolves and validates the telemetry section of an app definition
3
+ * into a normalized config the TelemetryService and
4
+ * usage rollup consume: `{ exporter, northStar, sampleRatio }`.
5
+ *
6
+ * Exporter default is keyed off STAGE: only a genuinely LOCAL run (STAGE=local)
7
+ * gets `console` (visible, free); every deployed stage — including `dev` —
8
+ * defaults to `none`. `dev` is a deployed AWS stage, and `console` there would
9
+ * write full spans to CloudWatch by default (cost + a data-exposure surface).
10
+ * Adopters opt into `console`/`otlp` explicitly for deployed stages.
11
+ */
12
+ const VALID_EXPORTER_TYPES = [
13
+ 'none',
14
+ 'noop',
15
+ 'console',
16
+ 'otlp',
17
+ 'honeycomb',
18
+ 'datadog',
19
+ ];
20
+
21
+ function normalizeExporterConfig(exporter, stage) {
22
+ if (!exporter) {
23
+ return stage === 'local' ? { type: 'console' } : { type: 'none' };
24
+ }
25
+
26
+ // Pre-built exporter instances (tests / advanced adopters) bypass type checks.
27
+ if (exporter.traceExporter || exporter.metricExporter) {
28
+ return exporter;
29
+ }
30
+
31
+ if (!VALID_EXPORTER_TYPES.includes(exporter.type)) {
32
+ throw new Error(
33
+ `[Frigg][telemetry] invalid exporter type "${exporter.type}". ` +
34
+ `Supported: ${VALID_EXPORTER_TYPES.join(', ')}`
35
+ );
36
+ }
37
+ return exporter;
38
+ }
39
+
40
+ // Fraction of TRACES exported (0..1, default 1) — a cost knob wired to the OTel
41
+ // sampler in otel-telemetry. Does NOT thin usage counters; those stay exact.
42
+ function resolveSampleRatio(sampleRatio) {
43
+ if (sampleRatio === undefined || sampleRatio === null) return 1;
44
+ if (
45
+ typeof sampleRatio !== 'number' ||
46
+ Number.isNaN(sampleRatio) ||
47
+ sampleRatio < 0 ||
48
+ sampleRatio > 1
49
+ ) {
50
+ throw new Error(
51
+ `[Frigg][telemetry] sampleRatio must be a number in [0,1], got ${sampleRatio}`
52
+ );
53
+ }
54
+ return sampleRatio;
55
+ }
56
+
57
+ function validateNorthStarEntry(entry, where) {
58
+ if (!entry || typeof entry.name !== 'string' || !entry.name) {
59
+ throw new Error(
60
+ `[Frigg][telemetry] northStar.${where} must reference a counter { name }`
61
+ );
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Adopter-declared telemetry subscribers. Each is either a factory
67
+ * function `fn(telemetry)` or a declarative `{ event?, handler }` object. Kept as
68
+ * an array so `wireTelemetrySubscribers` can attach them to the bus at runtime.
69
+ */
70
+ function resolveSubscribers(subscribers) {
71
+ if (subscribers === undefined || subscribers === null) return [];
72
+ if (!Array.isArray(subscribers)) {
73
+ throw new Error(
74
+ '[Frigg][telemetry] subscribers must be an array of functions or { handler } objects'
75
+ );
76
+ }
77
+ for (const subscriber of subscribers) {
78
+ const ok =
79
+ typeof subscriber === 'function' ||
80
+ (subscriber && typeof subscriber.handler === 'function');
81
+ if (!ok) {
82
+ throw new Error(
83
+ '[Frigg][telemetry] each subscriber must be a function or an object with a handler function'
84
+ );
85
+ }
86
+ }
87
+ return subscribers;
88
+ }
89
+
90
+ function resolveNorthStar(northStar) {
91
+ if (!northStar) return null;
92
+ if (northStar.default) validateNorthStarEntry(northStar.default, 'default');
93
+ if (northStar.byType) {
94
+ for (const [type, entry] of Object.entries(northStar.byType)) {
95
+ validateNorthStarEntry(entry, `byType.${type}`);
96
+ }
97
+ }
98
+ return northStar;
99
+ }
100
+
101
+ /**
102
+ * @param {object} appDefinition The backend `Definition` export.
103
+ * @param {object} [ctx]
104
+ * @param {string} [ctx.stage] Deployment stage (defaults to STAGE/NODE_ENV).
105
+ * @returns {{ exporter: object, northStar: object|null, sampleRatio: number }}
106
+ */
107
+ function resolveTelemetryConfig(appDefinition = {}, ctx = {}) {
108
+ const stage =
109
+ ctx.stage || process.env.STAGE || process.env.NODE_ENV || 'production';
110
+ const telemetry = appDefinition.telemetry || {};
111
+
112
+ return {
113
+ exporter: normalizeExporterConfig(telemetry.exporter, stage),
114
+ northStar: resolveNorthStar(telemetry.northStar),
115
+ sampleRatio: resolveSampleRatio(telemetry.sampleRatio),
116
+ subscribers: resolveSubscribers(telemetry.subscribers),
117
+ };
118
+ }
119
+
120
+ module.exports = { resolveTelemetryConfig };
@@ -0,0 +1,51 @@
1
+ const {
2
+ runInContext,
3
+ getContext,
4
+ hasOnlyLoggerKeys,
5
+ LOGGER_SCOPE_KEY,
6
+ } = require('../logs/context');
7
+
8
+ /**
9
+ * Ambient telemetry context. The one process-wide AsyncLocalStorage
10
+ * (owned by logs/context.js, shared with the logger scope) holds the standard identifiers ({integrationId, integrationType, userId,
11
+ * version, ...}) for the duration of a handler, set once at the handler seam via
12
+ * `telemetry.withContext(...)`. Any emission during that async scope — including
13
+ * deep calls like an API-module request — reads the ambient context, so the
14
+ * usage rollup can attribute counters per-integration WITHOUT threading context
15
+ * through every call and WITHOUT relying on OTel baggage (which does not exist
16
+ * on the no-op path). This is the propagation mechanism the plan intended.
17
+ *
18
+ * Only bus-payload `context` is populated from here; high-cardinality ids never
19
+ * touch OTel metric labels. A nested run merges: an undefined key keeps the
20
+ * outer value, an explicit null is stored as null.
21
+ */
22
+ function withoutLoggerKeys(store) {
23
+ if (!store || hasOnlyLoggerKeys(store)) return null;
24
+ const { [LOGGER_SCOPE_KEY]: _logger, ...rest } = store;
25
+ return rest;
26
+ }
27
+
28
+ function runWithTelemetryContext(context, fn) {
29
+ return runInContext(context, fn);
30
+ }
31
+
32
+ function getTelemetryContextStore() {
33
+ return withoutLoggerKeys(getContext());
34
+ }
35
+
36
+ /**
37
+ * Merge the ambient context with an explicit per-call context (explicit keys
38
+ * win, e.g. a request `url`). Returns undefined when there is nothing to attach.
39
+ * The logger sub-object never reaches the bus payload.
40
+ */
41
+ function mergeTelemetryContext(explicit) {
42
+ const ambient = withoutLoggerKeys(getContext());
43
+ if (!ambient && !explicit) return undefined;
44
+ return { ...(ambient || {}), ...(explicit || {}) };
45
+ }
46
+
47
+ module.exports = {
48
+ runWithTelemetryContext,
49
+ getTelemetryContextStore,
50
+ mergeTelemetryContext,
51
+ };
@@ -0,0 +1,58 @@
1
+ /**
2
+ * TelemetryEventBus — the internal event stream telemetry flows onto.
3
+ * Plugins/extensions and the built-in usage rollup
4
+ * subscribe here; it is deliberately independent of OTel export (Decision 7),
5
+ * so usage counters persist even when the OTel exporter is a no-op.
6
+ *
7
+ * This is intentionally a **synchronous** in-process fan-out (Frigg runs one
8
+ * invocation per Lambda container): a plain subscriber list with per-subscriber
9
+ * `try/catch` so a misbehaving subscriber can never break emission or its
10
+ * siblings. No queue/backpressure machinery — emission volume is bounded by a
11
+ * single invocation's work.
12
+ *
13
+ * ## Public event contract (semver-stable)
14
+ * Event types and their payload shapes:
15
+ * - `'metric'` → `{ name: string, value: number, attributes: object, context?: object }`
16
+ * - `'event'` → `{ name: string, attributes: object, context?: object }`
17
+ * `attributes` are the bounded OTel metric labels. `context` (present when an
18
+ * ambient telemetry context is active) carries the high-cardinality identifiers
19
+ * — {integrationId, integrationType, userId, version, ...} plus per-call extras
20
+ * like a request `url` — which the usage rollup reads for attribution. Those ids
21
+ * NEVER appear in `attributes` (Cardinality note).
22
+ */
23
+ function createTelemetryEventBus() {
24
+ /** @type {Map<string, Set<Function>>} */
25
+ const subscribers = new Map();
26
+
27
+ function on(eventType, callback) {
28
+ if (!subscribers.has(eventType)) {
29
+ subscribers.set(eventType, new Set());
30
+ }
31
+ const set = subscribers.get(eventType);
32
+ set.add(callback);
33
+ return function off() {
34
+ set.delete(callback);
35
+ };
36
+ }
37
+
38
+ function emit(eventType, payload) {
39
+ const set = subscribers.get(eventType);
40
+ if (!set || set.size === 0) return;
41
+ for (const callback of set) {
42
+ try {
43
+ callback(payload);
44
+ } catch (error) {
45
+ // A subscriber must never break emission or its siblings.
46
+ console.warn(
47
+ `[Frigg][telemetry] subscriber for "${eventType}" threw: ${
48
+ error && error.message
49
+ }`
50
+ );
51
+ }
52
+ }
53
+ }
54
+
55
+ return { on, emit };
56
+ }
57
+
58
+ module.exports = { createTelemetryEventBus };