@contember/engine-actions 2.2.0-alpha.3 → 2.2.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 (200) hide show
  1. package/CLAUDE.md +58 -0
  2. package/dist/development/index.cjs +19 -7
  3. package/dist/development/index.cjs.map +1 -1
  4. package/dist/development/index.js +19 -7
  5. package/dist/development/index.js.map +1 -1
  6. package/dist/development/src/ActionsExecutionContainerHookFactory.cjs +5 -2
  7. package/dist/development/src/ActionsExecutionContainerHookFactory.cjs.map +1 -1
  8. package/dist/development/src/ActionsExecutionContainerHookFactory.js +5 -2
  9. package/dist/development/src/ActionsExecutionContainerHookFactory.js.map +1 -1
  10. package/dist/development/src/ActionsMetrics.cjs +98 -0
  11. package/dist/development/src/ActionsMetrics.cjs.map +1 -0
  12. package/dist/development/src/ActionsMetrics.js +98 -0
  13. package/dist/development/src/ActionsMetrics.js.map +1 -0
  14. package/dist/development/src/dispatch/EventDispatcher.cjs +27 -9
  15. package/dist/development/src/dispatch/EventDispatcher.cjs.map +1 -1
  16. package/dist/development/src/dispatch/EventDispatcher.js +27 -9
  17. package/dist/development/src/dispatch/EventDispatcher.js.map +1 -1
  18. package/dist/development/src/dispatch/EventsRepository.cjs +49 -20
  19. package/dist/development/src/dispatch/EventsRepository.cjs.map +1 -1
  20. package/dist/development/src/dispatch/EventsRepository.js +49 -20
  21. package/dist/development/src/dispatch/EventsRepository.js.map +1 -1
  22. package/dist/development/src/dispatch/ProjectDispatcher.cjs +21 -13
  23. package/dist/development/src/dispatch/ProjectDispatcher.cjs.map +1 -1
  24. package/dist/development/src/dispatch/ProjectDispatcher.js +21 -13
  25. package/dist/development/src/dispatch/ProjectDispatcher.js.map +1 -1
  26. package/dist/development/src/dispatch/WebhookTargetHandler.cjs +29 -2
  27. package/dist/development/src/dispatch/WebhookTargetHandler.cjs.map +1 -1
  28. package/dist/development/src/dispatch/WebhookTargetHandler.js +29 -2
  29. package/dist/development/src/dispatch/WebhookTargetHandler.js.map +1 -1
  30. package/dist/development/src/graphql/resolvers/ResolversFactory.cjs +1 -1
  31. package/dist/development/src/graphql/resolvers/ResolversFactory.cjs.map +1 -1
  32. package/dist/development/src/graphql/resolvers/ResolversFactory.js +1 -1
  33. package/dist/development/src/graphql/resolvers/ResolversFactory.js.map +1 -1
  34. package/dist/development/src/graphql/resolvers/mutation/SetVariablesMutationResolver.cjs +1 -1
  35. package/dist/development/src/graphql/resolvers/mutation/SetVariablesMutationResolver.cjs.map +1 -1
  36. package/dist/development/src/graphql/resolvers/mutation/SetVariablesMutationResolver.js +1 -1
  37. package/dist/development/src/graphql/resolvers/mutation/SetVariablesMutationResolver.js.map +1 -1
  38. package/dist/development/src/graphql/resolvers/query/EventsQueryResolver.cjs +1 -1
  39. package/dist/development/src/graphql/resolvers/query/EventsQueryResolver.cjs.map +1 -1
  40. package/dist/development/src/graphql/resolvers/query/EventsQueryResolver.js +1 -1
  41. package/dist/development/src/graphql/resolvers/query/EventsQueryResolver.js.map +1 -1
  42. package/dist/development/src/graphql/resolvers/query/VariablesQueryResolver.cjs +1 -4
  43. package/dist/development/src/graphql/resolvers/query/VariablesQueryResolver.cjs.map +1 -1
  44. package/dist/development/src/graphql/resolvers/query/VariablesQueryResolver.js +1 -4
  45. package/dist/development/src/graphql/resolvers/query/VariablesQueryResolver.js.map +1 -1
  46. package/dist/development/src/graphql/schema/actions.graphql.cjs +20 -8
  47. package/dist/development/src/graphql/schema/actions.graphql.cjs.map +1 -1
  48. package/dist/development/src/graphql/schema/actions.graphql.js +20 -8
  49. package/dist/development/src/graphql/schema/actions.graphql.js.map +1 -1
  50. package/dist/development/src/model/VariablesManager.cjs +54 -5
  51. package/dist/development/src/model/VariablesManager.cjs.map +1 -1
  52. package/dist/development/src/model/VariablesManager.js +54 -5
  53. package/dist/development/src/model/VariablesManager.js.map +1 -1
  54. package/dist/development/src/triggers/TriggerPayloadPersister.cjs +3 -1
  55. package/dist/development/src/triggers/TriggerPayloadPersister.cjs.map +1 -1
  56. package/dist/development/src/triggers/TriggerPayloadPersister.js +3 -1
  57. package/dist/development/src/triggers/TriggerPayloadPersister.js.map +1 -1
  58. package/dist/production/index.cjs +19 -7
  59. package/dist/production/index.cjs.map +1 -1
  60. package/dist/production/index.js +19 -7
  61. package/dist/production/index.js.map +1 -1
  62. package/dist/production/src/ActionsExecutionContainerHookFactory.cjs +5 -2
  63. package/dist/production/src/ActionsExecutionContainerHookFactory.cjs.map +1 -1
  64. package/dist/production/src/ActionsExecutionContainerHookFactory.js +5 -2
  65. package/dist/production/src/ActionsExecutionContainerHookFactory.js.map +1 -1
  66. package/dist/production/src/ActionsMetrics.cjs +98 -0
  67. package/dist/production/src/ActionsMetrics.cjs.map +1 -0
  68. package/dist/production/src/ActionsMetrics.js +98 -0
  69. package/dist/production/src/ActionsMetrics.js.map +1 -0
  70. package/dist/production/src/dispatch/EventDispatcher.cjs +27 -9
  71. package/dist/production/src/dispatch/EventDispatcher.cjs.map +1 -1
  72. package/dist/production/src/dispatch/EventDispatcher.js +27 -9
  73. package/dist/production/src/dispatch/EventDispatcher.js.map +1 -1
  74. package/dist/production/src/dispatch/EventsRepository.cjs +49 -20
  75. package/dist/production/src/dispatch/EventsRepository.cjs.map +1 -1
  76. package/dist/production/src/dispatch/EventsRepository.js +49 -20
  77. package/dist/production/src/dispatch/EventsRepository.js.map +1 -1
  78. package/dist/production/src/dispatch/ProjectDispatcher.cjs +21 -13
  79. package/dist/production/src/dispatch/ProjectDispatcher.cjs.map +1 -1
  80. package/dist/production/src/dispatch/ProjectDispatcher.js +21 -13
  81. package/dist/production/src/dispatch/ProjectDispatcher.js.map +1 -1
  82. package/dist/production/src/dispatch/WebhookTargetHandler.cjs +29 -2
  83. package/dist/production/src/dispatch/WebhookTargetHandler.cjs.map +1 -1
  84. package/dist/production/src/dispatch/WebhookTargetHandler.js +29 -2
  85. package/dist/production/src/dispatch/WebhookTargetHandler.js.map +1 -1
  86. package/dist/production/src/graphql/resolvers/ResolversFactory.cjs +1 -1
  87. package/dist/production/src/graphql/resolvers/ResolversFactory.cjs.map +1 -1
  88. package/dist/production/src/graphql/resolvers/ResolversFactory.js +1 -1
  89. package/dist/production/src/graphql/resolvers/ResolversFactory.js.map +1 -1
  90. package/dist/production/src/graphql/resolvers/mutation/SetVariablesMutationResolver.cjs +1 -1
  91. package/dist/production/src/graphql/resolvers/mutation/SetVariablesMutationResolver.cjs.map +1 -1
  92. package/dist/production/src/graphql/resolvers/mutation/SetVariablesMutationResolver.js +1 -1
  93. package/dist/production/src/graphql/resolvers/mutation/SetVariablesMutationResolver.js.map +1 -1
  94. package/dist/production/src/graphql/resolvers/query/EventsQueryResolver.cjs +1 -1
  95. package/dist/production/src/graphql/resolvers/query/EventsQueryResolver.cjs.map +1 -1
  96. package/dist/production/src/graphql/resolvers/query/EventsQueryResolver.js +1 -1
  97. package/dist/production/src/graphql/resolvers/query/EventsQueryResolver.js.map +1 -1
  98. package/dist/production/src/graphql/resolvers/query/VariablesQueryResolver.cjs +1 -4
  99. package/dist/production/src/graphql/resolvers/query/VariablesQueryResolver.cjs.map +1 -1
  100. package/dist/production/src/graphql/resolvers/query/VariablesQueryResolver.js +1 -4
  101. package/dist/production/src/graphql/resolvers/query/VariablesQueryResolver.js.map +1 -1
  102. package/dist/production/src/graphql/schema/actions.graphql.cjs +20 -8
  103. package/dist/production/src/graphql/schema/actions.graphql.cjs.map +1 -1
  104. package/dist/production/src/graphql/schema/actions.graphql.js +20 -8
  105. package/dist/production/src/graphql/schema/actions.graphql.js.map +1 -1
  106. package/dist/production/src/model/VariablesManager.cjs +54 -5
  107. package/dist/production/src/model/VariablesManager.cjs.map +1 -1
  108. package/dist/production/src/model/VariablesManager.js +54 -5
  109. package/dist/production/src/model/VariablesManager.js.map +1 -1
  110. package/dist/production/src/triggers/TriggerPayloadPersister.cjs +3 -1
  111. package/dist/production/src/triggers/TriggerPayloadPersister.cjs.map +1 -1
  112. package/dist/production/src/triggers/TriggerPayloadPersister.js +3 -1
  113. package/dist/production/src/triggers/TriggerPayloadPersister.js.map +1 -1
  114. package/dist/tests/cases/unit/actionsMetrics.test.d.ts +2 -0
  115. package/dist/tests/cases/unit/actionsMetrics.test.d.ts.map +1 -0
  116. package/dist/tests/cases/unit/eventsRepository.test.d.ts +2 -0
  117. package/dist/tests/cases/unit/eventsRepository.test.d.ts.map +1 -0
  118. package/dist/tests/cases/unit/variablesManager.test.d.ts +2 -0
  119. package/dist/tests/cases/unit/variablesManager.test.d.ts.map +1 -0
  120. package/dist/tests/src/event.d.ts +4 -0
  121. package/dist/tests/src/event.d.ts.map +1 -0
  122. package/dist/tests/src/gql.d.ts.map +1 -1
  123. package/dist/tests/src/uuid.d.ts.map +1 -1
  124. package/dist/tests/tsconfig.tsbuildinfo +1 -1
  125. package/dist/types/ActionsExecutionContainerHookFactory.d.ts +3 -1
  126. package/dist/types/ActionsExecutionContainerHookFactory.d.ts.map +1 -1
  127. package/dist/types/ActionsMetrics.d.ts +59 -0
  128. package/dist/types/ActionsMetrics.d.ts.map +1 -0
  129. package/dist/types/ListenerStoreProvider.d.ts.map +1 -1
  130. package/dist/types/authorization/ActionsPermissionsFactory.d.ts.map +1 -1
  131. package/dist/types/dispatch/DispatchWorkerSupervisor.d.ts.map +1 -1
  132. package/dist/types/dispatch/EventDispatcher.d.ts +12 -3
  133. package/dist/types/dispatch/EventDispatcher.d.ts.map +1 -1
  134. package/dist/types/dispatch/EventsRepository.d.ts +14 -2
  135. package/dist/types/dispatch/EventsRepository.d.ts.map +1 -1
  136. package/dist/types/dispatch/LazyDispatchWorker.d.ts.map +1 -1
  137. package/dist/types/dispatch/ProjectDispatcher.d.ts +5 -2
  138. package/dist/types/dispatch/ProjectDispatcher.d.ts.map +1 -1
  139. package/dist/types/dispatch/TargetHandlerResolver.d.ts.map +1 -1
  140. package/dist/types/dispatch/WebhookFetcher.d.ts.map +1 -1
  141. package/dist/types/dispatch/WebhookTargetHandler.d.ts.map +1 -1
  142. package/dist/types/graphql/http/ActionsApiMiddlewareFactory.d.ts.map +1 -1
  143. package/dist/types/graphql/http/ActionsContextResolver.d.ts.map +1 -1
  144. package/dist/types/graphql/http/ActionsGraphQLHandlerFactory.d.ts.map +1 -1
  145. package/dist/types/graphql/http/ActionsWebsocketControllerFactory.d.ts.map +1 -1
  146. package/dist/types/graphql/resolvers/ResolversFactory.d.ts.map +1 -1
  147. package/dist/types/graphql/resolvers/mutation/ProcessBatchMutationResolver.d.ts.map +1 -1
  148. package/dist/types/graphql/resolvers/mutation/RetryEventMutationResolver.d.ts.map +1 -1
  149. package/dist/types/graphql/resolvers/mutation/SetVariablesMutationResolver.d.ts.map +1 -1
  150. package/dist/types/graphql/resolvers/mutation/StopEventMutationResolver.d.ts.map +1 -1
  151. package/dist/types/graphql/resolvers/query/EventsQueryResolver.d.ts.map +1 -1
  152. package/dist/types/graphql/resolvers/query/VariablesQueryResolver.d.ts +1 -4
  153. package/dist/types/graphql/resolvers/query/VariablesQueryResolver.d.ts.map +1 -1
  154. package/dist/types/graphql/schema/actions.graphql.d.ts.map +1 -1
  155. package/dist/types/graphql/schema/index.d.ts +27 -17
  156. package/dist/types/graphql/schema/index.d.ts.map +1 -1
  157. package/dist/types/index.d.ts +6 -0
  158. package/dist/types/index.d.ts.map +1 -1
  159. package/dist/types/model/EventByIdQuery.d.ts.map +1 -1
  160. package/dist/types/model/EventsInProcessingQuery.d.ts.map +1 -1
  161. package/dist/types/model/EventsToProcessQuery.d.ts.map +1 -1
  162. package/dist/types/model/FailedEventsQuery.d.ts.map +1 -1
  163. package/dist/types/model/SetVariableCommand.d.ts.map +1 -1
  164. package/dist/types/model/VariablesManager.d.ts +16 -3
  165. package/dist/types/model/VariablesManager.d.ts.map +1 -1
  166. package/dist/types/model/VariablesQuery.d.ts.map +1 -1
  167. package/dist/types/triggers/TriggerHandler.d.ts.map +1 -1
  168. package/dist/types/triggers/TriggerIndirectChangesFetcher.d.ts.map +1 -1
  169. package/dist/types/triggers/TriggerListenersBuilder.d.ts.map +1 -1
  170. package/dist/types/triggers/TriggerListenersFactory.d.ts.map +1 -1
  171. package/dist/types/triggers/TriggerListenersStore.d.ts.map +1 -1
  172. package/dist/types/triggers/TriggerPayloadBuilder.d.ts.map +1 -1
  173. package/dist/types/triggers/TriggerPayloadManager.d.ts.map +1 -1
  174. package/dist/types/triggers/TriggerPayloadPersister.d.ts +3 -1
  175. package/dist/types/triggers/TriggerPayloadPersister.d.ts.map +1 -1
  176. package/dist/types/tsconfig.tsbuildinfo +1 -1
  177. package/dist/types/utils/map.d.ts.map +1 -1
  178. package/dist/types/utils/notifyChannel.d.ts.map +1 -1
  179. package/graphql.codegen.yml +1 -1
  180. package/package.json +18 -16
  181. package/src/ActionsExecutionContainerHookFactory.ts +6 -0
  182. package/src/ActionsMetrics.ts +135 -0
  183. package/src/dispatch/EventDispatcher.ts +36 -11
  184. package/src/dispatch/EventsRepository.ts +68 -26
  185. package/src/dispatch/ProjectDispatcher.ts +27 -11
  186. package/src/dispatch/WebhookTargetHandler.ts +36 -1
  187. package/src/graphql/resolvers/ResolversFactory.ts +1 -1
  188. package/src/graphql/resolvers/mutation/SetVariablesMutationResolver.ts +1 -1
  189. package/src/graphql/resolvers/query/EventsQueryResolver.ts +1 -1
  190. package/src/graphql/resolvers/query/VariablesQueryResolver.ts +1 -4
  191. package/src/graphql/schema/actions.graphql.ts +20 -8
  192. package/src/graphql/schema/index.ts +30 -17
  193. package/src/index.ts +27 -5
  194. package/src/model/VariablesManager.ts +66 -6
  195. package/src/triggers/TriggerPayloadPersister.ts +6 -0
  196. package/tests/cases/unit/actionsMetrics.test.ts +76 -0
  197. package/tests/cases/unit/eventsRepository.test.ts +136 -0
  198. package/tests/cases/unit/variablesManager.test.ts +154 -0
  199. package/tests/cases/unit/webhookHandler.test.ts +80 -24
  200. package/tests/src/event.ts +27 -0
package/CLAUDE.md CHANGED
@@ -33,12 +33,70 @@ States: `created` → `processing` → `succeed` | `retrying` → `failed` | `st
33
33
  - Response: optional `{ failures: [{ eventId, error }] }`
34
34
  - Payload wrapped in meta envelope (eventId, transactionId, identity, timestamps, retries)
35
35
 
36
+ ## Variables
37
+
38
+ `{{name}}` in a target's URL or headers, resolved at dispatch time from two sources:
39
+
40
+ - rows in `actions_variable`, written by the `setVariables` mutation
41
+ - the engine environment — `<PROJECT>_ACTIONS_VARIABLE_<NAME>`, falling back to `DEFAULT_ACTIONS_VARIABLE_<NAME>`,
42
+ with the project part built by `projectNameToEnvName` (the same convention as `%project.env.X%`)
43
+
44
+ An environment value overrides a row of the same name and is neither readable nor writable through the API:
45
+ `listVariables` reports it as `source: ENVIRONMENT` with a `null` value and `setVariables` rejects it, so its
46
+ only owner is the secret store it came from. Only `fetchVariables` (dispatch) ever sees it. The env map reaches
47
+ `VariablesManager` as the master container's `env` service; the project slug comes from `ProjectDispatcher`
48
+ (worker) or `ActionsContext` (API).
49
+
36
50
  ## GraphQL API (mounted at `/actions/:projectSlug`)
37
51
 
38
52
  Mutations: `processBatch`, `retryEvent`, `stopEvent`, `setVariables` (MERGE/SET/APPEND_ONLY_MISSING)
39
53
 
40
54
  Queries: `failedEvents`, `eventsToProcess`, `eventsInProcessing`, `event`, `variables`
41
55
 
56
+ Also mounted at `/panel/api/actions/:projectSlug` via the `panelApiMount` service when the management
57
+ panel is served, which is what makes the API reachable from the panel UI.
58
+
59
+ ## Observability (`ActionsMetrics`)
60
+
61
+ Cheap in-memory Prometheus metrics (no table polling), registered onto the engine's shared registry
62
+ via `getMasterContainerHook`, labelled by `contember_project`:
63
+
64
+ - `contember_actions_events_enqueued_total` — inflow (from `TriggerPayloadPersister`, pre-commit)
65
+ - `contember_actions_events_succeeded_total` — terminal success
66
+ - `contember_actions_delivery_attempts_failed_total` — failed webhook attempts (incl. retries)
67
+ - `contember_actions_events_failed_total` — terminal failures (retries exhausted or unknown target)
68
+ - `contember_actions_worker_heartbeat_timestamp_seconds` — gauge set each loop iteration; staleness ⇒ stuck/dead worker
69
+ - `contember_actions_worker_crashed_total` — dispatch-loop crashes (each auto-restarted by the supervisor)
70
+
71
+ Backlog is *estimated* as a trend: `enqueued − succeeded − failed` (rate comparison; the absolute value
72
+ drifts across restarts and ignores manual retry/stop — query `actions_event` for an exact depth).
73
+
74
+ The `ProjectDispatcher` idle wait is capped at `MAX_IDLE_SLEEP_MS` (30s) even when the queue is empty,
75
+ so a lost `pg_notify` self-heals and the heartbeat keeps refreshing while idle.
76
+
77
+ ### Log
78
+
79
+ Metrics say *how many*; the log says *which event, which target, why*. Every way a delivery can fail
80
+ emits a line, so a target that rejects everything is visible without querying `actions_event`. The
81
+ level splits on whether an operator has to act: `error` for a terminal state nothing will retry,
82
+ `warn` for a failed attempt that still has attempts left.
83
+
84
+ | Level | Message | Emitted from |
85
+ |---|---|---|
86
+ | `warn` | (the thrown error) — request never completed, e.g. DNS, timeout | `WebhookTargetHandler.handle` |
87
+ | `warn` | `Webhook target responded with an error status` | `WebhookTargetHandler` non-2xx branch |
88
+ | `warn` | `Webhook target reported failed events` | per-event `failures` in a 2xx response |
89
+ | `warn` | `Webhook target reported failures for event ids outside the batch` | `failures` naming unknown ids |
90
+ | `warn` | `Webhook target returned a malformed response` | body is not the documented JSON shape |
91
+ | `error` | `Action event failed permanently, no attempts left` | `EventsRepository.persistProcessed` |
92
+ | `error` | `Action event failed permanently, its target is not in the schema` | `EventsRepository.fetchBatch` |
93
+
94
+ **Never log a credential.** The target is identified by `name` only — its URL and headers carry
95
+ interpolated variables, which is where tokens live. The request body, the response payload and the
96
+ parser message (which quotes the payload) stay out too; they are already kept per event in
97
+ `actions_event.log`. The unit tests assert the log attributes with an exact match precisely so a
98
+ later edit cannot quietly add one of these back.
99
+
42
100
  ## Plugin Integration
43
101
 
44
102
  Implements `Plugin` interface with:
@@ -26,6 +26,7 @@ const authorization = require("@contember/authorization");
26
26
  require("./src/authorization/ActionsAuthorizationActions.cjs");
27
27
  const ActionsPermissionsFactory = require("./src/authorization/ActionsPermissionsFactory.cjs");
28
28
  const WebhookFetcher = require("./src/dispatch/WebhookFetcher.cjs");
29
+ const ActionsMetrics = require("./src/ActionsMetrics.cjs");
29
30
  const TriggerIndirectChangesFetcher = require("./src/triggers/TriggerIndirectChangesFetcher.cjs");
30
31
  const TriggerListenersStore = require("./src/triggers/TriggerListenersStore.cjs");
31
32
  require("@contember/schema-utils");
@@ -34,30 +35,35 @@ const TriggerHandler = require("./src/triggers/TriggerHandler.cjs");
34
35
  const TriggerPayloadManager = require("./src/triggers/TriggerPayloadManager.cjs");
35
36
  var __defProp = Object.defineProperty;
36
37
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
37
- var __publicField = (obj, key, value) => __defNormalProp(obj, key + "", value);
38
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
38
39
  class ActionsPlugin {
39
40
  constructor() {
40
41
  __publicField(this, "name", "contember/actions");
42
+ __publicField(this, "actionsMetrics");
41
43
  }
42
44
  getSystemMigrations() {
43
45
  return index.migrationsGroup;
44
46
  }
45
47
  getExecutionContainerHook() {
46
- const hookFactory = new ActionsExecutionContainerHookFactory.ActionsExecutionContainerHookFactory(new ListenerStoreProvider.ListenerStoreProvider());
48
+ const hookFactory = new ActionsExecutionContainerHookFactory.ActionsExecutionContainerHookFactory(new ListenerStoreProvider.ListenerStoreProvider(), () => this.actionsMetrics);
47
49
  return hookFactory.create();
48
50
  }
49
51
  getMasterContainerHook() {
50
52
  const hook = (builder) => {
51
- return builder.addService("actions_variableManager", () => {
52
- return new VariablesManager.VariablesManager();
53
+ return builder.addService("actions_metrics", ({ promRegistry }) => {
54
+ const metrics = new ActionsMetrics.ActionsMetrics(promRegistry);
55
+ this.actionsMetrics = metrics;
56
+ return metrics;
57
+ }).addService("actions_variableManager", ({ env }) => {
58
+ return new VariablesManager.VariablesManager(env);
53
59
  }).addService("actions_eventRepository", () => {
54
60
  return new EventsRepository.EventsRepository();
55
61
  }).addService("actions_eventDispatcher", ({ actions_eventRepository, actions_variableManager }) => {
56
62
  const webhookTargetHandler = new WebhookTargetHandler.WebhookTargetHandler(new WebhookFetcher.WebhookFetcherNative());
57
63
  const targetHandlerResolver = new TargetHandlerResolver.TargetHandlerResolver(webhookTargetHandler);
58
64
  return new EventDispatcher.EventDispatcher(actions_eventRepository, actions_variableManager, targetHandlerResolver);
59
- }).addService("actions_dispatchWorkerSupervisorFactory", ({ actions_eventDispatcher }) => {
60
- const projectDispatcherFactory = new ProjectDispatcher.ProjectDispatcherFactory(actions_eventDispatcher);
65
+ }).addService("actions_dispatchWorkerSupervisorFactory", ({ actions_eventDispatcher, actions_metrics }) => {
66
+ const projectDispatcherFactory = new ProjectDispatcher.ProjectDispatcherFactory(actions_eventDispatcher, actions_metrics);
61
67
  return new DispatchWorkerSupervisor.DispatchWorkerSupervisorFactory(projectDispatcherFactory);
62
68
  }).addService("actions_authorizator", () => {
63
69
  return new authorization.Authorizator.Default(new authorization.AccessEvaluator.PermissionEvaluator(new ActionsPermissionsFactory.ActionsPermissionsFactory().create()));
@@ -70,7 +76,8 @@ class ActionsPlugin {
70
76
  actions_eventDispatcher,
71
77
  actions_dispatchWorkerSupervisorFactory,
72
78
  actions_variableManager,
73
- actions_authorizator
79
+ actions_authorizator,
80
+ panelApiMount
74
81
  }) => {
75
82
  const handlerFactory = new ActionsGraphQLHandlerFactory.ActionsGraphQLHandlerFactory();
76
83
  const eventsQueryResolver = new EventsQueryResolver.EventsQueryResolver();
@@ -98,6 +105,11 @@ class ActionsPlugin {
98
105
  );
99
106
  it.addRoute("actions", "/actions/:projectSlug", actionsMiddlewareFactory.create());
100
107
  it.addWebsocketRoute("actions", "/actions/_worker", actionsWebsocketMiddlewareFactory.create());
108
+ panelApiMount.mount(it, {
109
+ name: "actions",
110
+ path: "actions/:projectSlug",
111
+ controller: actionsMiddlewareFactory.create()
112
+ });
101
113
  }
102
114
  ).setupService(
103
115
  "applicationWorkers",
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../../packages/engine-actions/src/index.ts"],"sourcesContent":["import { Plugin } from '@contember/engine-plugins'\nimport { migrationsGroup } from './migrations/index.js'\nimport { ActionsExecutionContainerHookFactory } from './ActionsExecutionContainerHookFactory.js'\nimport { ListenerStoreProvider } from './ListenerStoreProvider.js'\nimport { MigrationGroup } from '@contember/database-migrations'\nimport { MasterContainerBuilder, MasterContainerHook } from '@contember/engine-http'\nimport { ActionsApiMiddlewareFactory } from './graphql/http/ActionsApiMiddlewareFactory.js'\nimport { ActionsGraphQLHandlerFactory } from './graphql/http/ActionsGraphQLHandlerFactory.js'\nimport { ResolversFactory } from './graphql/resolvers/ResolversFactory.js'\nimport {\n\tEventsQueryResolver,\n\tProcessBatchMutationResolver,\n\tRetryEventMutationResolver,\n\tSetVariablesMutationResolver,\n\tStopEventMutationResolver,\n} from './graphql/resolvers/index.js'\nimport { EventDispatcher } from './dispatch/EventDispatcher.js'\nimport { EventsRepository } from './dispatch/EventsRepository.js'\nimport { TargetHandlerResolver } from './dispatch/TargetHandlerResolver.js'\nimport { WebhookTargetHandler } from './dispatch/WebhookTargetHandler.js'\nimport { ActionsContextResolver } from './graphql/http/ActionsContextResolver.js'\nimport { ActionsWebsocketControllerFactory } from './graphql/http/ActionsWebsocketControllerFactory.js'\nimport { DispatchWorkerSupervisorFactory } from './dispatch/DispatchWorkerSupervisor.js'\nimport { LazyDispatchWorker } from './dispatch/LazyDispatchWorker.js'\nimport { ProjectDispatcherFactory } from './dispatch/ProjectDispatcher.js'\nimport { VariablesQueryResolver } from './graphql/resolvers/query/VariablesQueryResolver.js'\nimport { VariablesManager } from './model/VariablesManager.js'\nimport { AccessEvaluator, Authorizator } from '@contember/authorization'\nimport { ActionsPermissionsFactory } from './authorization/index.js'\nimport { WebhookFetcherNative } from './dispatch/WebhookFetcher.js'\n\nexport {\n\tTriggerHandler,\n\tTriggerIndirectChangesFetcher,\n\tTriggerListenersFactory,\n\tTriggerListenersStore,\n\tTriggerPayloadManager,\n} from './triggers/index.js'\nexport { ActionsExecutionContainerHookFactory } from './ActionsExecutionContainerHookFactory.js'\nexport { ListenerStoreProvider } from './ListenerStoreProvider.js'\n\nexport default class ActionsPlugin implements Plugin {\n\tname = 'contember/actions'\n\n\tgetSystemMigrations(): MigrationGroup {\n\t\treturn migrationsGroup\n\t}\n\n\tgetExecutionContainerHook() {\n\t\tconst hookFactory = new ActionsExecutionContainerHookFactory(new ListenerStoreProvider())\n\t\treturn hookFactory.create()\n\t}\n\n\tgetMasterContainerHook() {\n\t\tconst hook: MasterContainerHook = (builder: MasterContainerBuilder) => {\n\t\t\treturn builder\n\t\t\t\t.addService('actions_variableManager', () => {\n\t\t\t\t\treturn new VariablesManager()\n\t\t\t\t})\n\t\t\t\t.addService('actions_eventRepository', () => {\n\t\t\t\t\treturn new EventsRepository()\n\t\t\t\t})\n\t\t\t\t.addService('actions_eventDispatcher', ({ actions_eventRepository, actions_variableManager }) => {\n\t\t\t\t\tconst webhookTargetHandler = new WebhookTargetHandler(new WebhookFetcherNative())\n\t\t\t\t\tconst targetHandlerResolver = new TargetHandlerResolver(webhookTargetHandler)\n\t\t\t\t\treturn new EventDispatcher(actions_eventRepository, actions_variableManager, targetHandlerResolver)\n\t\t\t\t})\n\t\t\t\t.addService('actions_dispatchWorkerSupervisorFactory', ({ actions_eventDispatcher }) => {\n\t\t\t\t\tconst projectDispatcherFactory = new ProjectDispatcherFactory(actions_eventDispatcher)\n\t\t\t\t\treturn new DispatchWorkerSupervisorFactory(projectDispatcherFactory)\n\t\t\t\t})\n\t\t\t\t.addService('actions_authorizator', () => {\n\t\t\t\t\treturn new Authorizator.Default(new AccessEvaluator.PermissionEvaluator(new ActionsPermissionsFactory().create()))\n\t\t\t\t})\n\t\t\t\t.setupService(\n\t\t\t\t\t'application',\n\t\t\t\t\t(\n\t\t\t\t\t\tit,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tprojectContextResolver,\n\t\t\t\t\t\t\tdebugMode,\n\t\t\t\t\t\t\tactions_eventRepository,\n\t\t\t\t\t\t\tactions_eventDispatcher,\n\t\t\t\t\t\t\tactions_dispatchWorkerSupervisorFactory,\n\t\t\t\t\t\t\tactions_variableManager,\n\t\t\t\t\t\t\tactions_authorizator,\n\t\t\t\t\t\t},\n\t\t\t\t\t) => {\n\t\t\t\t\t\tconst handlerFactory = new ActionsGraphQLHandlerFactory()\n\t\t\t\t\t\tconst eventsQueryResolver = new EventsQueryResolver()\n\t\t\t\t\t\tconst processBatchMutationResolver = new ProcessBatchMutationResolver(actions_eventDispatcher)\n\t\t\t\t\t\tconst variablesQueryResolver = new VariablesQueryResolver(actions_variableManager)\n\t\t\t\t\t\tconst setVariablesMutationResolver = new SetVariablesMutationResolver(actions_variableManager)\n\t\t\t\t\t\tconst resolversFactory = new ResolversFactory(\n\t\t\t\t\t\t\teventsQueryResolver,\n\t\t\t\t\t\t\tprocessBatchMutationResolver,\n\t\t\t\t\t\t\tvariablesQueryResolver,\n\t\t\t\t\t\t\tsetVariablesMutationResolver,\n\t\t\t\t\t\t\tnew RetryEventMutationResolver(actions_eventRepository),\n\t\t\t\t\t\t\tnew StopEventMutationResolver(actions_eventRepository),\n\t\t\t\t\t\t)\n\n\t\t\t\t\t\tconst actionsContextResolver = new ActionsContextResolver(debugMode, projectContextResolver)\n\t\t\t\t\t\tconst actionsMiddlewareFactory = new ActionsApiMiddlewareFactory(\n\t\t\t\t\t\t\tactionsContextResolver,\n\t\t\t\t\t\t\thandlerFactory.create(resolversFactory),\n\t\t\t\t\t\t\tactions_authorizator,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tconst actionsWebsocketMiddlewareFactory = new ActionsWebsocketControllerFactory(\n\t\t\t\t\t\t\tdebugMode,\n\t\t\t\t\t\t\tactionsContextResolver,\n\t\t\t\t\t\t\tactions_dispatchWorkerSupervisorFactory,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tit.addRoute('actions', '/actions/:projectSlug', actionsMiddlewareFactory.create())\n\t\t\t\t\t\tit.addWebsocketRoute('actions', '/actions/_worker', actionsWebsocketMiddlewareFactory.create())\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\t.setupService(\n\t\t\t\t\t'applicationWorkers',\n\t\t\t\t\t(it, { actions_dispatchWorkerSupervisorFactory, projectGroupContainer, projectGroupContainerResolver, serverConfig }) => {\n\t\t\t\t\t\tif (!(serverConfig as any).projectGroup) {\n\t\t\t\t\t\t\tit.registerWorker(this.name, actions_dispatchWorkerSupervisorFactory.create(projectGroupContainer))\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tit.registerWorker(this.name, new LazyDispatchWorker(projectGroupContainerResolver, actions_dispatchWorkerSupervisorFactory))\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t) as unknown as MasterContainerBuilder\n\t\t}\n\t\treturn hook\n\t}\n}\n"],"names":["migrationsGroup","ActionsExecutionContainerHookFactory","ListenerStoreProvider","VariablesManager","EventsRepository","WebhookTargetHandler","WebhookFetcherNative","TargetHandlerResolver","EventDispatcher","ProjectDispatcherFactory","DispatchWorkerSupervisorFactory","Authorizator","AccessEvaluator","ActionsPermissionsFactory","ActionsGraphQLHandlerFactory","EventsQueryResolver","ProcessBatchMutationResolver","VariablesQueryResolver","SetVariablesMutationResolver","ResolversFactory","RetryEventMutationResolver","StopEventMutationResolver","ActionsContextResolver","ActionsApiMiddlewareFactory","ActionsWebsocketControllerFactory","LazyDispatchWorker"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCA,MAAqB,cAAgC;AAAA,EAArD,cAAA;AACC,kBAAA,MAAA,QAAO,mBAAA;AAAA,EAAA;AAAA,EAEP,sBAAsC;AACrC,WAAOA,MAAAA;AAAAA,EACR;AAAA,EAEA,4BAA4B;AAC3B,UAAM,cAAc,IAAIC,0EAAqC,IAAIC,sBAAAA,uBAAuB;AACxF,WAAO,YAAY,OAAA;AAAA,EACpB;AAAA,EAEA,yBAAyB;AACxB,UAAM,OAA4B,CAAC,YAAoC;AACtE,aAAO,QACL,WAAW,2BAA2B,MAAM;AAC5C,eAAO,IAAIC,iBAAAA,iBAAA;AAAA,MACZ,CAAC,EACA,WAAW,2BAA2B,MAAM;AAC5C,eAAO,IAAIC,iBAAAA,iBAAA;AAAA,MACZ,CAAC,EACA,WAAW,2BAA2B,CAAC,EAAE,yBAAyB,8BAA8B;AAChG,cAAM,uBAAuB,IAAIC,0CAAqB,IAAIC,eAAAA,sBAAsB;AAChF,cAAM,wBAAwB,IAAIC,sBAAAA,sBAAsB,oBAAoB;AAC5E,eAAO,IAAIC,gBAAAA,gBAAgB,yBAAyB,yBAAyB,qBAAqB;AAAA,MACnG,CAAC,EACA,WAAW,2CAA2C,CAAC,EAAE,8BAA8B;AACvF,cAAM,2BAA2B,IAAIC,kBAAAA,yBAAyB,uBAAuB;AACrF,eAAO,IAAIC,yBAAAA,gCAAgC,wBAAwB;AAAA,MACpE,CAAC,EACA,WAAW,wBAAwB,MAAM;AACzC,eAAO,IAAIC,cAAAA,aAAa,QAAQ,IAAIC,cAAAA,gBAAgB,oBAAoB,IAAIC,0BAAAA,0BAAA,EAA4B,OAAA,CAAQ,CAAC;AAAA,MAClH,CAAC,EACA;AAAA,QACA;AAAA,QACA,CACC,IACA;AAAA,UACC;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QAAA,MAEG;AACJ,gBAAM,iBAAiB,IAAIC,0DAAA;AAC3B,gBAAM,sBAAsB,IAAIC,wCAAA;AAChC,gBAAM,+BAA+B,IAAIC,6BAAAA,6BAA6B,uBAAuB;AAC7F,gBAAM,yBAAyB,IAAIC,uBAAAA,uBAAuB,uBAAuB;AACjF,gBAAM,+BAA+B,IAAIC,6BAAAA,6BAA6B,uBAAuB;AAC7F,gBAAM,mBAAmB,IAAIC,iBAAAA;AAAAA,YAC5B;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,IAAIC,2BAAAA,2BAA2B,uBAAuB;AAAA,YACtD,IAAIC,0BAAAA,0BAA0B,uBAAuB;AAAA,UAAA;AAGtD,gBAAM,yBAAyB,IAAIC,8CAAuB,WAAW,sBAAsB;AAC3F,gBAAM,2BAA2B,IAAIC,4BAAAA;AAAAA,YACpC;AAAA,YACA,eAAe,OAAO,gBAAgB;AAAA,YACtC;AAAA,UAAA;AAED,gBAAM,oCAAoC,IAAIC,kCAAAA;AAAAA,YAC7C;AAAA,YACA;AAAA,YACA;AAAA,UAAA;AAED,aAAG,SAAS,WAAW,yBAAyB,yBAAyB,QAAQ;AACjF,aAAG,kBAAkB,WAAW,oBAAoB,kCAAkC,QAAQ;AAAA,QAC/F;AAAA,MAAA,EAEA;AAAA,QACA;AAAA,QACA,CAAC,IAAI,EAAE,yCAAyC,uBAAuB,+BAA+B,mBAAmB;AACxH,cAAI,CAAE,aAAqB,cAAc;AACxC,eAAG,eAAe,KAAK,MAAM,wCAAwC,OAAO,qBAAqB,CAAC;AAAA,UACnG,OAAO;AACN,eAAG,eAAe,KAAK,MAAM,IAAIC,sCAAmB,+BAA+B,uCAAuC,CAAC;AAAA,UAC5H;AAAA,QACD;AAAA,MAAA;AAAA,IAEH;AACA,WAAO;AAAA,EACR;AACD;;;;;;;;;"}
1
+ {"version":3,"file":"index.cjs","sources":["../../../packages/engine-actions/src/index.ts"],"sourcesContent":["import { Plugin } from '@contember/engine-plugins'\nimport { migrationsGroup } from './migrations/index.js'\nimport { ActionsExecutionContainerHookFactory } from './ActionsExecutionContainerHookFactory.js'\nimport { ListenerStoreProvider } from './ListenerStoreProvider.js'\nimport { MigrationGroup } from '@contember/database-migrations'\nimport { MasterContainerBuilder, MasterContainerHook } from '@contember/engine-http'\nimport { ActionsApiMiddlewareFactory } from './graphql/http/ActionsApiMiddlewareFactory.js'\nimport { ActionsGraphQLHandlerFactory } from './graphql/http/ActionsGraphQLHandlerFactory.js'\nimport { ResolversFactory } from './graphql/resolvers/ResolversFactory.js'\nimport {\n\tEventsQueryResolver,\n\tProcessBatchMutationResolver,\n\tRetryEventMutationResolver,\n\tSetVariablesMutationResolver,\n\tStopEventMutationResolver,\n} from './graphql/resolvers/index.js'\nimport { EventDispatcher } from './dispatch/EventDispatcher.js'\nimport { EventsRepository } from './dispatch/EventsRepository.js'\nimport { TargetHandlerResolver } from './dispatch/TargetHandlerResolver.js'\nimport { WebhookTargetHandler } from './dispatch/WebhookTargetHandler.js'\nimport { ActionsContextResolver } from './graphql/http/ActionsContextResolver.js'\nimport { ActionsWebsocketControllerFactory } from './graphql/http/ActionsWebsocketControllerFactory.js'\nimport { DispatchWorkerSupervisorFactory } from './dispatch/DispatchWorkerSupervisor.js'\nimport { LazyDispatchWorker } from './dispatch/LazyDispatchWorker.js'\nimport { ProjectDispatcherFactory } from './dispatch/ProjectDispatcher.js'\nimport { VariablesQueryResolver } from './graphql/resolvers/query/VariablesQueryResolver.js'\nimport { VariablesManager } from './model/VariablesManager.js'\nimport { AccessEvaluator, Authorizator } from '@contember/authorization'\nimport { ActionsPermissionsFactory } from './authorization/index.js'\nimport { WebhookFetcherNative } from './dispatch/WebhookFetcher.js'\nimport { ActionsMetrics } from './ActionsMetrics.js'\n\nexport {\n\tTriggerHandler,\n\tTriggerIndirectChangesFetcher,\n\tTriggerListenersFactory,\n\tTriggerListenersStore,\n\tTriggerPayloadManager,\n} from './triggers/index.js'\nexport { ActionsExecutionContainerHookFactory } from './ActionsExecutionContainerHookFactory.js'\nexport { ListenerStoreProvider } from './ListenerStoreProvider.js'\n\nexport default class ActionsPlugin implements Plugin {\n\tname = 'contember/actions'\n\n\t/**\n\t * Metrics singleton, created in {@link getMasterContainerHook} (where the Prometheus registry is\n\t * available) and read back here in {@link getExecutionContainerHook}, which runs in the per-request\n\t * content container with no access to master-level services.\n\t */\n\tprivate actionsMetrics: ActionsMetrics | undefined\n\n\tgetSystemMigrations(): MigrationGroup {\n\t\treturn migrationsGroup\n\t}\n\n\tgetExecutionContainerHook() {\n\t\tconst hookFactory = new ActionsExecutionContainerHookFactory(new ListenerStoreProvider(), () => this.actionsMetrics)\n\t\treturn hookFactory.create()\n\t}\n\n\tgetMasterContainerHook() {\n\t\tconst hook: MasterContainerHook = (builder: MasterContainerBuilder) => {\n\t\t\treturn builder\n\t\t\t\t.addService('actions_metrics', ({ promRegistry }) => {\n\t\t\t\t\tconst metrics = new ActionsMetrics(promRegistry)\n\t\t\t\t\t// expose to getExecutionContainerHook (runs in a different container scope)\n\t\t\t\t\tthis.actionsMetrics = metrics\n\t\t\t\t\treturn metrics\n\t\t\t\t})\n\t\t\t\t.addService('actions_variableManager', ({ env }) => {\n\t\t\t\t\treturn new VariablesManager(env)\n\t\t\t\t})\n\t\t\t\t.addService('actions_eventRepository', () => {\n\t\t\t\t\treturn new EventsRepository()\n\t\t\t\t})\n\t\t\t\t.addService('actions_eventDispatcher', ({ actions_eventRepository, actions_variableManager }) => {\n\t\t\t\t\tconst webhookTargetHandler = new WebhookTargetHandler(new WebhookFetcherNative())\n\t\t\t\t\tconst targetHandlerResolver = new TargetHandlerResolver(webhookTargetHandler)\n\t\t\t\t\treturn new EventDispatcher(actions_eventRepository, actions_variableManager, targetHandlerResolver)\n\t\t\t\t})\n\t\t\t\t.addService('actions_dispatchWorkerSupervisorFactory', ({ actions_eventDispatcher, actions_metrics }) => {\n\t\t\t\t\tconst projectDispatcherFactory = new ProjectDispatcherFactory(actions_eventDispatcher, actions_metrics)\n\t\t\t\t\treturn new DispatchWorkerSupervisorFactory(projectDispatcherFactory)\n\t\t\t\t})\n\t\t\t\t.addService('actions_authorizator', () => {\n\t\t\t\t\treturn new Authorizator.Default(new AccessEvaluator.PermissionEvaluator(new ActionsPermissionsFactory().create()))\n\t\t\t\t})\n\t\t\t\t.setupService(\n\t\t\t\t\t'application',\n\t\t\t\t\t(\n\t\t\t\t\t\tit,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tprojectContextResolver,\n\t\t\t\t\t\t\tdebugMode,\n\t\t\t\t\t\t\tactions_eventRepository,\n\t\t\t\t\t\t\tactions_eventDispatcher,\n\t\t\t\t\t\t\tactions_dispatchWorkerSupervisorFactory,\n\t\t\t\t\t\t\tactions_variableManager,\n\t\t\t\t\t\t\tactions_authorizator,\n\t\t\t\t\t\t\tpanelApiMount,\n\t\t\t\t\t\t},\n\t\t\t\t\t) => {\n\t\t\t\t\t\tconst handlerFactory = new ActionsGraphQLHandlerFactory()\n\t\t\t\t\t\tconst eventsQueryResolver = new EventsQueryResolver()\n\t\t\t\t\t\tconst processBatchMutationResolver = new ProcessBatchMutationResolver(actions_eventDispatcher)\n\t\t\t\t\t\tconst variablesQueryResolver = new VariablesQueryResolver(actions_variableManager)\n\t\t\t\t\t\tconst setVariablesMutationResolver = new SetVariablesMutationResolver(actions_variableManager)\n\t\t\t\t\t\tconst resolversFactory = new ResolversFactory(\n\t\t\t\t\t\t\teventsQueryResolver,\n\t\t\t\t\t\t\tprocessBatchMutationResolver,\n\t\t\t\t\t\t\tvariablesQueryResolver,\n\t\t\t\t\t\t\tsetVariablesMutationResolver,\n\t\t\t\t\t\t\tnew RetryEventMutationResolver(actions_eventRepository),\n\t\t\t\t\t\t\tnew StopEventMutationResolver(actions_eventRepository),\n\t\t\t\t\t\t)\n\n\t\t\t\t\t\tconst actionsContextResolver = new ActionsContextResolver(debugMode, projectContextResolver)\n\t\t\t\t\t\tconst actionsMiddlewareFactory = new ActionsApiMiddlewareFactory(\n\t\t\t\t\t\t\tactionsContextResolver,\n\t\t\t\t\t\t\thandlerFactory.create(resolversFactory),\n\t\t\t\t\t\t\tactions_authorizator,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tconst actionsWebsocketMiddlewareFactory = new ActionsWebsocketControllerFactory(\n\t\t\t\t\t\t\tdebugMode,\n\t\t\t\t\t\t\tactionsContextResolver,\n\t\t\t\t\t\t\tactions_dispatchWorkerSupervisorFactory,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tit.addRoute('actions', '/actions/:projectSlug', actionsMiddlewareFactory.create())\n\t\t\t\t\t\tit.addWebsocketRoute('actions', '/actions/_worker', actionsWebsocketMiddlewareFactory.create())\n\t\t\t\t\t\t// Does nothing unless the panel is served; when it is, the panel's access gate applies\n\t\t\t\t\t\t// and the UI learns the actions module has an API to talk to.\n\t\t\t\t\t\tpanelApiMount.mount(it, {\n\t\t\t\t\t\t\tname: 'actions',\n\t\t\t\t\t\t\tpath: 'actions/:projectSlug',\n\t\t\t\t\t\t\tcontroller: actionsMiddlewareFactory.create(),\n\t\t\t\t\t\t})\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\t.setupService(\n\t\t\t\t\t'applicationWorkers',\n\t\t\t\t\t(it, { actions_dispatchWorkerSupervisorFactory, projectGroupContainer, projectGroupContainerResolver, serverConfig }) => {\n\t\t\t\t\t\tif (!(serverConfig as any).projectGroup) {\n\t\t\t\t\t\t\tit.registerWorker(this.name, actions_dispatchWorkerSupervisorFactory.create(projectGroupContainer))\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tit.registerWorker(this.name, new LazyDispatchWorker(projectGroupContainerResolver, actions_dispatchWorkerSupervisorFactory))\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t) as unknown as MasterContainerBuilder\n\t\t}\n\t\treturn hook\n\t}\n}\n"],"names":["migrationsGroup","ActionsExecutionContainerHookFactory","ListenerStoreProvider","ActionsMetrics","VariablesManager","EventsRepository","WebhookTargetHandler","WebhookFetcherNative","TargetHandlerResolver","EventDispatcher","ProjectDispatcherFactory","DispatchWorkerSupervisorFactory","Authorizator","AccessEvaluator","ActionsPermissionsFactory","ActionsGraphQLHandlerFactory","EventsQueryResolver","ProcessBatchMutationResolver","VariablesQueryResolver","SetVariablesMutationResolver","ResolversFactory","RetryEventMutationResolver","StopEventMutationResolver","ActionsContextResolver","ActionsApiMiddlewareFactory","ActionsWebsocketControllerFactory","LazyDispatchWorker"],"mappings":"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"}
@@ -24,6 +24,7 @@ import { Authorizator, AccessEvaluator } from "@contember/authorization";
24
24
  import "./src/authorization/ActionsAuthorizationActions.js";
25
25
  import { ActionsPermissionsFactory } from "./src/authorization/ActionsPermissionsFactory.js";
26
26
  import { WebhookFetcherNative } from "./src/dispatch/WebhookFetcher.js";
27
+ import { ActionsMetrics } from "./src/ActionsMetrics.js";
27
28
  import { TriggerIndirectChangesFetcher } from "./src/triggers/TriggerIndirectChangesFetcher.js";
28
29
  import { TriggerListenersStore } from "./src/triggers/TriggerListenersStore.js";
29
30
  import "@contember/schema-utils";
@@ -32,30 +33,35 @@ import { TriggerHandler } from "./src/triggers/TriggerHandler.js";
32
33
  import { TriggerPayloadManager } from "./src/triggers/TriggerPayloadManager.js";
33
34
  var __defProp = Object.defineProperty;
34
35
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
35
- var __publicField = (obj, key, value) => __defNormalProp(obj, key + "", value);
36
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
36
37
  class ActionsPlugin {
37
38
  constructor() {
38
39
  __publicField(this, "name", "contember/actions");
40
+ __publicField(this, "actionsMetrics");
39
41
  }
40
42
  getSystemMigrations() {
41
43
  return migrationsGroup;
42
44
  }
43
45
  getExecutionContainerHook() {
44
- const hookFactory = new ActionsExecutionContainerHookFactory(new ListenerStoreProvider());
46
+ const hookFactory = new ActionsExecutionContainerHookFactory(new ListenerStoreProvider(), () => this.actionsMetrics);
45
47
  return hookFactory.create();
46
48
  }
47
49
  getMasterContainerHook() {
48
50
  const hook = (builder) => {
49
- return builder.addService("actions_variableManager", () => {
50
- return new VariablesManager();
51
+ return builder.addService("actions_metrics", ({ promRegistry }) => {
52
+ const metrics = new ActionsMetrics(promRegistry);
53
+ this.actionsMetrics = metrics;
54
+ return metrics;
55
+ }).addService("actions_variableManager", ({ env }) => {
56
+ return new VariablesManager(env);
51
57
  }).addService("actions_eventRepository", () => {
52
58
  return new EventsRepository();
53
59
  }).addService("actions_eventDispatcher", ({ actions_eventRepository, actions_variableManager }) => {
54
60
  const webhookTargetHandler = new WebhookTargetHandler(new WebhookFetcherNative());
55
61
  const targetHandlerResolver = new TargetHandlerResolver(webhookTargetHandler);
56
62
  return new EventDispatcher(actions_eventRepository, actions_variableManager, targetHandlerResolver);
57
- }).addService("actions_dispatchWorkerSupervisorFactory", ({ actions_eventDispatcher }) => {
58
- const projectDispatcherFactory = new ProjectDispatcherFactory(actions_eventDispatcher);
63
+ }).addService("actions_dispatchWorkerSupervisorFactory", ({ actions_eventDispatcher, actions_metrics }) => {
64
+ const projectDispatcherFactory = new ProjectDispatcherFactory(actions_eventDispatcher, actions_metrics);
59
65
  return new DispatchWorkerSupervisorFactory(projectDispatcherFactory);
60
66
  }).addService("actions_authorizator", () => {
61
67
  return new Authorizator.Default(new AccessEvaluator.PermissionEvaluator(new ActionsPermissionsFactory().create()));
@@ -68,7 +74,8 @@ class ActionsPlugin {
68
74
  actions_eventDispatcher,
69
75
  actions_dispatchWorkerSupervisorFactory,
70
76
  actions_variableManager,
71
- actions_authorizator
77
+ actions_authorizator,
78
+ panelApiMount
72
79
  }) => {
73
80
  const handlerFactory = new ActionsGraphQLHandlerFactory();
74
81
  const eventsQueryResolver = new EventsQueryResolver();
@@ -96,6 +103,11 @@ class ActionsPlugin {
96
103
  );
97
104
  it.addRoute("actions", "/actions/:projectSlug", actionsMiddlewareFactory.create());
98
105
  it.addWebsocketRoute("actions", "/actions/_worker", actionsWebsocketMiddlewareFactory.create());
106
+ panelApiMount.mount(it, {
107
+ name: "actions",
108
+ path: "actions/:projectSlug",
109
+ controller: actionsMiddlewareFactory.create()
110
+ });
99
111
  }
100
112
  ).setupService(
101
113
  "applicationWorkers",
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../packages/engine-actions/src/index.ts"],"sourcesContent":["import { Plugin } from '@contember/engine-plugins'\nimport { migrationsGroup } from './migrations/index.js'\nimport { ActionsExecutionContainerHookFactory } from './ActionsExecutionContainerHookFactory.js'\nimport { ListenerStoreProvider } from './ListenerStoreProvider.js'\nimport { MigrationGroup } from '@contember/database-migrations'\nimport { MasterContainerBuilder, MasterContainerHook } from '@contember/engine-http'\nimport { ActionsApiMiddlewareFactory } from './graphql/http/ActionsApiMiddlewareFactory.js'\nimport { ActionsGraphQLHandlerFactory } from './graphql/http/ActionsGraphQLHandlerFactory.js'\nimport { ResolversFactory } from './graphql/resolvers/ResolversFactory.js'\nimport {\n\tEventsQueryResolver,\n\tProcessBatchMutationResolver,\n\tRetryEventMutationResolver,\n\tSetVariablesMutationResolver,\n\tStopEventMutationResolver,\n} from './graphql/resolvers/index.js'\nimport { EventDispatcher } from './dispatch/EventDispatcher.js'\nimport { EventsRepository } from './dispatch/EventsRepository.js'\nimport { TargetHandlerResolver } from './dispatch/TargetHandlerResolver.js'\nimport { WebhookTargetHandler } from './dispatch/WebhookTargetHandler.js'\nimport { ActionsContextResolver } from './graphql/http/ActionsContextResolver.js'\nimport { ActionsWebsocketControllerFactory } from './graphql/http/ActionsWebsocketControllerFactory.js'\nimport { DispatchWorkerSupervisorFactory } from './dispatch/DispatchWorkerSupervisor.js'\nimport { LazyDispatchWorker } from './dispatch/LazyDispatchWorker.js'\nimport { ProjectDispatcherFactory } from './dispatch/ProjectDispatcher.js'\nimport { VariablesQueryResolver } from './graphql/resolvers/query/VariablesQueryResolver.js'\nimport { VariablesManager } from './model/VariablesManager.js'\nimport { AccessEvaluator, Authorizator } from '@contember/authorization'\nimport { ActionsPermissionsFactory } from './authorization/index.js'\nimport { WebhookFetcherNative } from './dispatch/WebhookFetcher.js'\n\nexport {\n\tTriggerHandler,\n\tTriggerIndirectChangesFetcher,\n\tTriggerListenersFactory,\n\tTriggerListenersStore,\n\tTriggerPayloadManager,\n} from './triggers/index.js'\nexport { ActionsExecutionContainerHookFactory } from './ActionsExecutionContainerHookFactory.js'\nexport { ListenerStoreProvider } from './ListenerStoreProvider.js'\n\nexport default class ActionsPlugin implements Plugin {\n\tname = 'contember/actions'\n\n\tgetSystemMigrations(): MigrationGroup {\n\t\treturn migrationsGroup\n\t}\n\n\tgetExecutionContainerHook() {\n\t\tconst hookFactory = new ActionsExecutionContainerHookFactory(new ListenerStoreProvider())\n\t\treturn hookFactory.create()\n\t}\n\n\tgetMasterContainerHook() {\n\t\tconst hook: MasterContainerHook = (builder: MasterContainerBuilder) => {\n\t\t\treturn builder\n\t\t\t\t.addService('actions_variableManager', () => {\n\t\t\t\t\treturn new VariablesManager()\n\t\t\t\t})\n\t\t\t\t.addService('actions_eventRepository', () => {\n\t\t\t\t\treturn new EventsRepository()\n\t\t\t\t})\n\t\t\t\t.addService('actions_eventDispatcher', ({ actions_eventRepository, actions_variableManager }) => {\n\t\t\t\t\tconst webhookTargetHandler = new WebhookTargetHandler(new WebhookFetcherNative())\n\t\t\t\t\tconst targetHandlerResolver = new TargetHandlerResolver(webhookTargetHandler)\n\t\t\t\t\treturn new EventDispatcher(actions_eventRepository, actions_variableManager, targetHandlerResolver)\n\t\t\t\t})\n\t\t\t\t.addService('actions_dispatchWorkerSupervisorFactory', ({ actions_eventDispatcher }) => {\n\t\t\t\t\tconst projectDispatcherFactory = new ProjectDispatcherFactory(actions_eventDispatcher)\n\t\t\t\t\treturn new DispatchWorkerSupervisorFactory(projectDispatcherFactory)\n\t\t\t\t})\n\t\t\t\t.addService('actions_authorizator', () => {\n\t\t\t\t\treturn new Authorizator.Default(new AccessEvaluator.PermissionEvaluator(new ActionsPermissionsFactory().create()))\n\t\t\t\t})\n\t\t\t\t.setupService(\n\t\t\t\t\t'application',\n\t\t\t\t\t(\n\t\t\t\t\t\tit,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tprojectContextResolver,\n\t\t\t\t\t\t\tdebugMode,\n\t\t\t\t\t\t\tactions_eventRepository,\n\t\t\t\t\t\t\tactions_eventDispatcher,\n\t\t\t\t\t\t\tactions_dispatchWorkerSupervisorFactory,\n\t\t\t\t\t\t\tactions_variableManager,\n\t\t\t\t\t\t\tactions_authorizator,\n\t\t\t\t\t\t},\n\t\t\t\t\t) => {\n\t\t\t\t\t\tconst handlerFactory = new ActionsGraphQLHandlerFactory()\n\t\t\t\t\t\tconst eventsQueryResolver = new EventsQueryResolver()\n\t\t\t\t\t\tconst processBatchMutationResolver = new ProcessBatchMutationResolver(actions_eventDispatcher)\n\t\t\t\t\t\tconst variablesQueryResolver = new VariablesQueryResolver(actions_variableManager)\n\t\t\t\t\t\tconst setVariablesMutationResolver = new SetVariablesMutationResolver(actions_variableManager)\n\t\t\t\t\t\tconst resolversFactory = new ResolversFactory(\n\t\t\t\t\t\t\teventsQueryResolver,\n\t\t\t\t\t\t\tprocessBatchMutationResolver,\n\t\t\t\t\t\t\tvariablesQueryResolver,\n\t\t\t\t\t\t\tsetVariablesMutationResolver,\n\t\t\t\t\t\t\tnew RetryEventMutationResolver(actions_eventRepository),\n\t\t\t\t\t\t\tnew StopEventMutationResolver(actions_eventRepository),\n\t\t\t\t\t\t)\n\n\t\t\t\t\t\tconst actionsContextResolver = new ActionsContextResolver(debugMode, projectContextResolver)\n\t\t\t\t\t\tconst actionsMiddlewareFactory = new ActionsApiMiddlewareFactory(\n\t\t\t\t\t\t\tactionsContextResolver,\n\t\t\t\t\t\t\thandlerFactory.create(resolversFactory),\n\t\t\t\t\t\t\tactions_authorizator,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tconst actionsWebsocketMiddlewareFactory = new ActionsWebsocketControllerFactory(\n\t\t\t\t\t\t\tdebugMode,\n\t\t\t\t\t\t\tactionsContextResolver,\n\t\t\t\t\t\t\tactions_dispatchWorkerSupervisorFactory,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tit.addRoute('actions', '/actions/:projectSlug', actionsMiddlewareFactory.create())\n\t\t\t\t\t\tit.addWebsocketRoute('actions', '/actions/_worker', actionsWebsocketMiddlewareFactory.create())\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\t.setupService(\n\t\t\t\t\t'applicationWorkers',\n\t\t\t\t\t(it, { actions_dispatchWorkerSupervisorFactory, projectGroupContainer, projectGroupContainerResolver, serverConfig }) => {\n\t\t\t\t\t\tif (!(serverConfig as any).projectGroup) {\n\t\t\t\t\t\t\tit.registerWorker(this.name, actions_dispatchWorkerSupervisorFactory.create(projectGroupContainer))\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tit.registerWorker(this.name, new LazyDispatchWorker(projectGroupContainerResolver, actions_dispatchWorkerSupervisorFactory))\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t) as unknown as MasterContainerBuilder\n\t\t}\n\t\treturn hook\n\t}\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCA,MAAqB,cAAgC;AAAA,EAArD,cAAA;AACC,kBAAA,MAAA,QAAO,mBAAA;AAAA,EAAA;AAAA,EAEP,sBAAsC;AACrC,WAAO;AAAA,EACR;AAAA,EAEA,4BAA4B;AAC3B,UAAM,cAAc,IAAI,qCAAqC,IAAI,uBAAuB;AACxF,WAAO,YAAY,OAAA;AAAA,EACpB;AAAA,EAEA,yBAAyB;AACxB,UAAM,OAA4B,CAAC,YAAoC;AACtE,aAAO,QACL,WAAW,2BAA2B,MAAM;AAC5C,eAAO,IAAI,iBAAA;AAAA,MACZ,CAAC,EACA,WAAW,2BAA2B,MAAM;AAC5C,eAAO,IAAI,iBAAA;AAAA,MACZ,CAAC,EACA,WAAW,2BAA2B,CAAC,EAAE,yBAAyB,8BAA8B;AAChG,cAAM,uBAAuB,IAAI,qBAAqB,IAAI,sBAAsB;AAChF,cAAM,wBAAwB,IAAI,sBAAsB,oBAAoB;AAC5E,eAAO,IAAI,gBAAgB,yBAAyB,yBAAyB,qBAAqB;AAAA,MACnG,CAAC,EACA,WAAW,2CAA2C,CAAC,EAAE,8BAA8B;AACvF,cAAM,2BAA2B,IAAI,yBAAyB,uBAAuB;AACrF,eAAO,IAAI,gCAAgC,wBAAwB;AAAA,MACpE,CAAC,EACA,WAAW,wBAAwB,MAAM;AACzC,eAAO,IAAI,aAAa,QAAQ,IAAI,gBAAgB,oBAAoB,IAAI,0BAAA,EAA4B,OAAA,CAAQ,CAAC;AAAA,MAClH,CAAC,EACA;AAAA,QACA;AAAA,QACA,CACC,IACA;AAAA,UACC;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QAAA,MAEG;AACJ,gBAAM,iBAAiB,IAAI,6BAAA;AAC3B,gBAAM,sBAAsB,IAAI,oBAAA;AAChC,gBAAM,+BAA+B,IAAI,6BAA6B,uBAAuB;AAC7F,gBAAM,yBAAyB,IAAI,uBAAuB,uBAAuB;AACjF,gBAAM,+BAA+B,IAAI,6BAA6B,uBAAuB;AAC7F,gBAAM,mBAAmB,IAAI;AAAA,YAC5B;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,IAAI,2BAA2B,uBAAuB;AAAA,YACtD,IAAI,0BAA0B,uBAAuB;AAAA,UAAA;AAGtD,gBAAM,yBAAyB,IAAI,uBAAuB,WAAW,sBAAsB;AAC3F,gBAAM,2BAA2B,IAAI;AAAA,YACpC;AAAA,YACA,eAAe,OAAO,gBAAgB;AAAA,YACtC;AAAA,UAAA;AAED,gBAAM,oCAAoC,IAAI;AAAA,YAC7C;AAAA,YACA;AAAA,YACA;AAAA,UAAA;AAED,aAAG,SAAS,WAAW,yBAAyB,yBAAyB,QAAQ;AACjF,aAAG,kBAAkB,WAAW,oBAAoB,kCAAkC,QAAQ;AAAA,QAC/F;AAAA,MAAA,EAEA;AAAA,QACA;AAAA,QACA,CAAC,IAAI,EAAE,yCAAyC,uBAAuB,+BAA+B,mBAAmB;AACxH,cAAI,CAAE,aAAqB,cAAc;AACxC,eAAG,eAAe,KAAK,MAAM,wCAAwC,OAAO,qBAAqB,CAAC;AAAA,UACnG,OAAO;AACN,eAAG,eAAe,KAAK,MAAM,IAAI,mBAAmB,+BAA+B,uCAAuC,CAAC;AAAA,UAC5H;AAAA,QACD;AAAA,MAAA;AAAA,IAEH;AACA,WAAO;AAAA,EACR;AACD;"}
1
+ {"version":3,"file":"index.js","sources":["../../../packages/engine-actions/src/index.ts"],"sourcesContent":["import { Plugin } from '@contember/engine-plugins'\nimport { migrationsGroup } from './migrations/index.js'\nimport { ActionsExecutionContainerHookFactory } from './ActionsExecutionContainerHookFactory.js'\nimport { ListenerStoreProvider } from './ListenerStoreProvider.js'\nimport { MigrationGroup } from '@contember/database-migrations'\nimport { MasterContainerBuilder, MasterContainerHook } from '@contember/engine-http'\nimport { ActionsApiMiddlewareFactory } from './graphql/http/ActionsApiMiddlewareFactory.js'\nimport { ActionsGraphQLHandlerFactory } from './graphql/http/ActionsGraphQLHandlerFactory.js'\nimport { ResolversFactory } from './graphql/resolvers/ResolversFactory.js'\nimport {\n\tEventsQueryResolver,\n\tProcessBatchMutationResolver,\n\tRetryEventMutationResolver,\n\tSetVariablesMutationResolver,\n\tStopEventMutationResolver,\n} from './graphql/resolvers/index.js'\nimport { EventDispatcher } from './dispatch/EventDispatcher.js'\nimport { EventsRepository } from './dispatch/EventsRepository.js'\nimport { TargetHandlerResolver } from './dispatch/TargetHandlerResolver.js'\nimport { WebhookTargetHandler } from './dispatch/WebhookTargetHandler.js'\nimport { ActionsContextResolver } from './graphql/http/ActionsContextResolver.js'\nimport { ActionsWebsocketControllerFactory } from './graphql/http/ActionsWebsocketControllerFactory.js'\nimport { DispatchWorkerSupervisorFactory } from './dispatch/DispatchWorkerSupervisor.js'\nimport { LazyDispatchWorker } from './dispatch/LazyDispatchWorker.js'\nimport { ProjectDispatcherFactory } from './dispatch/ProjectDispatcher.js'\nimport { VariablesQueryResolver } from './graphql/resolvers/query/VariablesQueryResolver.js'\nimport { VariablesManager } from './model/VariablesManager.js'\nimport { AccessEvaluator, Authorizator } from '@contember/authorization'\nimport { ActionsPermissionsFactory } from './authorization/index.js'\nimport { WebhookFetcherNative } from './dispatch/WebhookFetcher.js'\nimport { ActionsMetrics } from './ActionsMetrics.js'\n\nexport {\n\tTriggerHandler,\n\tTriggerIndirectChangesFetcher,\n\tTriggerListenersFactory,\n\tTriggerListenersStore,\n\tTriggerPayloadManager,\n} from './triggers/index.js'\nexport { ActionsExecutionContainerHookFactory } from './ActionsExecutionContainerHookFactory.js'\nexport { ListenerStoreProvider } from './ListenerStoreProvider.js'\n\nexport default class ActionsPlugin implements Plugin {\n\tname = 'contember/actions'\n\n\t/**\n\t * Metrics singleton, created in {@link getMasterContainerHook} (where the Prometheus registry is\n\t * available) and read back here in {@link getExecutionContainerHook}, which runs in the per-request\n\t * content container with no access to master-level services.\n\t */\n\tprivate actionsMetrics: ActionsMetrics | undefined\n\n\tgetSystemMigrations(): MigrationGroup {\n\t\treturn migrationsGroup\n\t}\n\n\tgetExecutionContainerHook() {\n\t\tconst hookFactory = new ActionsExecutionContainerHookFactory(new ListenerStoreProvider(), () => this.actionsMetrics)\n\t\treturn hookFactory.create()\n\t}\n\n\tgetMasterContainerHook() {\n\t\tconst hook: MasterContainerHook = (builder: MasterContainerBuilder) => {\n\t\t\treturn builder\n\t\t\t\t.addService('actions_metrics', ({ promRegistry }) => {\n\t\t\t\t\tconst metrics = new ActionsMetrics(promRegistry)\n\t\t\t\t\t// expose to getExecutionContainerHook (runs in a different container scope)\n\t\t\t\t\tthis.actionsMetrics = metrics\n\t\t\t\t\treturn metrics\n\t\t\t\t})\n\t\t\t\t.addService('actions_variableManager', ({ env }) => {\n\t\t\t\t\treturn new VariablesManager(env)\n\t\t\t\t})\n\t\t\t\t.addService('actions_eventRepository', () => {\n\t\t\t\t\treturn new EventsRepository()\n\t\t\t\t})\n\t\t\t\t.addService('actions_eventDispatcher', ({ actions_eventRepository, actions_variableManager }) => {\n\t\t\t\t\tconst webhookTargetHandler = new WebhookTargetHandler(new WebhookFetcherNative())\n\t\t\t\t\tconst targetHandlerResolver = new TargetHandlerResolver(webhookTargetHandler)\n\t\t\t\t\treturn new EventDispatcher(actions_eventRepository, actions_variableManager, targetHandlerResolver)\n\t\t\t\t})\n\t\t\t\t.addService('actions_dispatchWorkerSupervisorFactory', ({ actions_eventDispatcher, actions_metrics }) => {\n\t\t\t\t\tconst projectDispatcherFactory = new ProjectDispatcherFactory(actions_eventDispatcher, actions_metrics)\n\t\t\t\t\treturn new DispatchWorkerSupervisorFactory(projectDispatcherFactory)\n\t\t\t\t})\n\t\t\t\t.addService('actions_authorizator', () => {\n\t\t\t\t\treturn new Authorizator.Default(new AccessEvaluator.PermissionEvaluator(new ActionsPermissionsFactory().create()))\n\t\t\t\t})\n\t\t\t\t.setupService(\n\t\t\t\t\t'application',\n\t\t\t\t\t(\n\t\t\t\t\t\tit,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tprojectContextResolver,\n\t\t\t\t\t\t\tdebugMode,\n\t\t\t\t\t\t\tactions_eventRepository,\n\t\t\t\t\t\t\tactions_eventDispatcher,\n\t\t\t\t\t\t\tactions_dispatchWorkerSupervisorFactory,\n\t\t\t\t\t\t\tactions_variableManager,\n\t\t\t\t\t\t\tactions_authorizator,\n\t\t\t\t\t\t\tpanelApiMount,\n\t\t\t\t\t\t},\n\t\t\t\t\t) => {\n\t\t\t\t\t\tconst handlerFactory = new ActionsGraphQLHandlerFactory()\n\t\t\t\t\t\tconst eventsQueryResolver = new EventsQueryResolver()\n\t\t\t\t\t\tconst processBatchMutationResolver = new ProcessBatchMutationResolver(actions_eventDispatcher)\n\t\t\t\t\t\tconst variablesQueryResolver = new VariablesQueryResolver(actions_variableManager)\n\t\t\t\t\t\tconst setVariablesMutationResolver = new SetVariablesMutationResolver(actions_variableManager)\n\t\t\t\t\t\tconst resolversFactory = new ResolversFactory(\n\t\t\t\t\t\t\teventsQueryResolver,\n\t\t\t\t\t\t\tprocessBatchMutationResolver,\n\t\t\t\t\t\t\tvariablesQueryResolver,\n\t\t\t\t\t\t\tsetVariablesMutationResolver,\n\t\t\t\t\t\t\tnew RetryEventMutationResolver(actions_eventRepository),\n\t\t\t\t\t\t\tnew StopEventMutationResolver(actions_eventRepository),\n\t\t\t\t\t\t)\n\n\t\t\t\t\t\tconst actionsContextResolver = new ActionsContextResolver(debugMode, projectContextResolver)\n\t\t\t\t\t\tconst actionsMiddlewareFactory = new ActionsApiMiddlewareFactory(\n\t\t\t\t\t\t\tactionsContextResolver,\n\t\t\t\t\t\t\thandlerFactory.create(resolversFactory),\n\t\t\t\t\t\t\tactions_authorizator,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tconst actionsWebsocketMiddlewareFactory = new ActionsWebsocketControllerFactory(\n\t\t\t\t\t\t\tdebugMode,\n\t\t\t\t\t\t\tactionsContextResolver,\n\t\t\t\t\t\t\tactions_dispatchWorkerSupervisorFactory,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tit.addRoute('actions', '/actions/:projectSlug', actionsMiddlewareFactory.create())\n\t\t\t\t\t\tit.addWebsocketRoute('actions', '/actions/_worker', actionsWebsocketMiddlewareFactory.create())\n\t\t\t\t\t\t// Does nothing unless the panel is served; when it is, the panel's access gate applies\n\t\t\t\t\t\t// and the UI learns the actions module has an API to talk to.\n\t\t\t\t\t\tpanelApiMount.mount(it, {\n\t\t\t\t\t\t\tname: 'actions',\n\t\t\t\t\t\t\tpath: 'actions/:projectSlug',\n\t\t\t\t\t\t\tcontroller: actionsMiddlewareFactory.create(),\n\t\t\t\t\t\t})\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\t.setupService(\n\t\t\t\t\t'applicationWorkers',\n\t\t\t\t\t(it, { actions_dispatchWorkerSupervisorFactory, projectGroupContainer, projectGroupContainerResolver, serverConfig }) => {\n\t\t\t\t\t\tif (!(serverConfig as any).projectGroup) {\n\t\t\t\t\t\t\tit.registerWorker(this.name, actions_dispatchWorkerSupervisorFactory.create(projectGroupContainer))\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tit.registerWorker(this.name, new LazyDispatchWorker(projectGroupContainerResolver, actions_dispatchWorkerSupervisorFactory))\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t) as unknown as MasterContainerBuilder\n\t\t}\n\t\treturn hook\n\t}\n}\n"],"names":[],"mappings":"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"}
@@ -7,14 +7,16 @@ const TriggerPayloadManager = require("./triggers/TriggerPayloadManager.cjs");
7
7
  const TriggerPayloadBuilder = require("./triggers/TriggerPayloadBuilder.cjs");
8
8
  const TriggerPayloadPersister = require("./triggers/TriggerPayloadPersister.cjs");
9
9
  class ActionsExecutionContainerHookFactory {
10
- constructor(listenerStoreProvider) {
10
+ constructor(listenerStoreProvider, metricsProvider) {
11
11
  this.listenerStoreProvider = listenerStoreProvider;
12
+ this.metricsProvider = metricsProvider;
12
13
  }
13
14
  create() {
14
15
  return (builder) => {
15
16
  return builder.setupService(
16
17
  "mapperFactory",
17
18
  (mapperFactory, { whereBuilder, schema, pathFactory, systemSchema, providers, stage, project, schemaMeta, joinBuilder, userInfo, triggeredActionsCollector }) => {
19
+ const projectMetrics = this.metricsProvider()?.forProject(project.slug);
18
20
  mapperFactory.hooks.push((mapper) => {
19
21
  const triggerPayloadPersister = new TriggerPayloadPersister.TriggerPayloadPersister(
20
22
  mapper,
@@ -25,7 +27,8 @@ class ActionsExecutionContainerHookFactory {
25
27
  schemaMeta.id,
26
28
  mapper.identityId,
27
29
  userInfo,
28
- triggeredActionsCollector
30
+ triggeredActionsCollector,
31
+ projectMetrics
29
32
  );
30
33
  const triggerPayloadBuilder = new TriggerPayloadBuilder.TriggerPayloadBuilder(mapper);
31
34
  const payloadManager = new TriggerPayloadManager.TriggerPayloadManager(triggerPayloadBuilder, triggerPayloadPersister);
@@ -1 +1 @@
1
- {"version":3,"file":"ActionsExecutionContainerHookFactory.cjs","sources":["../../../../packages/engine-actions/src/ActionsExecutionContainerHookFactory.ts"],"sourcesContent":["import { TriggerHandler, TriggerIndirectChangesFetcher, TriggerPayloadManager } from './triggers/index.js'\nimport { ListenerStoreProvider } from './ListenerStoreProvider.js'\nimport { TriggerPayloadBuilder } from './triggers/TriggerPayloadBuilder.js'\nimport { TriggerPayloadPersister } from './triggers/TriggerPayloadPersister.js'\nimport { ExecutionContainerHook } from '@contember/engine-content-api'\n\nexport class ActionsExecutionContainerHookFactory {\n\tconstructor(\n\t\tprivate readonly listenerStoreProvider: ListenerStoreProvider,\n\t) {\n\t}\n\n\tcreate(): ExecutionContainerHook {\n\t\treturn builder => {\n\t\t\treturn builder.setupService(\n\t\t\t\t'mapperFactory',\n\t\t\t\t(\n\t\t\t\t\tmapperFactory,\n\t\t\t\t\t{ whereBuilder, schema, pathFactory, systemSchema, providers, stage, project, schemaMeta, joinBuilder, userInfo, triggeredActionsCollector },\n\t\t\t\t) => {\n\t\t\t\t\tmapperFactory.hooks.push(mapper => {\n\t\t\t\t\t\tconst triggerPayloadPersister = new TriggerPayloadPersister(\n\t\t\t\t\t\t\tmapper,\n\t\t\t\t\t\t\tmapper.db.forSchema(systemSchema),\n\t\t\t\t\t\t\tproviders,\n\t\t\t\t\t\t\tproject.slug,\n\t\t\t\t\t\t\tstage.id,\n\t\t\t\t\t\t\tschemaMeta.id,\n\t\t\t\t\t\t\tmapper.identityId,\n\t\t\t\t\t\t\tuserInfo,\n\t\t\t\t\t\t\ttriggeredActionsCollector,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tconst triggerPayloadBuilder = new TriggerPayloadBuilder(mapper)\n\t\t\t\t\t\tconst payloadManager = new TriggerPayloadManager(triggerPayloadBuilder, triggerPayloadPersister)\n\t\t\t\t\t\tconst changesFetcher = new TriggerIndirectChangesFetcher(schema.model, mapper, whereBuilder, joinBuilder, pathFactory)\n\t\t\t\t\t\tconst listenersStore = this.listenerStoreProvider.getListenerStore(schema)\n\t\t\t\t\t\tconst triggerHandler = new TriggerHandler(payloadManager, listenersStore, changesFetcher)\n\t\t\t\t\t\ttriggerHandler.attach(mapper.eventManager)\n\t\t\t\t\t})\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\t}\n}\n"],"names":["TriggerPayloadPersister","TriggerPayloadBuilder","TriggerPayloadManager","TriggerIndirectChangesFetcher","TriggerHandler"],"mappings":";;;;;;;;AAMO,MAAM,qCAAqC;AAAA,EACjD,YACkB,uBAChB;AADgB,SAAA,wBAAA;AAAA,EAElB;AAAA,EAEA,SAAiC;AAChC,WAAO,CAAA,YAAW;AACjB,aAAO,QAAQ;AAAA,QACd;AAAA,QACA,CACC,eACA,EAAE,cAAc,QAAQ,aAAa,cAAc,WAAW,OAAO,SAAS,YAAY,aAAa,UAAU,gCAC7G;AACJ,wBAAc,MAAM,KAAK,CAAA,WAAU;AAClC,kBAAM,0BAA0B,IAAIA,wBAAAA;AAAAA,cACnC;AAAA,cACA,OAAO,GAAG,UAAU,YAAY;AAAA,cAChC;AAAA,cACA,QAAQ;AAAA,cACR,MAAM;AAAA,cACN,WAAW;AAAA,cACX,OAAO;AAAA,cACP;AAAA,cACA;AAAA,YAAA;AAED,kBAAM,wBAAwB,IAAIC,sBAAAA,sBAAsB,MAAM;AAC9D,kBAAM,iBAAiB,IAAIC,4CAAsB,uBAAuB,uBAAuB;AAC/F,kBAAM,iBAAiB,IAAIC,8BAAAA,8BAA8B,OAAO,OAAO,QAAQ,cAAc,aAAa,WAAW;AACrH,kBAAM,iBAAiB,KAAK,sBAAsB,iBAAiB,MAAM;AACzE,kBAAM,iBAAiB,IAAIC,eAAAA,eAAe,gBAAgB,gBAAgB,cAAc;AACxF,2BAAe,OAAO,OAAO,YAAY;AAAA,UAC1C,CAAC;AAAA,QACF;AAAA,MAAA;AAAA,IAEF;AAAA,EACD;AACD;;"}
1
+ {"version":3,"file":"ActionsExecutionContainerHookFactory.cjs","sources":["../../../../packages/engine-actions/src/ActionsExecutionContainerHookFactory.ts"],"sourcesContent":["import { TriggerHandler, TriggerIndirectChangesFetcher, TriggerPayloadManager } from './triggers/index.js'\nimport { ListenerStoreProvider } from './ListenerStoreProvider.js'\nimport { TriggerPayloadBuilder } from './triggers/TriggerPayloadBuilder.js'\nimport { TriggerPayloadPersister } from './triggers/TriggerPayloadPersister.js'\nimport { ExecutionContainerHook } from '@contember/engine-content-api'\nimport { ActionsMetrics } from './ActionsMetrics.js'\n\nexport class ActionsExecutionContainerHookFactory {\n\tconstructor(\n\t\tprivate readonly listenerStoreProvider: ListenerStoreProvider,\n\t\t// Resolved lazily: the metrics singleton lives in the master container and is wired up when the\n\t\t// dispatch worker boots, which precedes any content request that could enqueue an event.\n\t\tprivate readonly metricsProvider: () => ActionsMetrics | undefined,\n\t) {\n\t}\n\n\tcreate(): ExecutionContainerHook {\n\t\treturn builder => {\n\t\t\treturn builder.setupService(\n\t\t\t\t'mapperFactory',\n\t\t\t\t(\n\t\t\t\t\tmapperFactory,\n\t\t\t\t\t{ whereBuilder, schema, pathFactory, systemSchema, providers, stage, project, schemaMeta, joinBuilder, userInfo, triggeredActionsCollector },\n\t\t\t\t) => {\n\t\t\t\t\tconst projectMetrics = this.metricsProvider()?.forProject(project.slug)\n\t\t\t\t\tmapperFactory.hooks.push(mapper => {\n\t\t\t\t\t\tconst triggerPayloadPersister = new TriggerPayloadPersister(\n\t\t\t\t\t\t\tmapper,\n\t\t\t\t\t\t\tmapper.db.forSchema(systemSchema),\n\t\t\t\t\t\t\tproviders,\n\t\t\t\t\t\t\tproject.slug,\n\t\t\t\t\t\t\tstage.id,\n\t\t\t\t\t\t\tschemaMeta.id,\n\t\t\t\t\t\t\tmapper.identityId,\n\t\t\t\t\t\t\tuserInfo,\n\t\t\t\t\t\t\ttriggeredActionsCollector,\n\t\t\t\t\t\t\tprojectMetrics,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tconst triggerPayloadBuilder = new TriggerPayloadBuilder(mapper)\n\t\t\t\t\t\tconst payloadManager = new TriggerPayloadManager(triggerPayloadBuilder, triggerPayloadPersister)\n\t\t\t\t\t\tconst changesFetcher = new TriggerIndirectChangesFetcher(schema.model, mapper, whereBuilder, joinBuilder, pathFactory)\n\t\t\t\t\t\tconst listenersStore = this.listenerStoreProvider.getListenerStore(schema)\n\t\t\t\t\t\tconst triggerHandler = new TriggerHandler(payloadManager, listenersStore, changesFetcher)\n\t\t\t\t\t\ttriggerHandler.attach(mapper.eventManager)\n\t\t\t\t\t})\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\t}\n}\n"],"names":["TriggerPayloadPersister","TriggerPayloadBuilder","TriggerPayloadManager","TriggerIndirectChangesFetcher","TriggerHandler"],"mappings":";;;;;;;;AAOO,MAAM,qCAAqC;AAAA,EACjD,YACkB,uBAGA,iBAChB;AAJgB,SAAA,wBAAA;AAGA,SAAA,kBAAA;AAAA,EAElB;AAAA,EAEA,SAAiC;AAChC,WAAO,CAAA,YAAW;AACjB,aAAO,QAAQ;AAAA,QACd;AAAA,QACA,CACC,eACA,EAAE,cAAc,QAAQ,aAAa,cAAc,WAAW,OAAO,SAAS,YAAY,aAAa,UAAU,gCAC7G;AACJ,gBAAM,iBAAiB,KAAK,gBAAA,GAAmB,WAAW,QAAQ,IAAI;AACtE,wBAAc,MAAM,KAAK,CAAA,WAAU;AAClC,kBAAM,0BAA0B,IAAIA,wBAAAA;AAAAA,cACnC;AAAA,cACA,OAAO,GAAG,UAAU,YAAY;AAAA,cAChC;AAAA,cACA,QAAQ;AAAA,cACR,MAAM;AAAA,cACN,WAAW;AAAA,cACX,OAAO;AAAA,cACP;AAAA,cACA;AAAA,cACA;AAAA,YAAA;AAED,kBAAM,wBAAwB,IAAIC,sBAAAA,sBAAsB,MAAM;AAC9D,kBAAM,iBAAiB,IAAIC,4CAAsB,uBAAuB,uBAAuB;AAC/F,kBAAM,iBAAiB,IAAIC,8BAAAA,8BAA8B,OAAO,OAAO,QAAQ,cAAc,aAAa,WAAW;AACrH,kBAAM,iBAAiB,KAAK,sBAAsB,iBAAiB,MAAM;AACzE,kBAAM,iBAAiB,IAAIC,eAAAA,eAAe,gBAAgB,gBAAgB,cAAc;AACxF,2BAAe,OAAO,OAAO,YAAY;AAAA,UAC1C,CAAC;AAAA,QACF;AAAA,MAAA;AAAA,IAEF;AAAA,EACD;AACD;;"}
@@ -5,14 +5,16 @@ import { TriggerPayloadManager } from "./triggers/TriggerPayloadManager.js";
5
5
  import { TriggerPayloadBuilder } from "./triggers/TriggerPayloadBuilder.js";
6
6
  import { TriggerPayloadPersister } from "./triggers/TriggerPayloadPersister.js";
7
7
  class ActionsExecutionContainerHookFactory {
8
- constructor(listenerStoreProvider) {
8
+ constructor(listenerStoreProvider, metricsProvider) {
9
9
  this.listenerStoreProvider = listenerStoreProvider;
10
+ this.metricsProvider = metricsProvider;
10
11
  }
11
12
  create() {
12
13
  return (builder) => {
13
14
  return builder.setupService(
14
15
  "mapperFactory",
15
16
  (mapperFactory, { whereBuilder, schema, pathFactory, systemSchema, providers, stage, project, schemaMeta, joinBuilder, userInfo, triggeredActionsCollector }) => {
17
+ const projectMetrics = this.metricsProvider()?.forProject(project.slug);
16
18
  mapperFactory.hooks.push((mapper) => {
17
19
  const triggerPayloadPersister = new TriggerPayloadPersister(
18
20
  mapper,
@@ -23,7 +25,8 @@ class ActionsExecutionContainerHookFactory {
23
25
  schemaMeta.id,
24
26
  mapper.identityId,
25
27
  userInfo,
26
- triggeredActionsCollector
28
+ triggeredActionsCollector,
29
+ projectMetrics
27
30
  );
28
31
  const triggerPayloadBuilder = new TriggerPayloadBuilder(mapper);
29
32
  const payloadManager = new TriggerPayloadManager(triggerPayloadBuilder, triggerPayloadPersister);
@@ -1 +1 @@
1
- {"version":3,"file":"ActionsExecutionContainerHookFactory.js","sources":["../../../../packages/engine-actions/src/ActionsExecutionContainerHookFactory.ts"],"sourcesContent":["import { TriggerHandler, TriggerIndirectChangesFetcher, TriggerPayloadManager } from './triggers/index.js'\nimport { ListenerStoreProvider } from './ListenerStoreProvider.js'\nimport { TriggerPayloadBuilder } from './triggers/TriggerPayloadBuilder.js'\nimport { TriggerPayloadPersister } from './triggers/TriggerPayloadPersister.js'\nimport { ExecutionContainerHook } from '@contember/engine-content-api'\n\nexport class ActionsExecutionContainerHookFactory {\n\tconstructor(\n\t\tprivate readonly listenerStoreProvider: ListenerStoreProvider,\n\t) {\n\t}\n\n\tcreate(): ExecutionContainerHook {\n\t\treturn builder => {\n\t\t\treturn builder.setupService(\n\t\t\t\t'mapperFactory',\n\t\t\t\t(\n\t\t\t\t\tmapperFactory,\n\t\t\t\t\t{ whereBuilder, schema, pathFactory, systemSchema, providers, stage, project, schemaMeta, joinBuilder, userInfo, triggeredActionsCollector },\n\t\t\t\t) => {\n\t\t\t\t\tmapperFactory.hooks.push(mapper => {\n\t\t\t\t\t\tconst triggerPayloadPersister = new TriggerPayloadPersister(\n\t\t\t\t\t\t\tmapper,\n\t\t\t\t\t\t\tmapper.db.forSchema(systemSchema),\n\t\t\t\t\t\t\tproviders,\n\t\t\t\t\t\t\tproject.slug,\n\t\t\t\t\t\t\tstage.id,\n\t\t\t\t\t\t\tschemaMeta.id,\n\t\t\t\t\t\t\tmapper.identityId,\n\t\t\t\t\t\t\tuserInfo,\n\t\t\t\t\t\t\ttriggeredActionsCollector,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tconst triggerPayloadBuilder = new TriggerPayloadBuilder(mapper)\n\t\t\t\t\t\tconst payloadManager = new TriggerPayloadManager(triggerPayloadBuilder, triggerPayloadPersister)\n\t\t\t\t\t\tconst changesFetcher = new TriggerIndirectChangesFetcher(schema.model, mapper, whereBuilder, joinBuilder, pathFactory)\n\t\t\t\t\t\tconst listenersStore = this.listenerStoreProvider.getListenerStore(schema)\n\t\t\t\t\t\tconst triggerHandler = new TriggerHandler(payloadManager, listenersStore, changesFetcher)\n\t\t\t\t\t\ttriggerHandler.attach(mapper.eventManager)\n\t\t\t\t\t})\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\t}\n}\n"],"names":[],"mappings":";;;;;;AAMO,MAAM,qCAAqC;AAAA,EACjD,YACkB,uBAChB;AADgB,SAAA,wBAAA;AAAA,EAElB;AAAA,EAEA,SAAiC;AAChC,WAAO,CAAA,YAAW;AACjB,aAAO,QAAQ;AAAA,QACd;AAAA,QACA,CACC,eACA,EAAE,cAAc,QAAQ,aAAa,cAAc,WAAW,OAAO,SAAS,YAAY,aAAa,UAAU,gCAC7G;AACJ,wBAAc,MAAM,KAAK,CAAA,WAAU;AAClC,kBAAM,0BAA0B,IAAI;AAAA,cACnC;AAAA,cACA,OAAO,GAAG,UAAU,YAAY;AAAA,cAChC;AAAA,cACA,QAAQ;AAAA,cACR,MAAM;AAAA,cACN,WAAW;AAAA,cACX,OAAO;AAAA,cACP;AAAA,cACA;AAAA,YAAA;AAED,kBAAM,wBAAwB,IAAI,sBAAsB,MAAM;AAC9D,kBAAM,iBAAiB,IAAI,sBAAsB,uBAAuB,uBAAuB;AAC/F,kBAAM,iBAAiB,IAAI,8BAA8B,OAAO,OAAO,QAAQ,cAAc,aAAa,WAAW;AACrH,kBAAM,iBAAiB,KAAK,sBAAsB,iBAAiB,MAAM;AACzE,kBAAM,iBAAiB,IAAI,eAAe,gBAAgB,gBAAgB,cAAc;AACxF,2BAAe,OAAO,OAAO,YAAY;AAAA,UAC1C,CAAC;AAAA,QACF;AAAA,MAAA;AAAA,IAEF;AAAA,EACD;AACD;"}
1
+ {"version":3,"file":"ActionsExecutionContainerHookFactory.js","sources":["../../../../packages/engine-actions/src/ActionsExecutionContainerHookFactory.ts"],"sourcesContent":["import { TriggerHandler, TriggerIndirectChangesFetcher, TriggerPayloadManager } from './triggers/index.js'\nimport { ListenerStoreProvider } from './ListenerStoreProvider.js'\nimport { TriggerPayloadBuilder } from './triggers/TriggerPayloadBuilder.js'\nimport { TriggerPayloadPersister } from './triggers/TriggerPayloadPersister.js'\nimport { ExecutionContainerHook } from '@contember/engine-content-api'\nimport { ActionsMetrics } from './ActionsMetrics.js'\n\nexport class ActionsExecutionContainerHookFactory {\n\tconstructor(\n\t\tprivate readonly listenerStoreProvider: ListenerStoreProvider,\n\t\t// Resolved lazily: the metrics singleton lives in the master container and is wired up when the\n\t\t// dispatch worker boots, which precedes any content request that could enqueue an event.\n\t\tprivate readonly metricsProvider: () => ActionsMetrics | undefined,\n\t) {\n\t}\n\n\tcreate(): ExecutionContainerHook {\n\t\treturn builder => {\n\t\t\treturn builder.setupService(\n\t\t\t\t'mapperFactory',\n\t\t\t\t(\n\t\t\t\t\tmapperFactory,\n\t\t\t\t\t{ whereBuilder, schema, pathFactory, systemSchema, providers, stage, project, schemaMeta, joinBuilder, userInfo, triggeredActionsCollector },\n\t\t\t\t) => {\n\t\t\t\t\tconst projectMetrics = this.metricsProvider()?.forProject(project.slug)\n\t\t\t\t\tmapperFactory.hooks.push(mapper => {\n\t\t\t\t\t\tconst triggerPayloadPersister = new TriggerPayloadPersister(\n\t\t\t\t\t\t\tmapper,\n\t\t\t\t\t\t\tmapper.db.forSchema(systemSchema),\n\t\t\t\t\t\t\tproviders,\n\t\t\t\t\t\t\tproject.slug,\n\t\t\t\t\t\t\tstage.id,\n\t\t\t\t\t\t\tschemaMeta.id,\n\t\t\t\t\t\t\tmapper.identityId,\n\t\t\t\t\t\t\tuserInfo,\n\t\t\t\t\t\t\ttriggeredActionsCollector,\n\t\t\t\t\t\t\tprojectMetrics,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tconst triggerPayloadBuilder = new TriggerPayloadBuilder(mapper)\n\t\t\t\t\t\tconst payloadManager = new TriggerPayloadManager(triggerPayloadBuilder, triggerPayloadPersister)\n\t\t\t\t\t\tconst changesFetcher = new TriggerIndirectChangesFetcher(schema.model, mapper, whereBuilder, joinBuilder, pathFactory)\n\t\t\t\t\t\tconst listenersStore = this.listenerStoreProvider.getListenerStore(schema)\n\t\t\t\t\t\tconst triggerHandler = new TriggerHandler(payloadManager, listenersStore, changesFetcher)\n\t\t\t\t\t\ttriggerHandler.attach(mapper.eventManager)\n\t\t\t\t\t})\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\t}\n}\n"],"names":[],"mappings":";;;;;;AAOO,MAAM,qCAAqC;AAAA,EACjD,YACkB,uBAGA,iBAChB;AAJgB,SAAA,wBAAA;AAGA,SAAA,kBAAA;AAAA,EAElB;AAAA,EAEA,SAAiC;AAChC,WAAO,CAAA,YAAW;AACjB,aAAO,QAAQ;AAAA,QACd;AAAA,QACA,CACC,eACA,EAAE,cAAc,QAAQ,aAAa,cAAc,WAAW,OAAO,SAAS,YAAY,aAAa,UAAU,gCAC7G;AACJ,gBAAM,iBAAiB,KAAK,gBAAA,GAAmB,WAAW,QAAQ,IAAI;AACtE,wBAAc,MAAM,KAAK,CAAA,WAAU;AAClC,kBAAM,0BAA0B,IAAI;AAAA,cACnC;AAAA,cACA,OAAO,GAAG,UAAU,YAAY;AAAA,cAChC;AAAA,cACA,QAAQ;AAAA,cACR,MAAM;AAAA,cACN,WAAW;AAAA,cACX,OAAO;AAAA,cACP;AAAA,cACA;AAAA,cACA;AAAA,YAAA;AAED,kBAAM,wBAAwB,IAAI,sBAAsB,MAAM;AAC9D,kBAAM,iBAAiB,IAAI,sBAAsB,uBAAuB,uBAAuB;AAC/F,kBAAM,iBAAiB,IAAI,8BAA8B,OAAO,OAAO,QAAQ,cAAc,aAAa,WAAW;AACrH,kBAAM,iBAAiB,KAAK,sBAAsB,iBAAiB,MAAM;AACzE,kBAAM,iBAAiB,IAAI,eAAe,gBAAgB,gBAAgB,cAAc;AACxF,2BAAe,OAAO,OAAO,YAAY;AAAA,UAC1C,CAAC;AAAA,QACF;AAAA,MAAA;AAAA,IAEF;AAAA,EACD;AACD;"}
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const prom = require("prom-client");
4
+ var __defProp = Object.defineProperty;
5
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
7
+ const LABEL_PROJECT = "contember_project";
8
+ class ActionsMetrics {
9
+ constructor(registry) {
10
+ __publicField(this, "eventsEnqueued");
11
+ __publicField(this, "eventsSucceeded");
12
+ __publicField(this, "deliveryAttemptsFailed");
13
+ __publicField(this, "eventsFailed");
14
+ __publicField(this, "workerHeartbeat");
15
+ __publicField(this, "workerCrashed");
16
+ const labelNames = [LABEL_PROJECT];
17
+ this.eventsEnqueued = new prom.Counter({
18
+ registers: [registry],
19
+ name: "contember_actions_events_enqueued_total",
20
+ help: "Total number of action events written to the queue (inflow), by contember_project.",
21
+ labelNames
22
+ });
23
+ this.eventsSucceeded = new prom.Counter({
24
+ registers: [registry],
25
+ name: "contember_actions_events_succeeded_total",
26
+ help: "Total number of action events delivered successfully, by contember_project.",
27
+ labelNames
28
+ });
29
+ this.deliveryAttemptsFailed = new prom.Counter({
30
+ registers: [registry],
31
+ name: "contember_actions_delivery_attempts_failed_total",
32
+ help: "Total number of failed webhook delivery attempts (including attempts that will be retried), by contember_project.",
33
+ labelNames
34
+ });
35
+ this.eventsFailed = new prom.Counter({
36
+ registers: [registry],
37
+ name: "contember_actions_events_failed_total",
38
+ help: "Total number of action events that reached a terminal failed state (retries exhausted or unknown target), by contember_project.",
39
+ labelNames
40
+ });
41
+ this.workerHeartbeat = new prom.Gauge({
42
+ registers: [registry],
43
+ name: "contember_actions_worker_heartbeat_timestamp_seconds",
44
+ help: "Unix timestamp of the last dispatch-loop iteration per contember_project; staleness indicates a stuck or dead worker.",
45
+ labelNames
46
+ });
47
+ this.workerCrashed = new prom.Counter({
48
+ registers: [registry],
49
+ name: "contember_actions_worker_crashed_total",
50
+ help: "Total number of dispatch-loop crashes per contember_project (each is auto-restarted by the supervisor).",
51
+ labelNames
52
+ });
53
+ }
54
+ forProject(projectSlug) {
55
+ return new ProjectActionsMetrics(this, projectSlug);
56
+ }
57
+ }
58
+ class ProjectActionsMetrics {
59
+ constructor(metrics, projectSlug) {
60
+ this.metrics = metrics;
61
+ this.projectSlug = projectSlug;
62
+ __publicField(this, "labels");
63
+ this.labels = { [LABEL_PROJECT]: projectSlug };
64
+ }
65
+ enqueued(count) {
66
+ if (count > 0) {
67
+ this.metrics.eventsEnqueued.inc(this.labels, count);
68
+ }
69
+ }
70
+ succeeded(count) {
71
+ if (count > 0) {
72
+ this.metrics.eventsSucceeded.inc(this.labels, count);
73
+ }
74
+ }
75
+ deliveryAttemptFailed(count) {
76
+ if (count > 0) {
77
+ this.metrics.deliveryAttemptsFailed.inc(this.labels, count);
78
+ }
79
+ }
80
+ failed(count) {
81
+ if (count > 0) {
82
+ this.metrics.eventsFailed.inc(this.labels, count);
83
+ }
84
+ }
85
+ heartbeat() {
86
+ this.metrics.workerHeartbeat.set(this.labels, Date.now() / 1e3);
87
+ }
88
+ crashed() {
89
+ this.metrics.workerCrashed.inc(this.labels, 1);
90
+ }
91
+ /** Drop the per-project heartbeat series when the worker stops, so a removed project doesn't look stuck. */
92
+ dispose() {
93
+ this.metrics.workerHeartbeat.remove(this.projectSlug);
94
+ }
95
+ }
96
+ exports.ActionsMetrics = ActionsMetrics;
97
+ exports.ProjectActionsMetrics = ProjectActionsMetrics;
98
+ //# sourceMappingURL=ActionsMetrics.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ActionsMetrics.cjs","sources":["../../../../packages/engine-actions/src/ActionsMetrics.ts"],"sourcesContent":["import prom, { Registry } from 'prom-client'\n\nconst LABEL_PROJECT = 'contember_project'\ntype Label = typeof LABEL_PROJECT\n\n/**\n * Prometheus metrics for the Actions dispatch subsystem.\n *\n * Two audiences, deliberately kept as cheap in-memory counters/gauges (no table polling):\n * - system / operator — is the dispatch loop alive and flowing, or stuck?\n * `workerHeartbeat` (liveness; works even when the queue is empty) + `workerCrashed`.\n * - userland — are webhook deliveries failing?\n * `eventsSucceeded` / `deliveryAttemptsFailed` / `eventsFailed`.\n *\n * Counting units matter: a *delivery attempt* and an *event* are different. A success is always\n * terminal (one event = one successful attempt), but a failure splits — a failed attempt may be\n * retried many times, while a terminally failed event gives up once. Hence the asymmetric set:\n * one success counter, but both a per-attempt failure counter and a terminal-event failure counter.\n *\n * Queue backlog is *estimated* as a trend from the counters:\n * enqueued − succeeded − failed (compare rates; the absolute value drifts across restarts and\n * ignores manual retry/stop, so for an exact depth query the `actions_event` table instead).\n *\n * Labelled only by `contember_project` to keep cardinality bounded; per-target / per-trigger\n * detail belongs in the table-backed userland view, not in Prometheus.\n */\nexport class ActionsMetrics {\n\t/** Events written to the queue (inflow). Unit: event. */\n\tpublic readonly eventsEnqueued: prom.Counter<Label>\n\t/** Events delivered successfully (terminal). Unit: event (= successful attempt). */\n\tpublic readonly eventsSucceeded: prom.Counter<Label>\n\t/** Failed webhook delivery attempts, including ones that will be retried. Unit: attempt. */\n\tpublic readonly deliveryAttemptsFailed: prom.Counter<Label>\n\t/** Events that reached a terminal failed state (retries exhausted or unknown target). Unit: event. */\n\tpublic readonly eventsFailed: prom.Counter<Label>\n\t/** Unix timestamp (seconds) of the last dispatch-loop iteration; staleness ⇒ stuck/dead worker. */\n\tpublic readonly workerHeartbeat: prom.Gauge<Label>\n\t/** Dispatch-loop crashes (each is auto-restarted by the supervisor). */\n\tpublic readonly workerCrashed: prom.Counter<Label>\n\n\tconstructor(registry: Registry) {\n\t\tconst labelNames: Label[] = [LABEL_PROJECT]\n\t\tthis.eventsEnqueued = new prom.Counter({\n\t\t\tregisters: [registry],\n\t\t\tname: 'contember_actions_events_enqueued_total',\n\t\t\thelp: 'Total number of action events written to the queue (inflow), by contember_project.',\n\t\t\tlabelNames,\n\t\t})\n\t\tthis.eventsSucceeded = new prom.Counter({\n\t\t\tregisters: [registry],\n\t\t\tname: 'contember_actions_events_succeeded_total',\n\t\t\thelp: 'Total number of action events delivered successfully, by contember_project.',\n\t\t\tlabelNames,\n\t\t})\n\t\tthis.deliveryAttemptsFailed = new prom.Counter({\n\t\t\tregisters: [registry],\n\t\t\tname: 'contember_actions_delivery_attempts_failed_total',\n\t\t\thelp: 'Total number of failed webhook delivery attempts (including attempts that will be retried), by contember_project.',\n\t\t\tlabelNames,\n\t\t})\n\t\tthis.eventsFailed = new prom.Counter({\n\t\t\tregisters: [registry],\n\t\t\tname: 'contember_actions_events_failed_total',\n\t\t\thelp: 'Total number of action events that reached a terminal failed state (retries exhausted or unknown target), by contember_project.',\n\t\t\tlabelNames,\n\t\t})\n\t\tthis.workerHeartbeat = new prom.Gauge({\n\t\t\tregisters: [registry],\n\t\t\tname: 'contember_actions_worker_heartbeat_timestamp_seconds',\n\t\t\thelp: 'Unix timestamp of the last dispatch-loop iteration per contember_project; staleness indicates a stuck or dead worker.',\n\t\t\tlabelNames,\n\t\t})\n\t\tthis.workerCrashed = new prom.Counter({\n\t\t\tregisters: [registry],\n\t\t\tname: 'contember_actions_worker_crashed_total',\n\t\t\thelp: 'Total number of dispatch-loop crashes per contember_project (each is auto-restarted by the supervisor).',\n\t\t\tlabelNames,\n\t\t})\n\t}\n\n\tpublic forProject(projectSlug: string): ProjectActionsMetrics {\n\t\treturn new ProjectActionsMetrics(this, projectSlug)\n\t}\n}\n\n/**\n * A view of {@link ActionsMetrics} bound to a single project, so call sites don't repeat the label.\n */\nexport class ProjectActionsMetrics {\n\tprivate readonly labels: { [LABEL_PROJECT]: string }\n\n\tconstructor(\n\t\tprivate readonly metrics: ActionsMetrics,\n\t\tprivate readonly projectSlug: string,\n\t) {\n\t\tthis.labels = { [LABEL_PROJECT]: projectSlug }\n\t}\n\n\tpublic enqueued(count: number): void {\n\t\tif (count > 0) {\n\t\t\tthis.metrics.eventsEnqueued.inc(this.labels, count)\n\t\t}\n\t}\n\n\tpublic succeeded(count: number): void {\n\t\tif (count > 0) {\n\t\t\tthis.metrics.eventsSucceeded.inc(this.labels, count)\n\t\t}\n\t}\n\n\tpublic deliveryAttemptFailed(count: number): void {\n\t\tif (count > 0) {\n\t\t\tthis.metrics.deliveryAttemptsFailed.inc(this.labels, count)\n\t\t}\n\t}\n\n\tpublic failed(count: number): void {\n\t\tif (count > 0) {\n\t\t\tthis.metrics.eventsFailed.inc(this.labels, count)\n\t\t}\n\t}\n\n\tpublic heartbeat(): void {\n\t\tthis.metrics.workerHeartbeat.set(this.labels, Date.now() / 1000)\n\t}\n\n\tpublic crashed(): void {\n\t\tthis.metrics.workerCrashed.inc(this.labels, 1)\n\t}\n\n\t/** Drop the per-project heartbeat series when the worker stops, so a removed project doesn't look stuck. */\n\tpublic dispose(): void {\n\t\tthis.metrics.workerHeartbeat.remove(this.projectSlug)\n\t}\n}\n"],"names":[],"mappings":";;;;;;AAEA,MAAM,gBAAgB;AAwBf,MAAM,eAAe;AAAA,EAc3B,YAAY,UAAoB;AAZhC,kBAAA,MAAgB,gBAAA;AAEhB,kBAAA,MAAgB,iBAAA;AAEhB,kBAAA,MAAgB,wBAAA;AAEhB,kBAAA,MAAgB,cAAA;AAEhB,kBAAA,MAAgB,iBAAA;AAEhB,kBAAA,MAAgB,eAAA;AAGf,UAAM,aAAsB,CAAC,aAAa;AAC1C,SAAK,iBAAiB,IAAI,KAAK,QAAQ;AAAA,MACtC,WAAW,CAAC,QAAQ;AAAA,MACpB,MAAM;AAAA,MACN,MAAM;AAAA,MACN;AAAA,IAAA,CACA;AACD,SAAK,kBAAkB,IAAI,KAAK,QAAQ;AAAA,MACvC,WAAW,CAAC,QAAQ;AAAA,MACpB,MAAM;AAAA,MACN,MAAM;AAAA,MACN;AAAA,IAAA,CACA;AACD,SAAK,yBAAyB,IAAI,KAAK,QAAQ;AAAA,MAC9C,WAAW,CAAC,QAAQ;AAAA,MACpB,MAAM;AAAA,MACN,MAAM;AAAA,MACN;AAAA,IAAA,CACA;AACD,SAAK,eAAe,IAAI,KAAK,QAAQ;AAAA,MACpC,WAAW,CAAC,QAAQ;AAAA,MACpB,MAAM;AAAA,MACN,MAAM;AAAA,MACN;AAAA,IAAA,CACA;AACD,SAAK,kBAAkB,IAAI,KAAK,MAAM;AAAA,MACrC,WAAW,CAAC,QAAQ;AAAA,MACpB,MAAM;AAAA,MACN,MAAM;AAAA,MACN;AAAA,IAAA,CACA;AACD,SAAK,gBAAgB,IAAI,KAAK,QAAQ;AAAA,MACrC,WAAW,CAAC,QAAQ;AAAA,MACpB,MAAM;AAAA,MACN,MAAM;AAAA,MACN;AAAA,IAAA,CACA;AAAA,EACF;AAAA,EAEO,WAAW,aAA4C;AAC7D,WAAO,IAAI,sBAAsB,MAAM,WAAW;AAAA,EACnD;AACD;AAKO,MAAM,sBAAsB;AAAA,EAGlC,YACkB,SACA,aAChB;AAFgB,SAAA,UAAA;AACA,SAAA,cAAA;AAJlB,kBAAA,MAAiB,QAAA;AAMhB,SAAK,SAAS,EAAE,CAAC,aAAa,GAAG,YAAA;AAAA,EAClC;AAAA,EAEO,SAAS,OAAqB;AACpC,QAAI,QAAQ,GAAG;AACd,WAAK,QAAQ,eAAe,IAAI,KAAK,QAAQ,KAAK;AAAA,IACnD;AAAA,EACD;AAAA,EAEO,UAAU,OAAqB;AACrC,QAAI,QAAQ,GAAG;AACd,WAAK,QAAQ,gBAAgB,IAAI,KAAK,QAAQ,KAAK;AAAA,IACpD;AAAA,EACD;AAAA,EAEO,sBAAsB,OAAqB;AACjD,QAAI,QAAQ,GAAG;AACd,WAAK,QAAQ,uBAAuB,IAAI,KAAK,QAAQ,KAAK;AAAA,IAC3D;AAAA,EACD;AAAA,EAEO,OAAO,OAAqB;AAClC,QAAI,QAAQ,GAAG;AACd,WAAK,QAAQ,aAAa,IAAI,KAAK,QAAQ,KAAK;AAAA,IACjD;AAAA,EACD;AAAA,EAEO,YAAkB;AACxB,SAAK,QAAQ,gBAAgB,IAAI,KAAK,QAAQ,KAAK,IAAA,IAAQ,GAAI;AAAA,EAChE;AAAA,EAEO,UAAgB;AACtB,SAAK,QAAQ,cAAc,IAAI,KAAK,QAAQ,CAAC;AAAA,EAC9C;AAAA;AAAA,EAGO,UAAgB;AACtB,SAAK,QAAQ,gBAAgB,OAAO,KAAK,WAAW;AAAA,EACrD;AACD;;;"}
@@ -0,0 +1,98 @@
1
+ import prom from "prom-client";
2
+ var __defProp = Object.defineProperty;
3
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
+ const LABEL_PROJECT = "contember_project";
6
+ class ActionsMetrics {
7
+ constructor(registry) {
8
+ __publicField(this, "eventsEnqueued");
9
+ __publicField(this, "eventsSucceeded");
10
+ __publicField(this, "deliveryAttemptsFailed");
11
+ __publicField(this, "eventsFailed");
12
+ __publicField(this, "workerHeartbeat");
13
+ __publicField(this, "workerCrashed");
14
+ const labelNames = [LABEL_PROJECT];
15
+ this.eventsEnqueued = new prom.Counter({
16
+ registers: [registry],
17
+ name: "contember_actions_events_enqueued_total",
18
+ help: "Total number of action events written to the queue (inflow), by contember_project.",
19
+ labelNames
20
+ });
21
+ this.eventsSucceeded = new prom.Counter({
22
+ registers: [registry],
23
+ name: "contember_actions_events_succeeded_total",
24
+ help: "Total number of action events delivered successfully, by contember_project.",
25
+ labelNames
26
+ });
27
+ this.deliveryAttemptsFailed = new prom.Counter({
28
+ registers: [registry],
29
+ name: "contember_actions_delivery_attempts_failed_total",
30
+ help: "Total number of failed webhook delivery attempts (including attempts that will be retried), by contember_project.",
31
+ labelNames
32
+ });
33
+ this.eventsFailed = new prom.Counter({
34
+ registers: [registry],
35
+ name: "contember_actions_events_failed_total",
36
+ help: "Total number of action events that reached a terminal failed state (retries exhausted or unknown target), by contember_project.",
37
+ labelNames
38
+ });
39
+ this.workerHeartbeat = new prom.Gauge({
40
+ registers: [registry],
41
+ name: "contember_actions_worker_heartbeat_timestamp_seconds",
42
+ help: "Unix timestamp of the last dispatch-loop iteration per contember_project; staleness indicates a stuck or dead worker.",
43
+ labelNames
44
+ });
45
+ this.workerCrashed = new prom.Counter({
46
+ registers: [registry],
47
+ name: "contember_actions_worker_crashed_total",
48
+ help: "Total number of dispatch-loop crashes per contember_project (each is auto-restarted by the supervisor).",
49
+ labelNames
50
+ });
51
+ }
52
+ forProject(projectSlug) {
53
+ return new ProjectActionsMetrics(this, projectSlug);
54
+ }
55
+ }
56
+ class ProjectActionsMetrics {
57
+ constructor(metrics, projectSlug) {
58
+ this.metrics = metrics;
59
+ this.projectSlug = projectSlug;
60
+ __publicField(this, "labels");
61
+ this.labels = { [LABEL_PROJECT]: projectSlug };
62
+ }
63
+ enqueued(count) {
64
+ if (count > 0) {
65
+ this.metrics.eventsEnqueued.inc(this.labels, count);
66
+ }
67
+ }
68
+ succeeded(count) {
69
+ if (count > 0) {
70
+ this.metrics.eventsSucceeded.inc(this.labels, count);
71
+ }
72
+ }
73
+ deliveryAttemptFailed(count) {
74
+ if (count > 0) {
75
+ this.metrics.deliveryAttemptsFailed.inc(this.labels, count);
76
+ }
77
+ }
78
+ failed(count) {
79
+ if (count > 0) {
80
+ this.metrics.eventsFailed.inc(this.labels, count);
81
+ }
82
+ }
83
+ heartbeat() {
84
+ this.metrics.workerHeartbeat.set(this.labels, Date.now() / 1e3);
85
+ }
86
+ crashed() {
87
+ this.metrics.workerCrashed.inc(this.labels, 1);
88
+ }
89
+ /** Drop the per-project heartbeat series when the worker stops, so a removed project doesn't look stuck. */
90
+ dispose() {
91
+ this.metrics.workerHeartbeat.remove(this.projectSlug);
92
+ }
93
+ }
94
+ export {
95
+ ActionsMetrics,
96
+ ProjectActionsMetrics
97
+ };
98
+ //# sourceMappingURL=ActionsMetrics.js.map