@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/logs/logger.js CHANGED
@@ -1,69 +1,157 @@
1
- const util = require('util');
2
- const aws = require('aws-sdk');
1
+ const { LEVELS, parseLevel } = require('./levels');
2
+ const { getLoggerScope } = require('./context');
3
+ const runtime = require('./logger-runtime');
4
+ const { buildRecord, DEFAULT_LOGGER_NAME } = require('./record');
5
+
6
+ const LOGGER_OWN_NAME = 'frigg.logger';
7
+
8
+ function copyBindings(bindings, into = {}) {
9
+ if (!bindings || typeof bindings !== 'object') return into;
10
+ for (const key of Object.keys(bindings)) {
11
+ try {
12
+ into[key] = bindings[key];
13
+ } catch {
14
+ // A throwing getter drops only that binding.
15
+ }
16
+ }
17
+ return into;
18
+ }
3
19
 
4
- // Except in some outlier circumstances, for example steam or event error handlers, this should be the only place that calls `console.*`. That way, this file can be modified to log everything properly on a variety of platforms because all the logging code is here in one place.
5
- /* eslint-disable no-console */
20
+ // One plain object per record. Static sources were copied at child() time.
21
+ function evaluateBindings(sources) {
22
+ const merged = {};
23
+ for (const source of sources) {
24
+ if (typeof source !== 'function') {
25
+ Object.assign(merged, source);
26
+ continue;
27
+ }
28
+ let value;
29
+ try {
30
+ value = source();
31
+ } catch {
32
+ continue;
33
+ }
34
+ copyBindings(value, merged);
35
+ }
36
+ return merged;
37
+ }
6
38
 
7
- const logs = [];
8
- let flushCalled = false;
39
+ function isFriggViolation(record) {
40
+ return (
41
+ record.logger.startsWith('frigg.') &&
42
+ LEVELS[record.level] >= LEVELS.WARN &&
43
+ !record.eventName
44
+ );
45
+ }
9
46
 
10
- // Log AWS SDK calls
11
- aws.config.logger = { log: debug };
47
+ class Logger {
48
+ constructor(name, bindingSources = []) {
49
+ this.name = name;
50
+ this._bindingSources = bindingSources;
51
+ }
12
52
 
13
- function debug(...messages) {
14
- if (messages.length) {
15
- const date = new Date();
16
- const text = util.format.apply(null, messages);
53
+ trace(message, fields) {
54
+ this._log('TRACE', message, fields);
55
+ }
17
56
 
18
- if (process.env.DEBUG_VERBOSE === '1') {
19
- console.debug(date, text);
20
- } else {
21
- logs.push({ date, text });
22
- }
57
+ debug(message, fields) {
58
+ this._log('DEBUG', message, fields);
59
+ }
60
+
61
+ info(message, fields) {
62
+ this._log('INFO', message, fields);
23
63
  }
24
- }
25
64
 
26
- function initDebugLog(...initMessages) {
27
- flushCalled = false;
65
+ warn(message, fields) {
66
+ this._log('WARN', message, fields);
67
+ }
28
68
 
29
- // Hacky but fast way to empty an array.
30
- logs.length = 0;
69
+ error(message, fields) {
70
+ this._log('ERROR', message, fields);
71
+ }
31
72
 
32
- // Log initial event
33
- debug(...initMessages);
34
- }
73
+ fatal(message, fields) {
74
+ this._log('FATAL', message, fields);
75
+ }
35
76
 
36
- function flushDebugLog(error) {
37
- if (flushCalled) {
38
- console.debug(
39
- 'Another error was encountered while handling the same request or event! All debug messages are included again in this output as well.'
40
- );
77
+ child(bindings) {
78
+ const source = typeof bindings === 'function' ? bindings : copyBindings(bindings);
79
+ return new Logger(this.name, [...this._bindingSources, source]);
41
80
  }
42
81
 
43
- flushCalled = true;
82
+ isLevelEnabled(level) {
83
+ try {
84
+ const name = parseLevel(level);
85
+ return name !== null && LEVELS[name] >= runtime.getConfig().threshold;
86
+ } catch {
87
+ return false;
88
+ }
89
+ }
44
90
 
45
- // Output unless in verbose mode. In verbose mode, these will already have been output so we don't want to output the messages twice.
46
- if (process.env.DEBUG_VERBOSE !== '1') {
47
- if (logs?.length > 0) {
48
- for (const { date, text } of logs) {
49
- console.debug(date, text);
91
+ _log(level, message, fields) {
92
+ const state = runtime.state();
93
+ if (state.inLog) return;
94
+ try {
95
+ const config = runtime.getConfig();
96
+ emitConfigWarnings();
97
+ if (LEVELS[level] < config.threshold) return;
98
+ // Set before fields, bindings and sinks run: any of them may log.
99
+ state.inLog = true;
100
+
101
+ const record = buildRecord({
102
+ level,
103
+ logger: this.name,
104
+ message,
105
+ fields,
106
+ bindings: evaluateBindings(this._bindingSources),
107
+ scope: getLoggerScope(),
108
+ spanContext: runtime.getSpanContext(),
109
+ resource: { appName: config.appName, stage: config.stage },
110
+ });
111
+ if (isFriggViolation(record)) {
112
+ runtime.recordViolation({
113
+ logger: record.logger,
114
+ level: record.level,
115
+ message: record.message,
116
+ });
50
117
  }
118
+ writeToSinks(record);
119
+ } catch {
120
+ // The logger never throws.
121
+ } finally {
122
+ state.inLog = false;
51
123
  }
52
124
  }
125
+ }
53
126
 
54
- if (!error) {
55
- error = new Error('flushDebugLog called with empty error');
127
+ function writeToSinks(record) {
128
+ for (const sink of runtime.getSinks()) {
129
+ try {
130
+ sink.write(record);
131
+ } catch {
132
+ // One failing sink must not stop the others.
133
+ }
56
134
  }
135
+ }
57
136
 
58
- console.error(error);
137
+ function emitConfigWarnings() {
138
+ const warnings = runtime.takeConfigWarnings();
139
+ if (!warnings.length) return;
140
+ const logger = getLogger(LOGGER_OWN_NAME);
141
+ for (const warning of warnings) {
142
+ logger.warn(warning.message, {
143
+ ...warning.fields,
144
+ eventName: warning.eventName,
145
+ });
146
+ }
147
+ }
59
148
 
60
- let { cause: parentError } = error;
149
+ const loggers = new Map();
61
150
 
62
- while (parentError) {
63
- console.error('(Caused By)-------------------------');
64
- console.error(parentError);
65
- parentError = parentError.cause;
66
- }
151
+ function getLogger(name) {
152
+ const key = typeof name === 'string' && name ? name : DEFAULT_LOGGER_NAME;
153
+ if (!loggers.has(key)) loggers.set(key, new Logger(key));
154
+ return loggers.get(key);
67
155
  }
68
156
 
69
- module.exports = { debug, initDebugLog, flushDebugLog };
157
+ module.exports = { Logger, getLogger };
package/logs/record.js ADDED
@@ -0,0 +1,276 @@
1
+ const { LEVELS } = require('./levels');
2
+ const { serializeValue, serializeError, isError } = require('./serialize');
3
+ const { isPlainObject } = require('./context');
4
+ const {
5
+ RESOURCE_KEYS,
6
+ DROPPED_KEYS_FIELD,
7
+ OWNED_KEYS,
8
+ RESERVED_KEYS,
9
+ PAYLOAD_KEYS,
10
+ } = require('./contract-keys');
11
+
12
+ const MAX_RECORD_BYTES = 16 * 1024;
13
+ const DEFAULT_LOGGER_NAME = 'frigg.unknown';
14
+
15
+ function deepFreeze(value) {
16
+ if (value && typeof value === 'object' && !Object.isFrozen(value)) {
17
+ for (const key of Object.keys(value)) deepFreeze(value[key]);
18
+ Object.freeze(value);
19
+ }
20
+ return value;
21
+ }
22
+
23
+ function readFields(source) {
24
+ const result = {};
25
+ if (!source || typeof source !== 'object') return result;
26
+ let keys;
27
+ try {
28
+ keys = Object.keys(source);
29
+ } catch {
30
+ return result;
31
+ }
32
+ for (const key of keys) {
33
+ try {
34
+ result[key] = source[key];
35
+ } catch {
36
+ result[key] = '[Getter threw]';
37
+ }
38
+ }
39
+ return result;
40
+ }
41
+
42
+ // Returns the message text. An Error message is serialized once; when the
43
+ // call site has no `error`, that result becomes the record's `error`.
44
+ function buildMessage(message, callSite) {
45
+ if (typeof message === 'string') {
46
+ return { text: serializeValue(message) };
47
+ }
48
+ if (message === undefined || message === null) return { text: '' };
49
+ if (isError(message)) {
50
+ const error = serializeError(message);
51
+ const text = typeof error?.message === 'string' ? error.message : '';
52
+ if (callSite.error !== undefined) return { text };
53
+ callSite.error = message;
54
+ return { text, error };
55
+ }
56
+ if (callSite.value === undefined) callSite.value = message;
57
+ return { text: '[non-string message]' };
58
+ }
59
+
60
+ const INVOCATION_KEY = 'invocation';
61
+
62
+ // A boundary adds request detail to the scope's invocation; scope keys win.
63
+ function extendInvocation(scoped, detail) {
64
+ const merged = { ...scoped };
65
+ for (const key of Object.keys(detail)) {
66
+ if (!(key in merged)) merged[key] = detail[key];
67
+ }
68
+ return merged;
69
+ }
70
+
71
+ function traceFields(spanContext) {
72
+ if (
73
+ !spanContext ||
74
+ typeof spanContext.traceId !== 'string' ||
75
+ typeof spanContext.spanId !== 'string'
76
+ ) {
77
+ return {};
78
+ }
79
+ const flags = Number(spanContext.traceFlags) || 0;
80
+ return {
81
+ trace_id: spanContext.traceId,
82
+ span_id: spanContext.spanId,
83
+ trace_flags: (flags & 0xff).toString(16).padStart(2, '0'),
84
+ };
85
+ }
86
+
87
+ function sameValue(a, b) {
88
+ if (a === b) return true;
89
+ return (
90
+ typeof a === 'object' &&
91
+ typeof b === 'object' &&
92
+ JSON.stringify(a) === JSON.stringify(b)
93
+ );
94
+ }
95
+
96
+ function byteLength(record) {
97
+ return Buffer.byteLength(JSON.stringify(record));
98
+ }
99
+
100
+ function isDroppedKey(key, dropPayloads) {
101
+ return (
102
+ OWNED_KEYS.has(key) ||
103
+ RESERVED_KEYS.has(key) ||
104
+ (dropPayloads && PAYLOAD_KEYS.has(key))
105
+ );
106
+ }
107
+
108
+ // Filters and serializes one source. `error` is serialized on its own, once
109
+ // (or taken from `preSerializedError`), and never walked by serializeValue.
110
+ function prepareSource(source, dropPayloads, preSerializedError) {
111
+ const accepted = {};
112
+ const keys = [];
113
+ const dropped = [];
114
+ let rawError;
115
+ for (const [key, value] of Object.entries(source)) {
116
+ if (value === undefined || value === null) continue;
117
+ if (isDroppedKey(key, dropPayloads)) {
118
+ dropped.push(key);
119
+ continue;
120
+ }
121
+ keys.push(key);
122
+ if (key === 'error') rawError = value;
123
+ else accepted[key] = value;
124
+ }
125
+ // One pass over the object, so key rules (denied keys, digests,
126
+ // headers, OAuth shapes) apply to top-level fields too.
127
+ const safe = serializeValue(accepted);
128
+ const entries = [];
129
+ for (const key of keys) {
130
+ const value =
131
+ key === 'error'
132
+ ? preSerializedError ?? serializeError(rawError)
133
+ : safe?.[key];
134
+ if (value !== undefined && value !== null) entries.push([key, value]);
135
+ }
136
+ return { entries, dropped };
137
+ }
138
+
139
+ // The scope object is frozen and shared by every record of one scope.
140
+ const preparedScopes = new WeakMap();
141
+
142
+ function prepareScope(scope, dropPayloads) {
143
+ if (!scope || typeof scope !== 'object') return { entries: [], dropped: [] };
144
+ let byLevel = preparedScopes.get(scope);
145
+ if (!byLevel) {
146
+ byLevel = {};
147
+ preparedScopes.set(scope, byLevel);
148
+ }
149
+ const slot = dropPayloads ? 'info' : 'debug';
150
+ if (!byLevel[slot]) byLevel[slot] = prepareSource(scope, dropPayloads);
151
+ return byLevel[slot];
152
+ }
153
+
154
+ function buildRecord({
155
+ level,
156
+ logger,
157
+ message,
158
+ fields,
159
+ bindings,
160
+ scope,
161
+ spanContext,
162
+ resource = {},
163
+ now = new Date(),
164
+ } = {}) {
165
+ const dropPayloads = LEVELS[level] >= LEVELS.INFO;
166
+ // log.error('msg', err): own props of an Error (axios config, request) must not become fields.
167
+ const callSite = readFields(isError(fields) ? { error: fields } : fields);
168
+ const built = buildMessage(message, callSite);
169
+ const record = {
170
+ timestamp: now.toISOString(),
171
+ level,
172
+ message: built.text,
173
+ logger: typeof logger === 'string' && logger ? logger : DEFAULT_LOGGER_NAME,
174
+ };
175
+ for (const key of RESOURCE_KEYS) {
176
+ if (typeof resource[key] === 'string' && resource[key]) {
177
+ record[key] = resource[key];
178
+ }
179
+ }
180
+ Object.assign(record, traceFields(spanContext));
181
+
182
+ const dropped = new Set();
183
+ const callSiteKeys = [];
184
+ // Call-site keys merged into the scope invocation; the size cap must reach them too.
185
+ const invocationDetailKeys = [];
186
+ const place = ({ entries, dropped: droppedHere }, isCallSite) => {
187
+ for (const key of droppedHere) dropped.add(key);
188
+ for (const [key, value] of entries) {
189
+ if (Object.prototype.hasOwnProperty.call(record, key)) {
190
+ if (
191
+ key === INVOCATION_KEY &&
192
+ isPlainObject(record[key]) &&
193
+ isPlainObject(value)
194
+ ) {
195
+ const merged = extendInvocation(record[key], value);
196
+ if (isCallSite) {
197
+ for (const detailKey of Object.keys(value)) {
198
+ if (!(detailKey in record[key])) invocationDetailKeys.push(detailKey);
199
+ }
200
+ }
201
+ record[key] = merged;
202
+ } else if (!sameValue(record[key], value)) {
203
+ // A repeat of the winning value is no conflict.
204
+ dropped.add(key);
205
+ }
206
+ continue;
207
+ }
208
+ record[key] = value;
209
+ if (isCallSite) callSiteKeys.push(key);
210
+ }
211
+ };
212
+ place(prepareScope(scope, dropPayloads), false);
213
+ place(prepareSource(bindings || {}, dropPayloads), false);
214
+ place(prepareSource(callSite, dropPayloads, built.error), true);
215
+
216
+ const setDroppedKeys = () => {
217
+ delete record[DROPPED_KEYS_FIELD];
218
+ if (dropped.size) record[DROPPED_KEYS_FIELD] = [...dropped];
219
+ };
220
+ setDroppedKeys();
221
+ let size = byteLength(record);
222
+
223
+ if (size > MAX_RECORD_BYTES) {
224
+ const candidates = [
225
+ ...callSiteKeys
226
+ .filter((key) => key !== 'error')
227
+ .map((key) => ({
228
+ name: key,
229
+ value: record[key],
230
+ remove: () => delete record[key],
231
+ })),
232
+ ...invocationDetailKeys.map((key) => ({
233
+ name: `${INVOCATION_KEY}.${key}`,
234
+ value: record[INVOCATION_KEY][key],
235
+ remove: () => {
236
+ const rest = { ...record[INVOCATION_KEY] };
237
+ delete rest[key];
238
+ record[INVOCATION_KEY] = rest;
239
+ },
240
+ })),
241
+ ];
242
+ const bySize = candidates
243
+ .map((candidate) => [candidate, Buffer.byteLength(JSON.stringify(candidate.value))])
244
+ .sort((a, b) => b[1] - a[1]);
245
+ for (const [candidate] of bySize) {
246
+ candidate.remove();
247
+ dropped.add(candidate.name);
248
+ setDroppedKeys();
249
+ size = byteLength(record);
250
+ if (size <= MAX_RECORD_BYTES) break;
251
+ }
252
+ }
253
+ for (const part of ['stack', 'cause']) {
254
+ if (
255
+ size > MAX_RECORD_BYTES &&
256
+ record.error &&
257
+ typeof record.error === 'object' &&
258
+ record.error[part] !== undefined
259
+ ) {
260
+ const { [part]: _removed, ...rest } = record.error;
261
+ record.error = rest;
262
+ size = byteLength(record);
263
+ }
264
+ }
265
+
266
+ return deepFreeze(record);
267
+ }
268
+
269
+ module.exports = {
270
+ buildRecord,
271
+ deepFreeze,
272
+ MAX_RECORD_BYTES,
273
+ RESERVED_KEYS,
274
+ PAYLOAD_KEYS,
275
+ DEFAULT_LOGGER_NAME,
276
+ };