@workglow/task-graph 0.2.13 → 0.2.14

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 (38) hide show
  1. package/dist/browser.js +190 -31
  2. package/dist/browser.js.map +19 -18
  3. package/dist/bun.js +190 -31
  4. package/dist/bun.js.map +19 -18
  5. package/dist/node.js +190 -31
  6. package/dist/node.js.map +19 -18
  7. package/dist/task/EntitlementEnforcer.d.ts +37 -4
  8. package/dist/task/EntitlementEnforcer.d.ts.map +1 -1
  9. package/dist/task/EntitlementPolicy.d.ts +10 -0
  10. package/dist/task/EntitlementPolicy.d.ts.map +1 -1
  11. package/dist/task/FallbackTask.d.ts +2 -1
  12. package/dist/task/FallbackTask.d.ts.map +1 -1
  13. package/dist/task/GraphAsTask.d.ts +8 -0
  14. package/dist/task/GraphAsTask.d.ts.map +1 -1
  15. package/dist/task/IteratorTask.d.ts +25 -6
  16. package/dist/task/IteratorTask.d.ts.map +1 -1
  17. package/dist/task/IteratorTaskRunner.d.ts +1 -1
  18. package/dist/task/IteratorTaskRunner.d.ts.map +1 -1
  19. package/dist/task/MapTask.d.ts +47 -3
  20. package/dist/task/MapTask.d.ts.map +1 -1
  21. package/dist/task/ReduceTask.d.ts +9 -3
  22. package/dist/task/ReduceTask.d.ts.map +1 -1
  23. package/dist/task/TaskJSON.d.ts +8 -1
  24. package/dist/task/TaskJSON.d.ts.map +1 -1
  25. package/dist/task/WhileTask.d.ts +20 -7
  26. package/dist/task/WhileTask.d.ts.map +1 -1
  27. package/dist/task-graph/ConditionalBuilder.d.ts +49 -0
  28. package/dist/task-graph/ConditionalBuilder.d.ts.map +1 -0
  29. package/dist/task-graph/Conversions.d.ts.map +1 -1
  30. package/dist/task-graph/GraphSchemaUtils.d.ts +2 -2
  31. package/dist/task-graph/GraphSchemaUtils.d.ts.map +1 -1
  32. package/dist/task-graph/GraphToWorkflowCode.d.ts.map +1 -1
  33. package/dist/task-graph/TaskGraph.d.ts +6 -0
  34. package/dist/task-graph/TaskGraph.d.ts.map +1 -1
  35. package/dist/task-graph/Workflow.d.ts +18 -1
  36. package/dist/task-graph/Workflow.d.ts.map +1 -1
  37. package/package.json +7 -7
  38. package/src/EXECUTION_MODEL.md +6 -0
package/dist/bun.js CHANGED
@@ -637,7 +637,8 @@ function computeGraphInputSchema(graph, options) {
637
637
  for (const [inputName, inputProp] of Object.entries(taskProperties)) {
638
638
  if (!properties[inputName]) {
639
639
  properties[inputName] = inputProp;
640
- if (taskInputSchema.required && taskInputSchema.required.includes(inputName)) {
640
+ const isRequired = taskInputSchema.required?.includes(inputName) === true && !(task.defaults && task.defaults[inputName] !== undefined);
641
+ if (isRequired) {
641
642
  required.push(inputName);
642
643
  }
643
644
  if (trackOrigins) {
@@ -950,6 +951,7 @@ import { DirectedAcyclicGraph } from "@workglow/util/graph";
950
951
 
951
952
  // src/task/GraphAsTask.ts
952
953
  import { getLogger as getLogger4 } from "@workglow/util";
954
+ import { CycleError } from "@workglow/util/graph";
953
955
  import { compileSchema as compileSchema2 } from "@workglow/util/schema";
954
956
 
955
957
  // src/task-graph/TaskGraphRunner.ts
@@ -2474,6 +2476,11 @@ function evaluatePolicy(policy, required) {
2474
2476
  }
2475
2477
  return results;
2476
2478
  }
2479
+ function can(policy, id, resources) {
2480
+ const required = resources !== undefined ? { id, resources } : { id };
2481
+ const [result] = evaluatePolicy(policy, { entitlements: [required] });
2482
+ return result;
2483
+ }
2477
2484
 
2478
2485
  // src/task/EntitlementResolver.ts
2479
2486
  import { createServiceToken as createServiceToken2 } from "@workglow/util";
@@ -2490,6 +2497,16 @@ var DENY_ALL_RESOLVER = {
2490
2497
  var ENTITLEMENT_RESOLVER = createServiceToken2("workglow.entitlementResolver");
2491
2498
 
2492
2499
  // src/task/EntitlementEnforcer.ts
2500
+ function formatEntitlementDenial(denial) {
2501
+ switch (denial.reason) {
2502
+ case "policy-deny":
2503
+ return `${denial.entitlement.id} (denied by rule ${denial.matchedRule.id})`;
2504
+ case "user-deny":
2505
+ return `${denial.entitlement.id} (denied by user)`;
2506
+ case "default-deny":
2507
+ return `${denial.entitlement.id} (no matching grant)`;
2508
+ }
2509
+ }
2493
2510
  var PERMISSIVE_ENFORCER = {
2494
2511
  checkAll: async () => [],
2495
2512
  checkTask: async () => []
@@ -2500,24 +2517,27 @@ function createPolicyEnforcer(policy, resolver = PERMISSIVE_RESOLVER) {
2500
2517
  const denied = [];
2501
2518
  for (const result of results) {
2502
2519
  if (result.verdict === "denied") {
2503
- denied.push(result.entitlement);
2520
+ if (result.matchedRule) {
2521
+ denied.push({ entitlement: result.entitlement, reason: "policy-deny", matchedRule: result.matchedRule });
2522
+ } else {
2523
+ denied.push({ entitlement: result.entitlement, reason: "default-deny" });
2524
+ }
2504
2525
  } else if (result.verdict === "ask") {
2505
2526
  const request = {
2506
2527
  entitlement: result.entitlement,
2507
2528
  taskType: taskType ?? "unknown",
2508
2529
  taskId: taskId ?? "unknown"
2509
2530
  };
2510
- const saved = resolver.lookup(request);
2511
- if (saved !== undefined) {
2512
- if (saved === "deny") {
2513
- denied.push(result.entitlement);
2514
- }
2515
- continue;
2531
+ let answer = resolver.lookup(request);
2532
+ if (answer === undefined) {
2533
+ answer = await resolver.prompt(request);
2534
+ resolver.save(request, answer);
2516
2535
  }
2517
- const answer = await resolver.prompt(request);
2518
- resolver.save(request, answer);
2519
2536
  if (answer === "deny") {
2520
- denied.push(result.entitlement);
2537
+ if (!result.matchedRule) {
2538
+ throw new Error(`Invariant violation: ask verdict for "${result.entitlement.id}" is missing matchedRule`);
2539
+ }
2540
+ denied.push({ entitlement: result.entitlement, reason: "user-deny", matchedRule: result.matchedRule });
2521
2541
  }
2522
2542
  }
2523
2543
  }
@@ -3025,7 +3045,7 @@ class TaskGraphRunner {
3025
3045
  if (this.activeEnforcer && task.constructor.hasDynamicEntitlements) {
3026
3046
  const denied = await this.activeEnforcer.checkTask(task);
3027
3047
  if (denied.length > 0) {
3028
- throw new TaskEntitlementError(`Task ${task.constructor.type} denied entitlements: ${denied.map((e) => e.id).join(", ")}`);
3048
+ throw new TaskEntitlementError(`Task ${task.constructor.type} denied entitlements: ${denied.map(formatEntitlementDenial).join(", ")}`);
3029
3049
  }
3030
3050
  }
3031
3051
  if (isStreamable) {
@@ -3248,7 +3268,7 @@ class TaskGraphRunner {
3248
3268
  const enforcer = this.registry.get(ENTITLEMENT_ENFORCER);
3249
3269
  const denied = await enforcer.checkAll(computeGraphEntitlements(this.graph));
3250
3270
  if (denied.length > 0) {
3251
- throw new TaskEntitlementError(`Denied entitlements: ${denied.map((e) => e.id).join(", ")}`);
3271
+ throw new TaskEntitlementError(`Denied entitlements: ${denied.map(formatEntitlementDenial).join(", ")}`);
3252
3272
  }
3253
3273
  this.activeEnforcer = enforcer;
3254
3274
  } else {
@@ -3592,6 +3612,18 @@ class GraphAsTask extends Task {
3592
3612
  yield { type: "finish", data: input };
3593
3613
  }
3594
3614
  }
3615
+ validateAcyclic() {
3616
+ if (!this.hasChildren())
3617
+ return;
3618
+ if (!this.subGraph.isAcyclic()) {
3619
+ throw new CycleError(`${this.type} (${this.id}): subgraph contains a cycle \u2014 loop tasks must wrap an acyclic subgraph.`);
3620
+ }
3621
+ for (const child of this.subGraph.getTasks()) {
3622
+ if (child instanceof GraphAsTask) {
3623
+ child.validateAcyclic();
3624
+ }
3625
+ }
3626
+ }
3595
3627
  regenerateGraph() {
3596
3628
  this._inputSchemaNode = undefined;
3597
3629
  this.events.emit("regenerate");
@@ -3742,7 +3774,7 @@ function convertPipeFunctionToTask(fn, config) {
3742
3774
  properties: {
3743
3775
  [DATAFLOW_ALL_PORTS]: {}
3744
3776
  },
3745
- additionalProperties: false
3777
+ additionalProperties: true
3746
3778
  };
3747
3779
  };
3748
3780
  static outputSchema = () => {
@@ -3751,7 +3783,7 @@ function convertPipeFunctionToTask(fn, config) {
3751
3783
  properties: {
3752
3784
  [DATAFLOW_ALL_PORTS]: {}
3753
3785
  },
3754
- additionalProperties: false
3786
+ additionalProperties: true
3755
3787
  };
3756
3788
  };
3757
3789
  static cacheable = false;
@@ -3860,6 +3892,9 @@ class TaskGraph {
3860
3892
  topologicallySortedNodes() {
3861
3893
  return this._dag.topologicallySortedNodes();
3862
3894
  }
3895
+ isAcyclic() {
3896
+ return this._dag.isAcyclic();
3897
+ }
3863
3898
  addTask(task, config) {
3864
3899
  return this._dag.addNode(ensureTask(task, config));
3865
3900
  }
@@ -4133,7 +4168,75 @@ function serialGraph(tasks, inputHandle, outputHandle) {
4133
4168
  return graph;
4134
4169
  }
4135
4170
  // src/task-graph/Workflow.ts
4136
- import { EventEmitter as EventEmitter5, getLogger as getLogger5, uuid4 as uuid45 } from "@workglow/util";
4171
+ import { EventEmitter as EventEmitter5, getLogger as getLogger5, uuid4 as uuid46 } from "@workglow/util";
4172
+
4173
+ // src/task-graph/ConditionalBuilder.ts
4174
+ import { uuid4 as uuid45 } from "@workglow/util";
4175
+ class ConditionalBuilder {
4176
+ workflow;
4177
+ condition;
4178
+ thenSpec;
4179
+ elseSpec;
4180
+ constructor(workflow, condition) {
4181
+ this.workflow = workflow;
4182
+ this.condition = condition;
4183
+ }
4184
+ then(taskClass, input, config) {
4185
+ this.thenSpec = { taskClass, input, config };
4186
+ return this;
4187
+ }
4188
+ else(taskClass, input, config) {
4189
+ this.elseSpec = { taskClass, input, config };
4190
+ return this;
4191
+ }
4192
+ endIf() {
4193
+ if (!this.thenSpec) {
4194
+ throw new WorkflowError(".endIf() called without a prior .then(...) call");
4195
+ }
4196
+ const thenPort = "then";
4197
+ const elsePort = "else";
4198
+ const branches = [
4199
+ {
4200
+ id: thenPort,
4201
+ condition: this.condition,
4202
+ outputPort: thenPort
4203
+ }
4204
+ ];
4205
+ if (this.elseSpec) {
4206
+ branches.push({
4207
+ id: elsePort,
4208
+ condition: (input) => !this.condition(input),
4209
+ outputPort: elsePort
4210
+ });
4211
+ }
4212
+ const conditionalTask = new ConditionalTask({
4213
+ id: uuid45(),
4214
+ branches,
4215
+ exclusive: true,
4216
+ defaultBranch: this.elseSpec ? elsePort : undefined
4217
+ });
4218
+ this.workflow.graph.addTask(conditionalTask);
4219
+ const thenTask = instantiate(this.thenSpec);
4220
+ this.workflow.graph.addTask(thenTask);
4221
+ this.workflow.graph.addDataflow(new Dataflow(conditionalTask.id, thenPort, thenTask.id, "*"));
4222
+ if (this.elseSpec) {
4223
+ const elseTask = instantiate(this.elseSpec);
4224
+ this.workflow.graph.addTask(elseTask);
4225
+ this.workflow.graph.addDataflow(new Dataflow(conditionalTask.id, elsePort, elseTask.id, "*"));
4226
+ }
4227
+ return this.workflow;
4228
+ }
4229
+ }
4230
+ function instantiate(spec) {
4231
+ const config = {
4232
+ id: uuid45(),
4233
+ ...spec.config,
4234
+ defaults: spec.input
4235
+ };
4236
+ return new spec.taskClass(config);
4237
+ }
4238
+
4239
+ // src/task-graph/Workflow.ts
4137
4240
  function getLastTask(workflow) {
4138
4241
  const tasks = workflow.graph.getTasks();
4139
4242
  return tasks.length > 0 ? tasks[tasks.length - 1] : undefined;
@@ -4276,7 +4379,7 @@ class Workflow {
4276
4379
  this._error = "";
4277
4380
  const parent = getLastTask(this);
4278
4381
  const task = this.addTaskToGraph(taskClass, {
4279
- id: uuid45(),
4382
+ id: uuid46(),
4280
4383
  ...config,
4281
4384
  defaults: input
4282
4385
  });
@@ -4557,7 +4660,7 @@ class Workflow {
4557
4660
  addLoopTask(taskClass, config = {}) {
4558
4661
  this._error = "";
4559
4662
  const parent = getLastTask(this);
4560
- const task = this.addTaskToGraph(taskClass, { id: uuid45(), ...config });
4663
+ const task = this.addTaskToGraph(taskClass, { id: uuid46(), ...config });
4561
4664
  if (this._dataFlows.length > 0) {
4562
4665
  this._dataFlows.forEach((dataflow) => {
4563
4666
  const taskSchema = task.inputSchema();
@@ -4577,6 +4680,9 @@ class Workflow {
4577
4680
  }
4578
4681
  return loopBuilder;
4579
4682
  }
4683
+ if(condition) {
4684
+ return new ConditionalBuilder(this, condition);
4685
+ }
4580
4686
  autoConnectLoopTask(pending) {
4581
4687
  if (!pending)
4582
4688
  return;
@@ -4934,6 +5040,7 @@ class Workflow {
4934
5040
  return;
4935
5041
  }
4936
5042
  this._iteratorTask.subGraph = this.graph;
5043
+ this._iteratorTask.validateAcyclic();
4937
5044
  }
4938
5045
  finalizeAndReturn() {
4939
5046
  if (!this._parentWorkflow) {
@@ -4968,6 +5075,7 @@ function getMethodNameMap() {
4968
5075
  }
4969
5076
  var LOOP_TASK_TYPES = {
4970
5077
  MapTask: { method: "map", endMethod: "endMap" },
5078
+ ForEachTask: { method: "forEach", endMethod: "endForEach" },
4971
5079
  ReduceTask: { method: "reduce", endMethod: "endReduce" },
4972
5080
  WhileTask: { method: "while", endMethod: "endWhile" },
4973
5081
  GraphAsTask: { method: "group", endMethod: "endGroup" }
@@ -5150,7 +5258,8 @@ function extractLoopConfig(task) {
5150
5258
  }
5151
5259
  break;
5152
5260
  }
5153
- case "MapTask": {
5261
+ case "MapTask":
5262
+ case "ForEachTask": {
5154
5263
  if (rawConfig.preserveOrder !== undefined && rawConfig.preserveOrder !== true) {
5155
5264
  config.preserveOrder = rawConfig.preserveOrder;
5156
5265
  }
@@ -5163,16 +5272,22 @@ function extractLoopConfig(task) {
5163
5272
  if (rawConfig.batchSize !== undefined) {
5164
5273
  config.batchSize = rawConfig.batchSize;
5165
5274
  }
5275
+ if (rawConfig.maxIterations !== undefined) {
5276
+ config.maxIterations = rawConfig.maxIterations;
5277
+ }
5166
5278
  break;
5167
5279
  }
5168
5280
  case "ReduceTask": {
5169
5281
  if (rawConfig.initialValue !== undefined) {
5170
5282
  config.initialValue = rawConfig.initialValue;
5171
5283
  }
5284
+ if (rawConfig.maxIterations !== undefined) {
5285
+ config.maxIterations = rawConfig.maxIterations;
5286
+ }
5172
5287
  break;
5173
5288
  }
5174
5289
  case "WhileTask": {
5175
- if (rawConfig.maxIterations !== undefined && rawConfig.maxIterations !== 100) {
5290
+ if (rawConfig.maxIterations !== undefined) {
5176
5291
  config.maxIterations = rawConfig.maxIterations;
5177
5292
  }
5178
5293
  if (rawConfig.chainIterations !== undefined && rawConfig.chainIterations !== true) {
@@ -5610,15 +5725,15 @@ async function compactSchemaInputs(input, schema, config, visited = new Set) {
5610
5725
  return compacted;
5611
5726
  }
5612
5727
  // src/task/IteratorTaskRunner.ts
5613
- import { uuid4 as uuid46 } from "@workglow/util";
5728
+ import { uuid4 as uuid47 } from "@workglow/util";
5614
5729
  class IteratorTaskRunner extends GraphAsTaskRunner {
5615
5730
  aggregatingParentMapProgress = false;
5616
5731
  mapPartialProgress = [];
5617
5732
  mapPartialIterationCount = 0;
5618
5733
  async executeTask(input) {
5619
5734
  let analysis = this.task.analyzeIterationInput(input);
5620
- const maxIterations = this.task.config.maxIterations;
5621
- if (maxIterations !== undefined && maxIterations > 0 && analysis.iterationCount > maxIterations) {
5735
+ const maxIterations = resolveIterationBound(this.task.config.maxIterations);
5736
+ if (analysis.iterationCount > maxIterations) {
5622
5737
  analysis = { ...analysis, iterationCount: maxIterations };
5623
5738
  }
5624
5739
  if (analysis.iterationCount === 0) {
@@ -5724,7 +5839,7 @@ class IteratorTaskRunner extends GraphAsTaskRunner {
5724
5839
  const idMap = new Map;
5725
5840
  for (const task of graph.getTasks()) {
5726
5841
  const ctor = task.constructor;
5727
- const newId = uuid46();
5842
+ const newId = uuid47();
5728
5843
  idMap.set(task.config.id, newId);
5729
5844
  const clonedConfig = { ...task.config, id: newId };
5730
5845
  const newTask = new ctor({ ...clonedConfig, defaults: task.defaults }, task.runConfig);
@@ -5794,15 +5909,21 @@ var ITERATOR_CONTEXT_SCHEMA = {
5794
5909
  }
5795
5910
  }
5796
5911
  };
5912
+ function resolveIterationBound(bound) {
5913
+ return bound === "unbounded" ? Number.POSITIVE_INFINITY : bound;
5914
+ }
5797
5915
  var iteratorTaskConfigSchema = {
5798
5916
  type: "object",
5799
5917
  properties: {
5800
5918
  ...graphAsTaskConfigSchema["properties"],
5801
5919
  concurrencyLimit: { type: "integer", minimum: 1 },
5802
5920
  batchSize: { type: "integer", minimum: 1 },
5803
- maxIterations: { type: "integer", minimum: 1 },
5921
+ maxIterations: {
5922
+ oneOf: [{ type: "integer", minimum: 1 }, { type: "string", const: "unbounded" }]
5923
+ },
5804
5924
  iterationInputConfig: { type: "object", additionalProperties: true }
5805
5925
  },
5926
+ required: ["maxIterations"],
5806
5927
  additionalProperties: false
5807
5928
  };
5808
5929
  function isArrayVariant(schema) {
@@ -5917,6 +6038,12 @@ class IteratorTask extends GraphAsTask {
5917
6038
  static configSchema() {
5918
6039
  return iteratorTaskConfigSchema;
5919
6040
  }
6041
+ constructor(config = {}, runConfig = {}) {
6042
+ if (config.maxIterations === undefined) {
6043
+ throw new TaskConfigurationError(`${new.target.type ?? "IteratorTask"}: maxIterations is required. ` + `Pass a positive integer to cap iteration, or "unbounded" to opt out explicitly.`);
6044
+ }
6045
+ super(config, runConfig);
6046
+ }
5920
6047
  static getIterationContextSchema() {
5921
6048
  return ITERATOR_CONTEXT_SCHEMA;
5922
6049
  }
@@ -6306,13 +6433,16 @@ var whileTaskConfigSchema = {
6306
6433
  properties: {
6307
6434
  ...graphAsTaskConfigSchema["properties"],
6308
6435
  condition: {},
6309
- maxIterations: { type: "integer", minimum: 1 },
6436
+ maxIterations: {
6437
+ oneOf: [{ type: "integer", minimum: 1 }, { type: "string", const: "unbounded" }]
6438
+ },
6310
6439
  chainIterations: { type: "boolean" },
6311
6440
  conditionField: { type: "string" },
6312
6441
  conditionOperator: { type: "string" },
6313
6442
  conditionValue: { type: "string" },
6314
6443
  iterationInputConfig: { type: "object", additionalProperties: true }
6315
6444
  },
6445
+ required: ["maxIterations"],
6316
6446
  additionalProperties: false
6317
6447
  };
6318
6448
 
@@ -6325,6 +6455,12 @@ class WhileTask extends GraphAsTask {
6325
6455
  static configSchema() {
6326
6456
  return whileTaskConfigSchema;
6327
6457
  }
6458
+ constructor(config = {}, runConfig = {}) {
6459
+ if (config.maxIterations === undefined) {
6460
+ throw new TaskConfigurationError(`${new.target.type ?? "WhileTask"}: maxIterations is required. ` + `Pass a positive integer to cap iteration, or "unbounded" to opt out explicitly.`);
6461
+ }
6462
+ super(config, runConfig);
6463
+ }
6328
6464
  static getIterationContextSchema() {
6329
6465
  return WHILE_CONTEXT_SCHEMA;
6330
6466
  }
@@ -6342,7 +6478,7 @@ class WhileTask extends GraphAsTask {
6342
6478
  return this.config.condition;
6343
6479
  }
6344
6480
  get maxIterations() {
6345
- return this.config.maxIterations ?? 100;
6481
+ return resolveIterationBound(this.config.maxIterations);
6346
6482
  }
6347
6483
  get chainIterations() {
6348
6484
  return this.config.chainIterations ?? true;
@@ -6949,8 +7085,10 @@ var mapTaskConfigSchema = {
6949
7085
  properties: {
6950
7086
  ...iteratorTaskConfigSchema["properties"],
6951
7087
  preserveOrder: { type: "boolean" },
6952
- flatten: { type: "boolean" }
7088
+ flatten: { type: "boolean" },
7089
+ discardResults: { type: "boolean" }
6953
7090
  },
7091
+ required: iteratorTaskConfigSchema.required,
6954
7092
  additionalProperties: false
6955
7093
  };
6956
7094
 
@@ -6983,6 +7121,9 @@ class MapTask extends IteratorTask {
6983
7121
  get flatten() {
6984
7122
  return this.config.flatten ?? false;
6985
7123
  }
7124
+ get discardResults() {
7125
+ return this.config.discardResults ?? false;
7126
+ }
6986
7127
  preserveIterationOrder() {
6987
7128
  return this.preserveOrder;
6988
7129
  }
@@ -7004,6 +7145,9 @@ class MapTask extends IteratorTask {
7004
7145
  return this.getWrappedOutputSchema();
7005
7146
  }
7006
7147
  collectResults(results) {
7148
+ if (this.discardResults) {
7149
+ return this.getEmptyResult();
7150
+ }
7007
7151
  const collected = super.collectResults(results);
7008
7152
  if (!this.flatten || typeof collected !== "object" || collected === null) {
7009
7153
  return collected;
@@ -7019,8 +7163,19 @@ class MapTask extends IteratorTask {
7019
7163
  return flattened;
7020
7164
  }
7021
7165
  }
7166
+
7167
+ class ForEachTask extends MapTask {
7168
+ static type = "ForEachTask";
7169
+ static title = "For Each";
7170
+ static description = "Runs a workflow per array item for side effects; discards collected results";
7171
+ constructor(config = {}, runConfig = {}) {
7172
+ super({ discardResults: true, ...config }, runConfig);
7173
+ }
7174
+ }
7022
7175
  Workflow.prototype.map = CreateLoopWorkflow(MapTask);
7023
7176
  Workflow.prototype.endMap = CreateEndLoopWorkflow("endMap");
7177
+ Workflow.prototype.forEach = CreateLoopWorkflow(ForEachTask);
7178
+ Workflow.prototype.endForEach = CreateEndLoopWorkflow("endForEach");
7024
7179
  // src/task/ReduceTask.ts
7025
7180
  var reduceTaskConfigSchema = {
7026
7181
  type: "object",
@@ -7039,13 +7194,13 @@ class ReduceTask extends IteratorTask {
7039
7194
  static configSchema() {
7040
7195
  return reduceTaskConfigSchema;
7041
7196
  }
7042
- constructor(config = {}) {
7197
+ constructor(config = {}, runConfig = {}) {
7043
7198
  const reduceConfig = {
7044
7199
  ...config,
7045
7200
  concurrencyLimit: 1,
7046
7201
  batchSize: 1
7047
7202
  };
7048
- super(reduceConfig);
7203
+ super(reduceConfig, runConfig);
7049
7204
  }
7050
7205
  get initialValue() {
7051
7206
  return this.config.initialValue ?? {};
@@ -7489,6 +7644,7 @@ export {
7489
7644
  scanGraphForCredentials,
7490
7645
  resourcePatternMatches,
7491
7646
  resolveSchemaInputs,
7647
+ resolveIterationBound,
7492
7648
  resetMethodNameCache,
7493
7649
  removeIterationProperties,
7494
7650
  registerJobQueueFactory,
@@ -7531,6 +7687,7 @@ export {
7531
7687
  getFormatPrefix,
7532
7688
  getAppendPortId,
7533
7689
  formatValue,
7690
+ formatEntitlementDenial,
7534
7691
  findArrayPorts,
7535
7692
  filterIterationProperties,
7536
7693
  fallbackTaskConfigSchema,
@@ -7559,6 +7716,7 @@ export {
7559
7716
  computeGraphInputSchema,
7560
7717
  computeGraphEntitlements,
7561
7718
  compactSchemaInputs,
7719
+ can,
7562
7720
  calculateNodeDepths,
7563
7721
  buildIterationInputSchema,
7564
7722
  addIterationContextToSchema,
@@ -7611,6 +7769,7 @@ export {
7611
7769
  GraphAsTaskRunner,
7612
7770
  GraphAsTask,
7613
7771
  GRAPH_RESULT_ARRAY,
7772
+ ForEachTask,
7614
7773
  FallbackTaskRunner,
7615
7774
  FallbackTask,
7616
7775
  EventTaskGraphToDagMapping,
@@ -7634,4 +7793,4 @@ export {
7634
7793
  BROWSER_GRANTS
7635
7794
  };
7636
7795
 
7637
- //# debugId=D70838C34E16DC2B64756E2164756E21
7796
+ //# debugId=ACCBFB832EC2FB9F64756E2164756E21