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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (410) hide show
  1. package/.eslintrc.json +18 -1
  2. package/CLAUDE.md +830 -0
  3. package/README.md +996 -50
  4. package/admin-scripts/index.js +52 -0
  5. package/admin-scripts/repositories/admin-script-execution-repository-documentdb.js +21 -0
  6. package/admin-scripts/repositories/admin-script-execution-repository-factory.js +51 -0
  7. package/admin-scripts/repositories/admin-script-execution-repository-interface.js +171 -0
  8. package/admin-scripts/repositories/admin-script-execution-repository-mongo.js +238 -0
  9. package/admin-scripts/repositories/admin-script-execution-repository-postgres.js +278 -0
  10. package/admin-scripts/repositories/script-schedule-repository-documentdb.js +21 -0
  11. package/admin-scripts/repositories/script-schedule-repository-factory.js +51 -0
  12. package/admin-scripts/repositories/script-schedule-repository-interface.js +108 -0
  13. package/admin-scripts/repositories/script-schedule-repository-mongo.js +179 -0
  14. package/admin-scripts/repositories/script-schedule-repository-postgres.js +210 -0
  15. package/application/commands/README.md +451 -0
  16. package/application/commands/admin-script-commands.js +359 -0
  17. package/application/commands/credential-commands.js +262 -0
  18. package/application/commands/entity-commands.js +294 -0
  19. package/application/commands/integration-commands.js +419 -0
  20. package/application/commands/integration-mapping-commands.js +25 -0
  21. package/application/commands/process-commands.js +135 -0
  22. package/application/commands/report-commands.js +188 -0
  23. package/application/commands/scheduler-commands.js +263 -0
  24. package/application/commands/usage-commands.js +56 -0
  25. package/application/commands/user-commands.js +312 -0
  26. package/application/index.js +83 -0
  27. package/artifacts/repositories/artifact-repository-factory.js +19 -0
  28. package/artifacts/repositories/artifact-repository-interface.js +27 -0
  29. package/artifacts/repositories/artifact-repository-local.js +42 -0
  30. package/artifacts/repositories/artifact-repository-s3.js +61 -0
  31. package/assertions/index.js +0 -3
  32. package/core/CLAUDE.md +715 -0
  33. package/core/Worker.js +55 -24
  34. package/core/create-handler.js +121 -38
  35. package/core/index.js +8 -1
  36. package/core/invocation-scope.js +225 -0
  37. package/core/parameters-to-env.js +257 -0
  38. package/core/secrets-to-env.js +7 -6
  39. package/core/ssm-preload.mjs +34 -0
  40. package/credential/repositories/credential-active-type.js +32 -0
  41. package/credential/repositories/credential-repository-documentdb.js +355 -0
  42. package/credential/repositories/credential-repository-factory.js +54 -0
  43. package/credential/repositories/credential-repository-interface.js +113 -0
  44. package/credential/repositories/credential-repository-mongo.js +294 -0
  45. package/credential/repositories/credential-repository-postgres.js +312 -0
  46. package/credential/repositories/credential-repository.js +300 -0
  47. package/credential/use-cases/get-credential-for-user.js +25 -0
  48. package/credential/use-cases/update-authentication-status.js +15 -0
  49. package/database/MONGODB_TRANSACTION_FIX.md +198 -0
  50. package/database/adapters/lambda-invoker.js +97 -0
  51. package/database/config.js +147 -0
  52. package/database/documentdb-encryption-service.js +334 -0
  53. package/database/documentdb-utils.js +196 -0
  54. package/database/encryption/README.md +863 -0
  55. package/database/encryption/documentdb-encryption-service.md +3575 -0
  56. package/database/encryption/encryption-schema-registry.js +404 -0
  57. package/database/encryption/field-encryption-service.js +254 -0
  58. package/database/encryption/integration-mapping-encryption.js +97 -0
  59. package/database/encryption/logger.js +82 -0
  60. package/database/encryption/prisma-encryption-extension.js +241 -0
  61. package/database/index.js +21 -21
  62. package/database/prisma.js +182 -0
  63. package/database/repositories/health-check-repository-documentdb.js +138 -0
  64. package/database/repositories/health-check-repository-factory.js +48 -0
  65. package/database/repositories/health-check-repository-interface.js +82 -0
  66. package/database/repositories/health-check-repository-mongodb.js +89 -0
  67. package/database/repositories/health-check-repository-postgres.js +82 -0
  68. package/database/repositories/migration-status-repository-s3.js +137 -0
  69. package/database/use-cases/check-database-health-use-case.js +29 -0
  70. package/database/use-cases/check-database-state-use-case.js +81 -0
  71. package/database/use-cases/check-encryption-health-use-case.js +83 -0
  72. package/database/use-cases/get-database-state-via-worker-use-case.js +61 -0
  73. package/database/use-cases/get-migration-status-use-case.js +93 -0
  74. package/database/use-cases/resolve-migration-via-worker-use-case.js +49 -0
  75. package/database/use-cases/run-database-migration-use-case.js +139 -0
  76. package/database/use-cases/test-encryption-use-case.js +253 -0
  77. package/database/use-cases/trigger-database-migration-use-case.js +157 -0
  78. package/database/utils/mongodb-collection-utils.js +94 -0
  79. package/database/utils/mongodb-schema-init.js +108 -0
  80. package/database/utils/prisma-runner.js +491 -0
  81. package/database/utils/prisma-schema-parser.js +182 -0
  82. package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +517 -0
  83. package/encrypt/Cryptor.js +34 -168
  84. package/encrypt/index.js +1 -2
  85. package/errors/client-safe-error.js +26 -0
  86. package/errors/fetch-error.js +59 -57
  87. package/errors/index.js +6 -0
  88. package/errors/mapping-already-exists-error.js +14 -0
  89. package/generated/prisma-mongodb/client.d.ts +1 -0
  90. package/generated/prisma-mongodb/client.js +5 -0
  91. package/generated/prisma-mongodb/default.d.ts +1 -0
  92. package/generated/prisma-mongodb/default.js +5 -0
  93. package/generated/prisma-mongodb/edge.d.ts +1 -0
  94. package/generated/prisma-mongodb/edge.js +386 -0
  95. package/generated/prisma-mongodb/index-browser.js +368 -0
  96. package/generated/prisma-mongodb/index.d.ts +27065 -0
  97. package/generated/prisma-mongodb/index.js +411 -0
  98. package/generated/prisma-mongodb/libquery_engine-debian-openssl-3.0.x.so.node +0 -0
  99. package/generated/prisma-mongodb/libquery_engine-rhel-openssl-3.0.x.so.node +0 -0
  100. package/generated/prisma-mongodb/package.json +183 -0
  101. package/generated/prisma-mongodb/runtime/edge-esm.js +35 -0
  102. package/generated/prisma-mongodb/runtime/edge.js +35 -0
  103. package/generated/prisma-mongodb/runtime/index-browser.d.ts +370 -0
  104. package/generated/prisma-mongodb/runtime/index-browser.js +17 -0
  105. package/generated/prisma-mongodb/runtime/library.d.ts +3982 -0
  106. package/generated/prisma-mongodb/runtime/library.js +147 -0
  107. package/generated/prisma-mongodb/runtime/react-native.js +84 -0
  108. package/generated/prisma-mongodb/runtime/wasm-compiler-edge.js +85 -0
  109. package/generated/prisma-mongodb/runtime/wasm-engine-edge.js +38 -0
  110. package/generated/prisma-mongodb/schema.prisma +455 -0
  111. package/generated/prisma-mongodb/wasm-edge-light-loader.mjs +5 -0
  112. package/generated/prisma-mongodb/wasm-worker-loader.mjs +5 -0
  113. package/generated/prisma-mongodb/wasm.d.ts +1 -0
  114. package/generated/prisma-mongodb/wasm.js +393 -0
  115. package/generated/prisma-postgresql/client.d.ts +1 -0
  116. package/generated/prisma-postgresql/client.js +5 -0
  117. package/generated/prisma-postgresql/default.d.ts +1 -0
  118. package/generated/prisma-postgresql/default.js +5 -0
  119. package/generated/prisma-postgresql/edge.d.ts +1 -0
  120. package/generated/prisma-postgresql/edge.js +407 -0
  121. package/generated/prisma-postgresql/index-browser.js +389 -0
  122. package/generated/prisma-postgresql/index.d.ts +29904 -0
  123. package/generated/prisma-postgresql/index.js +432 -0
  124. package/generated/prisma-postgresql/libquery_engine-debian-openssl-3.0.x.so.node +0 -0
  125. package/generated/prisma-postgresql/libquery_engine-rhel-openssl-3.0.x.so.node +0 -0
  126. package/generated/prisma-postgresql/package.json +183 -0
  127. package/generated/prisma-postgresql/query_engine_bg.js +2 -0
  128. package/generated/prisma-postgresql/query_engine_bg.wasm +0 -0
  129. package/generated/prisma-postgresql/runtime/edge-esm.js +35 -0
  130. package/generated/prisma-postgresql/runtime/edge.js +35 -0
  131. package/generated/prisma-postgresql/runtime/index-browser.d.ts +370 -0
  132. package/generated/prisma-postgresql/runtime/index-browser.js +17 -0
  133. package/generated/prisma-postgresql/runtime/library.d.ts +3982 -0
  134. package/generated/prisma-postgresql/runtime/library.js +147 -0
  135. package/generated/prisma-postgresql/runtime/react-native.js +84 -0
  136. package/generated/prisma-postgresql/runtime/wasm-compiler-edge.js +85 -0
  137. package/generated/prisma-postgresql/runtime/wasm-engine-edge.js +38 -0
  138. package/generated/prisma-postgresql/schema.prisma +436 -0
  139. package/generated/prisma-postgresql/wasm-edge-light-loader.mjs +5 -0
  140. package/generated/prisma-postgresql/wasm-worker-loader.mjs +5 -0
  141. package/generated/prisma-postgresql/wasm.d.ts +1 -0
  142. package/generated/prisma-postgresql/wasm.js +414 -0
  143. package/handlers/WEBHOOKS.md +682 -0
  144. package/handlers/app-definition-loader.js +103 -0
  145. package/handlers/app-handler-helpers.js +20 -6
  146. package/handlers/backend-utils.js +272 -46
  147. package/handlers/database-migration-handler.js +236 -0
  148. package/handlers/integration-event-dispatcher.js +68 -0
  149. package/handlers/middleware/admin-auth.js +73 -0
  150. package/handlers/routers/HEALTHCHECK.md +342 -0
  151. package/handlers/routers/auth.js +4 -15
  152. package/handlers/routers/db-migration.handler.js +29 -0
  153. package/handlers/routers/db-migration.js +329 -0
  154. package/handlers/routers/health.js +518 -0
  155. package/handlers/routers/integration-defined-routers.js +85 -10
  156. package/handlers/routers/integration-webhook-routers.js +87 -0
  157. package/handlers/routers/user.js +27 -5
  158. package/handlers/routers/websocket.js +31 -9
  159. package/handlers/use-cases/check-external-apis-health-use-case.js +81 -0
  160. package/handlers/use-cases/check-integrations-health-use-case.js +44 -0
  161. package/handlers/workers/db-migration.js +438 -0
  162. package/handlers/workers/dlq-processor.js +89 -0
  163. package/handlers/workers/integration-defined-workers.js +13 -7
  164. package/index.js +123 -47
  165. package/infrastructure/scheduler/eventbridge-scheduler-adapter.js +238 -0
  166. package/infrastructure/scheduler/index.js +33 -0
  167. package/infrastructure/scheduler/mock-scheduler-adapter.js +143 -0
  168. package/infrastructure/scheduler/scheduler-service-factory.js +73 -0
  169. package/infrastructure/scheduler/scheduler-service-interface.js +47 -0
  170. package/integrations/EXTENSIONS.md +240 -0
  171. package/integrations/WEBHOOK-QUICKSTART.md +151 -0
  172. package/integrations/extension.js +254 -0
  173. package/integrations/index.js +20 -10
  174. package/integrations/integration-base.js +777 -74
  175. package/integrations/integration-router.js +399 -180
  176. package/integrations/options.js +1 -1
  177. package/integrations/repositories/config-patch-shared.js +43 -0
  178. package/integrations/repositories/integration-mapping-query-pipeline.js +152 -0
  179. package/integrations/repositories/integration-mapping-query.js +193 -0
  180. package/integrations/repositories/integration-mapping-repository-documentdb.js +406 -0
  181. package/integrations/repositories/integration-mapping-repository-factory.js +57 -0
  182. package/integrations/repositories/integration-mapping-repository-interface.js +183 -0
  183. package/integrations/repositories/integration-mapping-repository-mongo.js +284 -0
  184. package/integrations/repositories/integration-mapping-repository-postgres.js +403 -0
  185. package/integrations/repositories/integration-mapping-repository.js +185 -0
  186. package/integrations/repositories/integration-repository-documentdb.js +354 -0
  187. package/integrations/repositories/integration-repository-factory.js +51 -0
  188. package/integrations/repositories/integration-repository-interface.js +219 -0
  189. package/integrations/repositories/integration-repository-mongo.js +502 -0
  190. package/integrations/repositories/integration-repository-postgres.js +550 -0
  191. package/integrations/repositories/process-repository-documentdb.js +311 -0
  192. package/integrations/repositories/process-repository-factory.js +53 -0
  193. package/integrations/repositories/process-repository-interface.js +136 -0
  194. package/integrations/repositories/process-repository-mongo.js +262 -0
  195. package/integrations/repositories/process-repository-postgres.js +380 -0
  196. package/integrations/repositories/process-update-ops-shared.js +112 -0
  197. package/integrations/repositories/report-id.js +13 -0
  198. package/integrations/tests/doubles/config-capturing-integration.js +81 -0
  199. package/integrations/tests/doubles/dummy-integration-class.js +113 -0
  200. package/integrations/tests/doubles/test-integration-repository.js +146 -0
  201. package/integrations/use-cases/add-entities-to-integration.js +92 -0
  202. package/integrations/use-cases/create-integration.js +253 -0
  203. package/integrations/use-cases/create-process.js +130 -0
  204. package/integrations/use-cases/delete-integration-for-user.js +130 -0
  205. package/integrations/use-cases/find-integration-by-entity-external-id.js +74 -0
  206. package/integrations/use-cases/find-integration-context-by-external-entity-id.js +76 -0
  207. package/integrations/use-cases/get-integration-for-user.js +78 -0
  208. package/integrations/use-cases/get-integration-instance-by-definition.js +67 -0
  209. package/integrations/use-cases/get-integration-instance.js +83 -0
  210. package/integrations/use-cases/get-integrations-for-user.js +88 -0
  211. package/integrations/use-cases/get-possible-integrations.js +27 -0
  212. package/integrations/use-cases/get-process.js +89 -0
  213. package/integrations/use-cases/index.js +19 -0
  214. package/integrations/use-cases/list-integrations-by-entity-external-id.js +46 -0
  215. package/integrations/use-cases/load-integration-context.js +71 -0
  216. package/integrations/use-cases/patch-integration-config.js +39 -0
  217. package/integrations/use-cases/process-errors.js +28 -0
  218. package/integrations/use-cases/remove-entities-from-integration.js +70 -0
  219. package/integrations/use-cases/update-integration-config.js +32 -0
  220. package/integrations/use-cases/update-integration-messages.js +44 -0
  221. package/integrations/use-cases/update-integration-status.js +32 -0
  222. package/integrations/use-cases/update-integration.js +92 -0
  223. package/integrations/use-cases/update-process-metrics.js +222 -0
  224. package/integrations/use-cases/update-process-state.js +163 -0
  225. package/integrations/utils/assert-entity-ids-input.js +42 -0
  226. package/integrations/utils/map-integration-dto.js +37 -0
  227. package/jest-global-setup-noop.js +3 -0
  228. package/jest-global-teardown-noop.js +3 -0
  229. package/jest.config.js +2 -0
  230. package/logs/.eslintrc.json +26 -1
  231. package/logs/__fixtures__/events.js +82 -0
  232. package/logs/__fixtures__/matchers.js +45 -0
  233. package/logs/__fixtures__/secrets.js +59 -0
  234. package/logs/__fixtures__/vectors.js +329 -0
  235. package/logs/__fixtures__/with-env.js +45 -0
  236. package/logs/context.js +109 -0
  237. package/logs/contract-keys.js +67 -0
  238. package/logs/debug-shims.js +46 -0
  239. package/logs/denied-keys.js +21 -0
  240. package/logs/index.js +14 -3
  241. package/logs/jest-logger-setup.js +25 -0
  242. package/logs/levels.js +71 -0
  243. package/logs/logger-runtime.js +137 -0
  244. package/logs/logger.js +134 -46
  245. package/logs/record.js +276 -0
  246. package/logs/redact.js +328 -0
  247. package/logs/serialize.js +329 -0
  248. package/logs/sinks.js +93 -0
  249. package/logs/summarize-event.js +163 -0
  250. package/{module-plugin → modules}/index.js +0 -10
  251. package/modules/module-factory.js +56 -0
  252. package/modules/module.js +320 -0
  253. package/modules/repositories/module-repository-documentdb.js +350 -0
  254. package/modules/repositories/module-repository-factory.js +40 -0
  255. package/modules/repositories/module-repository-interface.js +145 -0
  256. package/modules/repositories/module-repository-mongo.js +436 -0
  257. package/modules/repositories/module-repository-postgres.js +481 -0
  258. package/modules/repositories/module-repository.js +369 -0
  259. package/modules/requester/api-key.js +52 -0
  260. package/modules/requester/oauth-2.js +561 -0
  261. package/modules/requester/requester.js +605 -0
  262. package/{module-plugin → modules}/test/mock-api/api.js +8 -3
  263. package/{module-plugin → modules}/test/mock-api/definition.js +14 -10
  264. package/modules/tests/doubles/test-module-factory.js +16 -0
  265. package/modules/tests/doubles/test-module-repository.js +39 -0
  266. package/modules/use-cases/get-entities-for-user.js +32 -0
  267. package/modules/use-cases/get-entity-options-by-id.js +71 -0
  268. package/modules/use-cases/get-entity-options-by-type.js +34 -0
  269. package/modules/use-cases/get-module-instance-from-type.js +34 -0
  270. package/modules/use-cases/get-module.js +74 -0
  271. package/modules/use-cases/process-authorization-callback.js +294 -0
  272. package/modules/use-cases/refresh-entity-options.js +72 -0
  273. package/modules/use-cases/test-module-auth.js +72 -0
  274. package/modules/utils/map-module-dto.js +20 -0
  275. package/modules/utils/to-credential-id.js +14 -0
  276. package/package.json +92 -52
  277. package/prisma-mongodb/schema.prisma +455 -0
  278. package/prisma-postgresql/migrations/20250930193005_init/migration.sql +315 -0
  279. package/prisma-postgresql/migrations/20251006135218_init/migration.sql +9 -0
  280. package/prisma-postgresql/migrations/20251010000000_remove_unused_entity_reference_map/migration.sql +3 -0
  281. package/prisma-postgresql/migrations/20251112195422_update_user_unique_constraints/migration.sql +25 -0
  282. package/prisma-postgresql/migrations/20260422120000_add_entity_data_column/migration.sql +10 -0
  283. package/prisma-postgresql/migrations/20260422120001_create_process_table/migration.sql +48 -0
  284. package/prisma-postgresql/migrations/20260625000000_add_user_organization_id_index/migration.sql +2 -0
  285. package/prisma-postgresql/migrations/20260703000000_add_integration_status_in_creation_in_deletion/migration.sql +11 -0
  286. package/prisma-postgresql/migrations/20260703000001_integration_status_default_in_creation/migration.sql +8 -0
  287. package/prisma-postgresql/migrations/20260705000000_create_usage_counter/migration.sql +26 -0
  288. package/prisma-postgresql/migrations/20260706000000_add_admin_script_execution_and_schedule/migration.sql +61 -0
  289. package/prisma-postgresql/migrations/migration_lock.toml +3 -0
  290. package/prisma-postgresql/schema.prisma +436 -0
  291. package/queues/queue-delivery.js +41 -0
  292. package/queues/queuer-util.js +89 -21
  293. package/reporting/README.md +154 -0
  294. package/reporting/builtin-reports.js +6 -0
  295. package/reporting/index.js +13 -0
  296. package/reporting/report-base.js +49 -0
  297. package/reporting/reports/integrations-report.js +221 -0
  298. package/syncs/manager.js +468 -443
  299. package/syncs/repositories/sync-repository-documentdb.js +240 -0
  300. package/syncs/repositories/sync-repository-factory.js +43 -0
  301. package/syncs/repositories/sync-repository-interface.js +109 -0
  302. package/syncs/repositories/sync-repository-mongo.js +239 -0
  303. package/syncs/repositories/sync-repository-postgres.js +319 -0
  304. package/syncs/sync.js +0 -1
  305. package/telemetry/README.md +331 -0
  306. package/telemetry/bind-telemetry-context.js +77 -0
  307. package/telemetry/canonical-counters.js +52 -0
  308. package/telemetry/exporters.js +85 -0
  309. package/telemetry/index.js +26 -0
  310. package/telemetry/instrument-handler.js +104 -0
  311. package/telemetry/no-op-telemetry.js +71 -0
  312. package/telemetry/north-star.js +103 -0
  313. package/telemetry/otel-telemetry.js +232 -0
  314. package/telemetry/plugin-subscribers.js +77 -0
  315. package/telemetry/telemetry-config.js +120 -0
  316. package/telemetry/telemetry-context.js +51 -0
  317. package/telemetry/telemetry-event-bus.js +58 -0
  318. package/telemetry/telemetry-runtime.js +164 -0
  319. package/telemetry/telemetry-service.js +52 -0
  320. package/telemetry/usage-rollup-subscriber.js +116 -0
  321. package/token/repositories/token-repository-documentdb.js +137 -0
  322. package/token/repositories/token-repository-factory.js +40 -0
  323. package/token/repositories/token-repository-interface.js +131 -0
  324. package/token/repositories/token-repository-mongo.js +219 -0
  325. package/token/repositories/token-repository-postgres.js +264 -0
  326. package/token/repositories/token-repository.js +219 -0
  327. package/types/associations/index.d.ts +0 -17
  328. package/types/core/index.d.ts +12 -4
  329. package/types/database/index.d.ts +10 -2
  330. package/types/encrypt/index.d.ts +5 -3
  331. package/types/errors/index.d.ts +24 -10
  332. package/types/integrations/index.d.ts +3 -8
  333. package/types/logs/index.d.ts +61 -2
  334. package/types/module-plugin/index.d.ts +20 -69
  335. package/types/syncs/index.d.ts +0 -17
  336. package/usage/README.md +54 -0
  337. package/usage/index.js +17 -0
  338. package/usage/repositories/usage-repository-documentdb.js +194 -0
  339. package/usage/repositories/usage-repository-factory.js +25 -0
  340. package/usage/repositories/usage-repository-interface.js +37 -0
  341. package/usage/repositories/usage-repository-prisma.js +146 -0
  342. package/usage/tracked-metrics.js +38 -0
  343. package/usage/usage-windows.js +24 -0
  344. package/user/repositories/user-repository-documentdb.js +426 -0
  345. package/user/repositories/user-repository-factory.js +52 -0
  346. package/user/repositories/user-repository-interface.js +214 -0
  347. package/user/repositories/user-repository-mongo.js +323 -0
  348. package/user/repositories/user-repository-postgres.js +377 -0
  349. package/user/tests/doubles/test-user-repository.js +72 -0
  350. package/user/use-cases/authenticate-user.js +143 -0
  351. package/user/use-cases/authenticate-with-shared-secret.js +48 -0
  352. package/user/use-cases/create-individual-user.js +61 -0
  353. package/user/use-cases/create-organization-user.js +47 -0
  354. package/user/use-cases/create-token-for-user-id.js +30 -0
  355. package/user/use-cases/get-user-from-adopter-jwt.js +149 -0
  356. package/user/use-cases/get-user-from-bearer-token.js +82 -0
  357. package/user/use-cases/get-user-from-x-frigg-headers.js +132 -0
  358. package/user/use-cases/login-user.js +122 -0
  359. package/user/user.js +125 -0
  360. package/utils/backend-path.js +38 -0
  361. package/utils/index.js +6 -0
  362. package/websocket/repositories/websocket-connection-repository-documentdb.js +119 -0
  363. package/websocket/repositories/websocket-connection-repository-factory.js +44 -0
  364. package/websocket/repositories/websocket-connection-repository-interface.js +106 -0
  365. package/websocket/repositories/websocket-connection-repository-mongo.js +156 -0
  366. package/websocket/repositories/websocket-connection-repository-postgres.js +196 -0
  367. package/websocket/repositories/websocket-connection-repository.js +161 -0
  368. package/assertions/is-equal.js +0 -17
  369. package/associations/model.js +0 -54
  370. package/database/models/IndividualUser.js +0 -76
  371. package/database/models/OrganizationUser.js +0 -29
  372. package/database/models/State.js +0 -9
  373. package/database/models/Token.js +0 -70
  374. package/database/models/UserModel.js +0 -7
  375. package/database/models/WebsocketConnection.js +0 -49
  376. package/database/mongo.js +0 -45
  377. package/database/mongoose.js +0 -5
  378. package/encrypt/Cryptor.test.js +0 -32
  379. package/encrypt/encrypt.js +0 -132
  380. package/encrypt/encrypt.test.js +0 -1069
  381. package/encrypt/test-encrypt.js +0 -107
  382. package/errors/base-error.test.js +0 -32
  383. package/errors/fetch-error.test.js +0 -79
  384. package/errors/halt-error.test.js +0 -11
  385. package/errors/validation-errors.test.js +0 -120
  386. package/handlers/routers/middleware/loadUser.js +0 -15
  387. package/handlers/routers/middleware/requireLoggedInUser.js +0 -12
  388. package/integrations/create-frigg-backend.js +0 -31
  389. package/integrations/integration-factory.js +0 -251
  390. package/integrations/integration-mapping.js +0 -43
  391. package/integrations/integration-model.js +0 -46
  392. package/integrations/integration-user.js +0 -144
  393. package/integrations/test/integration-base.test.js +0 -144
  394. package/lambda/TimeoutCatcher.test.js +0 -68
  395. package/logs/logger.test.js +0 -76
  396. package/module-plugin/auther.js +0 -393
  397. package/module-plugin/credential.js +0 -22
  398. package/module-plugin/entity-manager.js +0 -70
  399. package/module-plugin/entity.js +0 -46
  400. package/module-plugin/manager.js +0 -169
  401. package/module-plugin/module-factory.js +0 -61
  402. package/module-plugin/requester/api-key.js +0 -36
  403. package/module-plugin/requester/oauth-2.js +0 -219
  404. package/module-plugin/requester/requester.js +0 -165
  405. package/module-plugin/requester/requester.test.js +0 -28
  406. package/module-plugin/test/auther.test.js +0 -97
  407. package/syncs/model.js +0 -62
  408. /package/{module-plugin → modules}/ModuleConstants.js +0 -0
  409. /package/{module-plugin → modules}/requester/basic.js +0 -0
  410. /package/{module-plugin → modules}/test/mock-api/mocks/hubspot.js +0 -0
package/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  const {
2
- expectShallowEqualDbObject,
3
2
  get,
4
3
  getAll,
5
4
  verifyType,
@@ -12,61 +11,103 @@ const {
12
11
  Worker,
13
12
  loadInstalledModules,
14
13
  createHandler,
14
+ runInvocationScope,
15
15
  } = require('./core/index');
16
16
  const {
17
- mongoose,
18
- connectToDatabase,
19
- disconnectFromDatabase,
20
- createObjectId,
21
- IndividualUser,
22
- OrganizationUser,
23
- State,
24
- Token,
25
- UserModel,
26
- WebsocketConnection,
17
+ prisma,
18
+ connectPrisma,
19
+ disconnectPrisma,
20
+ TokenRepository,
21
+ WebsocketConnectionRepository,
27
22
  } = require('./database/index');
28
- const { Encrypt, Cryptor } = require('./encrypt/encrypt');
23
+ const {
24
+ createUserRepository,
25
+ UserRepositoryMongo,
26
+ UserRepositoryPostgres,
27
+ } = require('./user/repositories/user-repository-factory');
28
+ const {
29
+ GetUserFromXFriggHeaders,
30
+ } = require('./user/use-cases/get-user-from-x-frigg-headers');
31
+ const {
32
+ GetUserFromAdopterJwt,
33
+ } = require('./user/use-cases/get-user-from-adopter-jwt');
34
+ const { AuthenticateUser } = require('./user/use-cases/authenticate-user');
35
+
36
+ const {
37
+ CredentialRepository,
38
+ } = require('./credential/repositories/credential-repository');
39
+ const {
40
+ ModuleRepository,
41
+ } = require('./modules/repositories/module-repository');
42
+ const {
43
+ IntegrationMappingRepository,
44
+ } = require('./integrations/repositories/integration-mapping-repository');
45
+ const { CreateProcess } = require('./integrations/use-cases/create-process');
46
+ const {
47
+ UpdateProcessState,
48
+ } = require('./integrations/use-cases/update-process-state');
49
+ const {
50
+ UpdateProcessMetrics,
51
+ } = require('./integrations/use-cases/update-process-metrics');
52
+ const { GetProcess } = require('./integrations/use-cases/get-process');
53
+ const { Cryptor } = require('./encrypt');
29
54
  const {
30
55
  BaseError,
31
56
  FetchError,
32
57
  HaltError,
33
58
  RequiredPropertyError,
34
59
  ParameterTypeError,
60
+ MappingAlreadyExistsError,
35
61
  } = require('./errors/index');
36
62
  const {
37
63
  IntegrationBase,
38
- IntegrationModel,
39
64
  Options,
40
- IntegrationMapping,
41
- IntegrationFactory,
42
- IntegrationHelper,
43
65
  createIntegrationRouter,
44
66
  checkRequiredParams,
45
- createFriggBackend,
67
+ getModulesDefinitionFromIntegrationClasses,
68
+ LoadIntegrationContextUseCase,
46
69
  } = require('./integrations/index');
70
+ const {
71
+ ReportBase,
72
+ IntegrationsReport,
73
+ BUILTIN_REPORTS,
74
+ createReportCommands,
75
+ } = require('./reporting/index');
76
+ const {
77
+ createTelemetry,
78
+ getTelemetry,
79
+ CANONICAL_COUNTERS,
80
+ } = require('./telemetry/index');
81
+ const { createUsageRepository } = require('./usage/index');
47
82
  const { TimeoutCatcher } = require('./lambda/index');
48
- const { debug, initDebugLog, flushDebugLog } = require('./logs/index');
83
+ const {
84
+ getLogger,
85
+ createMemorySink,
86
+ resetLoggerForTests,
87
+ serializeError,
88
+ redactValue,
89
+ toSanitizedSurrogate,
90
+ debug,
91
+ initDebugLog,
92
+ flushDebugLog,
93
+ } = require('./logs/index');
49
94
  const {
50
95
  Credential,
51
- EntityManager,
52
96
  Entity,
53
- ModuleManager,
54
97
  ApiKeyRequester,
55
98
  BasicAuthRequester,
56
99
  OAuth2Requester,
57
100
  Requester,
58
101
  ModuleConstants,
59
102
  ModuleFactory,
60
- Auther,
61
- } = require('./module-plugin/index');
62
-
63
- // const {Sync } = require('./syncs/model');
103
+ } = require('./modules/index');
104
+ const application = require('./application');
105
+ const utils = require('./utils');
64
106
 
65
107
  const { QueuerUtil } = require('./queues');
66
108
 
67
109
  module.exports = {
68
110
  // assertions
69
- expectShallowEqualDbObject,
70
111
  get,
71
112
  getAll,
72
113
  verifyType,
@@ -79,21 +120,23 @@ module.exports = {
79
120
  Worker,
80
121
  loadInstalledModules,
81
122
  createHandler,
123
+ runInvocationScope,
82
124
 
83
125
  // database
84
- mongoose,
85
- connectToDatabase,
86
- disconnectFromDatabase,
87
- createObjectId,
88
- IndividualUser,
89
- OrganizationUser,
90
- State,
91
- Token,
92
- UserModel,
93
- WebsocketConnection,
94
-
95
- // encrypt
96
- Encrypt,
126
+ prisma,
127
+ connectPrisma,
128
+ disconnectPrisma,
129
+ TokenRepository,
130
+ WebsocketConnectionRepository,
131
+ createUserRepository,
132
+ UserRepositoryMongo,
133
+ UserRepositoryPostgres,
134
+ GetUserFromXFriggHeaders,
135
+ GetUserFromAdopterJwt,
136
+ AuthenticateUser,
137
+ CredentialRepository,
138
+ ModuleRepository,
139
+ IntegrationMappingRepository,
97
140
  Cryptor,
98
141
 
99
142
  // errors
@@ -102,39 +145,72 @@ module.exports = {
102
145
  HaltError,
103
146
  RequiredPropertyError,
104
147
  ParameterTypeError,
148
+ MappingAlreadyExistsError,
105
149
 
106
150
  // integrations
107
151
  IntegrationBase,
108
- IntegrationModel,
109
152
  Options,
110
- IntegrationMapping,
111
- IntegrationFactory,
112
- IntegrationHelper,
113
153
  checkRequiredParams,
114
154
  createIntegrationRouter,
115
- createFriggBackend,
155
+ getModulesDefinitionFromIntegrationClasses,
156
+ LoadIntegrationContextUseCase,
157
+ CreateProcess,
158
+ UpdateProcessState,
159
+ UpdateProcessMetrics,
160
+ GetProcess,
161
+
162
+ // reporting
163
+ ReportBase,
164
+ IntegrationsReport,
165
+ BUILTIN_REPORTS,
166
+ createReportCommands,
167
+
168
+ // telemetry
169
+ createTelemetry,
170
+ getTelemetry,
171
+ CANONICAL_COUNTERS,
172
+ createUsageRepository,
173
+
174
+ // application - Command factories for integration developers
175
+ application,
176
+ createFriggCommands: application.createFriggCommands,
177
+ createIntegrationCommands: application.createIntegrationCommands,
178
+ createUserCommands: application.createUserCommands,
179
+ createEntityCommands: application.createEntityCommands,
180
+ createCredentialCommands: application.createCredentialCommands,
181
+ createProcessCommands: application.createProcessCommands,
182
+ createSchedulerCommands: application.createSchedulerCommands,
183
+ createUsageCommands: application.createUsageCommands,
184
+ findIntegrationContextByExternalEntityId:
185
+ application.findIntegrationContextByExternalEntityId,
186
+ integrationCommands: application.integrationCommands,
116
187
 
117
188
  // lambda
118
189
  TimeoutCatcher,
119
190
 
120
191
  // logs
192
+ getLogger,
193
+ createMemorySink,
194
+ resetLoggerForTests,
195
+ serializeError,
196
+ redactValue,
197
+ toSanitizedSurrogate,
121
198
  debug,
122
199
  initDebugLog,
123
200
  flushDebugLog,
124
201
 
125
202
  // module plugin
126
203
  Credential,
127
- EntityManager,
128
204
  Entity,
129
- ModuleManager,
130
205
  ApiKeyRequester,
131
206
  BasicAuthRequester,
132
207
  OAuth2Requester,
133
208
  Requester,
134
209
  ModuleConstants,
135
210
  ModuleFactory,
136
- Auther,
137
-
138
211
  // queues
139
212
  QueuerUtil,
213
+
214
+ // utils
215
+ ...utils,
140
216
  };
@@ -0,0 +1,238 @@
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 { SchedulerServiceInterface } = require('./scheduler-service-interface');
15
+
16
+ const SCHEDULER_SDK = '@aws-sdk/client-scheduler';
17
+
18
+ /**
19
+ * Lazily load the AWS EventBridge Scheduler SDK.
20
+ *
21
+ * Requiring `@aws-sdk/client-scheduler` at module top level would put the AWS
22
+ * SDK on the load path of every consumer of `@friggframework/core`, including
23
+ * those using the mock scheduler or no scheduler at all. Loading it here, on
24
+ * construction of the EventBridge adapter, keeps it out of the module-load
25
+ * path. The adapter calls it exactly once, in its constructor, and keeps the
26
+ * classes its methods need on the instance.
27
+ *
28
+ * Only a MODULE_NOT_FOUND for the scheduler SDK itself is rewritten into an
29
+ * actionable message; any other failure (including a missing transitive
30
+ * dependency) is rethrown unchanged so the real cause is not masked.
31
+ *
32
+ * @returns {object} The relevant exports from `@aws-sdk/client-scheduler`.
33
+ */
34
+ function loadSchedulerSdk() {
35
+ try {
36
+ // Keep the literal specifier so bundlers (esbuild) can resolve it.
37
+ return require('@aws-sdk/client-scheduler');
38
+ } catch (error) {
39
+ const isSchedulerSdkMissing =
40
+ error &&
41
+ error.code === 'MODULE_NOT_FOUND' &&
42
+ typeof error.message === 'string' &&
43
+ error.message.includes(SCHEDULER_SDK);
44
+ if (isSchedulerSdkMissing) {
45
+ throw new Error(
46
+ `The EventBridge scheduler requires the "${SCHEDULER_SDK}" package, ` +
47
+ `which is not installed. Install it (\`npm install ${SCHEDULER_SDK}\`) ` +
48
+ 'to use the EventBridge scheduler provider, or use the mock scheduler provider ' +
49
+ '(SCHEDULER_PROVIDER=mock) for local development.',
50
+ { cause: error }
51
+ );
52
+ }
53
+ throw error;
54
+ }
55
+ }
56
+
57
+ class EventBridgeSchedulerAdapter extends SchedulerServiceInterface {
58
+ constructor({ region } = {}) {
59
+ super();
60
+ const {
61
+ SchedulerClient,
62
+ CreateScheduleCommand,
63
+ DeleteScheduleCommand,
64
+ GetScheduleCommand,
65
+ ResourceNotFoundException,
66
+ } = loadSchedulerSdk();
67
+ this.sdk = {
68
+ CreateScheduleCommand,
69
+ DeleteScheduleCommand,
70
+ GetScheduleCommand,
71
+ ResourceNotFoundException,
72
+ };
73
+ this.client = new SchedulerClient({
74
+ region: region || process.env.AWS_REGION || 'us-east-1',
75
+ });
76
+ this.scheduleGroupName =
77
+ process.env.SCHEDULE_GROUP_NAME || 'frigg-integration-schedules';
78
+ this.roleArn = process.env.SCHEDULER_ROLE_ARN;
79
+ }
80
+
81
+ /**
82
+ * Create a one-time schedule that sends a message to SQS
83
+ *
84
+ * @param {Object} params
85
+ * @param {string} params.scheduleName - Unique name for the schedule
86
+ * @param {Date} params.scheduleAt - When to trigger the schedule
87
+ * @param {string} params.queueResourceId - Queue resource identifier (ARN) to send message to
88
+ * @param {Object} params.payload - Message payload
89
+ * @returns {Promise<{scheduledJobId: string, scheduledAt: string}>}
90
+ */
91
+ async scheduleOneTime({
92
+ scheduleName,
93
+ scheduleAt,
94
+ queueResourceId,
95
+ payload,
96
+ }) {
97
+ if (!scheduleName) {
98
+ throw new Error('scheduleName is required');
99
+ }
100
+ if (!scheduleAt || !(scheduleAt instanceof Date)) {
101
+ throw new Error('scheduleAt must be a valid Date object');
102
+ }
103
+ if (!queueResourceId) {
104
+ throw new Error('queueResourceId is required');
105
+ }
106
+ if (!this.roleArn) {
107
+ throw new Error(
108
+ 'SCHEDULER_ROLE_ARN environment variable is not set'
109
+ );
110
+ }
111
+
112
+ // Format date to AWS schedule expression (at(yyyy-mm-ddThh:mm:ss))
113
+ const scheduleExpression = `at(${scheduleAt
114
+ .toISOString()
115
+ .replace(/\.\d{3}Z$/, '')})`;
116
+
117
+ const { CreateScheduleCommand } = this.sdk;
118
+ const command = new CreateScheduleCommand({
119
+ Name: scheduleName,
120
+ GroupName: this.scheduleGroupName,
121
+ ScheduleExpression: scheduleExpression,
122
+ ScheduleExpressionTimezone: 'UTC',
123
+ FlexibleTimeWindow: {
124
+ Mode: 'OFF',
125
+ },
126
+ Target: {
127
+ Arn: queueResourceId,
128
+ RoleArn: this.roleArn,
129
+ Input: JSON.stringify(payload),
130
+ },
131
+ ActionAfterCompletion: 'DELETE', // Auto-cleanup after execution
132
+ });
133
+
134
+ try {
135
+ const response = await this.client.send(command);
136
+ console.log(
137
+ `[Scheduler] Created schedule ${scheduleName} for ${scheduleAt.toISOString()}`
138
+ );
139
+
140
+ return {
141
+ scheduledJobId: response.ScheduleArn,
142
+ scheduledAt: scheduleAt.toISOString(),
143
+ };
144
+ } catch (error) {
145
+ console.error(
146
+ `[Scheduler] Failed to create schedule ${scheduleName}:`,
147
+ error.message
148
+ );
149
+ throw error;
150
+ }
151
+ }
152
+
153
+ /**
154
+ * Delete a schedule
155
+ *
156
+ * @param {string} scheduleName - Name of the schedule to delete
157
+ * @returns {Promise<void>}
158
+ */
159
+ async deleteSchedule(scheduleName) {
160
+ if (!scheduleName) {
161
+ throw new Error('scheduleName is required');
162
+ }
163
+
164
+ const { DeleteScheduleCommand, ResourceNotFoundException } = this.sdk;
165
+ const command = new DeleteScheduleCommand({
166
+ Name: scheduleName,
167
+ GroupName: this.scheduleGroupName,
168
+ });
169
+
170
+ try {
171
+ await this.client.send(command);
172
+ console.log(`[Scheduler] Deleted schedule ${scheduleName}`);
173
+ } catch (error) {
174
+ if (error instanceof ResourceNotFoundException) {
175
+ console.log(
176
+ `[Scheduler] Schedule ${scheduleName} not found (already deleted or executed)`
177
+ );
178
+ return; // Graceful handling - schedule doesn't exist
179
+ }
180
+ console.error(
181
+ `[Scheduler] Failed to delete schedule ${scheduleName}:`,
182
+ error.message
183
+ );
184
+ throw error;
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Get schedule status
190
+ *
191
+ * @param {string} scheduleName - Name of the schedule
192
+ * @returns {Promise<{exists: boolean, scheduledAt?: string, state?: string}>}
193
+ */
194
+ async getScheduleStatus(scheduleName) {
195
+ if (!scheduleName) {
196
+ throw new Error('scheduleName is required');
197
+ }
198
+
199
+ const { GetScheduleCommand, ResourceNotFoundException } = this.sdk;
200
+ const command = new GetScheduleCommand({
201
+ Name: scheduleName,
202
+ GroupName: this.scheduleGroupName,
203
+ });
204
+
205
+ try {
206
+ const response = await this.client.send(command);
207
+
208
+ // Parse the schedule expression to get the scheduled time
209
+ // Format: at(yyyy-mm-ddThh:mm:ss)
210
+ let scheduledAt = null;
211
+ if (response.ScheduleExpression) {
212
+ const match = response.ScheduleExpression.match(/^at\((.+)\)$/);
213
+ if (match) {
214
+ scheduledAt = new Date(match[1] + 'Z').toISOString();
215
+ }
216
+ }
217
+
218
+ return {
219
+ exists: true,
220
+ scheduledAt,
221
+ state: response.State,
222
+ };
223
+ } catch (error) {
224
+ if (error instanceof ResourceNotFoundException) {
225
+ return {
226
+ exists: false,
227
+ };
228
+ }
229
+ console.error(
230
+ `[Scheduler] Failed to get schedule ${scheduleName}:`,
231
+ error.message
232
+ );
233
+ throw error;
234
+ }
235
+ }
236
+ }
237
+
238
+ 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 };