diff --git a/src/modules/Elsa.JavaScript/Features/JavaScriptFeature.cs b/src/modules/Elsa.JavaScript/Features/JavaScriptFeature.cs
index d2ff8d3d1..6f25bff29 100644
--- a/src/modules/Elsa.JavaScript/Features/JavaScriptFeature.cs
+++ b/src/modules/Elsa.JavaScript/Features/JavaScriptFeature.cs
@@ -33,6 +33,13 @@ public class JavaScriptFeature : FeatureBase
///
public override void Configure()
{
+ Module.UseWorkflowManagement(management => management.AddActivitiesFrom());
+ }
+
+ ///
+ public override void Apply()
+ {
+ // JavaScript services.
Services
.AddSingleton()
.AddSingleton()
@@ -41,6 +48,7 @@ public class JavaScriptFeature : FeatureBase
.AddExpressionHandler()
;
+ // Type definition services.
Services
.AddSingleton()
.AddSingleton()
@@ -50,7 +58,8 @@ public class JavaScriptFeature : FeatureBase
.AddSingleton()
.AddSingleton()
;
-
- Module.UseWorkflowManagement(management => management.AddActivitiesFrom());
+
+ // Handlers.
+ Services.AddNotificationHandlersFrom();
}
}
\ No newline at end of file
diff --git a/src/modules/Elsa.JavaScript/Handlers/WorkflowDefinitionActivityJavaScriptHandler.cs b/src/modules/Elsa.JavaScript/Handlers/WorkflowDefinitionActivityJavaScriptHandler.cs
new file mode 100644
index 000000000..281d2a751
--- /dev/null
+++ b/src/modules/Elsa.JavaScript/Handlers/WorkflowDefinitionActivityJavaScriptHandler.cs
@@ -0,0 +1,73 @@
+using Elsa.Expressions.Models;
+using Elsa.Expressions.Services;
+using Elsa.Extensions;
+using Elsa.JavaScript.Notifications;
+using Elsa.Mediator.Services;
+using Elsa.Workflows.Core.Models;
+using Elsa.Workflows.Management.Activities;
+using Elsa.Workflows.Management.Extensions;
+using Elsa.Workflows.Management.Services;
+using Humanizer;
+using JetBrains.Annotations;
+using Jint;
+
+namespace Elsa.JavaScript.Handlers;
+
+///
+/// Configures the JavaScript engine with workflow input getters.
+///
+[PublicAPI]
+public class WorkflowDefinitionActivityJavaScriptHandler : INotificationHandler
+{
+ private readonly IActivityRegistry _activityRegistry;
+ private readonly IExpressionEvaluator _expressionEvaluator;
+
+ ///
+ /// Constructor.
+ ///
+ public WorkflowDefinitionActivityJavaScriptHandler(IActivityRegistry activityRegistry, IExpressionEvaluator expressionEvaluator)
+ {
+ _activityRegistry = activityRegistry;
+ _expressionEvaluator = expressionEvaluator;
+ }
+
+ ///
+ public async Task HandleAsync(EvaluatingJavaScript notification, CancellationToken cancellationToken)
+ {
+ var engine = notification.Engine;
+ var context = notification.Context;
+
+ // If we are already evaluating inputs, then we're in a circular evaluation loop. In this case, we should not attempt to evaluate the inputs.
+ if(context.TransientProperties.TryGetValue("EvaluatingInputs", out var evaluatingInputs) && (bool)evaluatingInputs)
+ return;
+
+ // To prevent a circular evaluation loop, set a flag on the context to indicate that we're currently evaluating the inputs.
+ context.TransientProperties["EvaluatingInputs"] = true;
+
+ // Create input getters.
+ await CreateInputAccessorsAsync(engine, context);
+ }
+
+ private async Task CreateInputAccessorsAsync(Engine engine, ExpressionExecutionContext context)
+ {
+ var workflowDefinitionActivity = GetFirstWorkflowDefinitionActivity(context);
+
+ if (workflowDefinitionActivity == null)
+ return;
+
+ var descriptor = _activityRegistry.Find(workflowDefinitionActivity.Type, workflowDefinitionActivity.Version)!;
+ var inputDefinitions = descriptor.Inputs;
+
+ foreach (var inputDefinition in inputDefinitions)
+ {
+ var inputPascalName = inputDefinition.Name.Pascalize();
+ var input = workflowDefinitionActivity.SyntheticProperties.TryGetValue(inputDefinition.Name, out var inputValue) ? (Input?)inputValue : default;
+ var evaluatedExpression = input != null ? await _expressionEvaluator.EvaluateAsync(input, context) : input;
+
+ engine.SetValue($"get{inputPascalName}", (Func