@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
@@ -1,5 +1,5 @@
1
1
  const { RequiredPropertyError } = require('../errors');
2
- const { get, getAndVerifyType } = require('../assertions');
2
+ const { get } = require('../assertions');
3
3
 
4
4
  class Options {
5
5
  constructor(params) {
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Shared validation for IntegrationRepository.patchIntegrationConfig().
3
+ *
4
+ * A patch is an atomic shallow merge into Integration.config: every key in
5
+ * the patch is written, every other existing key is left untouched. This
6
+ * contract is enforced here, before any adapter emits a query, so a bug fix
7
+ * (or a tighter rule) fixes all three backends in one place.
8
+ *
9
+ * Keys may not contain '.' or start with '$' — both are reserved by the
10
+ * MongoDB/DocumentDB update-command syntax the mongo and documentdb adapters
11
+ * use to address `config.<key>` paths. A value of `null` is allowed and sets
12
+ * the key to null — the only way to clear a config field over the PATCH HTTP
13
+ * endpoint (it sets the value, it does not remove the key). `undefined` is
14
+ * rejected: it can't arrive over JSON and signals a programming error, not an
15
+ * intent. Removing a key entirely still requires a full replace via updateConfig.
16
+ */
17
+ function validateConfigPatch(patch) {
18
+ if (!patch || typeof patch !== 'object' || Array.isArray(patch)) {
19
+ throw new Error('patchIntegrationConfig: patch must be a non-null object');
20
+ }
21
+
22
+ const keys = Object.keys(patch);
23
+ if (keys.length === 0) {
24
+ throw new Error(
25
+ 'patchIntegrationConfig: patch must contain at least one key'
26
+ );
27
+ }
28
+
29
+ for (const key of keys) {
30
+ if (key.includes('.') || key.startsWith('$')) {
31
+ throw new Error(
32
+ `patchIntegrationConfig: patch key '${key}' cannot contain '.' or start with '$'`
33
+ );
34
+ }
35
+ if (patch[key] === undefined) {
36
+ throw new Error(
37
+ `patchIntegrationConfig: patch['${key}'] cannot be undefined`
38
+ );
39
+ }
40
+ }
41
+ }
42
+
43
+ module.exports = { validateConfigPatch };
@@ -0,0 +1,152 @@
1
+ const SORT_KEY = '__sortKey';
2
+ const MONGO_DIRECTIONS = { asc: 1, desc: -1 };
3
+ const SORT_TYPE_RANKS = [
4
+ ['string'],
5
+ ['int', 'long', 'double', 'decimal'],
6
+ ['bool'],
7
+ ['array'],
8
+ ['object'],
9
+ ];
10
+ const SCALAR_TYPES = SORT_TYPE_RANKS.slice(0, 3).flat();
11
+
12
+ const isType = (expression, type) => ({ $eq: [{ $type: expression }, type] });
13
+ const isAbsent = (expression) => ({
14
+ $eq: [{ $ifNull: [expression, null] }, null],
15
+ });
16
+ const mappingField = (segments) => `$mapping.${segments.join('.')}`;
17
+
18
+ const CONDITION_EXPRESSIONS = {
19
+ exists: (operand) => ({ $ne: [{ $ifNull: [operand, null] }, null] }),
20
+ notExists: (operand) => isAbsent(operand),
21
+ in: (operand, values) => ({
22
+ $and: [
23
+ isType(operand, 'string'),
24
+ { $in: [operand, { $literal: values }] },
25
+ ],
26
+ }),
27
+ notStartsWith: (operand, prefix) => ({
28
+ $cond: [
29
+ isType(operand, 'string'),
30
+ {
31
+ $ne: [
32
+ { $substrCP: [operand, 0, [...prefix].length] },
33
+ { $literal: prefix },
34
+ ],
35
+ },
36
+ true,
37
+ ],
38
+ }),
39
+ };
40
+
41
+ /**
42
+ * Aggregation stages that answer a validated queryMappings query on the
43
+ * MongoDB wire protocol.
44
+ *
45
+ * @param {*} integrationId - The value IntegrationMapping.integrationId is stored as
46
+ * @param {ReturnType<import('./integration-mapping-query').validateMappingQuery>} query
47
+ * @returns {{match: Object, page: Object[], sort: Object}} `match` selects
48
+ * the matching documents; `page` sorts, skips and limits them; `sort` is
49
+ * the $sort stage inside `page`
50
+ */
51
+ function buildMappingQueryStages(
52
+ integrationId,
53
+ { where, orderBy, skip, take, omit }
54
+ ) {
55
+ const match = {
56
+ $match: {
57
+ integrationId,
58
+ $expr: {
59
+ $and: [
60
+ isType('$mapping', 'object'),
61
+ ...where.map(entryExpression),
62
+ ],
63
+ },
64
+ },
65
+ };
66
+ const sort = { $sort: sortSpec(orderBy) };
67
+ const page = [
68
+ ...(orderBy
69
+ ? [{ $addFields: { [SORT_KEY]: sortKey(orderBy.path) } }]
70
+ : []),
71
+ ...(omit.length > 0 ? [{ $project: omitProjection(omit) }] : []),
72
+ sort,
73
+ ...(skip > 0 ? [{ $skip: skip }] : []),
74
+ { $limit: take },
75
+ ];
76
+ return { match, page, sort };
77
+ }
78
+
79
+ function entryExpression(entry) {
80
+ if (!entry.anyOf) return conditionExpression(entry);
81
+ return { $or: entry.anyOf.map(conditionExpression) };
82
+ }
83
+
84
+ function conditionExpression({ field, path, op, value }) {
85
+ const operand = field === 'sourceId' ? '$sourceId' : resolvePath(path);
86
+ return CONDITION_EXPRESSIONS[op](operand, value);
87
+ }
88
+
89
+ /**
90
+ * The value at a mapping path; null when an enclosing value is not an object.
91
+ */
92
+ function resolvePath(segments) {
93
+ const enclosing = segments
94
+ .slice(0, -1)
95
+ .map((_, i) =>
96
+ isType(mappingField(segments.slice(0, i + 1)), 'object')
97
+ );
98
+ if (enclosing.length === 0) return mappingField(segments);
99
+ return {
100
+ $cond: [
101
+ enclosing.length === 1 ? enclosing[0] : { $and: enclosing },
102
+ mappingField(segments),
103
+ null,
104
+ ],
105
+ };
106
+ }
107
+
108
+ /**
109
+ * Orders values like jsonb: strings < numbers < booleans < arrays < objects,
110
+ * scalars by value within their type. Null and absent values sort last in
111
+ * both directions.
112
+ */
113
+ function sortKey(path) {
114
+ const type = { $type: '$$value' };
115
+ return {
116
+ $let: {
117
+ vars: { value: resolvePath(path) },
118
+ in: {
119
+ missing: isAbsent('$$value'),
120
+ rank: {
121
+ $switch: {
122
+ branches: SORT_TYPE_RANKS.map((types, i) => ({
123
+ case: { $in: [type, types] },
124
+ then: i + 1,
125
+ })),
126
+ default: 0,
127
+ },
128
+ },
129
+ value: {
130
+ $cond: [{ $in: [type, SCALAR_TYPES] }, '$$value', null],
131
+ },
132
+ },
133
+ },
134
+ };
135
+ }
136
+
137
+ function sortSpec(orderBy) {
138
+ if (!orderBy) return { _id: 1 };
139
+ const direction = MONGO_DIRECTIONS[orderBy.direction];
140
+ return {
141
+ [`${SORT_KEY}.missing`]: 1,
142
+ [`${SORT_KEY}.rank`]: direction,
143
+ [`${SORT_KEY}.value`]: direction,
144
+ _id: direction,
145
+ };
146
+ }
147
+
148
+ function omitProjection(omit) {
149
+ return Object.fromEntries(omit.map((key) => [`mapping.${key}`, 0]));
150
+ }
151
+
152
+ module.exports = { buildMappingQueryStages };
@@ -0,0 +1,193 @@
1
+ const SEGMENT_REGEX = /^[A-Za-z_][A-Za-z0-9_]*$/;
2
+ const MAX_TAKE = 500;
3
+ const MAX_IN_VALUES = 500;
4
+ const MAX_CONDITIONS = 20;
5
+ const DIRECTIONS = ['asc', 'desc'];
6
+
7
+ const OPERATORS = {
8
+ exists: { fields: ['mapping'] },
9
+ notExists: { fields: ['mapping'] },
10
+ in: { fields: ['mapping'], value: toStringList },
11
+ notStartsWith: { fields: ['sourceId'], value: toPrefix },
12
+ };
13
+
14
+ /**
15
+ * Checks a queryMappings query and normalizes it for an adapter.
16
+ *
17
+ * @param {Object} query - See IntegrationMappingRepositoryInterface.queryMappings
18
+ * @returns {{where: Array<Object>, orderBy: ({path: string[], direction: 'asc'|'desc'}|null), skip: number, take: number, omit: string[]}}
19
+ * @throws {Error} When the query does not fit that shape
20
+ */
21
+ function validateMappingQuery(query) {
22
+ if (!isPlainObject(query)) {
23
+ throw new Error('queryMappings: query must be an object');
24
+ }
25
+ const { where = [], orderBy, skip = 0, take, omit = [] } = query;
26
+ if (!Array.isArray(where)) {
27
+ throw new Error('queryMappings: where must be an array');
28
+ }
29
+ if (!Number.isInteger(take) || take < 1 || take > MAX_TAKE) {
30
+ throw new Error(
31
+ `queryMappings: take must be an integer between 1 and ${MAX_TAKE}`
32
+ );
33
+ }
34
+ if (!Number.isSafeInteger(skip) || skip < 0) {
35
+ throw new Error('queryMappings: skip must be a non-negative integer');
36
+ }
37
+ if (
38
+ !Array.isArray(omit) ||
39
+ !omit.every((key) => typeof key === 'string' && SEGMENT_REGEX.test(key))
40
+ ) {
41
+ throw new Error(
42
+ `queryMappings: omit must be an array of top-level mapping keys matching ${SEGMENT_REGEX}`
43
+ );
44
+ }
45
+
46
+ const whereEntries = where.map(toWhereEntry);
47
+ const conditionCount = whereEntries.reduce(
48
+ (count, entry) => count + (entry.anyOf ? entry.anyOf.length : 1),
49
+ 0
50
+ );
51
+ if (conditionCount > MAX_CONDITIONS) {
52
+ throw new Error(
53
+ `queryMappings: where must have at most ${MAX_CONDITIONS} conditions, anyOf members included`
54
+ );
55
+ }
56
+
57
+ return {
58
+ where: whereEntries,
59
+ orderBy: orderBy === undefined ? null : toOrderBy(orderBy),
60
+ skip,
61
+ take,
62
+ omit,
63
+ };
64
+ }
65
+
66
+ function toOrderBy(orderBy) {
67
+ if (!isPlainObject(orderBy)) {
68
+ throw new Error('queryMappings: orderBy must be an object');
69
+ }
70
+ const { field, segments } = parsePath(orderBy.path);
71
+ if (field !== 'mapping') {
72
+ throw new Error(
73
+ "queryMappings: orderBy.path must be a mapping path ('mapping.<segment>...')"
74
+ );
75
+ }
76
+ if (!DIRECTIONS.includes(orderBy.direction)) {
77
+ throw new Error(
78
+ "queryMappings: orderBy.direction must be 'asc' or 'desc'"
79
+ );
80
+ }
81
+ return { path: segments, direction: orderBy.direction };
82
+ }
83
+
84
+ function toWhereEntry(entry) {
85
+ assertWhereEntryShape(entry);
86
+ if (!('anyOf' in entry)) return toCondition(entry);
87
+
88
+ const { anyOf } = entry;
89
+ if (!Array.isArray(anyOf) || anyOf.length === 0) {
90
+ throw new Error('queryMappings: anyOf must be a non-empty array');
91
+ }
92
+ return {
93
+ anyOf: anyOf.map((condition) => {
94
+ assertWhereEntryShape(condition);
95
+ if ('anyOf' in condition) {
96
+ throw new Error('queryMappings: nested anyOf is not supported');
97
+ }
98
+ return toCondition(condition);
99
+ }),
100
+ };
101
+ }
102
+
103
+ function assertWhereEntryShape(entry) {
104
+ if (!isPlainObject(entry)) {
105
+ throw new Error('queryMappings: each where entry must be an object');
106
+ }
107
+ }
108
+
109
+ function isPlainObject(value) {
110
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
111
+ }
112
+
113
+ /**
114
+ * `{ path: 'mapping.outbound.status', op: 'in', value: ['failed'] }` →
115
+ * `{ field: 'mapping', path: ['outbound', 'status'], op: 'in', value: ['failed'] }`.
116
+ * A `sourceId` condition has no `path`; an op without a value has no `value`.
117
+ */
118
+ function toCondition({ path, op, value }) {
119
+ const { field, segments } = parsePath(path);
120
+ const operator = Object.hasOwn(OPERATORS, op) ? OPERATORS[op] : null;
121
+ if (!operator?.fields.includes(field)) {
122
+ throw new Error(
123
+ `queryMappings: op ${JSON.stringify(
124
+ op
125
+ )} is not allowed on '${path}' (allowed: ${operatorsOn(field).join(
126
+ ', '
127
+ )})`
128
+ );
129
+ }
130
+ return {
131
+ field,
132
+ ...(segments.length > 0 && { path: segments }),
133
+ op,
134
+ ...(operator.value && { value: operator.value(value, path) }),
135
+ };
136
+ }
137
+
138
+ function operatorsOn(field) {
139
+ return Object.keys(OPERATORS).filter((op) =>
140
+ OPERATORS[op].fields.includes(field)
141
+ );
142
+ }
143
+
144
+ function toStringList(value, path) {
145
+ if (
146
+ !Array.isArray(value) ||
147
+ value.length === 0 ||
148
+ !value.every((v) => typeof v === 'string')
149
+ ) {
150
+ throw new Error(
151
+ `queryMappings: 'in' value must be a non-empty array of strings on '${path}'`
152
+ );
153
+ }
154
+ if (value.length > MAX_IN_VALUES) {
155
+ throw new Error(
156
+ `queryMappings: 'in' value must have at most ${MAX_IN_VALUES} strings on '${path}'`
157
+ );
158
+ }
159
+ return value;
160
+ }
161
+
162
+ function toPrefix(value, path) {
163
+ if (typeof value !== 'string' || value.length === 0) {
164
+ throw new Error(
165
+ `queryMappings: 'notStartsWith' value must be a non-empty string on '${path}'`
166
+ );
167
+ }
168
+ return value;
169
+ }
170
+
171
+ /**
172
+ * `'mapping.outbound.status'` → `{ field: 'mapping', segments: ['outbound', 'status'] }`,
173
+ * `'sourceId'` → `{ field: 'sourceId', segments: [] }`.
174
+ */
175
+ function parsePath(path) {
176
+ const [field, ...segments] =
177
+ typeof path === 'string' ? path.split('.') : [];
178
+ const valid =
179
+ (field === 'sourceId' && segments.length === 0) ||
180
+ (field === 'mapping' &&
181
+ segments.length > 0 &&
182
+ segments.every((segment) => SEGMENT_REGEX.test(segment)));
183
+ if (!valid) {
184
+ throw new Error(
185
+ `queryMappings: invalid path ${JSON.stringify(
186
+ path
187
+ )} (must be 'sourceId' or 'mapping.<segment>...' with segments matching ${SEGMENT_REGEX})`
188
+ );
189
+ }
190
+ return { field, segments };
191
+ }
192
+
193
+ module.exports = { validateMappingQuery };