@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,358 @@
1
+ const ERROR_CODE_MAP = {
2
+ SCRIPT_NOT_FOUND: 404,
3
+ EXECUTION_NOT_FOUND: 404,
4
+ };
5
+
6
+ function mapErrorToResponse(error) {
7
+ const status = ERROR_CODE_MAP[error?.code] || 500;
8
+ return { error: status, reason: error?.message, code: error?.code };
9
+ }
10
+
11
+ /**
12
+ * Create admin script commands
13
+ * Provides command pattern API for admin script management
14
+ *
15
+ * This follows the Command pattern from integration-commands.js:
16
+ * - Creates repositories via factory functions
17
+ * - Maps errors to HTTP-friendly responses
18
+ * - Returns data or error objects (never throws)
19
+ *
20
+ * WHY SEPARATE FROM integration-commands.js:
21
+ * These commands are intentionally separate because they serve different domains:
22
+ * - integration-commands: User-context operations on integrations
23
+ * - Requires integrationClass constructor parameter
24
+ * - Works with userId, entityIds, integration contexts
25
+ * - Uses IntegrationRepository, ModuleRepository
26
+ * - admin-script-commands: System/admin operations without user context
27
+ * - No user context required
28
+ * - Works with AdminScriptExecution, ScriptSchedule
29
+ * - Uses AdminScriptExecutionRepository, ScriptScheduleRepository
30
+ *
31
+ * Merging them would violate SRP and create coupling between
32
+ * user-facing integration code and admin/system code.
33
+ *
34
+ * Authentication:
35
+ * - Uses ENV-based ADMIN_API_KEY (see handlers/middleware/admin-auth.js)
36
+ * - No database-backed API keys (simplified from original design)
37
+ *
38
+ * @returns {Object} Command methods for admin scripts
39
+ */
40
+ function createAdminScriptCommands() {
41
+ // Lazy-load repository factories to avoid circular dependencies
42
+ const {
43
+ createAdminScriptExecutionRepository,
44
+ } = require('../../admin-scripts/repositories/admin-script-execution-repository-factory');
45
+ const {
46
+ createScriptScheduleRepository,
47
+ } = require('../../admin-scripts/repositories/script-schedule-repository-factory');
48
+
49
+ const adminScriptExecutionRepository = createAdminScriptExecutionRepository();
50
+ const scheduleRepository = createScriptScheduleRepository();
51
+
52
+ return {
53
+ // ==================== Admin Script Execution Management Commands ====================
54
+
55
+ /**
56
+ * Create a new admin script execution record
57
+ *
58
+ * @param {Object} params - Execution creation parameters
59
+ * @param {string} params.scriptName - Name of script being executed
60
+ * @param {string} [params.scriptVersion] - Script version
61
+ * @param {string} params.trigger - Trigger type ('MANUAL', 'SCHEDULED', 'QUEUE', 'WEBHOOK')
62
+ * @param {string} [params.mode] - Execution mode ('sync' or 'async', default 'async')
63
+ * @param {Object} [params.input] - Input parameters
64
+ * @param {Object} [params.audit] - Audit information (apiKeyName, apiKeyLast4, ipAddress)
65
+ * @returns {Promise<Object>} Created admin script execution record
66
+ */
67
+ async createExecution({
68
+ scriptName,
69
+ scriptVersion,
70
+ trigger,
71
+ mode,
72
+ input,
73
+ audit,
74
+ parentExecutionId,
75
+ }) {
76
+ try {
77
+ const process = await adminScriptExecutionRepository.createExecution({
78
+ name: scriptName,
79
+ type: 'ADMIN_SCRIPT',
80
+ // Persisted to the parentExecutionId column (self-FK), not the
81
+ // context blob, so the parent/child hierarchy is queryable.
82
+ parentExecutionId,
83
+ context: {
84
+ scriptVersion,
85
+ trigger,
86
+ mode: mode || 'async',
87
+ input,
88
+ audit,
89
+ },
90
+ });
91
+ return process;
92
+ } catch (error) {
93
+ return mapErrorToResponse(error);
94
+ }
95
+ },
96
+
97
+ /**
98
+ * Find an admin script execution by ID
99
+ *
100
+ * @param {string|number} processId - The admin script execution ID
101
+ * @returns {Promise<Object>} Admin script execution record or error
102
+ */
103
+ async findExecutionById(processId) {
104
+ try {
105
+ const process = await adminScriptExecutionRepository.findExecutionById(
106
+ processId
107
+ );
108
+ if (!process) {
109
+ const error = new Error(`Execution ${processId} not found`);
110
+ error.code = 'EXECUTION_NOT_FOUND';
111
+ return mapErrorToResponse(error);
112
+ }
113
+ return process;
114
+ } catch (error) {
115
+ return mapErrorToResponse(error);
116
+ }
117
+ },
118
+
119
+ /**
120
+ * Find all admin script executions for a specific script
121
+ *
122
+ * @param {string} scriptName - Script name to filter by
123
+ * @param {Object} [options] - Query options (limit, offset, sortBy, sortOrder)
124
+ * @returns {Promise<Array>} Array of admin script execution records
125
+ */
126
+ async findExecutionsByName(scriptName, options = {}) {
127
+ try {
128
+ const processes =
129
+ await adminScriptExecutionRepository.findExecutionsByName(
130
+ scriptName,
131
+ options
132
+ );
133
+ return processes;
134
+ } catch (error) {
135
+ // Return empty array on error (non-critical)
136
+ return [];
137
+ }
138
+ },
139
+
140
+ /**
141
+ * Update admin script execution state
142
+ *
143
+ * @param {string|number} processId - The admin script execution ID
144
+ * @param {string} state - New state ('PENDING', 'RUNNING', 'COMPLETED', 'FAILED')
145
+ * @returns {Promise<Object>} Updated admin script execution record
146
+ */
147
+ async updateExecutionState(processId, state) {
148
+ try {
149
+ const updated = await adminScriptExecutionRepository.updateExecutionState(
150
+ processId,
151
+ state
152
+ );
153
+ return updated;
154
+ } catch (error) {
155
+ return mapErrorToResponse(error);
156
+ }
157
+ },
158
+
159
+ /**
160
+ * Append a log entry to an admin script execution's results.logs array
161
+ *
162
+ * @param {string|number} processId - The admin script execution ID
163
+ * @param {Object} logEntry - Log entry { level, message, data, timestamp }
164
+ * @returns {Promise<Object>} Updated admin script execution record
165
+ */
166
+ async appendExecutionLog(processId, logEntry) {
167
+ try {
168
+ const updated = await adminScriptExecutionRepository.appendExecutionLog(
169
+ processId,
170
+ logEntry
171
+ );
172
+ return updated;
173
+ } catch (error) {
174
+ return mapErrorToResponse(error);
175
+ }
176
+ },
177
+
178
+ /**
179
+ * Complete an admin script execution
180
+ * Updates state, output, error, and metrics
181
+ *
182
+ * @param {string|number} processId - The admin script execution ID
183
+ * @param {Object} params - Completion parameters
184
+ * @param {string} [params.state] - Final state ('COMPLETED', 'FAILED')
185
+ * @param {Object} [params.output] - Script output/result (stored in results.output)
186
+ * @param {Object} [params.error] - Error details { name, message, stack } (stored in results.error)
187
+ * @param {Object} [params.metrics] - Performance metrics { startTime, endTime, durationMs } (stored in results.metrics)
188
+ * @param {Array} [params.logs] - Execution log entries (stored in results.logs)
189
+ * @returns {Promise<Object>} { success: true } or error
190
+ */
191
+ async completeExecution(
192
+ processId,
193
+ { state, output, error, metrics, logs }
194
+ ) {
195
+ try {
196
+ if (state) {
197
+ await adminScriptExecutionRepository.updateExecutionState(
198
+ processId,
199
+ state
200
+ );
201
+ }
202
+
203
+ // Merge output/error/metrics/logs into the results JSON in one write
204
+ const resultsUpdate = {};
205
+ if (output !== undefined) resultsUpdate.output = output;
206
+ if (error) resultsUpdate.error = error;
207
+ if (metrics) resultsUpdate.metrics = metrics;
208
+ if (logs) resultsUpdate.logs = logs;
209
+ if (Object.keys(resultsUpdate).length > 0) {
210
+ await adminScriptExecutionRepository.updateExecutionResults(
211
+ processId,
212
+ resultsUpdate
213
+ );
214
+ }
215
+
216
+ return { success: true };
217
+ } catch (err) {
218
+ return mapErrorToResponse(err);
219
+ }
220
+ },
221
+
222
+ // ==================== Schedule Management Commands ====================
223
+
224
+ /**
225
+ * Get schedule by script name
226
+ * Returns database override or null
227
+ *
228
+ * @param {string} scriptName - The script name
229
+ * @returns {Promise<Object|null>} Schedule record or null
230
+ */
231
+ async getScheduleByScriptName(scriptName) {
232
+ try {
233
+ const schedule =
234
+ await scheduleRepository.findScheduleByScriptName(
235
+ scriptName
236
+ );
237
+ return schedule;
238
+ } catch (error) {
239
+ return mapErrorToResponse(error);
240
+ }
241
+ },
242
+
243
+ /**
244
+ * Create or update a schedule (upsert)
245
+ *
246
+ * @param {Object} params - Schedule parameters
247
+ * @param {string} params.scriptName - Name of the script
248
+ * @param {boolean} params.enabled - Whether schedule is enabled
249
+ * @param {string} params.cronExpression - Cron expression
250
+ * @param {string} [params.timezone] - Timezone (default 'UTC')
251
+ * @returns {Promise<Object>} Created or updated schedule
252
+ */
253
+ async upsertSchedule({
254
+ scriptName,
255
+ enabled,
256
+ cronExpression,
257
+ timezone,
258
+ }) {
259
+ try {
260
+ const schedule = await scheduleRepository.upsertSchedule({
261
+ scriptName,
262
+ enabled,
263
+ cronExpression,
264
+ timezone,
265
+ });
266
+ return schedule;
267
+ } catch (error) {
268
+ return mapErrorToResponse(error);
269
+ }
270
+ },
271
+
272
+ /**
273
+ * Delete a schedule by script name
274
+ *
275
+ * @param {string} scriptName - The script name
276
+ * @returns {Promise<Object>} Deletion result
277
+ */
278
+ async deleteSchedule(scriptName) {
279
+ try {
280
+ const result = await scheduleRepository.deleteSchedule(
281
+ scriptName
282
+ );
283
+ return result;
284
+ } catch (error) {
285
+ return mapErrorToResponse(error);
286
+ }
287
+ },
288
+
289
+ /**
290
+ * Update external scheduler information
291
+ *
292
+ * @param {string} scriptName - The script name
293
+ * @param {Object} externalInfo - External schedule information
294
+ * @param {string} [externalInfo.externalScheduleId] - External scheduler ID (e.g., AWS ARN)
295
+ * @param {string} [externalInfo.externalScheduleName] - External scheduler name
296
+ * @returns {Promise<Object>} Updated schedule
297
+ */
298
+ async updateScheduleExternalInfo(
299
+ scriptName,
300
+ { externalScheduleId, externalScheduleName }
301
+ ) {
302
+ try {
303
+ const schedule =
304
+ await scheduleRepository.updateScheduleExternalInfo(
305
+ scriptName,
306
+ {
307
+ externalScheduleId,
308
+ externalScheduleName,
309
+ }
310
+ );
311
+ return schedule;
312
+ } catch (error) {
313
+ return mapErrorToResponse(error);
314
+ }
315
+ },
316
+
317
+ /**
318
+ * Update last triggered timestamp
319
+ * Called when a schedule triggers
320
+ *
321
+ * @param {string} scriptName - The script name
322
+ * @param {Date} [timestamp] - Trigger timestamp (default: now)
323
+ * @returns {Promise<Object>} Updated schedule
324
+ */
325
+ async updateScheduleLastTriggered(scriptName, timestamp) {
326
+ try {
327
+ const schedule =
328
+ await scheduleRepository.updateScheduleLastTriggered(
329
+ scriptName,
330
+ timestamp
331
+ );
332
+ return schedule;
333
+ } catch (error) {
334
+ return mapErrorToResponse(error);
335
+ }
336
+ },
337
+
338
+ /**
339
+ * List all schedules
340
+ *
341
+ * @param {Object} [options] - Query options
342
+ * @param {boolean} [options.enabledOnly] - Only return enabled schedules
343
+ * @returns {Promise<Array>} Array of schedule records
344
+ */
345
+ async listSchedules(options = {}) {
346
+ try {
347
+ const schedules = await scheduleRepository.listSchedules(
348
+ options
349
+ );
350
+ return schedules;
351
+ } catch (error) {
352
+ return [];
353
+ }
354
+ },
355
+ };
356
+ }
357
+
358
+ module.exports = { createAdminScriptCommands };
@@ -0,0 +1,245 @@
1
+ const {
2
+ createCredentialRepository,
3
+ } = require('../../credential/repositories/credential-repository-factory');
4
+
5
+ const ERROR_CODE_MAP = {
6
+ CREDENTIAL_NOT_FOUND: 404,
7
+ INVALID_CREDENTIAL_DATA: 400,
8
+ };
9
+
10
+ function mapErrorToResponse(error) {
11
+ const status = ERROR_CODE_MAP[error?.code] || 500;
12
+ return {
13
+ error: status,
14
+ reason: error?.message,
15
+ code: error?.code,
16
+ };
17
+ }
18
+
19
+ /**
20
+ * Create credential command factory
21
+ *
22
+ * NOTE: This is an internal API. Integration developers should use createFriggCommands() instead.
23
+ *
24
+ * @returns {Object} Credential command object with CRUD operations
25
+ */
26
+ function createCredentialCommands() {
27
+ const credRepo = createCredentialRepository();
28
+
29
+ return {
30
+ /**
31
+ * Create a new credential
32
+ * @param {Object} params
33
+ * @param {string} params.userId - User ID who owns this credential
34
+ * @param {string} params.externalId - External identifier from the API module
35
+ * @param {string} params.access_token - OAuth access token
36
+ * @param {string} [params.refresh_token] - OAuth refresh token
37
+ * @param {string} [params.domain] - Domain for the credential
38
+ * @param {boolean} [params.authIsValid=true] - Whether authentication is valid
39
+ * @returns {Promise<Object>} Created credential object
40
+ */
41
+ async createCredential({
42
+ userId,
43
+ externalId,
44
+ access_token,
45
+ refresh_token,
46
+ domain,
47
+ authIsValid = true,
48
+ } = {}) {
49
+ try {
50
+ if (!userId || !externalId || !access_token) {
51
+ const error = new Error(
52
+ 'userId, externalId, and access_token are required'
53
+ );
54
+ error.code = 'INVALID_CREDENTIAL_DATA';
55
+ throw error;
56
+ }
57
+
58
+ const credentialData = {
59
+ identifiers: { userId, externalId },
60
+ details: {
61
+ access_token,
62
+ authIsValid,
63
+ },
64
+ };
65
+
66
+ if (refresh_token) {
67
+ credentialData.details.refresh_token = refresh_token;
68
+ }
69
+ if (domain) {
70
+ credentialData.details.domain = domain;
71
+ }
72
+
73
+ const credential = await credRepo.upsertCredential(
74
+ credentialData
75
+ );
76
+
77
+ return {
78
+ id: credential.id,
79
+ userId: credential.userId,
80
+ externalId: credential.externalId,
81
+ access_token: credential.access_token,
82
+ refresh_token: credential.refresh_token,
83
+ authIsValid: credential.authIsValid,
84
+ };
85
+ } catch (error) {
86
+ return mapErrorToResponse(error);
87
+ }
88
+ },
89
+
90
+ /**
91
+ * Find a credential by filter criteria
92
+ * @param {Object} filter
93
+ * @param {string} [filter.userId] - User ID to search for
94
+ * @param {string} [filter.externalId] - External ID to search for
95
+ * @param {string} [filter.credentialId] - Credential ID to search for
96
+ * @returns {Promise<Object|null>} Credential object or null if not found
97
+ */
98
+ async findCredential(filter = {}) {
99
+ try {
100
+ if (
101
+ !filter.userId &&
102
+ !filter.externalId &&
103
+ !filter.credentialId
104
+ ) {
105
+ const error = new Error(
106
+ 'At least one filter criterion is required'
107
+ );
108
+ error.code = 'INVALID_CREDENTIAL_DATA';
109
+ throw error;
110
+ }
111
+
112
+ const credential = await credRepo.findCredential(filter);
113
+
114
+ if (!credential) {
115
+ return null;
116
+ }
117
+
118
+ return {
119
+ id: credential.id,
120
+ userId: credential.userId,
121
+ externalId: credential.externalId,
122
+ access_token: credential.access_token,
123
+ refresh_token: credential.refresh_token,
124
+ authIsValid: credential.authIsValid,
125
+ domain: credential.domain,
126
+ };
127
+ } catch (error) {
128
+ return mapErrorToResponse(error);
129
+ }
130
+ },
131
+
132
+ /**
133
+ * Update a credential by ID
134
+ * @param {string} credentialId - Credential ID to update
135
+ * @param {Object} updates - Fields to update
136
+ * @returns {Promise<Object>} Updated credential object
137
+ */
138
+ async updateCredential(credentialId, updates) {
139
+ try {
140
+ if (!credentialId) {
141
+ const error = new Error('credentialId is required');
142
+ error.code = 'INVALID_CREDENTIAL_DATA';
143
+ throw error;
144
+ }
145
+
146
+ const credential = await credRepo.updateCredential(
147
+ credentialId,
148
+ updates
149
+ );
150
+
151
+ if (!credential) {
152
+ const error = new Error(
153
+ `Credential ${credentialId} not found`
154
+ );
155
+ error.code = 'CREDENTIAL_NOT_FOUND';
156
+ throw error;
157
+ }
158
+
159
+ return {
160
+ id: credential.id,
161
+ userId: credential.userId,
162
+ externalId: credential.externalId,
163
+ access_token: credential.access_token,
164
+ refresh_token: credential.refresh_token,
165
+ authIsValid: credential.authIsValid,
166
+ domain: credential.domain,
167
+ };
168
+ } catch (error) {
169
+ return mapErrorToResponse(error);
170
+ }
171
+ },
172
+
173
+ /**
174
+ * Update authentication status for a credential
175
+ * @param {string} credentialId - Credential ID to update
176
+ * @param {boolean} isValid - Whether authentication is valid
177
+ * @returns {Promise<Object>} Result object with success flag
178
+ */
179
+ async updateAuthenticationStatus(credentialId, isValid) {
180
+ try {
181
+ if (!credentialId) {
182
+ const error = new Error('credentialId is required');
183
+ error.code = 'INVALID_CREDENTIAL_DATA';
184
+ throw error;
185
+ }
186
+
187
+ await credRepo.updateAuthenticationStatus(
188
+ credentialId,
189
+ isValid
190
+ );
191
+
192
+ return { success: true };
193
+ } catch (error) {
194
+ return mapErrorToResponse(error);
195
+ }
196
+ },
197
+
198
+ /**
199
+ * Delete a credential by ID
200
+ * @param {string} credentialId - Credential ID to delete
201
+ * @returns {Promise<Object>} Result object with success flag
202
+ */
203
+ async deleteCredential(credentialId) {
204
+ try {
205
+ if (!credentialId) {
206
+ const error = new Error('credentialId is required');
207
+ error.code = 'INVALID_CREDENTIAL_DATA';
208
+ throw error;
209
+ }
210
+
211
+ await credRepo.deleteCredentialById(credentialId);
212
+
213
+ return { success: true };
214
+ } catch (error) {
215
+ return mapErrorToResponse(error);
216
+ }
217
+ },
218
+
219
+ /**
220
+ * Delete a credential by ID (alias for deleteCredential)
221
+ * @param {string} credentialId - Credential ID to delete
222
+ * @returns {Promise<Object>} Result object with success flag
223
+ */
224
+ async deleteCredentialById(credentialId) {
225
+ try {
226
+ if (!credentialId) {
227
+ const error = new Error('credentialId is required');
228
+ error.code = 'INVALID_CREDENTIAL_DATA';
229
+ throw error;
230
+ }
231
+
232
+ await credRepo.deleteCredentialById(credentialId);
233
+
234
+ return { success: true };
235
+ } catch (error) {
236
+ return mapErrorToResponse(error);
237
+ }
238
+ },
239
+ };
240
+ }
241
+
242
+ module.exports = {
243
+ createCredentialCommands,
244
+ ERROR_CODE_MAP,
245
+ };