@friggframework/core 2.0.0-next.1 → 2.0.0-next.100

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 (342) hide show
  1. package/CLAUDE.md +702 -0
  2. package/README.md +959 -50
  3. package/admin-scripts/index.js +52 -0
  4. package/admin-scripts/repositories/admin-script-execution-repository-documentdb.js +21 -0
  5. package/admin-scripts/repositories/admin-script-execution-repository-factory.js +51 -0
  6. package/admin-scripts/repositories/admin-script-execution-repository-interface.js +166 -0
  7. package/admin-scripts/repositories/admin-script-execution-repository-mongo.js +228 -0
  8. package/admin-scripts/repositories/admin-script-execution-repository-postgres.js +268 -0
  9. package/admin-scripts/repositories/script-schedule-repository-documentdb.js +21 -0
  10. package/admin-scripts/repositories/script-schedule-repository-factory.js +51 -0
  11. package/admin-scripts/repositories/script-schedule-repository-interface.js +108 -0
  12. package/admin-scripts/repositories/script-schedule-repository-mongo.js +179 -0
  13. package/admin-scripts/repositories/script-schedule-repository-postgres.js +210 -0
  14. package/application/commands/README.md +451 -0
  15. package/application/commands/admin-script-commands.js +358 -0
  16. package/application/commands/credential-commands.js +245 -0
  17. package/application/commands/entity-commands.js +336 -0
  18. package/application/commands/integration-commands.js +343 -0
  19. package/application/commands/process-commands.js +135 -0
  20. package/application/commands/scheduler-commands.js +263 -0
  21. package/application/commands/user-commands.js +312 -0
  22. package/application/index.js +82 -0
  23. package/assertions/index.js +0 -3
  24. package/core/CLAUDE.md +690 -0
  25. package/core/Worker.js +60 -24
  26. package/core/create-handler.js +84 -6
  27. package/credential/repositories/credential-repository-documentdb.js +304 -0
  28. package/credential/repositories/credential-repository-factory.js +54 -0
  29. package/credential/repositories/credential-repository-interface.js +98 -0
  30. package/credential/repositories/credential-repository-mongo.js +269 -0
  31. package/credential/repositories/credential-repository-postgres.js +287 -0
  32. package/credential/repositories/credential-repository.js +300 -0
  33. package/credential/use-cases/get-credential-for-user.js +25 -0
  34. package/credential/use-cases/update-authentication-status.js +15 -0
  35. package/database/MONGODB_TRANSACTION_FIX.md +198 -0
  36. package/database/adapters/lambda-invoker.js +97 -0
  37. package/database/config.js +154 -0
  38. package/database/documentdb-encryption-service.js +330 -0
  39. package/database/documentdb-utils.js +136 -0
  40. package/database/encryption/README.md +839 -0
  41. package/database/encryption/documentdb-encryption-service.md +3575 -0
  42. package/database/encryption/encryption-schema-registry.js +401 -0
  43. package/database/encryption/field-encryption-service.js +254 -0
  44. package/database/encryption/logger.js +79 -0
  45. package/database/encryption/prisma-encryption-extension.js +230 -0
  46. package/database/index.js +21 -21
  47. package/database/prisma.js +182 -0
  48. package/database/repositories/health-check-repository-documentdb.js +138 -0
  49. package/database/repositories/health-check-repository-factory.js +48 -0
  50. package/database/repositories/health-check-repository-interface.js +82 -0
  51. package/database/repositories/health-check-repository-mongodb.js +89 -0
  52. package/database/repositories/health-check-repository-postgres.js +82 -0
  53. package/database/repositories/migration-status-repository-s3.js +137 -0
  54. package/database/use-cases/check-database-health-use-case.js +29 -0
  55. package/database/use-cases/check-database-state-use-case.js +81 -0
  56. package/database/use-cases/check-encryption-health-use-case.js +83 -0
  57. package/database/use-cases/get-database-state-via-worker-use-case.js +61 -0
  58. package/database/use-cases/get-migration-status-use-case.js +93 -0
  59. package/database/use-cases/run-database-migration-use-case.js +139 -0
  60. package/database/use-cases/test-encryption-use-case.js +253 -0
  61. package/database/use-cases/trigger-database-migration-use-case.js +157 -0
  62. package/database/utils/mongodb-collection-utils.js +94 -0
  63. package/database/utils/mongodb-schema-init.js +108 -0
  64. package/database/utils/prisma-runner.js +477 -0
  65. package/database/utils/prisma-schema-parser.js +182 -0
  66. package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +517 -0
  67. package/encrypt/Cryptor.js +34 -168
  68. package/encrypt/index.js +1 -2
  69. package/errors/client-safe-error.js +26 -0
  70. package/errors/fetch-error.js +15 -7
  71. package/errors/index.js +2 -0
  72. package/generated/prisma-mongodb/client.d.ts +1 -0
  73. package/generated/prisma-mongodb/client.js +5 -0
  74. package/generated/prisma-mongodb/default.d.ts +1 -0
  75. package/generated/prisma-mongodb/default.js +5 -0
  76. package/generated/prisma-mongodb/edge.d.ts +1 -0
  77. package/generated/prisma-mongodb/edge.js +374 -0
  78. package/generated/prisma-mongodb/index-browser.js +356 -0
  79. package/generated/prisma-mongodb/index.d.ts +25667 -0
  80. package/generated/prisma-mongodb/index.js +399 -0
  81. package/generated/prisma-mongodb/libquery_engine-debian-openssl-3.0.x.so.node +0 -0
  82. package/generated/prisma-mongodb/libquery_engine-rhel-openssl-3.0.x.so.node +0 -0
  83. package/generated/prisma-mongodb/package.json +183 -0
  84. package/generated/prisma-mongodb/runtime/edge-esm.js +35 -0
  85. package/generated/prisma-mongodb/runtime/edge.js +35 -0
  86. package/generated/prisma-mongodb/runtime/index-browser.d.ts +370 -0
  87. package/generated/prisma-mongodb/runtime/index-browser.js +17 -0
  88. package/generated/prisma-mongodb/runtime/library.d.ts +3982 -0
  89. package/generated/prisma-mongodb/runtime/library.js +147 -0
  90. package/generated/prisma-mongodb/runtime/react-native.js +84 -0
  91. package/generated/prisma-mongodb/runtime/wasm-compiler-edge.js +85 -0
  92. package/generated/prisma-mongodb/runtime/wasm-engine-edge.js +38 -0
  93. package/generated/prisma-mongodb/schema.prisma +432 -0
  94. package/generated/prisma-mongodb/wasm-edge-light-loader.mjs +5 -0
  95. package/generated/prisma-mongodb/wasm-worker-loader.mjs +5 -0
  96. package/generated/prisma-mongodb/wasm.d.ts +1 -0
  97. package/generated/prisma-mongodb/wasm.js +381 -0
  98. package/generated/prisma-postgresql/client.d.ts +1 -0
  99. package/generated/prisma-postgresql/client.js +5 -0
  100. package/generated/prisma-postgresql/default.d.ts +1 -0
  101. package/generated/prisma-postgresql/default.js +5 -0
  102. package/generated/prisma-postgresql/edge.d.ts +1 -0
  103. package/generated/prisma-postgresql/edge.js +395 -0
  104. package/generated/prisma-postgresql/index-browser.js +377 -0
  105. package/generated/prisma-postgresql/index.d.ts +28455 -0
  106. package/generated/prisma-postgresql/index.js +420 -0
  107. package/generated/prisma-postgresql/libquery_engine-debian-openssl-3.0.x.so.node +0 -0
  108. package/generated/prisma-postgresql/libquery_engine-rhel-openssl-3.0.x.so.node +0 -0
  109. package/generated/prisma-postgresql/package.json +183 -0
  110. package/generated/prisma-postgresql/query_engine_bg.js +2 -0
  111. package/generated/prisma-postgresql/query_engine_bg.wasm +0 -0
  112. package/generated/prisma-postgresql/runtime/edge-esm.js +35 -0
  113. package/generated/prisma-postgresql/runtime/edge.js +35 -0
  114. package/generated/prisma-postgresql/runtime/index-browser.d.ts +370 -0
  115. package/generated/prisma-postgresql/runtime/index-browser.js +17 -0
  116. package/generated/prisma-postgresql/runtime/library.d.ts +3982 -0
  117. package/generated/prisma-postgresql/runtime/library.js +147 -0
  118. package/generated/prisma-postgresql/runtime/react-native.js +84 -0
  119. package/generated/prisma-postgresql/runtime/wasm-compiler-edge.js +85 -0
  120. package/generated/prisma-postgresql/runtime/wasm-engine-edge.js +38 -0
  121. package/generated/prisma-postgresql/schema.prisma +414 -0
  122. package/generated/prisma-postgresql/wasm-edge-light-loader.mjs +5 -0
  123. package/generated/prisma-postgresql/wasm-worker-loader.mjs +5 -0
  124. package/generated/prisma-postgresql/wasm.d.ts +1 -0
  125. package/generated/prisma-postgresql/wasm.js +402 -0
  126. package/handlers/WEBHOOKS.md +653 -0
  127. package/handlers/app-definition-loader.js +43 -0
  128. package/handlers/app-handler-helpers.js +57 -0
  129. package/handlers/backend-utils.js +316 -0
  130. package/handlers/database-migration-handler.js +227 -0
  131. package/handlers/integration-event-dispatcher.js +54 -0
  132. package/handlers/middleware/admin-auth.js +73 -0
  133. package/handlers/routers/HEALTHCHECK.md +342 -0
  134. package/handlers/routers/auth.js +15 -0
  135. package/handlers/routers/db-migration.handler.js +29 -0
  136. package/handlers/routers/db-migration.js +311 -0
  137. package/handlers/routers/health.js +518 -0
  138. package/handlers/routers/integration-defined-routers.js +117 -0
  139. package/handlers/routers/integration-webhook-routers.js +67 -0
  140. package/handlers/routers/reporting.js +9 -0
  141. package/handlers/routers/user.js +63 -0
  142. package/handlers/routers/websocket.js +57 -0
  143. package/handlers/use-cases/check-external-apis-health-use-case.js +81 -0
  144. package/handlers/use-cases/check-integrations-health-use-case.js +44 -0
  145. package/handlers/workers/db-migration.js +352 -0
  146. package/handlers/workers/dlq-processor.js +63 -0
  147. package/handlers/workers/integration-defined-workers.js +30 -0
  148. package/index.js +111 -50
  149. package/infrastructure/scheduler/eventbridge-scheduler-adapter.js +184 -0
  150. package/infrastructure/scheduler/index.js +33 -0
  151. package/infrastructure/scheduler/mock-scheduler-adapter.js +143 -0
  152. package/infrastructure/scheduler/scheduler-service-factory.js +73 -0
  153. package/infrastructure/scheduler/scheduler-service-interface.js +47 -0
  154. package/integrations/EXTENSIONS.md +240 -0
  155. package/integrations/WEBHOOK-QUICKSTART.md +151 -0
  156. package/integrations/extension.js +254 -0
  157. package/integrations/index.js +20 -10
  158. package/integrations/integration-base.js +619 -72
  159. package/integrations/integration-router.js +460 -218
  160. package/integrations/options.js +3 -4
  161. package/integrations/repositories/config-patch-shared.js +43 -0
  162. package/integrations/repositories/integration-mapping-repository-documentdb.js +280 -0
  163. package/integrations/repositories/integration-mapping-repository-factory.js +57 -0
  164. package/integrations/repositories/integration-mapping-repository-interface.js +106 -0
  165. package/integrations/repositories/integration-mapping-repository-mongo.js +161 -0
  166. package/integrations/repositories/integration-mapping-repository-postgres.js +227 -0
  167. package/integrations/repositories/integration-mapping-repository.js +156 -0
  168. package/integrations/repositories/integration-repository-documentdb.js +284 -0
  169. package/integrations/repositories/integration-repository-factory.js +51 -0
  170. package/integrations/repositories/integration-repository-interface.js +173 -0
  171. package/integrations/repositories/integration-repository-mongo.js +414 -0
  172. package/integrations/repositories/integration-repository-postgres.js +452 -0
  173. package/integrations/repositories/process-repository-documentdb.js +311 -0
  174. package/integrations/repositories/process-repository-factory.js +53 -0
  175. package/integrations/repositories/process-repository-interface.js +136 -0
  176. package/integrations/repositories/process-repository-mongo.js +262 -0
  177. package/integrations/repositories/process-repository-postgres.js +380 -0
  178. package/integrations/repositories/process-update-ops-shared.js +112 -0
  179. package/integrations/tests/doubles/config-capturing-integration.js +81 -0
  180. package/integrations/tests/doubles/dummy-integration-class.js +113 -0
  181. package/integrations/tests/doubles/test-integration-repository.js +146 -0
  182. package/integrations/use-cases/create-integration.js +215 -0
  183. package/integrations/use-cases/create-process.js +130 -0
  184. package/integrations/use-cases/delete-integration-for-user.js +119 -0
  185. package/integrations/use-cases/find-integration-by-entity-external-id.js +74 -0
  186. package/integrations/use-cases/find-integration-context-by-external-entity-id.js +76 -0
  187. package/integrations/use-cases/get-integration-for-user.js +78 -0
  188. package/integrations/use-cases/get-integration-instance-by-definition.js +67 -0
  189. package/integrations/use-cases/get-integration-instance.js +83 -0
  190. package/integrations/use-cases/get-integrations-for-user.js +88 -0
  191. package/integrations/use-cases/get-possible-integrations.js +27 -0
  192. package/integrations/use-cases/get-process.js +89 -0
  193. package/integrations/use-cases/index.js +19 -0
  194. package/integrations/use-cases/list-integrations-by-entity-external-id.js +46 -0
  195. package/integrations/use-cases/load-integration-context.js +71 -0
  196. package/integrations/use-cases/patch-integration-config.js +39 -0
  197. package/integrations/use-cases/process-errors.js +28 -0
  198. package/integrations/use-cases/update-integration-config.js +32 -0
  199. package/integrations/use-cases/update-integration-messages.js +44 -0
  200. package/integrations/use-cases/update-integration-status.js +32 -0
  201. package/integrations/use-cases/update-integration.js +92 -0
  202. package/integrations/use-cases/update-process-metrics.js +216 -0
  203. package/integrations/use-cases/update-process-state.js +163 -0
  204. package/integrations/utils/map-integration-dto.js +37 -0
  205. package/jest-global-setup-noop.js +3 -0
  206. package/jest-global-teardown-noop.js +3 -0
  207. package/logs/logger.js +0 -4
  208. package/{module-plugin → modules}/index.js +0 -10
  209. package/modules/module-factory.js +56 -0
  210. package/modules/module.js +274 -0
  211. package/modules/repositories/module-repository-documentdb.js +350 -0
  212. package/modules/repositories/module-repository-factory.js +40 -0
  213. package/modules/repositories/module-repository-interface.js +145 -0
  214. package/modules/repositories/module-repository-mongo.js +436 -0
  215. package/modules/repositories/module-repository-postgres.js +481 -0
  216. package/modules/repositories/module-repository.js +369 -0
  217. package/modules/requester/api-key.js +52 -0
  218. package/modules/requester/oauth-2.js +396 -0
  219. package/modules/requester/requester.js +285 -0
  220. package/{module-plugin → modules}/test/mock-api/api.js +8 -3
  221. package/{module-plugin → modules}/test/mock-api/definition.js +14 -10
  222. package/modules/tests/doubles/test-module-factory.js +16 -0
  223. package/modules/tests/doubles/test-module-repository.js +39 -0
  224. package/modules/use-cases/get-entities-for-user.js +32 -0
  225. package/modules/use-cases/get-entity-options-by-id.js +71 -0
  226. package/modules/use-cases/get-entity-options-by-type.js +34 -0
  227. package/modules/use-cases/get-module-instance-from-type.js +34 -0
  228. package/modules/use-cases/get-module.js +74 -0
  229. package/modules/use-cases/process-authorization-callback.js +243 -0
  230. package/modules/use-cases/refresh-entity-options.js +72 -0
  231. package/modules/use-cases/test-module-auth.js +72 -0
  232. package/modules/utils/map-module-dto.js +18 -0
  233. package/package.json +82 -50
  234. package/prisma-mongodb/schema.prisma +432 -0
  235. package/prisma-postgresql/migrations/20250930193005_init/migration.sql +315 -0
  236. package/prisma-postgresql/migrations/20251006135218_init/migration.sql +9 -0
  237. package/prisma-postgresql/migrations/20251010000000_remove_unused_entity_reference_map/migration.sql +3 -0
  238. package/prisma-postgresql/migrations/20251112195422_update_user_unique_constraints/migration.sql +25 -0
  239. package/prisma-postgresql/migrations/20260422120000_add_entity_data_column/migration.sql +10 -0
  240. package/prisma-postgresql/migrations/20260422120001_create_process_table/migration.sql +48 -0
  241. package/prisma-postgresql/migrations/20260625000000_add_user_organization_id_index/migration.sql +2 -0
  242. package/prisma-postgresql/migrations/20260703000000_add_integration_status_in_creation_in_deletion/migration.sql +11 -0
  243. package/prisma-postgresql/migrations/20260703000001_integration_status_default_in_creation/migration.sql +8 -0
  244. package/prisma-postgresql/migrations/20260706000000_add_admin_script_execution_and_schedule/migration.sql +61 -0
  245. package/prisma-postgresql/migrations/migration_lock.toml +3 -0
  246. package/prisma-postgresql/schema.prisma +414 -0
  247. package/queues/queuer-util.js +103 -21
  248. package/reporting/README.md +86 -0
  249. package/reporting/index.js +17 -0
  250. package/reporting/reporting-router.js +77 -0
  251. package/reporting/repositories/reporting-repository-documentdb.js +127 -0
  252. package/reporting/repositories/reporting-repository-factory.js +35 -0
  253. package/reporting/repositories/reporting-repository-interface.js +16 -0
  254. package/reporting/repositories/reporting-repository-mongo.js +54 -0
  255. package/reporting/repositories/reporting-repository-postgres.js +70 -0
  256. package/reporting/use-cases/index.js +6 -0
  257. package/reporting/use-cases/list-integrations-report.js +142 -0
  258. package/syncs/manager.js +468 -443
  259. package/syncs/repositories/sync-repository-documentdb.js +240 -0
  260. package/syncs/repositories/sync-repository-factory.js +43 -0
  261. package/syncs/repositories/sync-repository-interface.js +109 -0
  262. package/syncs/repositories/sync-repository-mongo.js +239 -0
  263. package/syncs/repositories/sync-repository-postgres.js +319 -0
  264. package/syncs/sync.js +0 -1
  265. package/token/repositories/token-repository-documentdb.js +137 -0
  266. package/token/repositories/token-repository-factory.js +40 -0
  267. package/token/repositories/token-repository-interface.js +131 -0
  268. package/token/repositories/token-repository-mongo.js +219 -0
  269. package/token/repositories/token-repository-postgres.js +264 -0
  270. package/token/repositories/token-repository.js +219 -0
  271. package/types/associations/index.d.ts +0 -17
  272. package/types/core/index.d.ts +12 -4
  273. package/types/database/index.d.ts +10 -2
  274. package/types/encrypt/index.d.ts +5 -3
  275. package/types/integrations/index.d.ts +3 -8
  276. package/types/module-plugin/index.d.ts +17 -69
  277. package/types/syncs/index.d.ts +0 -17
  278. package/user/repositories/user-repository-documentdb.js +458 -0
  279. package/user/repositories/user-repository-factory.js +52 -0
  280. package/user/repositories/user-repository-interface.js +214 -0
  281. package/user/repositories/user-repository-mongo.js +323 -0
  282. package/user/repositories/user-repository-postgres.js +377 -0
  283. package/user/tests/doubles/test-user-repository.js +72 -0
  284. package/user/use-cases/authenticate-user.js +127 -0
  285. package/user/use-cases/authenticate-with-shared-secret.js +48 -0
  286. package/user/use-cases/create-individual-user.js +61 -0
  287. package/user/use-cases/create-organization-user.js +47 -0
  288. package/user/use-cases/create-token-for-user-id.js +30 -0
  289. package/user/use-cases/get-user-from-adopter-jwt.js +149 -0
  290. package/user/use-cases/get-user-from-bearer-token.js +77 -0
  291. package/user/use-cases/get-user-from-x-frigg-headers.js +132 -0
  292. package/user/use-cases/login-user.js +122 -0
  293. package/user/user.js +125 -0
  294. package/utils/backend-path.js +38 -0
  295. package/utils/index.js +6 -0
  296. package/websocket/repositories/websocket-connection-repository-documentdb.js +119 -0
  297. package/websocket/repositories/websocket-connection-repository-factory.js +44 -0
  298. package/websocket/repositories/websocket-connection-repository-interface.js +106 -0
  299. package/websocket/repositories/websocket-connection-repository-mongo.js +156 -0
  300. package/websocket/repositories/websocket-connection-repository-postgres.js +196 -0
  301. package/websocket/repositories/websocket-connection-repository.js +161 -0
  302. package/assertions/is-equal.js +0 -17
  303. package/associations/model.js +0 -54
  304. package/database/models/IndividualUser.js +0 -76
  305. package/database/models/OrganizationUser.js +0 -29
  306. package/database/models/State.js +0 -9
  307. package/database/models/Token.js +0 -70
  308. package/database/models/UserModel.js +0 -7
  309. package/database/models/WebsocketConnection.js +0 -49
  310. package/database/mongo.js +0 -45
  311. package/database/mongoose.js +0 -5
  312. package/encrypt/Cryptor.test.js +0 -32
  313. package/encrypt/encrypt.js +0 -132
  314. package/encrypt/encrypt.test.js +0 -1069
  315. package/encrypt/test-encrypt.js +0 -107
  316. package/errors/base-error.test.js +0 -32
  317. package/errors/fetch-error.test.js +0 -79
  318. package/errors/halt-error.test.js +0 -11
  319. package/errors/validation-errors.test.js +0 -120
  320. package/integrations/create-frigg-backend.js +0 -31
  321. package/integrations/integration-factory.js +0 -251
  322. package/integrations/integration-mapping.js +0 -43
  323. package/integrations/integration-model.js +0 -46
  324. package/integrations/integration-user.js +0 -144
  325. package/integrations/test/integration-base.test.js +0 -144
  326. package/lambda/TimeoutCatcher.test.js +0 -68
  327. package/logs/logger.test.js +0 -76
  328. package/module-plugin/auther.js +0 -350
  329. package/module-plugin/credential.js +0 -22
  330. package/module-plugin/entity-manager.js +0 -70
  331. package/module-plugin/entity.js +0 -46
  332. package/module-plugin/manager.js +0 -169
  333. package/module-plugin/module-factory.js +0 -61
  334. package/module-plugin/requester/api-key.js +0 -36
  335. package/module-plugin/requester/oauth-2.js +0 -219
  336. package/module-plugin/requester/requester.js +0 -165
  337. package/module-plugin/requester/requester.test.js +0 -28
  338. package/module-plugin/test/auther.test.js +0 -97
  339. package/syncs/model.js +0 -62
  340. /package/{module-plugin → modules}/ModuleConstants.js +0 -0
  341. /package/{module-plugin → modules}/requester/basic.js +0 -0
  342. /package/{module-plugin → modules}/test/mock-api/mocks/hubspot.js +0 -0
@@ -0,0 +1,30 @@
1
+ const { createHandler } = require('@friggframework/core');
2
+ const { loadAppDefinition } = require('../app-definition-loader');
3
+ const { createQueueWorker } = require('../backend-utils');
4
+ // TODO(Phase 2): mount extension-declared workers in addition to the per-integration
5
+ // default queue worker. Today, getExtensionWorkers(IntegrationClass) returns the
6
+ // declared workers but they are not yet bound to dedicated SQS sources. Extension-
7
+ // contributed *events* still flow through the default queue worker below because
8
+ // _mergeExtensions() registers them in instance.events, so end-to-end webhook
9
+ // delivery for Tier 3 extensions works without this Phase 2 work.
10
+ // const { getExtensionWorkers } = require('../../integrations/extension');
11
+
12
+ const handlers = {};
13
+ const { integrations: integrationClasses } = loadAppDefinition();
14
+
15
+ integrationClasses.forEach((IntegrationClass) => {
16
+ const defaultQueueWorker = createQueueWorker(IntegrationClass);
17
+
18
+ handlers[`${IntegrationClass.Definition.name}`] = {
19
+ queueWorker: createHandler({
20
+ eventName: `Queue Worker for ${IntegrationClass.Definition.name}`,
21
+ isUserFacingResponse: false,
22
+ method: async (event, context) => {
23
+ const worker = new defaultQueueWorker();
24
+ return await worker.run(event, context);
25
+ },
26
+ }),
27
+ };
28
+ });
29
+
30
+ module.exports = { handlers };
package/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  const {
2
- expectShallowEqualDbObject,
3
2
  get,
4
3
  getAll,
5
4
  verifyType,
@@ -7,118 +6,180 @@ const {
7
6
  getArrayParamAndVerifyParamType,
8
7
  getAndVerifyType,
9
8
  } = require('./assertions/index');
10
- const { Delegate, Worker, loadInstalledModules, createHandler } = require('./core/index');
11
- const {
12
- mongoose,
13
- connectToDatabase,
14
- disconnectFromDatabase,
15
- createObjectId,
16
- IndividualUser,
17
- OrganizationUser,
18
- State,
19
- Token,
20
- UserModel
9
+ const {
10
+ Delegate,
11
+ Worker,
12
+ loadInstalledModules,
13
+ createHandler,
14
+ } = require('./core/index');
15
+ const {
16
+ prisma,
17
+ connectPrisma,
18
+ disconnectPrisma,
19
+ TokenRepository,
20
+ WebsocketConnectionRepository,
21
21
  } = require('./database/index');
22
- const { Encrypt, Cryptor } = require('./encrypt/encrypt');
22
+ const {
23
+ createUserRepository,
24
+ UserRepositoryMongo,
25
+ UserRepositoryPostgres,
26
+ } = require('./user/repositories/user-repository-factory');
27
+ const {
28
+ GetUserFromXFriggHeaders,
29
+ } = require('./user/use-cases/get-user-from-x-frigg-headers');
30
+ const {
31
+ GetUserFromAdopterJwt,
32
+ } = require('./user/use-cases/get-user-from-adopter-jwt');
33
+ const {
34
+ AuthenticateUser,
35
+ } = require('./user/use-cases/authenticate-user');
36
+
37
+ const {
38
+ CredentialRepository,
39
+ } = require('./credential/repositories/credential-repository');
40
+ const {
41
+ ModuleRepository,
42
+ } = require('./modules/repositories/module-repository');
43
+ const {
44
+ IntegrationMappingRepository,
45
+ } = require('./integrations/repositories/integration-mapping-repository');
46
+ const {
47
+ CreateProcess,
48
+ } = require('./integrations/use-cases/create-process');
49
+ const {
50
+ UpdateProcessState,
51
+ } = require('./integrations/use-cases/update-process-state');
52
+ const {
53
+ UpdateProcessMetrics,
54
+ } = require('./integrations/use-cases/update-process-metrics');
55
+ const {
56
+ GetProcess,
57
+ } = require('./integrations/use-cases/get-process');
58
+ const { Cryptor } = require('./encrypt');
23
59
  const {
24
60
  BaseError,
25
61
  FetchError,
26
62
  HaltError,
27
63
  RequiredPropertyError,
28
64
  ParameterTypeError,
29
- } = require('./errors/index');
65
+ } = require('./errors/index');
30
66
  const {
31
67
  IntegrationBase,
32
- IntegrationModel,
33
68
  Options,
34
- IntegrationMapping,
35
- IntegrationFactory,
36
- IntegrationHelper,
37
69
  createIntegrationRouter,
38
70
  checkRequiredParams,
39
- createFriggBackend
71
+ getModulesDefinitionFromIntegrationClasses,
72
+ LoadIntegrationContextUseCase,
40
73
  } = require('./integrations/index');
41
- const { TimeoutCatcher } = require('./lambda/index');
42
74
  const {
43
- debug,
44
- initDebugLog,
45
- flushDebugLog
46
- } = require('./logs/index');
75
+ createReportingRouter,
76
+ createReportingRepository,
77
+ } = require('./reporting/index');
78
+ const { TimeoutCatcher } = require('./lambda/index');
79
+ const { debug, initDebugLog, flushDebugLog } = require('./logs/index');
47
80
  const {
48
81
  Credential,
49
- EntityManager,
50
82
  Entity,
51
- ModuleManager,
52
83
  ApiKeyRequester,
53
84
  BasicAuthRequester,
54
85
  OAuth2Requester,
55
86
  Requester,
56
87
  ModuleConstants,
57
88
  ModuleFactory,
58
- Auther
59
- } = require('./module-plugin/index');
89
+ } = require('./modules/index');
90
+ const application = require('./application');
91
+ const utils = require('./utils');
60
92
 
61
- // const {Sync } = require('./syncs/model');
93
+ const { QueuerUtil } = require('./queues');
62
94
 
63
95
  module.exports = {
64
96
  // assertions
65
- expectShallowEqualDbObject,
66
97
  get,
67
98
  getAll,
68
99
  verifyType,
69
100
  getParamAndVerifyParamType,
70
101
  getArrayParamAndVerifyParamType,
71
102
  getAndVerifyType,
103
+
72
104
  // core
73
105
  Delegate,
74
106
  Worker,
75
107
  loadInstalledModules,
76
108
  createHandler,
109
+
77
110
  // database
78
- mongoose,
79
- connectToDatabase,
80
- disconnectFromDatabase,
81
- createObjectId,
82
- IndividualUser,
83
- OrganizationUser,
84
- State,
85
- Token,
86
- UserModel,
87
- // encrypt
88
- Encrypt,
111
+ prisma,
112
+ connectPrisma,
113
+ disconnectPrisma,
114
+ TokenRepository,
115
+ WebsocketConnectionRepository,
116
+ createUserRepository,
117
+ UserRepositoryMongo,
118
+ UserRepositoryPostgres,
119
+ GetUserFromXFriggHeaders,
120
+ GetUserFromAdopterJwt,
121
+ AuthenticateUser,
122
+ CredentialRepository,
123
+ ModuleRepository,
124
+ IntegrationMappingRepository,
89
125
  Cryptor,
126
+
90
127
  // errors
91
128
  BaseError,
92
129
  FetchError,
93
130
  HaltError,
94
131
  RequiredPropertyError,
95
132
  ParameterTypeError,
133
+
96
134
  // integrations
97
135
  IntegrationBase,
98
- IntegrationModel,
99
136
  Options,
100
- IntegrationMapping,
101
- IntegrationFactory,
102
- IntegrationHelper,
103
137
  checkRequiredParams,
104
138
  createIntegrationRouter,
105
- createFriggBackend,
139
+ getModulesDefinitionFromIntegrationClasses,
140
+ LoadIntegrationContextUseCase,
141
+ CreateProcess,
142
+ UpdateProcessState,
143
+ UpdateProcessMetrics,
144
+ GetProcess,
145
+
146
+ // reporting
147
+ createReportingRouter,
148
+ createReportingRepository,
149
+
150
+ // application - Command factories for integration developers
151
+ application,
152
+ createFriggCommands: application.createFriggCommands,
153
+ createIntegrationCommands: application.createIntegrationCommands,
154
+ createUserCommands: application.createUserCommands,
155
+ createEntityCommands: application.createEntityCommands,
156
+ createCredentialCommands: application.createCredentialCommands,
157
+ createProcessCommands: application.createProcessCommands,
158
+ createSchedulerCommands: application.createSchedulerCommands,
159
+ findIntegrationContextByExternalEntityId:
160
+ application.findIntegrationContextByExternalEntityId,
161
+ integrationCommands: application.integrationCommands,
162
+
106
163
  // lambda
107
164
  TimeoutCatcher,
165
+
108
166
  // logs
109
167
  debug,
110
168
  initDebugLog,
111
169
  flushDebugLog,
170
+
112
171
  // module plugin
113
172
  Credential,
114
- EntityManager,
115
173
  Entity,
116
- ModuleManager,
117
174
  ApiKeyRequester,
118
175
  BasicAuthRequester,
119
176
  OAuth2Requester,
120
177
  Requester,
121
178
  ModuleConstants,
122
179
  ModuleFactory,
123
- Auther
124
- }
180
+ // queues
181
+ QueuerUtil,
182
+
183
+ // utils
184
+ ...utils,
185
+ };
@@ -0,0 +1,184 @@
1
+ /**
2
+ * EventBridge Scheduler Adapter
3
+ *
4
+ * Infrastructure Layer - Hexagonal Architecture
5
+ *
6
+ * Responsible for:
7
+ * - Creating one-time EventBridge Scheduler schedules
8
+ * - Deleting schedules when no longer needed
9
+ * - Checking schedule status
10
+ *
11
+ * This adapter implements SchedulerServiceInterface for AWS EventBridge Scheduler.
12
+ */
13
+
14
+ const {
15
+ SchedulerClient,
16
+ CreateScheduleCommand,
17
+ DeleteScheduleCommand,
18
+ GetScheduleCommand,
19
+ ResourceNotFoundException,
20
+ } = require('@aws-sdk/client-scheduler');
21
+
22
+ const { SchedulerServiceInterface } = require('./scheduler-service-interface');
23
+
24
+ class EventBridgeSchedulerAdapter extends SchedulerServiceInterface {
25
+ constructor({ region } = {}) {
26
+ super();
27
+ this.client = new SchedulerClient({
28
+ region: region || process.env.AWS_REGION || 'us-east-1',
29
+ });
30
+ this.scheduleGroupName =
31
+ process.env.SCHEDULE_GROUP_NAME || 'frigg-integration-schedules';
32
+ this.roleArn = process.env.SCHEDULER_ROLE_ARN;
33
+ }
34
+
35
+ /**
36
+ * Create a one-time schedule that sends a message to SQS
37
+ *
38
+ * @param {Object} params
39
+ * @param {string} params.scheduleName - Unique name for the schedule
40
+ * @param {Date} params.scheduleAt - When to trigger the schedule
41
+ * @param {string} params.queueResourceId - Queue resource identifier (ARN) to send message to
42
+ * @param {Object} params.payload - Message payload
43
+ * @returns {Promise<{scheduledJobId: string, scheduledAt: string}>}
44
+ */
45
+ async scheduleOneTime({ scheduleName, scheduleAt, queueResourceId, payload }) {
46
+ if (!scheduleName) {
47
+ throw new Error('scheduleName is required');
48
+ }
49
+ if (!scheduleAt || !(scheduleAt instanceof Date)) {
50
+ throw new Error('scheduleAt must be a valid Date object');
51
+ }
52
+ if (!queueResourceId) {
53
+ throw new Error('queueResourceId is required');
54
+ }
55
+ if (!this.roleArn) {
56
+ throw new Error(
57
+ 'SCHEDULER_ROLE_ARN environment variable is not set'
58
+ );
59
+ }
60
+
61
+ // Format date to AWS schedule expression (at(yyyy-mm-ddThh:mm:ss))
62
+ const scheduleExpression = `at(${scheduleAt.toISOString().replace(/\.\d{3}Z$/, '')})`;
63
+
64
+ const command = new CreateScheduleCommand({
65
+ Name: scheduleName,
66
+ GroupName: this.scheduleGroupName,
67
+ ScheduleExpression: scheduleExpression,
68
+ ScheduleExpressionTimezone: 'UTC',
69
+ FlexibleTimeWindow: {
70
+ Mode: 'OFF',
71
+ },
72
+ Target: {
73
+ Arn: queueResourceId,
74
+ RoleArn: this.roleArn,
75
+ Input: JSON.stringify(payload),
76
+ },
77
+ ActionAfterCompletion: 'DELETE', // Auto-cleanup after execution
78
+ });
79
+
80
+ try {
81
+ const response = await this.client.send(command);
82
+ console.log(
83
+ `[Scheduler] Created schedule ${scheduleName} for ${scheduleAt.toISOString()}`
84
+ );
85
+
86
+ return {
87
+ scheduledJobId: response.ScheduleArn,
88
+ scheduledAt: scheduleAt.toISOString(),
89
+ };
90
+ } catch (error) {
91
+ console.error(
92
+ `[Scheduler] Failed to create schedule ${scheduleName}:`,
93
+ error.message
94
+ );
95
+ throw error;
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Delete a schedule
101
+ *
102
+ * @param {string} scheduleName - Name of the schedule to delete
103
+ * @returns {Promise<void>}
104
+ */
105
+ async deleteSchedule(scheduleName) {
106
+ if (!scheduleName) {
107
+ throw new Error('scheduleName is required');
108
+ }
109
+
110
+ const command = new DeleteScheduleCommand({
111
+ Name: scheduleName,
112
+ GroupName: this.scheduleGroupName,
113
+ });
114
+
115
+ try {
116
+ await this.client.send(command);
117
+ console.log(`[Scheduler] Deleted schedule ${scheduleName}`);
118
+ } catch (error) {
119
+ if (error instanceof ResourceNotFoundException) {
120
+ console.log(
121
+ `[Scheduler] Schedule ${scheduleName} not found (already deleted or executed)`
122
+ );
123
+ return; // Graceful handling - schedule doesn't exist
124
+ }
125
+ console.error(
126
+ `[Scheduler] Failed to delete schedule ${scheduleName}:`,
127
+ error.message
128
+ );
129
+ throw error;
130
+ }
131
+ }
132
+
133
+ /**
134
+ * Get schedule status
135
+ *
136
+ * @param {string} scheduleName - Name of the schedule
137
+ * @returns {Promise<{exists: boolean, scheduledAt?: string, state?: string}>}
138
+ */
139
+ async getScheduleStatus(scheduleName) {
140
+ if (!scheduleName) {
141
+ throw new Error('scheduleName is required');
142
+ }
143
+
144
+ const command = new GetScheduleCommand({
145
+ Name: scheduleName,
146
+ GroupName: this.scheduleGroupName,
147
+ });
148
+
149
+ try {
150
+ const response = await this.client.send(command);
151
+
152
+ // Parse the schedule expression to get the scheduled time
153
+ // Format: at(yyyy-mm-ddThh:mm:ss)
154
+ let scheduledAt = null;
155
+ if (response.ScheduleExpression) {
156
+ const match = response.ScheduleExpression.match(
157
+ /^at\((.+)\)$/
158
+ );
159
+ if (match) {
160
+ scheduledAt = new Date(match[1] + 'Z').toISOString();
161
+ }
162
+ }
163
+
164
+ return {
165
+ exists: true,
166
+ scheduledAt,
167
+ state: response.State,
168
+ };
169
+ } catch (error) {
170
+ if (error instanceof ResourceNotFoundException) {
171
+ return {
172
+ exists: false,
173
+ };
174
+ }
175
+ console.error(
176
+ `[Scheduler] Failed to get schedule ${scheduleName}:`,
177
+ error.message
178
+ );
179
+ throw error;
180
+ }
181
+ }
182
+ }
183
+
184
+ module.exports = { EventBridgeSchedulerAdapter };
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Scheduler Infrastructure
3
+ *
4
+ * Provides scheduling capabilities for one-time jobs.
5
+ * Follows hexagonal architecture with interface + adapters pattern.
6
+ *
7
+ * Providers:
8
+ * - eventbridge: AWS EventBridge Scheduler (production)
9
+ * - mock: In-memory mock scheduler (local development)
10
+ */
11
+
12
+ const { SchedulerServiceInterface } = require('./scheduler-service-interface');
13
+ const { EventBridgeSchedulerAdapter } = require('./eventbridge-scheduler-adapter');
14
+ const { MockSchedulerAdapter } = require('./mock-scheduler-adapter');
15
+ const {
16
+ createSchedulerService,
17
+ SCHEDULER_PROVIDERS,
18
+ determineProvider,
19
+ } = require('./scheduler-service-factory');
20
+
21
+ module.exports = {
22
+ // Interface (Port)
23
+ SchedulerServiceInterface,
24
+
25
+ // Adapters
26
+ EventBridgeSchedulerAdapter,
27
+ MockSchedulerAdapter,
28
+
29
+ // Factory
30
+ createSchedulerService,
31
+ SCHEDULER_PROVIDERS,
32
+ determineProvider,
33
+ };
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Mock Scheduler Adapter for Local Development
3
+ *
4
+ * Stores schedules in memory and logs instead of creating real EventBridge schedules.
5
+ * Used when SCHEDULER_PROVIDER=mock or in local/dev/test environments.
6
+ *
7
+ * This adapter implements SchedulerServiceInterface for local development and testing.
8
+ */
9
+
10
+ const { SchedulerServiceInterface } = require('./scheduler-service-interface');
11
+
12
+ class MockSchedulerAdapter extends SchedulerServiceInterface {
13
+ constructor(options = {}) {
14
+ super();
15
+ this.verbose = options.verbose || false;
16
+ this.schedules = new Map();
17
+ }
18
+
19
+ /**
20
+ * Schedule a one-time job to be executed at a specific time
21
+ *
22
+ * @param {Object} params
23
+ * @param {string} params.scheduleName - Unique name for the schedule
24
+ * @param {Date} params.scheduleAt - When to trigger the schedule
25
+ * @param {string} params.queueResourceId - Queue resource identifier to send message to
26
+ * @param {Object} params.payload - JSON payload to send
27
+ * @returns {Promise<{scheduledJobId: string, scheduledAt: string}>}
28
+ */
29
+ async scheduleOneTime({ scheduleName, scheduleAt, queueResourceId, payload }) {
30
+ if (!scheduleName) {
31
+ throw new Error('scheduleName is required');
32
+ }
33
+ if (!scheduleAt || !(scheduleAt instanceof Date)) {
34
+ throw new Error('scheduleAt must be a valid Date object');
35
+ }
36
+ if (!queueResourceId) {
37
+ throw new Error('queueResourceId is required');
38
+ }
39
+
40
+ const scheduleData = {
41
+ scheduleName,
42
+ scheduledAt: scheduleAt.toISOString(),
43
+ queueResourceId,
44
+ payload,
45
+ createdAt: new Date().toISOString(),
46
+ state: 'ENABLED',
47
+ };
48
+
49
+ this.schedules.set(scheduleName, scheduleData);
50
+
51
+ console.log(`[MockScheduler] Created schedule: ${scheduleName}`);
52
+ console.log(`[MockScheduler] Scheduled for: ${scheduleAt.toISOString()}`);
53
+ console.log(`[MockScheduler] Target: ${queueResourceId}`);
54
+ if (this.verbose) {
55
+ console.log(`[MockScheduler] Payload:`, JSON.stringify(payload, null, 2));
56
+ }
57
+
58
+ return {
59
+ scheduledJobId: `mock-job-${scheduleName}`,
60
+ scheduledAt: scheduleAt.toISOString(),
61
+ };
62
+ }
63
+
64
+ /**
65
+ * Delete a scheduled job
66
+ *
67
+ * @param {string} scheduleName - Name of the schedule to delete
68
+ * @returns {Promise<void>}
69
+ */
70
+ async deleteSchedule(scheduleName) {
71
+ if (!scheduleName) {
72
+ throw new Error('scheduleName is required');
73
+ }
74
+
75
+ const existed = this.schedules.has(scheduleName);
76
+ this.schedules.delete(scheduleName);
77
+
78
+ console.log(`[MockScheduler] Deleted schedule: ${scheduleName} (existed: ${existed})`);
79
+ }
80
+
81
+ /**
82
+ * Get the status of a scheduled job
83
+ *
84
+ * @param {string} scheduleName - Name of the schedule
85
+ * @returns {Promise<{exists: boolean, scheduledAt?: string, state?: string}>}
86
+ */
87
+ async getScheduleStatus(scheduleName) {
88
+ if (!scheduleName) {
89
+ throw new Error('scheduleName is required');
90
+ }
91
+
92
+ const schedule = this.schedules.get(scheduleName);
93
+
94
+ if (!schedule) {
95
+ return { exists: false };
96
+ }
97
+
98
+ return {
99
+ exists: true,
100
+ scheduledAt: schedule.scheduledAt,
101
+ state: schedule.state,
102
+ };
103
+ }
104
+
105
+ /**
106
+ * Get all scheduled jobs (helper for testing)
107
+ *
108
+ * @returns {Object} Map of all schedules as plain object
109
+ */
110
+ _getSchedules() {
111
+ return Object.fromEntries(this.schedules);
112
+ }
113
+
114
+ /**
115
+ * Clear all schedules (helper for testing)
116
+ */
117
+ _clearSchedules() {
118
+ const count = this.schedules.size;
119
+ this.schedules.clear();
120
+ console.log(`[MockScheduler] Cleared ${count} schedules`);
121
+ }
122
+
123
+ /**
124
+ * Simulate triggering a schedule (helper for testing)
125
+ *
126
+ * @param {string} scheduleName - Name of the schedule to trigger
127
+ * @returns {Object|null} The payload that would be sent, or null if not found
128
+ */
129
+ _simulateTrigger(scheduleName) {
130
+ const schedule = this.schedules.get(scheduleName);
131
+ if (!schedule) {
132
+ console.log(`[MockScheduler] Cannot trigger - schedule not found: ${scheduleName}`);
133
+ return null;
134
+ }
135
+
136
+ console.log(`[MockScheduler] Simulating trigger for: ${scheduleName}`);
137
+ console.log(`[MockScheduler] Payload:`, JSON.stringify(schedule.payload, null, 2));
138
+
139
+ return schedule.payload;
140
+ }
141
+ }
142
+
143
+ module.exports = { MockSchedulerAdapter };
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Scheduler Service Factory
3
+ *
4
+ * Creates scheduler service instances based on configuration.
5
+ * Returns implementations of SchedulerServiceInterface.
6
+ *
7
+ * Environment Detection:
8
+ * - SCHEDULER_PROVIDER=eventbridge -> Use AWS EventBridge Scheduler
9
+ * - SCHEDULER_PROVIDER=mock -> Use in-memory mock scheduler
10
+ * - Default in dev/test/local stages -> Mock scheduler
11
+ * - Default in other stages -> EventBridge scheduler
12
+ */
13
+
14
+ const { EventBridgeSchedulerAdapter } = require('./eventbridge-scheduler-adapter');
15
+ const { MockSchedulerAdapter } = require('./mock-scheduler-adapter');
16
+
17
+ const SCHEDULER_PROVIDERS = {
18
+ EVENTBRIDGE: 'eventbridge',
19
+ MOCK: 'mock',
20
+ };
21
+
22
+ const LOCAL_STAGES = ['dev', 'test', 'local'];
23
+
24
+ /**
25
+ * Determine the scheduler provider based on environment
26
+ *
27
+ * @returns {string} Provider name
28
+ */
29
+ function determineProvider() {
30
+ const explicitProvider = process.env.SCHEDULER_PROVIDER;
31
+ if (explicitProvider) {
32
+ return explicitProvider;
33
+ }
34
+
35
+ const stage = process.env.STAGE || 'dev';
36
+ if (LOCAL_STAGES.includes(stage)) {
37
+ return SCHEDULER_PROVIDERS.MOCK;
38
+ }
39
+
40
+ return SCHEDULER_PROVIDERS.EVENTBRIDGE;
41
+ }
42
+
43
+ /**
44
+ * Create a scheduler service instance
45
+ *
46
+ * @param {Object} options
47
+ * @param {string} options.provider - Scheduler provider ('eventbridge' or 'mock')
48
+ * @param {string} options.region - AWS region (for EventBridge)
49
+ * @param {boolean} options.verbose - Verbose logging (for Mock)
50
+ * @returns {SchedulerServiceInterface} Implementation of scheduler interface
51
+ */
52
+ function createSchedulerService(options = {}) {
53
+ const provider = options.provider || determineProvider();
54
+
55
+ switch (provider) {
56
+ case SCHEDULER_PROVIDERS.EVENTBRIDGE:
57
+ return new EventBridgeSchedulerAdapter({
58
+ region: options.region,
59
+ });
60
+ case SCHEDULER_PROVIDERS.MOCK:
61
+ return new MockSchedulerAdapter({
62
+ verbose: options.verbose,
63
+ });
64
+ default:
65
+ throw new Error(`Unknown scheduler provider: ${provider}`);
66
+ }
67
+ }
68
+
69
+ module.exports = {
70
+ createSchedulerService,
71
+ SCHEDULER_PROVIDERS,
72
+ determineProvider,
73
+ };