@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
package/logs/sinks.js ADDED
@@ -0,0 +1,93 @@
1
+ const fs = require('node:fs');
2
+ const { deepFreeze } = require('./record');
3
+
4
+ const DEFAULT_MAX_RETRIES = 10;
5
+ const MAX_SLEEP_MS = 20;
6
+
7
+ function sleepSync(ms) {
8
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
9
+ }
10
+
11
+ function defaultWriteStderr(line) {
12
+ fs.writeSync(2, line);
13
+ }
14
+
15
+ function safeCode(code) {
16
+ return String(code ?? 'UNKNOWN').replace(/[^A-Za-z0-9_]/g, '').slice(0, 32) || 'UNKNOWN';
17
+ }
18
+
19
+ function createStdoutSink({
20
+ fd = 1,
21
+ writeSync = fs.writeSync,
22
+ writeStderr = defaultWriteStderr,
23
+ sleep = sleepSync,
24
+ maxRetries = DEFAULT_MAX_RETRIES,
25
+ } = {}) {
26
+ const reportFailure = (code) => {
27
+ try {
28
+ writeStderr(`frigg.logger.write_failed code=${safeCode(code)}\n`);
29
+ } catch {
30
+ // Nothing is left to report to.
31
+ }
32
+ };
33
+
34
+ return {
35
+ name: 'stdout',
36
+ write(record) {
37
+ let buffer;
38
+ try {
39
+ buffer = Buffer.from(`${JSON.stringify(record)}\n`);
40
+ } catch {
41
+ reportFailure('SERIALIZE');
42
+ return;
43
+ }
44
+ let offset = 0;
45
+ let retries = 0;
46
+ // EAGAIN and a zero-byte write share one bounded retry budget.
47
+ const retry = () => {
48
+ if (retries >= maxRetries) {
49
+ reportFailure('EAGAIN');
50
+ return false;
51
+ }
52
+ retries += 1;
53
+ sleep(Math.min(retries, MAX_SLEEP_MS));
54
+ return true;
55
+ };
56
+ while (offset < buffer.length) {
57
+ let written;
58
+ try {
59
+ written = writeSync(fd, buffer, offset, buffer.length - offset);
60
+ } catch (error) {
61
+ if (error?.code !== 'EAGAIN') {
62
+ reportFailure(error?.code);
63
+ return;
64
+ }
65
+ if (!retry()) return;
66
+ continue;
67
+ }
68
+ if (written > 0) offset += written;
69
+ else if (!retry()) return;
70
+ }
71
+ },
72
+ };
73
+ }
74
+
75
+ function createMemorySink({ install = true } = {}) {
76
+ const records = [];
77
+ const sink = {
78
+ name: 'memory',
79
+ records,
80
+ write(record) {
81
+ records.push(deepFreeze(JSON.parse(JSON.stringify(record))));
82
+ },
83
+ clear() {
84
+ records.length = 0;
85
+ },
86
+ };
87
+ if (install) {
88
+ require('./logger-runtime').setSinks([sink]);
89
+ }
90
+ return sink;
91
+ }
92
+
93
+ module.exports = { createStdoutSink, createMemorySink };
@@ -0,0 +1,163 @@
1
+ const { redactUrl } = require('./redact');
2
+
3
+ // Best-effort extraction of the logical event/processId/integrationId from a
4
+ // JSON message body: `data.*` first, then the top level. Used only for log
5
+ // correlation. Never throws.
6
+ function summarizeMessageBody(bodyStr) {
7
+ try {
8
+ const parsed = JSON.parse(bodyStr);
9
+ return {
10
+ event: parsed?.event,
11
+ processId: parsed?.data?.processId ?? parsed?.processId,
12
+ integrationId: parsed?.data?.integrationId ?? parsed?.integrationId,
13
+ };
14
+ } catch {
15
+ return {};
16
+ }
17
+ }
18
+
19
+ function objectKeys(value) {
20
+ return value && typeof value === 'object' && !Array.isArray(value)
21
+ ? Object.keys(value)
22
+ : [];
23
+ }
24
+
25
+ function rawQueryKeys(rawQueryString) {
26
+ if (typeof rawQueryString !== 'string' || !rawQueryString) return [];
27
+ try {
28
+ return [...new URLSearchParams(rawQueryString).keys()];
29
+ } catch {
30
+ return [];
31
+ }
32
+ }
33
+
34
+ function unique(list) {
35
+ return [...new Set(list)];
36
+ }
37
+
38
+ // The route template keeps ids out of the field: REST v1 `resource`, or the
39
+ // path part of an HTTP API v2 `routeKey` such as `GET /api/{id}`.
40
+ function routeTemplate(event, path) {
41
+ if (typeof event.resource === 'string' && event.resource) {
42
+ return event.resource;
43
+ }
44
+ if (typeof event.routeKey === 'string') {
45
+ const space = event.routeKey.indexOf(' ');
46
+ if (space > 0) return event.routeKey.slice(space + 1);
47
+ }
48
+ return path;
49
+ }
50
+
51
+ function summarizeHttp(event) {
52
+ const path = event.path || event.rawPath;
53
+ const summary = {
54
+ source: 'http',
55
+ method: event.httpMethod || event.requestContext?.http?.method,
56
+ path,
57
+ route: routeTemplate(event, path),
58
+ queryKeys: unique([
59
+ ...objectKeys(event.queryStringParameters),
60
+ ...objectKeys(event.multiValueQueryStringParameters),
61
+ ...rawQueryKeys(event.rawQueryString),
62
+ ]),
63
+ headerNames: unique(
64
+ [...objectKeys(event.headers), ...objectKeys(event.multiValueHeaders)].map(
65
+ (name) => name.toLowerCase()
66
+ )
67
+ ),
68
+ };
69
+ if (typeof event.routeKey === 'string' && event.routeKey) {
70
+ summary.routeKey = event.routeKey;
71
+ }
72
+ return summary;
73
+ }
74
+
75
+ // Best-effort extraction of correlation identifiers from a Lambda event.
76
+ // For SQS: messageIds plus the parsed event/processId/integrationId of each
77
+ // record body. For HTTP: method, route, query keys and header names. Never
78
+ // throws and never returns a body, a query value or a header value.
79
+ function summarizeLambdaEvent(event) {
80
+ try {
81
+ if (!event || typeof event !== 'object') return {};
82
+ if (Array.isArray(event.Records)) {
83
+ return {
84
+ source: 'sqs',
85
+ records: event.Records.map((r) => ({
86
+ messageId: r?.messageId,
87
+ receiveCount: r?.attributes?.ApproximateReceiveCount,
88
+ ...summarizeMessageBody(r?.body),
89
+ })),
90
+ };
91
+ }
92
+ if (event.httpMethod || event.requestContext?.http) {
93
+ return summarizeHttp(event);
94
+ }
95
+ return { source: 'other' };
96
+ } catch {
97
+ return { source: 'other' };
98
+ }
99
+ }
100
+
101
+ // The bounded form that goes into the logger scope: no per-record array.
102
+ function toScopeInvocation(summary) {
103
+ if (!summary || typeof summary !== 'object' || !summary.source) {
104
+ return { source: 'other' };
105
+ }
106
+ if (summary.source === 'sqs') {
107
+ return {
108
+ source: 'sqs',
109
+ recordCount: Array.isArray(summary.records) ? summary.records.length : 0,
110
+ };
111
+ }
112
+ if (summary.source === 'http') {
113
+ const invocation = {
114
+ source: 'http',
115
+ method: summary.method,
116
+ route: summary.route,
117
+ };
118
+ if (summary.routeKey) invocation.routeKey = summary.routeKey;
119
+ return invocation;
120
+ }
121
+ return { source: summary.source };
122
+ }
123
+
124
+ // Per-request detail for the entry and failure records, never for the
125
+ // scope. A raw path can hold a token, so it goes through redactUrl.
126
+ function toRequestDetails(summary) {
127
+ if (!summary || summary.source !== 'http') return {};
128
+ return {
129
+ path: redactUrl(summary.path ?? ''),
130
+ queryKeys: summary.queryKeys ?? [],
131
+ headerNames: summary.headerNames ?? [],
132
+ };
133
+ }
134
+
135
+ // The full redacted request summary (ADR-048 §6: it goes under `invocation`).
136
+ function toRequestInvocation(summary) {
137
+ return { ...toScopeInvocation(summary), ...toRequestDetails(summary) };
138
+ }
139
+
140
+ // The same shape from an express request, for the express error boundary.
141
+ function summarizeExpressRequest(req) {
142
+ try {
143
+ if (!req || typeof req !== 'object') return { source: 'http' };
144
+ return {
145
+ source: 'http',
146
+ method: req.method,
147
+ path: redactUrl(req.path ?? ''),
148
+ queryKeys: objectKeys(req.query),
149
+ headerNames: unique(objectKeys(req.headers).map((name) => name.toLowerCase())),
150
+ };
151
+ } catch {
152
+ return { source: 'http' };
153
+ }
154
+ }
155
+
156
+ module.exports = {
157
+ summarizeLambdaEvent,
158
+ summarizeMessageBody,
159
+ toScopeInvocation,
160
+ toRequestDetails,
161
+ toRequestInvocation,
162
+ summarizeExpressRequest,
163
+ };
@@ -1,25 +1,15 @@
1
- const { Credential } = require('./credential');
2
- const { EntityManager } = require('./entity-manager');
3
- const { Entity } = require('./entity');
4
- const { ModuleManager } = require('./manager');
5
1
  const { ApiKeyRequester } = require('./requester/api-key');
6
2
  const { BasicAuthRequester } = require('./requester/basic');
7
3
  const { OAuth2Requester } = require('./requester/oauth-2');
8
4
  const { Requester } = require('./requester/requester');
9
5
  const { ModuleConstants } = require('./ModuleConstants');
10
6
  const { ModuleFactory } = require('./module-factory');
11
- const { Auther } = require('./auther');
12
7
 
13
8
  module.exports = {
14
- Credential,
15
- EntityManager,
16
- Entity,
17
- ModuleManager,
18
9
  ApiKeyRequester,
19
10
  BasicAuthRequester,
20
11
  OAuth2Requester,
21
12
  Requester,
22
13
  ModuleConstants,
23
14
  ModuleFactory,
24
- Auther
25
15
  };
@@ -0,0 +1,56 @@
1
+ // todo: remove this file
2
+
3
+ const { Module } = require('./module');
4
+
5
+ /**
6
+ * Acts as a factory for fully-hydrated domain Module instances.
7
+ * Provides methods to retrieve and construct Module objects with their associated
8
+ * entity and definition.
9
+ */
10
+ class ModuleFactory {
11
+ /**
12
+ * @param {Object} params - Configuration parameters.
13
+ * @param {import('./repositories/module-repository-interface').ModuleRepositoryInterface} params.moduleRepository - Repository for module data operations.
14
+ * @param {Array<Object>} params.moduleDefinitions - Array of module definitions.
15
+ */
16
+ constructor({ moduleRepository, moduleDefinitions }) {
17
+ this.moduleRepository = moduleRepository;
18
+ this.moduleDefinitions = moduleDefinitions;
19
+ }
20
+
21
+ async getModuleInstance(entityId, userId) {
22
+ const entity = await this.moduleRepository.findEntityById(
23
+ entityId,
24
+ userId
25
+ );
26
+
27
+ if (!entity) {
28
+ throw new Error(`Entity ${entityId} not found`);
29
+ }
30
+
31
+ if (entity.userId !== userId) {
32
+ throw new Error(
33
+ `Entity ${entityId} does not belong to user ${userId}`
34
+ );
35
+ }
36
+
37
+ const moduleName = entity.moduleName;
38
+ const moduleDefinition = this.moduleDefinitions.find((def) => {
39
+ return moduleName === def.moduleName;
40
+ });
41
+
42
+ if (!moduleDefinition) {
43
+ throw new Error(
44
+ `Module definition not found for module: ${moduleName}`
45
+ );
46
+ }
47
+
48
+ return new Module({
49
+ userId,
50
+ entity,
51
+ definition: moduleDefinition,
52
+ });
53
+ }
54
+ }
55
+
56
+ module.exports = { ModuleFactory };
@@ -0,0 +1,320 @@
1
+ const { Delegate } = require('../core');
2
+ const _ = require('lodash');
3
+ const { getLogger } = require('../logs');
4
+ const { ModuleConstants } = require('./ModuleConstants');
5
+ const {
6
+ createCredentialRepository,
7
+ } = require('../credential/repositories/credential-repository-factory');
8
+ const {
9
+ createModuleRepository,
10
+ } = require('./repositories/module-repository-factory');
11
+
12
+ // todo: this class should be a Domain class, and the Delegate function is preventing us from
13
+ // doing that, we probably have to get rid of the Delegate class as well as the event based
14
+ // calls since they go against the Domain Driven Design principles (eg. a domain class should not call repository methods or use cases)
15
+ class Module extends Delegate {
16
+ //todo: entity should be replaced with actual entity properties
17
+ /**
18
+ *
19
+ * @param {Object} params
20
+ * @param {Object} params.definition The definition of the Api Module
21
+ * @param {string} params.userId The user id
22
+ * @param {Object} params.entity The entity record from the database
23
+ * @param {string} [params.state] Optional OAuth state value forwarded to the API client (round-trips through the OAuth provider).
24
+ */
25
+ constructor({ definition, userId = null, entity: entityObj = null, state = null }) {
26
+ super({ definition, userId, entity: entityObj });
27
+
28
+ this.validateDefinition(definition);
29
+
30
+ this.userId = userId;
31
+ this.entity = entityObj;
32
+ this.credential = entityObj?.credential;
33
+ this.definition = definition;
34
+ this.name = this.definition.moduleName;
35
+ this.logger = getLogger(`module.${this.name ?? 'unknown'}`).child(() => ({
36
+ entityId: this.entity?.id,
37
+ credentialId:
38
+ this.credential?.id ??
39
+ (typeof this.credential === 'string'
40
+ ? this.credential
41
+ : undefined),
42
+ }));
43
+ this.modelName = this.definition.modelName;
44
+ this.apiClass = this.definition.API;
45
+
46
+ this.credentialRepository = createCredentialRepository();
47
+ this.moduleRepository = createModuleRepository();
48
+
49
+ // Module → parent delegate (typically IntegrationBase) events
50
+ this.DLGT_CREDENTIAL_INVALIDATED = 'CREDENTIAL_INVALIDATED';
51
+ this.delegateTypes.push(this.DLGT_CREDENTIAL_INVALIDATED);
52
+ this.DLGT_CREDENTIAL_VALIDATED = 'CREDENTIAL_VALIDATED';
53
+ this.delegateTypes.push(this.DLGT_CREDENTIAL_VALIDATED);
54
+
55
+ Object.assign(this, this.definition.requiredAuthMethods);
56
+
57
+ const apiParams = {
58
+ ...this.definition.env,
59
+ delegate: this,
60
+ logger: this.logger,
61
+ ...(state ? { state } : {}),
62
+ ...(this.credential?.data
63
+ ? this.apiParamsFromCredential(this.credential.data)
64
+ : {}), // Handle case when credential is undefined
65
+ ...this.apiParamsFromEntity(this.entity),
66
+ };
67
+ this.api = new this.apiClass(apiParams);
68
+ }
69
+
70
+ getName() {
71
+ return this.name;
72
+ }
73
+
74
+ getEntityOptions() {
75
+ return this.definition.getEntityOptions();
76
+ }
77
+
78
+ async refreshEntityOptions(options) {
79
+ await this.definition.refreshEntityOptions(options);
80
+ return this.getEntityOptions();
81
+ }
82
+
83
+ apiParamsFromCredential(credential) {
84
+ return _.pick(credential, ...this.apiPropertiesToPersist?.credential);
85
+ }
86
+
87
+ apiParamsFromEntity(entity) {
88
+ return _.pick(entity, ...this.apiPropertiesToPersist?.entity);
89
+ }
90
+
91
+ validateAuthorizationRequirements() {
92
+ const requirements = this.getAuthorizationRequirements();
93
+ let valid = true;
94
+ if (
95
+ ['oauth1', 'oauth2'].includes(requirements.type) &&
96
+ !requirements.url
97
+ ) {
98
+ valid = false;
99
+ }
100
+ return valid;
101
+ }
102
+
103
+ getAuthorizationRequirements(params) {
104
+ return this.api.getAuthorizationRequirements();
105
+ }
106
+
107
+ async testAuth() {
108
+ let validAuth = false;
109
+ try {
110
+ if (await this.testAuthRequest(this.api)) validAuth = true;
111
+ } catch (e) {
112
+ this.logger.warn('testAuth failed', {
113
+ eventName: `${this.logger.name}.test_auth_failed`,
114
+ error: e,
115
+ });
116
+ }
117
+ return validAuth;
118
+ }
119
+
120
+ async onTokenUpdate() {
121
+ const credentialDetails = await this.getCredentialDetails(
122
+ this.api,
123
+ this.userId
124
+ );
125
+ const apiParams = this.apiParamsFromCredential(this.api);
126
+
127
+ if (!apiParams.refresh_token && this.api.isRefreshable) {
128
+ this.logger.warn('No refresh_token in apiParams', {
129
+ eventName: `${this.logger.name}.refresh_token_missing`,
130
+ });
131
+ }
132
+
133
+ Object.assign(credentialDetails.details, apiParams);
134
+ credentialDetails.details.authIsValid = true;
135
+
136
+ const persisted = await this.credentialRepository.upsertCredential(
137
+ credentialDetails
138
+ );
139
+ this.credential = persisted;
140
+
141
+ if (this.credential?.id) {
142
+ try {
143
+ await this.notify(this.DLGT_CREDENTIAL_VALIDATED, {
144
+ credentialId: this.credential.id,
145
+ moduleName: this.name,
146
+ });
147
+ } catch (err) {
148
+ this.logger.error('Failed to propagate CREDENTIAL_VALIDATED', {
149
+ eventName: `${this.logger.name}.credential_validated_propagation_failed`,
150
+ error: err,
151
+ });
152
+ }
153
+ }
154
+ }
155
+
156
+ async receiveNotification(notifier, delegateString, object = null) {
157
+ if (delegateString === this.api.DLGT_TOKEN_UPDATE) {
158
+ await this.onTokenUpdate();
159
+ } else if (delegateString === this.api.DLGT_TOKEN_DEAUTHORIZED) {
160
+ await this.deauthorize();
161
+ } else if (delegateString === this.api.DLGT_INVALID_AUTH) {
162
+ await this.markCredentialsInvalid(object);
163
+ } else if (delegateString === this.api.DLGT_CREDENTIAL_RELOAD) {
164
+ return this.reloadCredential();
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Re-reads the credential row from the database. The requester can then
170
+ * adopt a concurrent invocation's refresh and does not race it.
171
+ * @returns {Promise<Object|null>} The persisted token fields, or null
172
+ * when no credential row is available. The requester treats null as
173
+ * "nothing to adopt" and continues with its own refresh.
174
+ */
175
+ async reloadCredential() {
176
+ if (!this.credential?.id) return null;
177
+ const freshFromDatabase =
178
+ await this.credentialRepository.findCredentialById(
179
+ this.credential.id
180
+ );
181
+ if (!freshFromDatabase) return null;
182
+ this.credential = freshFromDatabase;
183
+ return this.apiParamsFromCredential(freshFromDatabase);
184
+ }
185
+
186
+ async markCredentialsInvalid(diagnosticInfo = null) {
187
+ if (!this.credential) return;
188
+
189
+ if (!this.credential.id) return;
190
+
191
+ if (diagnosticInfo) {
192
+ this.logger.warn('Credentials rejected', {
193
+ eventName: `${this.logger.name}.credentials_rejected`,
194
+ statusCode: diagnosticInfo.statusCode,
195
+ error: diagnosticInfo,
196
+ });
197
+ }
198
+
199
+ await this.credentialRepository.updateAuthenticationStatus(
200
+ this.credential.id,
201
+ false
202
+ );
203
+
204
+ // Keep the in-memory snapshot consistent so that callers can read the
205
+ // updated state without another fetch.
206
+ this.credential.authIsValid = false;
207
+
208
+ // Propagate upward so a parent delegate (e.g. IntegrationBase) can
209
+ // react — for instance by flipping Integration.status to DISABLED.
210
+ // Delegate.notify is a silent no-op when this.delegate is null, so
211
+ // Module instances constructed outside of an Integration context
212
+ // (e.g. during ProcessAuthorizationCallback) remain unaffected.
213
+ //
214
+ // Best-effort: this method is invoked from the OAuth2Requester 401
215
+ // refresh catch block, which depends on us NOT throwing. A DB hiccup
216
+ // in the downstream status flip must not alter refreshAuth's
217
+ // documented `return false` contract. The credential has already
218
+ // been persisted as invalid; integrations left un-flipped can be
219
+ // recovered by the next retry or by operator intervention.
220
+ try {
221
+ await this.notify(this.DLGT_CREDENTIAL_INVALIDATED, {
222
+ credentialId: this.credential.id,
223
+ moduleName: this.name,
224
+ ...(diagnosticInfo && {
225
+ reason: diagnosticInfo.message,
226
+ statusCode: diagnosticInfo.statusCode,
227
+ }),
228
+ });
229
+ } catch (err) {
230
+ this.logger.error('Failed to propagate CREDENTIAL_INVALIDATED', {
231
+ eventName: `${this.logger.name}.credential_invalidated_propagation_failed`,
232
+ error: err,
233
+ });
234
+ }
235
+ }
236
+
237
+ async deauthorize() {
238
+ //todo: Check if this is correct, we're instantiating a new api without params (credentials, tokens, etc...)
239
+ this.api = new this.apiClass();
240
+ this.api.logger = this.logger;
241
+
242
+ // Remove persisted credential (if any)
243
+ if (this.entity?.credential) {
244
+ const credentialId =
245
+ this.entity.credential.id || this.entity.credential;
246
+
247
+ // Delete credential via repository
248
+ await this.credentialRepository.deleteCredentialById(credentialId);
249
+ this.credential = undefined;
250
+
251
+ // Unset credential reference on the Entity document
252
+ const entityId = this.entity.id;
253
+ if (entityId) {
254
+ await this.moduleRepository.unsetCredential(entityId);
255
+ }
256
+
257
+ // Keep in-memory snapshot consistent
258
+ this.entity.credential = undefined;
259
+ }
260
+ }
261
+
262
+ // todo: check if all these props are still up to date
263
+ validateDefinition(definition) {
264
+ if (!definition) {
265
+ throw new Error('Module definition is required');
266
+ }
267
+ if (!definition.moduleName) {
268
+ throw new Error('Module definition requires moduleName');
269
+ }
270
+ if (!definition.API) {
271
+ throw new Error('Module definition requires API class');
272
+ }
273
+ if (!definition.requiredAuthMethods) {
274
+ throw new Error('Module definition requires requiredAuthMethods');
275
+ } else {
276
+ if (
277
+ definition.API.requesterType ===
278
+ ModuleConstants.authType.oauth2 &&
279
+ !definition.requiredAuthMethods.getToken
280
+ ) {
281
+ throw new Error(
282
+ 'Module definition requires requiredAuthMethods.getToken'
283
+ );
284
+ }
285
+ if (!definition.requiredAuthMethods.getEntityDetails) {
286
+ throw new Error(
287
+ 'Module definition requires requiredAuthMethods.getEntityDetails'
288
+ );
289
+ }
290
+ if (!definition.requiredAuthMethods.getCredentialDetails) {
291
+ throw new Error(
292
+ 'Module definition requires requiredAuthMethods.getCredentialDetails'
293
+ );
294
+ }
295
+ if (!definition.requiredAuthMethods.apiPropertiesToPersist) {
296
+ throw new Error(
297
+ 'Module definition requires requiredAuthMethods.apiPropertiesToPersist'
298
+ );
299
+ } else if (definition.Credential) {
300
+ for (const prop of definition.requiredAuthMethods
301
+ .apiPropertiesToPersist?.credential) {
302
+ if (
303
+ !definition.Credential.schema.paths.hasOwnProperty(prop)
304
+ ) {
305
+ throw new Error(
306
+ `Module definition requires Credential schema to have property ${prop}`
307
+ );
308
+ }
309
+ }
310
+ }
311
+ if (!definition.requiredAuthMethods.testAuthRequest) {
312
+ throw new Error(
313
+ 'Module definition requires requiredAuthMethods.testAuth'
314
+ );
315
+ }
316
+ }
317
+ }
318
+ }
319
+
320
+ module.exports = { Module };