@contember/engine-actions 1.3.0-alpha.4

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 (289) hide show
  1. package/dist/src/ActionsExecutionContainerHookFactory.d.ts +8 -0
  2. package/dist/src/ActionsExecutionContainerHookFactory.d.ts.map +1 -0
  3. package/dist/src/ActionsExecutionContainerHookFactory.js +28 -0
  4. package/dist/src/ActionsExecutionContainerHookFactory.js.map +1 -0
  5. package/dist/src/ImplementationException.d.ts +3 -0
  6. package/dist/src/ImplementationException.d.ts.map +1 -0
  7. package/dist/src/ImplementationException.js +7 -0
  8. package/dist/src/ImplementationException.js.map +1 -0
  9. package/dist/src/ListenerStoreProvider.d.ts +7 -0
  10. package/dist/src/ListenerStoreProvider.d.ts.map +1 -0
  11. package/dist/src/ListenerStoreProvider.js +21 -0
  12. package/dist/src/ListenerStoreProvider.js.map +1 -0
  13. package/dist/src/dispatch/DispatchWorkerSupervisor.d.ts +17 -0
  14. package/dist/src/dispatch/DispatchWorkerSupervisor.d.ts.map +1 -0
  15. package/dist/src/dispatch/DispatchWorkerSupervisor.js +123 -0
  16. package/dist/src/dispatch/DispatchWorkerSupervisor.js.map +1 -0
  17. package/dist/src/dispatch/EventDispatcher.d.ts +25 -0
  18. package/dist/src/dispatch/EventDispatcher.d.ts.map +1 -0
  19. package/dist/src/dispatch/EventDispatcher.js +46 -0
  20. package/dist/src/dispatch/EventDispatcher.js.map +1 -0
  21. package/dist/src/dispatch/EventsRepository.d.ts +22 -0
  22. package/dist/src/dispatch/EventsRepository.d.ts.map +1 -0
  23. package/dist/src/dispatch/EventsRepository.js +138 -0
  24. package/dist/src/dispatch/EventsRepository.js.map +1 -0
  25. package/dist/src/dispatch/ProjectDispatcher.d.ts +22 -0
  26. package/dist/src/dispatch/ProjectDispatcher.d.ts.map +1 -0
  27. package/dist/src/dispatch/ProjectDispatcher.js +103 -0
  28. package/dist/src/dispatch/ProjectDispatcher.js.map +1 -0
  29. package/dist/src/dispatch/TargetHandlerResolver.d.ts +9 -0
  30. package/dist/src/dispatch/TargetHandlerResolver.d.ts.map +1 -0
  31. package/dist/src/dispatch/TargetHandlerResolver.js +17 -0
  32. package/dist/src/dispatch/TargetHandlerResolver.js.map +1 -0
  33. package/dist/src/dispatch/WebhookTargetHandler.d.ts +7 -0
  34. package/dist/src/dispatch/WebhookTargetHandler.d.ts.map +1 -0
  35. package/dist/src/dispatch/WebhookTargetHandler.js +85 -0
  36. package/dist/src/dispatch/WebhookTargetHandler.js.map +1 -0
  37. package/dist/src/dispatch/types.d.ts +27 -0
  38. package/dist/src/dispatch/types.d.ts.map +1 -0
  39. package/dist/src/dispatch/types.js +3 -0
  40. package/dist/src/dispatch/types.js.map +1 -0
  41. package/dist/src/graphql/http/ActionsApiMiddlewareFactory.d.ts +10 -0
  42. package/dist/src/graphql/http/ActionsApiMiddlewareFactory.d.ts.map +1 -0
  43. package/dist/src/graphql/http/ActionsApiMiddlewareFactory.js +31 -0
  44. package/dist/src/graphql/http/ActionsApiMiddlewareFactory.js.map +1 -0
  45. package/dist/src/graphql/http/ActionsContextResolver.d.ts +11 -0
  46. package/dist/src/graphql/http/ActionsContextResolver.d.ts.map +1 -0
  47. package/dist/src/graphql/http/ActionsContextResolver.js +33 -0
  48. package/dist/src/graphql/http/ActionsContextResolver.js.map +1 -0
  49. package/dist/src/graphql/http/ActionsGraphQLHandlerFactory.d.ts +8 -0
  50. package/dist/src/graphql/http/ActionsGraphQLHandlerFactory.d.ts.map +1 -0
  51. package/dist/src/graphql/http/ActionsGraphQLHandlerFactory.js +21 -0
  52. package/dist/src/graphql/http/ActionsGraphQLHandlerFactory.js.map +1 -0
  53. package/dist/src/graphql/http/ActionsWebsocketControllerFactory.d.ts +11 -0
  54. package/dist/src/graphql/http/ActionsWebsocketControllerFactory.d.ts.map +1 -0
  55. package/dist/src/graphql/http/ActionsWebsocketControllerFactory.js +150 -0
  56. package/dist/src/graphql/http/ActionsWebsocketControllerFactory.js.map +1 -0
  57. package/dist/src/graphql/resolvers/ActionsContext.d.ts +9 -0
  58. package/dist/src/graphql/resolvers/ActionsContext.d.ts.map +1 -0
  59. package/dist/src/graphql/resolvers/ActionsContext.js +3 -0
  60. package/dist/src/graphql/resolvers/ActionsContext.js.map +1 -0
  61. package/dist/src/graphql/resolvers/ResolversFactory.d.ts +13 -0
  62. package/dist/src/graphql/resolvers/ResolversFactory.d.ts.map +1 -0
  63. package/dist/src/graphql/resolvers/ResolversFactory.js +32 -0
  64. package/dist/src/graphql/resolvers/ResolversFactory.js.map +1 -0
  65. package/dist/src/graphql/resolvers/index.d.ts +3 -0
  66. package/dist/src/graphql/resolvers/index.d.ts.map +1 -0
  67. package/dist/src/graphql/resolvers/index.js +19 -0
  68. package/dist/src/graphql/resolvers/index.js.map +1 -0
  69. package/dist/src/graphql/resolvers/mutation/ProcessBatchMutationResolver.d.ts +11 -0
  70. package/dist/src/graphql/resolvers/mutation/ProcessBatchMutationResolver.d.ts.map +1 -0
  71. package/dist/src/graphql/resolvers/mutation/ProcessBatchMutationResolver.js +16 -0
  72. package/dist/src/graphql/resolvers/mutation/ProcessBatchMutationResolver.js.map +1 -0
  73. package/dist/src/graphql/resolvers/mutation/SetVariablesMutationResolver.d.ts +11 -0
  74. package/dist/src/graphql/resolvers/mutation/SetVariablesMutationResolver.d.ts.map +1 -0
  75. package/dist/src/graphql/resolvers/mutation/SetVariablesMutationResolver.js +16 -0
  76. package/dist/src/graphql/resolvers/mutation/SetVariablesMutationResolver.js.map +1 -0
  77. package/dist/src/graphql/resolvers/mutation/index.d.ts +3 -0
  78. package/dist/src/graphql/resolvers/mutation/index.d.ts.map +1 -0
  79. package/dist/src/graphql/resolvers/mutation/index.js +19 -0
  80. package/dist/src/graphql/resolvers/mutation/index.js.map +1 -0
  81. package/dist/src/graphql/resolvers/query/EventsQueryResolver.d.ts +11 -0
  82. package/dist/src/graphql/resolvers/query/EventsQueryResolver.d.ts.map +1 -0
  83. package/dist/src/graphql/resolvers/query/EventsQueryResolver.js +43 -0
  84. package/dist/src/graphql/resolvers/query/EventsQueryResolver.js.map +1 -0
  85. package/dist/src/graphql/resolvers/query/VariablesQueryResolver.d.ts +12 -0
  86. package/dist/src/graphql/resolvers/query/VariablesQueryResolver.d.ts.map +1 -0
  87. package/dist/src/graphql/resolvers/query/VariablesQueryResolver.js +16 -0
  88. package/dist/src/graphql/resolvers/query/VariablesQueryResolver.js.map +1 -0
  89. package/dist/src/graphql/resolvers/query/index.d.ts +2 -0
  90. package/dist/src/graphql/resolvers/query/index.d.ts.map +1 -0
  91. package/dist/src/graphql/resolvers/query/index.js +18 -0
  92. package/dist/src/graphql/resolvers/query/index.js.map +1 -0
  93. package/dist/src/graphql/schema/actions.graphql.d.ts +3 -0
  94. package/dist/src/graphql/schema/actions.graphql.d.ts.map +1 -0
  95. package/dist/src/graphql/schema/actions.graphql.js +93 -0
  96. package/dist/src/graphql/schema/actions.graphql.js.map +1 -0
  97. package/dist/src/graphql/schema/index.d.ts +224 -0
  98. package/dist/src/graphql/schema/index.d.ts.map +1 -0
  99. package/dist/src/graphql/schema/index.js +3 -0
  100. package/dist/src/graphql/schema/index.js.map +1 -0
  101. package/dist/src/index.d.ts +13 -0
  102. package/dist/src/index.d.ts.map +1 -0
  103. package/dist/src/index.js +81 -0
  104. package/dist/src/index.js.map +1 -0
  105. package/dist/src/migrations/2023-03-10-145000-actions-variables.d.ts +3 -0
  106. package/dist/src/migrations/2023-03-10-145000-actions-variables.d.ts.map +1 -0
  107. package/dist/src/migrations/2023-03-10-145000-actions-variables.js +17 -0
  108. package/dist/src/migrations/2023-03-10-145000-actions-variables.js.map +1 -0
  109. package/dist/src/migrations/index.d.ts +3 -0
  110. package/dist/src/migrations/index.d.ts.map +1 -0
  111. package/dist/src/migrations/index.js +13 -0
  112. package/dist/src/migrations/index.js.map +1 -0
  113. package/dist/src/migrations/snapshot.d.ts +3 -0
  114. package/dist/src/migrations/snapshot.d.ts.map +1 -0
  115. package/dist/src/migrations/snapshot.js +49 -0
  116. package/dist/src/migrations/snapshot.js.map +1 -0
  117. package/dist/src/model/EventsInProcessingQuery.d.ts +9 -0
  118. package/dist/src/model/EventsInProcessingQuery.d.ts.map +1 -0
  119. package/dist/src/model/EventsInProcessingQuery.js +22 -0
  120. package/dist/src/model/EventsInProcessingQuery.js.map +1 -0
  121. package/dist/src/model/EventsToProcessQuery.d.ts +9 -0
  122. package/dist/src/model/EventsToProcessQuery.d.ts.map +1 -0
  123. package/dist/src/model/EventsToProcessQuery.js +22 -0
  124. package/dist/src/model/EventsToProcessQuery.js.map +1 -0
  125. package/dist/src/model/EventsToProcessSpecification.d.ts +4 -0
  126. package/dist/src/model/EventsToProcessSpecification.d.ts.map +1 -0
  127. package/dist/src/model/EventsToProcessSpecification.js +14 -0
  128. package/dist/src/model/EventsToProcessSpecification.js.map +1 -0
  129. package/dist/src/model/FailedEventsQuery.d.ts +9 -0
  130. package/dist/src/model/FailedEventsQuery.d.ts.map +1 -0
  131. package/dist/src/model/FailedEventsQuery.js +22 -0
  132. package/dist/src/model/FailedEventsQuery.js.map +1 -0
  133. package/dist/src/model/SetVariableCommand.d.ts +8 -0
  134. package/dist/src/model/SetVariableCommand.d.ts.map +1 -0
  135. package/dist/src/model/SetVariableCommand.js +26 -0
  136. package/dist/src/model/SetVariableCommand.js.map +1 -0
  137. package/dist/src/model/VariablesManager.d.ts +8 -0
  138. package/dist/src/model/VariablesManager.d.ts.map +1 -0
  139. package/dist/src/model/VariablesManager.js +46 -0
  140. package/dist/src/model/VariablesManager.js.map +1 -0
  141. package/dist/src/model/VariablesQuery.d.ts +12 -0
  142. package/dist/src/model/VariablesQuery.d.ts.map +1 -0
  143. package/dist/src/model/VariablesQuery.js +13 -0
  144. package/dist/src/model/VariablesQuery.js.map +1 -0
  145. package/dist/src/model/types.d.ts +16 -0
  146. package/dist/src/model/types.d.ts.map +1 -0
  147. package/dist/src/model/types.js +3 -0
  148. package/dist/src/model/types.js.map +1 -0
  149. package/dist/src/triggers/Payload.d.ts +62 -0
  150. package/dist/src/triggers/Payload.d.ts.map +1 -0
  151. package/dist/src/triggers/Payload.js +3 -0
  152. package/dist/src/triggers/Payload.js.map +1 -0
  153. package/dist/src/triggers/TriggerHandler.d.ts +26 -0
  154. package/dist/src/triggers/TriggerHandler.d.ts.map +1 -0
  155. package/dist/src/triggers/TriggerHandler.js +130 -0
  156. package/dist/src/triggers/TriggerHandler.js.map +1 -0
  157. package/dist/src/triggers/TriggerIndirectChangesFetcher.d.ts +11 -0
  158. package/dist/src/triggers/TriggerIndirectChangesFetcher.d.ts.map +1 -0
  159. package/dist/src/triggers/TriggerIndirectChangesFetcher.js +24 -0
  160. package/dist/src/triggers/TriggerIndirectChangesFetcher.js.map +1 -0
  161. package/dist/src/triggers/TriggerListeners.d.ts +9 -0
  162. package/dist/src/triggers/TriggerListeners.d.ts.map +1 -0
  163. package/dist/src/triggers/TriggerListeners.js +3 -0
  164. package/dist/src/triggers/TriggerListeners.js.map +1 -0
  165. package/dist/src/triggers/TriggerListenersBuilder.d.ts +15 -0
  166. package/dist/src/triggers/TriggerListenersBuilder.d.ts.map +1 -0
  167. package/dist/src/triggers/TriggerListenersBuilder.js +169 -0
  168. package/dist/src/triggers/TriggerListenersBuilder.js.map +1 -0
  169. package/dist/src/triggers/TriggerListenersFactory.d.ts +8 -0
  170. package/dist/src/triggers/TriggerListenersFactory.d.ts.map +1 -0
  171. package/dist/src/triggers/TriggerListenersFactory.js +18 -0
  172. package/dist/src/triggers/TriggerListenersFactory.js.map +1 -0
  173. package/dist/src/triggers/TriggerListenersStore.d.ts +48 -0
  174. package/dist/src/triggers/TriggerListenersStore.d.ts.map +1 -0
  175. package/dist/src/triggers/TriggerListenersStore.js +30 -0
  176. package/dist/src/triggers/TriggerListenersStore.js.map +1 -0
  177. package/dist/src/triggers/TriggerPayloadBuilder.d.ts +14 -0
  178. package/dist/src/triggers/TriggerPayloadBuilder.d.ts.map +1 -0
  179. package/dist/src/triggers/TriggerPayloadBuilder.js +140 -0
  180. package/dist/src/triggers/TriggerPayloadBuilder.js.map +1 -0
  181. package/dist/src/triggers/TriggerPayloadManager.d.ts +27 -0
  182. package/dist/src/triggers/TriggerPayloadManager.d.ts.map +1 -0
  183. package/dist/src/triggers/TriggerPayloadManager.js +26 -0
  184. package/dist/src/triggers/TriggerPayloadManager.js.map +1 -0
  185. package/dist/src/triggers/TriggerPayloadPersister.d.ts +18 -0
  186. package/dist/src/triggers/TriggerPayloadPersister.d.ts.map +1 -0
  187. package/dist/src/triggers/TriggerPayloadPersister.js +44 -0
  188. package/dist/src/triggers/TriggerPayloadPersister.js.map +1 -0
  189. package/dist/src/triggers/index.d.ts +8 -0
  190. package/dist/src/triggers/index.d.ts.map +1 -0
  191. package/dist/src/triggers/index.js +24 -0
  192. package/dist/src/triggers/index.js.map +1 -0
  193. package/dist/src/tsconfig.tsbuildinfo +1 -0
  194. package/dist/src/utils/assertNever.d.ts +2 -0
  195. package/dist/src/utils/assertNever.d.ts.map +1 -0
  196. package/dist/src/utils/assertNever.js +8 -0
  197. package/dist/src/utils/assertNever.js.map +1 -0
  198. package/dist/src/utils/map.d.ts +2 -0
  199. package/dist/src/utils/map.d.ts.map +1 -0
  200. package/dist/src/utils/map.js +14 -0
  201. package/dist/src/utils/map.js.map +1 -0
  202. package/dist/tests/cases/integration/triggers.manyHasManyWatch.test.d.ts +2 -0
  203. package/dist/tests/cases/integration/triggers.manyHasManyWatch.test.d.ts.map +1 -0
  204. package/dist/tests/cases/integration/triggers.manyHasManyWatch.test.js +442 -0
  205. package/dist/tests/cases/integration/triggers.manyHasManyWatch.test.js.map +1 -0
  206. package/dist/tests/cases/integration/triggers.manyHasOneWatch.test.d.ts +2 -0
  207. package/dist/tests/cases/integration/triggers.manyHasOneWatch.test.d.ts.map +1 -0
  208. package/dist/tests/cases/integration/triggers.manyHasOneWatch.test.js +449 -0
  209. package/dist/tests/cases/integration/triggers.manyHasOneWatch.test.js.map +1 -0
  210. package/dist/tests/cases/integration/triggers.rootWatch.test.d.ts +2 -0
  211. package/dist/tests/cases/integration/triggers.rootWatch.test.d.ts.map +1 -0
  212. package/dist/tests/cases/integration/triggers.rootWatch.test.js +159 -0
  213. package/dist/tests/cases/integration/triggers.rootWatch.test.js.map +1 -0
  214. package/dist/tests/cases/integration/utils.d.ts +4 -0
  215. package/dist/tests/cases/integration/utils.d.ts.map +1 -0
  216. package/dist/tests/cases/integration/utils.js +12 -0
  217. package/dist/tests/cases/integration/utils.js.map +1 -0
  218. package/dist/tests/cases/unit/generator.test.d.ts +2 -0
  219. package/dist/tests/cases/unit/generator.test.d.ts.map +1 -0
  220. package/dist/tests/cases/unit/generator.test.js +627 -0
  221. package/dist/tests/cases/unit/generator.test.js.map +1 -0
  222. package/dist/tests/src/gql.d.ts +2 -0
  223. package/dist/tests/src/gql.d.ts.map +1 -0
  224. package/dist/tests/src/gql.js +14 -0
  225. package/dist/tests/src/gql.js.map +1 -0
  226. package/dist/tests/tsconfig.tsbuildinfo +1 -0
  227. package/graphql-actions.codegen.yml +21 -0
  228. package/package.json +41 -0
  229. package/src/ActionsExecutionContainerHookFactory.ts +28 -0
  230. package/src/ImplementationException.ts +2 -0
  231. package/src/ListenerStoreProvider.ts +17 -0
  232. package/src/dispatch/DispatchWorkerSupervisor.ts +137 -0
  233. package/src/dispatch/EventDispatcher.ts +64 -0
  234. package/src/dispatch/EventsRepository.ts +165 -0
  235. package/src/dispatch/ProjectDispatcher.ts +119 -0
  236. package/src/dispatch/TargetHandlerResolver.ts +18 -0
  237. package/src/dispatch/WebhookTargetHandler.ts +88 -0
  238. package/src/dispatch/types.ts +31 -0
  239. package/src/graphql/http/ActionsApiMiddlewareFactory.ts +36 -0
  240. package/src/graphql/http/ActionsContextResolver.ts +38 -0
  241. package/src/graphql/http/ActionsGraphQLHandlerFactory.ts +23 -0
  242. package/src/graphql/http/ActionsWebsocketControllerFactory.ts +143 -0
  243. package/src/graphql/resolvers/ActionsContext.ts +9 -0
  244. package/src/graphql/resolvers/ResolversFactory.ts +35 -0
  245. package/src/graphql/resolvers/index.ts +2 -0
  246. package/src/graphql/resolvers/mutation/ProcessBatchMutationResolver.ts +16 -0
  247. package/src/graphql/resolvers/mutation/SetVariablesMutationResolver.ts +19 -0
  248. package/src/graphql/resolvers/mutation/index.ts +2 -0
  249. package/src/graphql/resolvers/query/EventsQueryResolver.ts +55 -0
  250. package/src/graphql/resolvers/query/VariablesQueryResolver.ts +18 -0
  251. package/src/graphql/resolvers/query/index.ts +1 -0
  252. package/src/graphql/schema/actions.graphql.ts +91 -0
  253. package/src/graphql/schema/index.ts +295 -0
  254. package/src/index.ts +88 -0
  255. package/src/migrations/2023-03-10-145000-actions-variables.ts +16 -0
  256. package/src/migrations/index.ts +7 -0
  257. package/src/migrations/snapshot.ts +47 -0
  258. package/src/model/EventsInProcessingQuery.ts +21 -0
  259. package/src/model/EventsToProcessQuery.ts +21 -0
  260. package/src/model/EventsToProcessSpecification.ts +11 -0
  261. package/src/model/FailedEventsQuery.ts +21 -0
  262. package/src/model/SetVariableCommand.ts +26 -0
  263. package/src/model/VariablesManager.ts +49 -0
  264. package/src/model/VariablesQuery.ts +17 -0
  265. package/src/model/types.ts +15 -0
  266. package/src/triggers/Payload.ts +82 -0
  267. package/src/triggers/TriggerHandler.ts +161 -0
  268. package/src/triggers/TriggerIndirectChangesFetcher.ts +30 -0
  269. package/src/triggers/TriggerListeners.ts +16 -0
  270. package/src/triggers/TriggerListenersBuilder.ts +190 -0
  271. package/src/triggers/TriggerListenersFactory.ts +19 -0
  272. package/src/triggers/TriggerListenersStore.ts +76 -0
  273. package/src/triggers/TriggerPayloadBuilder.ts +148 -0
  274. package/src/triggers/TriggerPayloadManager.ts +47 -0
  275. package/src/triggers/TriggerPayloadPersister.ts +43 -0
  276. package/src/triggers/index.ts +7 -0
  277. package/src/tsconfig.json +21 -0
  278. package/src/utils/assertNever.ts +3 -0
  279. package/src/utils/map.ts +13 -0
  280. package/tests/cases/integration/triggers.manyHasManyWatch.test.ts +437 -0
  281. package/tests/cases/integration/triggers.manyHasOneWatch.test.ts +446 -0
  282. package/tests/cases/integration/triggers.rootWatch.test.ts +152 -0
  283. package/tests/cases/integration/utils.ts +9 -0
  284. package/tests/cases/unit/generator.test.ts +689 -0
  285. package/tests/src/gql.ts +7 -0
  286. package/tests/tsconfig.json +16 -0
  287. package/tsconfig.json +5 -0
  288. package/tsconfig.settings.json +8 -0
  289. package/vite.config.js +3 -0
@@ -0,0 +1,21 @@
1
+ schema:
2
+ - "./src/graphql/schema/actions.graphql.ts"
3
+ documents: []
4
+ config:
5
+ immutableTypes: "1"
6
+ generates:
7
+ ./src/graphql/schema/index.ts:
8
+ config:
9
+ immutableTypes: "1"
10
+ enumsAsTypes: "1"
11
+ scalars:
12
+ DateTime: Date
13
+ Uuid: String
14
+ Json: any
15
+ plugins:
16
+ - "typescript"
17
+ - "typescript-operations"
18
+ - "typescript-resolvers"
19
+ hooks:
20
+ afterAllFileWrite:
21
+ - eslint --fix
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@contember/engine-actions",
3
+ "version": "1.3.0-alpha.4",
4
+ "license": "proprietary",
5
+ "main": "dist/src/index.js",
6
+ "typings": "dist/src/index.d.ts",
7
+ "scripts": {
8
+ "generate": "gql-gen --config graphql-actions.codegen.yml",
9
+ "test": "vitest"
10
+ },
11
+ "dependencies": {
12
+ "@contember/database": "^1.3.0-alpha.4",
13
+ "@contember/database-migrations": "^1.3.0-alpha.4",
14
+ "@contember/engine-common": "^1.3.0-alpha.4",
15
+ "@contember/engine-content-api": "^1.3.0-alpha.4",
16
+ "@contember/engine-system-api": "^1.3.0-alpha.4",
17
+ "@contember/engine-tenant-api": "^1.3.0-alpha.4",
18
+ "@contember/engine-http": "^1.3.0-alpha.4",
19
+ "@contember/engine-plugins": "^1.3.0-alpha.4",
20
+ "@contember/graphql-utils": "^1.3.0-alpha.4",
21
+ "@contember/schema": "^1.3.0-alpha.4",
22
+ "@contember/schema-utils": "^1.3.0-alpha.4",
23
+ "@contember/typesafe": "^1.3.0-alpha.4",
24
+ "@contember/logger": "^1.3.0-alpha.4",
25
+ "@graphql-tools/schema": "^8.3.5",
26
+ "graphql-tag": "^2.12.5"
27
+ },
28
+ "devDependencies": {
29
+ "@contember/engine-api-tester": "^1.3.0-alpha.4",
30
+ "@graphql-codegen/cli": "^2.6.2",
31
+ "@graphql-codegen/typescript": "^2.5.1",
32
+ "@graphql-codegen/typescript-operations": "^2.4.2",
33
+ "@graphql-codegen/typescript-resolvers": "^2.6.6",
34
+ "@types/ws": "^8.5.3",
35
+ "graphql": "^16.5.0"
36
+ },
37
+ "peerDependencies": {
38
+ "graphql": ">= 14.6.0",
39
+ "pg": "^8.5.0"
40
+ }
41
+ }
@@ -0,0 +1,28 @@
1
+ import { TriggerHandler, TriggerIndirectChangesFetcher, TriggerPayloadManager } from './triggers'
2
+ import { ListenerStoreProvider } from './ListenerStoreProvider'
3
+ import { TriggerPayloadBuilder } from './triggers/TriggerPayloadBuilder'
4
+ import { TriggerPayloadPersister } from './triggers/TriggerPayloadPersister'
5
+ import { ExecutionContainerHook } from '@contember/engine-content-api'
6
+
7
+ export class ActionsExecutionContainerHookFactory {
8
+ constructor(
9
+ private readonly listenerStoreProvider: ListenerStoreProvider,
10
+ ) {
11
+ }
12
+
13
+ create(): ExecutionContainerHook {
14
+ return builder => {
15
+ return builder.setupService('mapperFactory', (mapperFactory, { whereBuilder, schema, pathFactory, systemSchema, providers, stage, project }) => {
16
+ mapperFactory.hooks.push(mapper => {
17
+ const triggerPayloadPersister = new TriggerPayloadPersister(mapper, mapper.db.forSchema(systemSchema), providers, project.slug, stage.id, schema.id)
18
+ const triggerPayloadBuilder = new TriggerPayloadBuilder(mapper)
19
+ const payloadManager = new TriggerPayloadManager(triggerPayloadBuilder, triggerPayloadPersister)
20
+ const changesFetcher = new TriggerIndirectChangesFetcher(mapper, whereBuilder, pathFactory)
21
+ const listenersStore = this.listenerStoreProvider.getListenerStore(schema)
22
+ const triggerHandler = new TriggerHandler(payloadManager, listenersStore, changesFetcher)
23
+ triggerHandler.attach(mapper.eventManager)
24
+ })
25
+ })
26
+ }
27
+ }
28
+ }
@@ -0,0 +1,2 @@
1
+ export class ImplementationException extends Error {
2
+ }
@@ -0,0 +1,17 @@
1
+ import { TriggerListenersFactory, TriggerListenersStore } from './triggers'
2
+ import { Schema } from '@contember/schema'
3
+
4
+ export class ListenerStoreProvider {
5
+ private listenersStoreCache = new WeakMap<Schema, TriggerListenersStore>()
6
+
7
+ public getListenerStore(schema: Schema): TriggerListenersStore {
8
+ const currentStore = this.listenersStoreCache.get(schema)
9
+ if (currentStore) {
10
+ return currentStore
11
+ }
12
+ const listenersFactory = new TriggerListenersFactory(schema)
13
+ const newStore = listenersFactory.create()
14
+ this.listenersStoreCache.set(schema, newStore)
15
+ return newStore
16
+ }
17
+ }
@@ -0,0 +1,137 @@
1
+ import { ProjectContainer, ProjectGroupContainer } from '@contember/engine-http'
2
+ import { AcquiringListener } from '@contember/database'
3
+ import { Runnable, RunnableArgs, Running, Supervisor } from '@contember/engine-common'
4
+ import { ProjectDispatcherFactory } from './ProjectDispatcher'
5
+ import { Logger } from '@contember/logger'
6
+ import { ImplementationException } from '../ImplementationException'
7
+
8
+ export class DispatchWorkerSupervisorFactory {
9
+
10
+ constructor(
11
+ private projectDispatcherFactory: ProjectDispatcherFactory,
12
+ ) {
13
+ }
14
+
15
+ public create(projectGroup: ProjectGroupContainer): DispatchWorkerSupervisor {
16
+ return new DispatchWorkerSupervisor(this.projectDispatcherFactory, projectGroup)
17
+ }
18
+ }
19
+
20
+ export class DispatchWorkerSupervisor implements Runnable {
21
+ constructor(
22
+ private projectDispatcherFactory: ProjectDispatcherFactory,
23
+ private projectGroup: ProjectGroupContainer,
24
+ ) {
25
+ }
26
+
27
+ public async run({ logger, onError }: RunnableArgs) {
28
+ const projectGroup = this.projectGroup
29
+ const tenantContainer = projectGroup.tenantContainer
30
+ const projectContainerResolver = projectGroup.projectContainerResolver
31
+
32
+ const running = new Map<string, { worker: Promise<Running>; container: ProjectContainer }>()
33
+
34
+ const cleanupListener = projectContainerResolver.on('destroy', async ({ container }) => {
35
+ const runningForProject = running.get(container.project.slug)
36
+ if (!runningForProject) {
37
+ return
38
+ }
39
+ running.delete(container.project.slug)
40
+ await (await runningForProject.worker).end()
41
+ })
42
+
43
+ const refreshProjectWorker = async (container: ProjectContainer, isReloading: boolean) => {
44
+ const db = container.systemDatabaseContextFactory.create()
45
+ const current = running.get(container.project.slug)
46
+ if (current && current.container === container) {
47
+ return
48
+ }
49
+ const dispatcher = this.projectDispatcherFactory.create({
50
+ db,
51
+ contentSchemaResolver: container.contentSchemaResolver,
52
+ projectSlug: container.project.slug,
53
+ })
54
+ const supervisedDispatcher = new Supervisor(
55
+ dispatcher,
56
+ { startupMax: isReloading ? Number.MAX_VALUE : 10 },
57
+ )
58
+ const worker = supervisedDispatcher.run({
59
+ logger,
60
+ onError: () => {
61
+ throw new ImplementationException('supervised project dispatcher crashed')
62
+ },
63
+ })
64
+ running.set(container.project.slug, { worker, container })
65
+ try {
66
+ if (current) {
67
+ await (await current.worker).end()
68
+ }
69
+ await worker
70
+ logger.debug('Project dispatch worker started', { project: container.project.slug })
71
+ } catch (e) {
72
+ logger.error(e, { message: 'Project dispatch worker start failed', project: container.project.slug })
73
+ running.delete(container.project.slug)
74
+ throw e
75
+ }
76
+ }
77
+ const projectTracker = new Supervisor(new AcquiringListener(
78
+ tenantContainer.databaseContext.client,
79
+ 'project_updated',
80
+ async () => {
81
+ logger.debug('Project config change detected, reloading dispatch workers')
82
+ await endProjectWorkers()
83
+ try {
84
+ await startWorkers(true)
85
+ } catch (e) {
86
+ logger.error(e, { message: 'Dispatch workers reload failed, terminating' })
87
+ await endAll()
88
+ onError(e)
89
+ }
90
+ },
91
+ ))
92
+
93
+ const runningProjectTracker = await projectTracker.run({
94
+ logger,
95
+ onError: () => {
96
+ throw new ImplementationException('supervised project tracker crashed')
97
+ },
98
+ })
99
+ const fetchProjects = async () => await tenantContainer.projectManager.getProjects(tenantContainer.databaseContext)
100
+
101
+ const startWorkers = async (isReloading: boolean) => {
102
+ try {
103
+ const projects = await fetchProjects()
104
+ for (const project of projects) {
105
+ const container = await projectGroup.projectContainerResolver.getProjectContainer(project.slug)
106
+ if (container) {
107
+ await refreshProjectWorker(container, isReloading)
108
+ }
109
+ }
110
+ } catch (e) {
111
+ await endAll()
112
+ throw e
113
+ }
114
+ }
115
+ const endProjectWorkers = async () => {
116
+ const workers = [...running.values()]
117
+ running.clear()
118
+ await Promise.allSettled(workers.map(async ({ worker }) => await (await worker).end()))
119
+ }
120
+ const endAll = async () => {
121
+ logger.debug('Terminating project dispatch workers...')
122
+ cleanupListener()
123
+ try {
124
+ await runningProjectTracker.end()
125
+ } catch {
126
+ }
127
+ await endProjectWorkers()
128
+ logger.debug('Project dispatch workers terminated')
129
+ }
130
+
131
+ await startWorkers(false)
132
+
133
+ return {
134
+ end: endAll,
135
+ }
136
+ }
137
+ }
@@ -0,0 +1,64 @@
1
+ import { EventsRepository } from './EventsRepository'
2
+ import { TargetHandlerResolver } from './TargetHandlerResolver'
3
+ import { HandledEvent } from './types'
4
+ import { Logger } from '@contember/logger'
5
+ import { ContentSchemaResolver } from '@contember/engine-http'
6
+ import { DatabaseContext } from '@contember/engine-system-api'
7
+ import { VariablesManager } from '../model/VariablesManager'
8
+
9
+
10
+ type ProcessBatchArgs = {
11
+ db: DatabaseContext
12
+ contentSchemaResolver: ContentSchemaResolver
13
+ logger: Logger
14
+ }
15
+
16
+ type ProcessBatchResult = {
17
+ succeed: number
18
+ failed: number
19
+ backoffMs: number | undefined
20
+ }
21
+
22
+ export class EventDispatcher {
23
+
24
+ constructor(
25
+ private readonly eventsRepository: EventsRepository,
26
+ private readonly variablesManager: VariablesManager,
27
+ private readonly invokeResolver: TargetHandlerResolver,
28
+ ) {
29
+ }
30
+
31
+ async processBatch({ db, contentSchemaResolver, logger }: ProcessBatchArgs): Promise<ProcessBatchResult> {
32
+ const schema = await contentSchemaResolver.getSchema(db)
33
+ const batch = await this.eventsRepository.fetchBatch(schema.actions, db.client)
34
+ const batchId = Math.random().toString().substring(2)
35
+ const batchLogger = logger.child({ loc: 'Actions.EventDispatcher', batchId })
36
+ if (!batch.ok) {
37
+ batchLogger.debug('Nothing to process', {
38
+ backoffMs: batch.backoffMs ?? 'undefined',
39
+ })
40
+ return { failed: 0, succeed: 0, backoffMs: batch.backoffMs }
41
+ }
42
+ const { target, events } = batch
43
+ try {
44
+ const handler = this.invokeResolver.resolveHandler(target)
45
+ batchLogger.debug('Processing started', {
46
+ events: batch.events.map(it => it.id),
47
+ })
48
+ const variables = await this.variablesManager.fetchVariables(db)
49
+ const handledEvents = await handler.handle({ target, events, logger: batchLogger, variables })
50
+ const [succeed, failed] = await this.eventsRepository.persistProcessed(db.client, handledEvents)
51
+ batchLogger.debug('Processing done', { succeed, failed })
52
+ return { succeed, failed, backoffMs: 0 }
53
+ } catch (e) {
54
+ logger.error(e, { loc: 'EventDispatcher', batchId })
55
+ const failedEvents = events.map((it): HandledEvent => ({
56
+ row: it,
57
+ result: { ok: false, errorMessage: `Internal error` },
58
+ }))
59
+ await this.eventsRepository.persistProcessed(db.client, failedEvents)
60
+
61
+ return { succeed: 0, failed: batch.events.length, backoffMs: 0 }
62
+ }
63
+ }
64
+ }
@@ -0,0 +1,165 @@
1
+ import {
2
+ Client,
3
+ Connection,
4
+ Literal,
5
+ LockModifier,
6
+ LockType,
7
+ Operator,
8
+ SelectBuilder,
9
+ UpdateBuilder,
10
+ } from '@contember/database'
11
+ import { EventRow, HandledEvent } from './types'
12
+ import { Actions } from '@contember/schema'
13
+ import { eventsToProcessSpecification, eventsToProcessStateSpecification } from '../model/EventsToProcessSpecification'
14
+
15
+
16
+ const ACK_TIMEOUT_MS = 1_000 * 60 * 10 // 10 minutes
17
+ const DEFAULT_REPEAT_INTERVAL_MS = 5_000 // 5 seconds
18
+ const DEFAULT_MAX_ATTEMPTS = 10
19
+ const DEFAULT_BATCH_SIZE = 20
20
+
21
+ export class EventsRepository {
22
+
23
+ public async fetchBatch(actions: Actions.Schema, db: Client): Promise<FetchBatchResult> {
24
+ const primaryEvent = (await this.fetchInternal(db, 1))[0]
25
+ if (!primaryEvent) {
26
+ return { ok: false, backoffMs: await this.fetchBackOff(db) }
27
+ }
28
+ const target = actions.targets[primaryEvent.target]
29
+ if (!target) {
30
+ await this.markFailedOnUnknownTarget(db, primaryEvent.target, primaryEvent.id)
31
+ return await this.fetchBatch(actions, db)
32
+ }
33
+ const batchSize = (target.batchSize ?? DEFAULT_BATCH_SIZE) - 1
34
+ const batch = batchSize > 0 ? await this.fetchInternal(db, batchSize) : []
35
+ return { ok: true, events: [primaryEvent, ...batch], target }
36
+ }
37
+
38
+
39
+ private async fetchBackOff(db: Client): Promise<number | undefined> {
40
+ const result = await SelectBuilder.create<{ ms: number }>()
41
+ .from('actions_event')
42
+ .match(eventsToProcessStateSpecification)
43
+ .select(it => it.raw('ceil(extract(epoch from visible_at - now()) * 1000)'), 'ms')
44
+ .orderBy('visible_at', 'asc')
45
+ .limit(1)
46
+ .getResult(db)
47
+
48
+ return result.length ? Math.max(0, result[0].ms) : undefined
49
+ }
50
+
51
+
52
+ private async fetchInternal(db: Client, limit: number, targetName?: string): Promise<EventRow[]> {
53
+ const visibleAt = new Date()
54
+ visibleAt.setTime(visibleAt.getTime() + ACK_TIMEOUT_MS)
55
+ return await UpdateBuilder.create()
56
+ .table('actions_event')
57
+ .with('events', qb => qb
58
+ .select(it => it.raw('*'))
59
+ .from('actions_event')
60
+ .match(eventsToProcessSpecification)
61
+ .where(targetName ? { target: targetName } : {})
62
+ .limit(limit)
63
+ .lock(LockType.forNoKeyUpdate, LockModifier.skipLocked),
64
+ )
65
+ .values<EventRow>({
66
+ state: 'processing',
67
+ last_state_change: new Date(),
68
+ visible_at: visibleAt,
69
+ })
70
+ .from(it => it.from('events').where(it => it.columnsEq(['events', 'id'], ['actions_event', 'id'])))
71
+ .returning<EventRow>(new Literal('*'))
72
+ .execute(db)
73
+ }
74
+
75
+ public async persistProcessed(db: Client, events: HandledEvent[]): Promise<[number, number]> {
76
+ return await db.transaction(async trx => {
77
+ await trx.query(Connection.REPEATABLE_READ)
78
+ const succeed = events.filter(it => it.result.ok)
79
+ await this.markSucceed(trx, succeed.map(it => it.row))
80
+
81
+ for (const event of events) {
82
+ if (!event.result.ok) {
83
+ await this.markFailed(trx, event)
84
+ }
85
+ }
86
+ return [succeed.length, events.length - succeed.length]
87
+ })
88
+ }
89
+
90
+ public async requeue(db: Client, events: EventRow[]): Promise<void> {
91
+ await UpdateBuilder.create()
92
+ .table('actions_event')
93
+ .values<EventRow>({
94
+ state: it => it.raw('CASE WHEN num_retries = 0 THEN ? ELSE ? END', 'created', 'retrying'),
95
+ last_state_change: new Date(),
96
+ visible_at: new Date(),
97
+ })
98
+ .where(it => it.in('id', events.map(it => it.id)))
99
+ .execute(db)
100
+ }
101
+
102
+ private async markSucceed(db: Client, rows: EventRow[]): Promise<void> {
103
+ const now = new Date()
104
+ await UpdateBuilder.create()
105
+ .table('actions_event')
106
+ .values<EventRow>({
107
+ state: 'succeed',
108
+ num_retries: it => it.raw('num_retries + 1'),
109
+ resolved_at: now,
110
+ last_state_change: now,
111
+ })
112
+ .where(it => it.in('id', rows.map(it => it.id)))
113
+ .execute(db)
114
+ }
115
+
116
+ private async markFailed(db: Client, event: HandledEvent): Promise<void> {
117
+ const numRetries = event.row.num_retries
118
+ const now = new Date()
119
+ const nextAttempt = new Date()
120
+ nextAttempt.setTime(nextAttempt.getTime() + (event.target?.initialRepeatIntervalMs ?? DEFAULT_REPEAT_INTERVAL_MS) * Math.pow(2, event.row.num_retries))
121
+ await UpdateBuilder.create()
122
+ .table('actions_event')
123
+ .values<EventRow>({
124
+ last_state_change: now,
125
+ num_retries: event.row.num_retries + 1,
126
+ log: JSON.stringify([...event.row.log, event.result]) as any,
127
+ ...(numRetries < (event.target?.maxAttempts ?? DEFAULT_MAX_ATTEMPTS) ? {
128
+ state: 'retrying',
129
+ visible_at: nextAttempt,
130
+ } : {
131
+ state: 'failed',
132
+ }),
133
+ })
134
+ .where({ id: event.row.id })
135
+ .execute(db)
136
+ }
137
+
138
+ private async markFailedOnUnknownTarget(db: Client, targetName: string, primaryEventId: string) {
139
+ await UpdateBuilder.create()
140
+ .table('actions_event')
141
+ .where(it => it.or(it => it
142
+ .and(it => it
143
+ .in('state', ['retrying', 'created', 'processing'])
144
+ .compare('visible_at', Operator.lte, 'now')
145
+ .compare('target', Operator.eq, targetName),
146
+ )
147
+ .and(it => it
148
+ .compare('id', Operator.eq, primaryEventId),
149
+ ),
150
+ ))
151
+ .values<EventRow>({
152
+ // intentionally not retrying
153
+ last_state_change: new Date(),
154
+ num_retries: it => it.raw('num_retries + 1'),
155
+ log: it => it.raw('log || ?::jsonb', { ok: false, errorMessage: `Event target ${targetName} not found, stopping.` }),
156
+ state: 'failed',
157
+ resolved_at: new Date(),
158
+ })
159
+ .execute(db)
160
+ }
161
+ }
162
+
163
+ export type FetchBatchResult =
164
+ | { ok: true; events: EventRow[]; target: Actions.AnyTarget }
165
+ | { ok: false; backoffMs?: number }
@@ -0,0 +1,119 @@
1
+ import { DatabaseContext } from '@contember/engine-system-api'
2
+ import { EventDispatcher } from './EventDispatcher'
3
+ import { ContentSchemaResolver } from '@contember/engine-http'
4
+ import { Runnable, RunnableArgs, Running } from '@contember/engine-common'
5
+ import { Listener } from '@contember/database'
6
+ import { NOTIFY_CHANNEL_NAME } from '../triggers/TriggerPayloadPersister'
7
+
8
+
9
+ export class ProjectDispatcherFactory {
10
+ constructor(
11
+ private readonly dispatcher: EventDispatcher,
12
+ ) {
13
+ }
14
+
15
+ public create({ db, contentSchemaResolver, projectSlug }: { db: DatabaseContext; contentSchemaResolver: ContentSchemaResolver; projectSlug: string}): ProjectDispatcher {
16
+ return new ProjectDispatcher(this.dispatcher, db, contentSchemaResolver, projectSlug)
17
+ }
18
+ }
19
+
20
+
21
+
22
+ export class ProjectDispatcher implements Runnable {
23
+ constructor(
24
+ private readonly dispatcher: EventDispatcher,
25
+ private readonly db: DatabaseContext,
26
+ private readonly contentSchemaResolver: ContentSchemaResolver,
27
+ private readonly projectSlug: string,
28
+ ) {
29
+ }
30
+
31
+ public async run({ logger, onError, onClose }: RunnableArgs): Promise<Running> {
32
+
33
+ return await new Promise<Running>(async (resolve, reject) => {
34
+
35
+ let resolvePending = () => {}
36
+ let rejectPending = (e: any) => {}
37
+
38
+ const resolvePendingRef = () => {
39
+ resolvePending()
40
+ }
41
+ let pendingError: any = undefined
42
+ const rejectPendingRef = (e: any) => {
43
+ pendingError = e
44
+ rejectPending(e)
45
+ }
46
+
47
+ let succeedTotal = 0
48
+ let failedTotal = 0
49
+ let aborted = false
50
+
51
+ try {
52
+ await this.db.scope(async db => {
53
+ const listener = await new Listener<string>(db.client, NOTIFY_CHANNEL_NAME, project => {
54
+ if (project === this.projectSlug) {
55
+ resolvePendingRef()
56
+ }
57
+ })
58
+ .run({ onError: rejectPendingRef, onClose: resolvePendingRef })
59
+
60
+ resolve({
61
+ end: async () => {
62
+ aborted = true
63
+ await listener.end()
64
+ logger.info('Worker terminated', {
65
+ succeed: succeedTotal,
66
+ failed: failedTotal,
67
+ })
68
+ },
69
+ })
70
+
71
+ try {
72
+ while (!aborted) {
73
+ const { succeed, failed, backoffMs } = await this.dispatcher.processBatch({
74
+ db,
75
+ contentSchemaResolver: this.contentSchemaResolver,
76
+ logger,
77
+ })
78
+ succeedTotal += succeed
79
+ failedTotal += failed
80
+
81
+ // listener error occurred during batch processing, rethrow
82
+ if (pendingError) {
83
+ throw pendingError
84
+ }
85
+
86
+ // queue is empty, wait
87
+ if (backoffMs !== 0) {
88
+ await new Promise<void>((resolve, reject) => {
89
+ let cleanup = () => {
90
+ }
91
+ if (backoffMs !== undefined) {
92
+ const timeoutHandle = setTimeout(resolve, backoffMs)
93
+ cleanup = () => clearTimeout(timeoutHandle)
94
+ }
95
+ resolvePending = () => {
96
+ resolve()
97
+ cleanup()
98
+ }
99
+ rejectPending = e => {
100
+ reject(e)
101
+ cleanup()
102
+ }
103
+ })
104
+ }
105
+ }
106
+ onClose?.()
107
+ } catch (e) {
108
+ await listener.end()
109
+ onError(e)
110
+ }
111
+ })
112
+ } catch (e) {
113
+ reject(e)
114
+ }
115
+ })
116
+
117
+
118
+ }
119
+ }
@@ -0,0 +1,18 @@
1
+ import { Actions } from '@contember/schema'
2
+ import { WebhookTargetHandler } from './WebhookTargetHandler'
3
+ import { ImplementationException } from '../ImplementationException'
4
+ import { InvokeHandler } from './types'
5
+
6
+ export class TargetHandlerResolver {
7
+ constructor(
8
+ private readonly webhookHandler: WebhookTargetHandler,
9
+ ) {
10
+ }
11
+
12
+ public resolveHandler<T extends Actions.AnyTarget>(target: T): InvokeHandler<T> {
13
+ if (target.type !== 'webhook') {
14
+ throw new ImplementationException('Invalid trigger invocation type')
15
+ }
16
+ return this.webhookHandler
17
+ }
18
+ }