@boboddy/sdk 0.4.2 → 0.5.0

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 (34) hide show
  1. package/dist/client.js +0 -23
  2. package/dist/definitions/advancement-policies/define-advancement-policy.d.ts +30 -5
  3. package/dist/definitions/advancement-policies/index.js +11 -1
  4. package/dist/definitions/pipelines/bindings.d.ts +62 -0
  5. package/dist/definitions/pipelines/builder-helpers.d.ts +36 -94
  6. package/dist/definitions/pipelines/chain-graph.d.ts +15 -14
  7. package/dist/definitions/pipelines/compile-node-definitions.d.ts +27 -0
  8. package/dist/definitions/pipelines/define-default-pipeline-assignment.d.ts +64 -14
  9. package/dist/definitions/pipelines/define-pipeline.d.ts +101 -154
  10. package/dist/definitions/pipelines/index.d.ts +1 -2
  11. package/dist/definitions/pipelines/index.js +485 -585
  12. package/dist/definitions/pipelines/node-input-ctx.d.ts +31 -0
  13. package/dist/definitions/pipelines/pipeline-definitions-client.d.ts +42 -12
  14. package/dist/definitions/pipelines/pipeline-states.d.ts +104 -0
  15. package/dist/definitions/pipelines/work-item-fields.d.ts +98 -0
  16. package/dist/definitions/steps/define-code-step.d.ts +50 -0
  17. package/dist/definitions/steps/define-step.d.ts +40 -8
  18. package/dist/definitions/steps/index.d.ts +1 -0
  19. package/dist/definitions/steps/index.js +41 -24
  20. package/dist/definitions/steps/step-definitions-client.d.ts +47 -11
  21. package/dist/definitions/validation/index.js +15148 -94
  22. package/dist/definitions/validation/validate-definition-specs.d.ts +19 -1
  23. package/dist/generated/index.d.ts +1 -1
  24. package/dist/generated/sdk.gen.d.ts +1 -4
  25. package/dist/generated/types.gen.d.ts +469 -875
  26. package/dist/index.js +525 -585
  27. package/dist/push/collect-definitions.d.ts +40 -1
  28. package/dist/push/index.d.ts +2 -2
  29. package/dist/push/index.js +756 -664
  30. package/dist/step-execution-plane-client.d.ts +9 -4
  31. package/package.json +2 -2
  32. package/dist/definitions/pipelines/builder.d.ts +0 -80
  33. package/dist/definitions/pipelines/fan-out-builder.d.ts +0 -66
  34. package/dist/definitions/pipelines/input-accessor.d.ts +0 -25
@@ -14328,10 +14328,19 @@ function any2(conditions, outcome) {
14328
14328
  return { _tag: "rule", mode: "any", conditions, outcome };
14329
14329
  }
14330
14330
  function when(signal2, operator, value, outcome) {
14331
+ const condition = {
14332
+ _tag: "signal",
14333
+ signal: signal2,
14334
+ operator,
14335
+ value
14336
+ };
14337
+ if (outcome === undefined) {
14338
+ return condition;
14339
+ }
14331
14340
  return {
14332
14341
  _tag: "rule",
14333
14342
  mode: "all",
14334
- conditions: [{ _tag: "signal", signal: signal2, operator, value }],
14343
+ conditions: [condition],
14335
14344
  outcome
14336
14345
  };
14337
14346
  }
@@ -14507,402 +14516,9 @@ function extractInlineStepSignalsListDefinitions(policy) {
14507
14516
  return [...byKey.values()];
14508
14517
  }
14509
14518
 
14510
- // src/definitions/pipelines/chain-graph.ts
14511
- function tryOrderChainNodeDefinitions(nodeDefinitions, dependencyEdges) {
14512
- const nodesByKey = new Map;
14513
- for (const nodeDefinition of nodeDefinitions) {
14514
- nodesByKey.set(nodeDefinition.nodeKey, nodeDefinition);
14515
- }
14516
- const outgoing = new Map;
14517
- const incomingCount = new Map;
14518
- for (const nodeDefinition of nodeDefinitions) {
14519
- incomingCount.set(nodeDefinition.nodeKey, 0);
14520
- }
14521
- for (const edge of dependencyEdges) {
14522
- if (!nodesByKey.has(edge.fromNodeKey) || !nodesByKey.has(edge.toNodeKey)) {
14523
- return null;
14524
- }
14525
- if (outgoing.has(edge.fromNodeKey))
14526
- return null;
14527
- outgoing.set(edge.fromNodeKey, edge.toNodeKey);
14528
- incomingCount.set(edge.toNodeKey, (incomingCount.get(edge.toNodeKey) ?? 0) + 1);
14529
- }
14530
- for (const count of incomingCount.values()) {
14531
- if (count > 1)
14532
- return null;
14533
- }
14534
- if (nodeDefinitions.length === 0)
14535
- return [];
14536
- const roots = nodeDefinitions.filter((nodeDefinition) => (incomingCount.get(nodeDefinition.nodeKey) ?? 0) === 0);
14537
- if (roots.length !== 1)
14538
- return null;
14539
- const rootNode = roots[0];
14540
- if (!rootNode)
14541
- return null;
14542
- const ordered = [];
14543
- const visited = new Set;
14544
- let currentKey = rootNode.nodeKey;
14545
- while (currentKey !== undefined) {
14546
- if (visited.has(currentKey))
14547
- return null;
14548
- visited.add(currentKey);
14549
- const currentNode = nodesByKey.get(currentKey);
14550
- if (!currentNode)
14551
- return null;
14552
- ordered.push(currentNode);
14553
- currentKey = outgoing.get(currentKey);
14554
- }
14555
- if (ordered.length !== nodeDefinitions.length)
14556
- return null;
14557
- return ordered;
14558
- }
14559
- function buildChainDependencyEdges(orderedNodes) {
14560
- const dependencyEdges = [];
14561
- for (let index = 0;index < orderedNodes.length - 1; index += 1) {
14562
- const from = orderedNodes[index];
14563
- const to = orderedNodes[index + 1];
14564
- if (!from || !to)
14565
- continue;
14566
- dependencyEdges.push({ fromNodeKey: from.nodeKey, toNodeKey: to.nodeKey });
14567
- }
14568
- return dependencyEdges;
14569
- }
14570
-
14571
- // src/definitions/pipelines/define-pipeline.ts
14572
- function serializeBinding(binding) {
14573
- if (binding.source === "pipeline_input") {
14574
- return { source: "pipeline_input", path: binding.path };
14575
- }
14576
- if (binding.source === "work_item") {
14577
- return { source: "work_item", field: binding.field };
14578
- }
14579
- if (binding.source === "step_signal") {
14580
- return {
14581
- source: "step_signal",
14582
- stepKey: binding.step.key,
14583
- signalKey: binding.signalKey
14584
- };
14585
- }
14586
- if (binding.source === "literal") {
14587
- return { source: "literal", value: binding.value };
14588
- }
14589
- if (binding.source === "signals_list") {
14590
- return { source: "signals_list", stepKey: binding.fanOutStep.key };
14591
- }
14592
- if (binding.source === "fan_out_item") {
14593
- return { source: "fan_out_item" };
14594
- }
14595
- return { source: "step_output", stepKey: binding.step.key };
14596
- }
14597
- var isFanOutConfig = (node) => ("nodeType" in node) && node.nodeType === "fanOut";
14598
- var isCohortGateConfig = (node) => ("nodeType" in node) && node.nodeType === "cohortGate";
14599
- function serializeInputBindings(input, pipelineInputBindings) {
14600
- const autoBindings = {
14601
- workItemTitle: { source: "work_item", field: "title" },
14602
- workItemDescription: { source: "work_item", field: "description" }
14603
- };
14604
- const pipelineBindings = {};
14605
- for (const [key, binding] of Object.entries(pipelineInputBindings ?? {})) {
14606
- pipelineBindings[key] = serializeBinding(binding);
14607
- }
14608
- const explicitBindings = Object.fromEntries(Object.entries(input ?? {}).filter((entry) => entry[1] !== undefined).map(([key, binding]) => [key, serializeBinding(binding)]));
14609
- return { ...autoBindings, ...pipelineBindings, ...explicitBindings };
14610
- }
14611
- function buildPipelineSpec(config2) {
14612
- const nodes = config2.nodes;
14613
- const stepDefMap = new Map;
14614
- const registerStepDef = (step) => {
14615
- const mapKey = `${step.key}@v${String(step.version)}`;
14616
- if (!stepDefMap.has(mapKey)) {
14617
- stepDefMap.set(mapKey, step);
14618
- }
14619
- };
14620
- for (const node of nodes) {
14621
- if (isFanOutConfig(node)) {
14622
- registerStepDef(node.fanOutStep);
14623
- } else if (!isCohortGateConfig(node)) {
14624
- registerStepDef(node.step);
14625
- }
14626
- }
14627
- let inputSchemaJson = null;
14628
- if (config2.input) {
14629
- try {
14630
- inputSchemaJson = exports_external.toJSONSchema(config2.input);
14631
- } catch {
14632
- inputSchemaJson = null;
14633
- }
14634
- }
14635
- const nodeDefinitions = nodes.map((node) => {
14636
- if (isCohortGateConfig(node)) {
14637
- const serializedPolicy = serializeCohortAdvancementPolicy(node.advanceAll);
14638
- const inlineStepSignalsListDefinitions = extractInlineStepSignalsListDefinitions(node.advanceAll);
14639
- return {
14640
- nodeKey: node.nodeKey,
14641
- kind: "cohortGate",
14642
- advanceAllPolicyDefinition: serializedPolicy,
14643
- stepSignalsListDefinitions: [
14644
- ...inlineStepSignalsListDefinitions,
14645
- ...node.stepSignalsListDefinitions ?? []
14646
- ]
14647
- };
14648
- }
14649
- if (isFanOutConfig(node)) {
14650
- return {
14651
- nodeKey: node.fanOutStep.key,
14652
- kind: "fanOut",
14653
- stepKey: node.fanOutStep.key,
14654
- stepName: node.fanOutStep.name,
14655
- stepDescription: node.fanOutStep.description,
14656
- inputBindingsJson: serializeInputBindings(node.input, config2.pipelineInputBindings),
14657
- timeoutSeconds: node.timeout ?? null,
14658
- overSignalKey: node.overSignalKey,
14659
- advanceEachPolicyDefinition: serializeCohortAdvancementPolicy(node.advanceEach)
14660
- };
14661
- }
14662
- return {
14663
- nodeKey: node.step.key,
14664
- kind: "step",
14665
- stepKey: node.step.key,
14666
- stepName: node.step.name,
14667
- stepDescription: node.step.description,
14668
- inputBindingsJson: serializeInputBindings(node.input, config2.pipelineInputBindings),
14669
- timeoutSeconds: node.timeout ?? null,
14670
- advancementPolicyDefinition: serializeAdvancementPolicy(node.advancement),
14671
- computedSignalDefinitions: extractInlineComputedSignals(node.advancement)
14672
- };
14673
- });
14674
- const dependencyEdges = buildChainDependencyEdges(nodeDefinitions);
14675
- return {
14676
- key: config2.key,
14677
- name: config2.name,
14678
- description: config2.description ?? null,
14679
- version: config2.version ?? 1,
14680
- status: config2.status ?? "active",
14681
- inputSchemaJson,
14682
- _stepDefinitions: [...stepDefMap.values()],
14683
- nodeDefinitions,
14684
- dependencyEdges
14685
- };
14686
- }
14687
- // src/definitions/advancement-policies/fluent-rules.ts
14688
- var LEAF_BRAND = Symbol.for("boboddy.fluentRule.leaf");
14689
- var GROUP_BRAND = Symbol.for("boboddy.fluentRule.group");
14690
- var SIGNAL_KEY = Symbol.for("boboddy.fluentRule.signalKey");
14691
- function createSignalRef(signal2) {
14692
- const leaf = (operator, value) => {
14693
- const condition = {
14694
- _tag: "signal",
14695
- signal: signal2,
14696
- operator,
14697
- value
14698
- };
14699
- return {
14700
- [LEAF_BRAND]: condition,
14701
- then(outcome) {
14702
- return {
14703
- _tag: "rule",
14704
- mode: "all",
14705
- conditions: [condition],
14706
- outcome
14707
- };
14708
- }
14709
- };
14710
- };
14711
- return {
14712
- eq: (v) => leaf("equal", v),
14713
- ne: (v) => leaf("notEqual", v),
14714
- gt: (v) => leaf("greaterThan", v),
14715
- gte: (v) => leaf("greaterThanInclusive", v),
14716
- lt: (v) => leaf("lessThan", v),
14717
- lte: (v) => leaf("lessThanInclusive", v),
14718
- in: (vs) => leaf("in", vs),
14719
- notIn: (vs) => leaf("notIn", vs),
14720
- contains: (v) => leaf("contains", v),
14721
- doesNotContain: (v) => leaf("doesNotContain", v)
14722
- };
14723
- }
14724
- function extractCondition(ref) {
14725
- if (LEAF_BRAND in ref)
14726
- return ref[LEAF_BRAND];
14727
- const group = ref[GROUP_BRAND];
14728
- return group.mode === "all" ? { _tag: "all", conditions: group.conditions } : { _tag: "any", conditions: group.conditions };
14729
- }
14730
- function createGroup(mode, refs) {
14731
- const conditions = refs.map(extractCondition);
14732
- return {
14733
- [GROUP_BRAND]: { mode, conditions },
14734
- then(outcome) {
14735
- return { _tag: "rule", mode, conditions, outcome };
14736
- }
14737
- };
14738
- }
14739
- function resolveComputedArg(arg) {
14740
- return arg[SIGNAL_KEY];
14741
- }
14742
- function makeKeyedSignalRef(key) {
14743
- const ref = createSignalRef(key);
14744
- return Object.assign(ref, {
14745
- [SIGNAL_KEY]: key
14746
- });
14747
- }
14748
- function makeAdvanceCtx() {
14749
- const wrapComputed = (token) => createSignalRef(token);
14750
- return {
14751
- signal: (key) => makeKeyedSignalRef(key),
14752
- stepSignals: new Proxy({}, {
14753
- get(_, key) {
14754
- if (typeof key === "string")
14755
- return makeKeyedSignalRef(key);
14756
- return;
14757
- }
14758
- }),
14759
- avg: (...args) => wrapComputed(Computed.average(args.map(resolveComputedArg))),
14760
- weightedAvg: (...args) => wrapComputed(Computed.weightedAverage(args.map(resolveComputedArg))),
14761
- sum: (...args) => wrapComputed(Computed.sum(args.map(resolveComputedArg))),
14762
- min: (...args) => wrapComputed(Computed.min(args.map(resolveComputedArg))),
14763
- max: (...args) => wrapComputed(Computed.max(args.map(resolveComputedArg))),
14764
- count: (...args) => wrapComputed(Computed.count(args.map(resolveComputedArg))),
14765
- booleanAny: (...args) => wrapComputed(Computed.booleanAny(args.map(resolveComputedArg))),
14766
- booleanAll: (...args) => wrapComputed(Computed.booleanAll(args.map(resolveComputedArg))),
14767
- all: (...refs) => createGroup("all", refs),
14768
- any: (...refs) => createGroup("any", refs),
14769
- route: (pipelineKey, inputJson) => inputJson !== undefined ? { outcome: "route", pipelineKey, inputJson } : { outcome: "route", pipelineKey }
14770
- };
14771
- }
14772
-
14773
- // src/definitions/pipelines/input-accessor.ts
14774
- var ACCESSOR_BRAND = Symbol.for("boboddy.inputAccessor.brand");
14775
- var ACCESSOR_PATH = Symbol.for("boboddy.inputAccessor.path");
14776
- function createInputAccessor(_schema) {
14777
- return createProxy([]);
14778
- }
14779
- function createProxy(path) {
14780
- const pathStr = path.join(".");
14781
- const target = Object.freeze({});
14782
- return new Proxy(target, {
14783
- get(_t, prop) {
14784
- if (prop === ACCESSOR_BRAND)
14785
- return true;
14786
- if (prop === ACCESSOR_PATH)
14787
- return pathStr;
14788
- if (prop === "toJSON") {
14789
- return () => ({
14790
- source: "pipeline_input",
14791
- path: pathStr
14792
- });
14793
- }
14794
- if (prop === Symbol.toPrimitive) {
14795
- return () => {
14796
- throw new Error(`Pipeline input accessor at path "${pathStr || "<root>"}" cannot be coerced to a primitive. ` + `Pass it to a step input field instead of using it in a string/number expression.`);
14797
- };
14798
- }
14799
- if (typeof prop === "symbol")
14800
- return;
14801
- return createProxy([...path, prop]);
14802
- },
14803
- has(_t, prop) {
14804
- return prop === ACCESSOR_BRAND || prop === ACCESSOR_PATH;
14805
- },
14806
- ownKeys() {
14807
- throw new Error(`Pipeline input accessor at path "${pathStr || "<root>"}" cannot be enumerated. ` + `Drill into specific fields instead of spreading the input.`);
14808
- },
14809
- set() {
14810
- throw new Error(`Pipeline input accessor at path "${pathStr || "<root>"}" is read-only.`);
14811
- }
14812
- });
14813
- }
14814
- function isInputAccessor(value) {
14815
- return typeof value === "object" && value !== null && value[ACCESSOR_BRAND] === true;
14816
- }
14817
- function materializeAccessor(accessor) {
14818
- return {
14819
- source: "pipeline_input",
14820
- path: accessor[ACCESSOR_PATH]
14821
- };
14822
- }
14823
-
14824
- // src/definitions/pipelines/builder-helpers.ts
14825
- var WORK_ITEM_ACCESSOR = Object.freeze({
14826
- title: Object.freeze({ source: "work_item", field: "title" }),
14827
- description: Object.freeze({
14828
- source: "work_item",
14829
- field: "description"
14830
- }),
14831
- field: (fieldName) => Object.freeze({ source: "work_item", field: `fields.${fieldName}` })
14832
- });
14833
- var WORK_ITEM_FIELD_BINDINGS = {
14834
- workItemTitle: { source: "work_item", field: "title" },
14835
- workItemDescription: { source: "work_item", field: "description" }
14836
- };
14837
- function makeStepInputCtx(inputSchema) {
14838
- const baseAccessor = createInputAccessor(inputSchema);
14839
- const input = new Proxy(baseAccessor, {
14840
- get(target, prop) {
14841
- if (typeof prop === "string" && prop in WORK_ITEM_FIELD_BINDINGS) {
14842
- return WORK_ITEM_FIELD_BINDINGS[prop];
14843
- }
14844
- return target[prop];
14845
- }
14846
- });
14847
- return {
14848
- input,
14849
- signal(step, key) {
14850
- return { source: "step_signal", step, signalKey: key };
14851
- },
14852
- output(step) {
14853
- return { source: "step_output", step };
14854
- },
14855
- literal: literal2,
14856
- signalsList(fanOutStep) {
14857
- return { source: "signals_list", fanOutStep };
14858
- }
14859
- };
14860
- }
14861
- function literal2(value) {
14862
- return { source: "literal", value };
14863
- }
14864
- function normalizeInputMapping(mapping) {
14865
- if (!mapping)
14866
- return;
14867
- const out = {};
14868
- for (const [key, value] of Object.entries(mapping)) {
14869
- if (value === undefined)
14870
- continue;
14871
- out[key] = isInputAccessor(value) ? materializeAccessor(value) : value;
14872
- }
14873
- return out;
14874
- }
14875
- function resolveAdditionalStepInputBindings(label, definition) {
14876
- if (!definition) {
14877
- return {};
14878
- }
14879
- const raw = definition.bindings({
14880
- workItemField: (fieldName) => ({
14881
- source: "work_item",
14882
- field: `fields.${fieldName}`
14883
- }),
14884
- literal: literal2
14885
- });
14886
- if (definition.schema instanceof exports_external.ZodObject) {
14887
- const validKeys = new Set(Object.keys(definition.schema.shape));
14888
- const unknown2 = Object.keys(raw).filter((key) => !validKeys.has(key));
14889
- if (unknown2.length > 0) {
14890
- throw new Error(`${label}.bindings returned key${unknown2.length > 1 ? "s" : ""} not in schema: ${unknown2.map((key) => `"${key}"`).join(", ")}`);
14891
- }
14892
- }
14893
- return normalizeInputMapping(raw) ?? {};
14894
- }
14895
- function mergeStepBindings(pipelineBindings, explicitBindings) {
14896
- const merged = {
14897
- ...pipelineBindings,
14898
- ...explicitBindings ?? {}
14899
- };
14900
- return Object.keys(merged).length > 0 ? merged : undefined;
14901
- }
14902
-
14903
14519
  // src/definitions/advancement-policies/cohort-fluent-rules.ts
14904
- var LEAF_BRAND2 = Symbol("boboddy.cohortRule.leaf");
14905
- var GROUP_BRAND2 = Symbol("boboddy.cohortRule.group");
14520
+ var LEAF_BRAND = Symbol("boboddy.cohortRule.leaf");
14521
+ var GROUP_BRAND = Symbol("boboddy.cohortRule.group");
14906
14522
  function createCohortSignalRef(signal2) {
14907
14523
  const leaf = (operator, value) => {
14908
14524
  const condition = {
@@ -14912,7 +14528,7 @@ function createCohortSignalRef(signal2) {
14912
14528
  value
14913
14529
  };
14914
14530
  return {
14915
- [LEAF_BRAND2]: condition,
14531
+ [LEAF_BRAND]: condition,
14916
14532
  then(outcome, paramsJson) {
14917
14533
  return {
14918
14534
  _tag: "rule",
@@ -14939,7 +14555,7 @@ function createCohortSignalRef(signal2) {
14939
14555
  }
14940
14556
  function createCohortLeafFromCondition(condition) {
14941
14557
  return {
14942
- [LEAF_BRAND2]: condition,
14558
+ [LEAF_BRAND]: condition,
14943
14559
  then(outcome, paramsJson) {
14944
14560
  return {
14945
14561
  _tag: "rule",
@@ -14952,15 +14568,15 @@ function createCohortLeafFromCondition(condition) {
14952
14568
  };
14953
14569
  }
14954
14570
  function extractCohortCondition(ref) {
14955
- if (LEAF_BRAND2 in ref)
14956
- return ref[LEAF_BRAND2];
14957
- const group = ref[GROUP_BRAND2];
14571
+ if (LEAF_BRAND in ref)
14572
+ return ref[LEAF_BRAND];
14573
+ const group = ref[GROUP_BRAND];
14958
14574
  return group.mode === "all" ? { _tag: "all", conditions: group.conditions } : { _tag: "any", conditions: group.conditions };
14959
14575
  }
14960
14576
  function createCohortGroup(mode, refs) {
14961
14577
  const conditions = refs.map(extractCohortCondition);
14962
14578
  return {
14963
- [GROUP_BRAND2]: { mode, conditions },
14579
+ [GROUP_BRAND]: { mode, conditions },
14964
14580
  then(outcome, paramsJson) {
14965
14581
  return {
14966
14582
  _tag: "rule",
@@ -15065,132 +14681,385 @@ function makeAdvanceAllCtx() {
15065
14681
  };
15066
14682
  }
15067
14683
 
15068
- // src/definitions/pipelines/fan-out-builder.ts
15069
- function beginFanOut(inputSchema, meta3, nodes, pipelineInputBindings, pipelineStepInputBindings, step, config2) {
15070
- const baseCtx = makeStepInputCtx(inputSchema);
15071
- const ctx = {
15072
- ...baseCtx,
14684
+ // src/definitions/pipelines/bindings.ts
14685
+ function serializeBinding(binding) {
14686
+ if (binding.source === "pipeline_input") {
14687
+ return { source: "pipeline_input", path: binding.path };
14688
+ }
14689
+ if (binding.source === "work_item") {
14690
+ return { source: "work_item", field: binding.field };
14691
+ }
14692
+ if (binding.source === "step_signal") {
14693
+ return {
14694
+ source: "step_signal",
14695
+ stepKey: binding.nodeKey,
14696
+ signalKey: binding.signalKey
14697
+ };
14698
+ }
14699
+ if (binding.source === "literal") {
14700
+ return { source: "literal", value: binding.value };
14701
+ }
14702
+ if (binding.source === "signals_list") {
14703
+ return { source: "signals_list", stepKey: binding.nodeKey };
14704
+ }
14705
+ if (binding.source === "fan_out_item") {
14706
+ return { source: "fan_out_item" };
14707
+ }
14708
+ return { source: "step_output", stepKey: binding.nodeKey };
14709
+ }
14710
+ function serializeInputBindings(input) {
14711
+ const autoBindings = {
14712
+ workItemTitle: { source: "work_item", field: "title" },
14713
+ workItemDescription: { source: "work_item", field: "description" }
14714
+ };
14715
+ const explicitBindings = Object.fromEntries(Object.entries(input).filter((entry) => entry[1] !== undefined).map(([key, binding]) => [key, serializeBinding(binding)]));
14716
+ return { ...autoBindings, ...explicitBindings };
14717
+ }
14718
+
14719
+ // src/definitions/pipelines/work-item-fields.ts
14720
+ var WORK_ITEM_TOP_LEVEL_FIELDS = [
14721
+ "id",
14722
+ "projectId",
14723
+ "platform",
14724
+ "platformId",
14725
+ "platformKey",
14726
+ "url",
14727
+ "title",
14728
+ "description",
14729
+ "sourceCreatedAt",
14730
+ "sourceUpdatedAt",
14731
+ "createdByUserId",
14732
+ "parentWorkItemId",
14733
+ "createdAt",
14734
+ "updatedAt"
14735
+ ];
14736
+ var WORK_ITEM_FIELDS_PATH_PREFIX = "fields.";
14737
+ function resolveWorkItemFieldPath(record2, path) {
14738
+ if (typeof record2 !== "object" || record2 === null)
14739
+ return;
14740
+ const asRecord = record2;
14741
+ if (path.startsWith(WORK_ITEM_FIELDS_PATH_PREFIX)) {
14742
+ const fieldName = path.slice(WORK_ITEM_FIELDS_PATH_PREFIX.length);
14743
+ const fields = asRecord["fields"];
14744
+ if (typeof fields !== "object" || fields === null)
14745
+ return;
14746
+ return fields[fieldName];
14747
+ }
14748
+ return asRecord[path];
14749
+ }
14750
+
14751
+ // src/definitions/pipelines/builder-helpers.ts
14752
+ var WORK_ITEM_ACCESSOR = Object.freeze({
14753
+ ...Object.fromEntries(WORK_ITEM_TOP_LEVEL_FIELDS.map((field) => [
14754
+ field,
14755
+ Object.freeze({ source: "work_item", field })
14756
+ ])),
14757
+ field: (fieldName) => Object.freeze({
14758
+ source: "work_item",
14759
+ field: `${WORK_ITEM_FIELDS_PATH_PREFIX}${fieldName}`
14760
+ })
14761
+ });
14762
+ function literal2(value) {
14763
+ return { source: "literal", value };
14764
+ }
14765
+
14766
+ // src/definitions/pipelines/node-input-ctx.ts
14767
+ function makeBaseNodeInputCtx() {
14768
+ return {
14769
+ pipelineInput: (path) => ({ source: "pipeline_input", path }),
14770
+ workItem: WORK_ITEM_ACCESSOR,
14771
+ signal: (nodeKey, signalKey) => ({
14772
+ source: "step_signal",
14773
+ nodeKey,
14774
+ signalKey
14775
+ }),
14776
+ output: (nodeKey) => ({ source: "step_output", nodeKey }),
14777
+ signalsList: (nodeKey) => ({ source: "signals_list", nodeKey }),
14778
+ literal: literal2
14779
+ };
14780
+ }
14781
+ function makeNodeInputCtx() {
14782
+ return makeBaseNodeInputCtx();
14783
+ }
14784
+ function makeFanOutNodeInputCtx() {
14785
+ return {
14786
+ ...makeBaseNodeInputCtx(),
15073
14787
  item: { source: "fan_out_item" }
15074
14788
  };
15075
- const rawInput = config2.input ? config2.input(ctx) : {};
15076
- const input = mergeStepBindings(pipelineStepInputBindings, normalizeInputMapping(rawInput));
15077
- const fanOutNodeConfig = {
15078
- nodeType: "fanOut",
15079
- fanOutStep: step,
15080
- overSignalKey: config2.over,
15081
- ...input ? { input } : {},
15082
- ...config2.timeout !== undefined ? { timeout: config2.timeout } : {}
15083
- };
15084
- const advanceEachCtx = makeAdvanceEachCtx();
15085
- const advanceEachResult = config2.advance(advanceEachCtx);
14789
+ }
14790
+
14791
+ // src/definitions/pipelines/compile-node-definitions.ts
14792
+ function assertTargetExists(ctx, fromKey, toKey) {
14793
+ if (!ctx.stateKeys.has(toKey)) {
14794
+ throw new Error(`Pipeline "${ctx.pipelineKey}": state "${fromKey}" targets unknown state "${toKey}"`);
14795
+ }
14796
+ }
14797
+ function overSignalKeyOf(over) {
14798
+ const lastDot = over.lastIndexOf(".");
14799
+ return lastDot === -1 ? over : over.slice(lastDot + 1);
14800
+ }
14801
+ function compileStepState(stateKey, state, ctx) {
14802
+ ctx.registerStep(state.step);
14803
+ const inputCtx = makeNodeInputCtx();
14804
+ const rawInput = state.input ? state.input(inputCtx) : {};
14805
+ const inputBindingsJson = serializeInputBindings(rawInput);
14806
+ const routeTarget = typeof state.next === "object" ? state.next : null;
14807
+ const defaultOutcome = routeTarget ? {
14808
+ outcome: "route",
14809
+ pipelineKey: routeTarget.routeToPipeline,
14810
+ ...routeTarget.input ? { inputJson: routeTarget.input } : {}
14811
+ } : "continue";
14812
+ const rules = state.blockWhen ? [{ _tag: "rule", mode: "all", conditions: [state.blockWhen], outcome: "block" }] : [];
14813
+ const policy = { defaultOutcome, rules };
14814
+ const nodeDefinitions = [
14815
+ {
14816
+ nodeKey: stateKey,
14817
+ kind: "step",
14818
+ stepKey: state.step.key,
14819
+ stepName: state.step.name,
14820
+ stepDescription: state.step.description,
14821
+ inputBindingsJson,
14822
+ timeoutSeconds: state.timeout ?? null,
14823
+ advancementPolicyDefinition: serializeAdvancementPolicy(policy),
14824
+ computedSignalDefinitions: extractInlineComputedSignals(policy)
14825
+ }
14826
+ ];
14827
+ const edges = [];
14828
+ if (!routeTarget) {
14829
+ const nextKey = state.next;
14830
+ assertTargetExists(ctx, stateKey, nextKey);
14831
+ edges.push({ fromNodeKey: stateKey, toNodeKey: nextKey });
14832
+ }
14833
+ return { nodeDefinitions, edges };
14834
+ }
14835
+ function compileChoiceState(stateKey, state, ctx) {
14836
+ const stateChoices = state.choices ?? [];
14837
+ if (stateChoices.length === 0 && !state.default) {
14838
+ throw new Error(`Pipeline "${ctx.pipelineKey}": choice state "${stateKey}" requires at least one entry in choices or a default target`);
14839
+ }
14840
+ const choices = stateChoices.map((choiceCase) => {
14841
+ assertTargetExists(ctx, stateKey, choiceCase.next);
14842
+ return {
14843
+ conditionJson: serializeCondition(choiceCase.when),
14844
+ targetNodeKey: choiceCase.next
14845
+ };
14846
+ });
14847
+ if (state.default)
14848
+ assertTargetExists(ctx, stateKey, state.default);
14849
+ const edges = stateChoices.map((choiceCase) => ({
14850
+ fromNodeKey: stateKey,
14851
+ toNodeKey: choiceCase.next,
14852
+ discriminantJson: { conditionSummary: serializeCondition(choiceCase.when) }
14853
+ }));
14854
+ if (state.default) {
14855
+ edges.push({
14856
+ fromNodeKey: stateKey,
14857
+ toNodeKey: state.default,
14858
+ discriminantJson: { default: true }
14859
+ });
14860
+ }
14861
+ return {
14862
+ nodeDefinitions: [
14863
+ { nodeKey: stateKey, kind: "choice", choices, default: state.default ?? null }
14864
+ ],
14865
+ edges
14866
+ };
14867
+ }
14868
+ function compileFanOutState(stateKey, state, ctx) {
14869
+ ctx.registerStep(state.step);
14870
+ const inputCtx = makeFanOutNodeInputCtx();
14871
+ const rawInput = state.input ? state.input(inputCtx) : {};
14872
+ const inputBindingsJson = serializeInputBindings(rawInput);
14873
+ const advanceEachResult = state.advanceEach(makeAdvanceEachCtx());
15086
14874
  const advanceEachPolicy = {
15087
14875
  default: advanceEachResult.default,
15088
14876
  ...advanceEachResult.rules !== undefined ? { rules: advanceEachResult.rules } : {}
15089
14877
  };
15090
- fanOutNodeConfig.advanceEach = advanceEachPolicy;
15091
- const cohortGateNodeConfig = {
15092
- nodeType: "cohortGate",
15093
- nodeKey: `${step.key}__cohortGate`
15094
- };
15095
- const advanceAllCtx = makeAdvanceAllCtx();
15096
- const advanceAllResult = config2.advanceAll(advanceAllCtx);
14878
+ const advanceAllResult = state.advanceAll(makeAdvanceAllCtx());
15097
14879
  const advanceAllPolicy = {
15098
14880
  default: advanceAllResult.default,
15099
14881
  ...advanceAllResult.rules !== undefined ? { rules: advanceAllResult.rules } : {}
15100
14882
  };
15101
- cohortGateNodeConfig.advanceAll = advanceAllPolicy;
15102
- nodes.push(fanOutNodeConfig, cohortGateNodeConfig);
15103
- return new PipelineStepBuilder(inputSchema, meta3, nodes, pipelineInputBindings, pipelineStepInputBindings);
15104
- }
15105
-
15106
- // src/definitions/pipelines/builder.ts
15107
- function pushStep(inputSchema, meta3, nodes, pipelineInputBindings, pipelineStepInputBindings, step, rawOptions) {
15108
- const options = rawOptions;
15109
- const ctx = makeStepInputCtx(inputSchema);
15110
- const rawInput = options.input ? options.input(ctx) : {};
15111
- const input = mergeStepBindings(pipelineStepInputBindings, normalizeInputMapping(rawInput));
15112
- const stepConfig = { step, input };
15113
- if (options.timeout !== undefined)
15114
- stepConfig.timeout = options.timeout;
15115
- const advanceCtx = makeAdvanceCtx();
15116
- const result = options.advance(advanceCtx);
15117
- const policy = {
15118
- defaultOutcome: result.default,
15119
- ...result.rules !== undefined ? { rules: result.rules } : {}
15120
- };
15121
- stepConfig.advancement = policy;
15122
- nodes.push(stepConfig);
15123
- return new PipelineStepBuilder(inputSchema, meta3, nodes, pipelineInputBindings, pipelineStepInputBindings);
15124
- }
15125
-
15126
- class PipelineStepBuilder {
15127
- inputSchema;
15128
- meta;
15129
- nodes;
15130
- pipelineInputBindings;
15131
- pipelineStepInputBindings;
15132
- constructor(inputSchema, meta3, nodes, pipelineInputBindings = {}, pipelineStepInputBindings = {}) {
15133
- this.inputSchema = inputSchema;
15134
- this.meta = meta3;
15135
- this.nodes = nodes;
15136
- this.pipelineInputBindings = pipelineInputBindings;
15137
- this.pipelineStepInputBindings = pipelineStepInputBindings;
15138
- }
15139
- step(step, options) {
15140
- return pushStep(this.inputSchema, this.meta, this.nodes, this.pipelineInputBindings, this.pipelineStepInputBindings, step, options);
15141
- }
15142
- fanOutStep(step, config2) {
15143
- return beginFanOut(this.inputSchema, this.meta, this.nodes, this.pipelineInputBindings, this.pipelineStepInputBindings, step, config2);
15144
- }
15145
- build() {
15146
- const config2 = {
15147
- key: this.meta.key,
15148
- name: this.meta.name,
15149
- description: this.meta.description,
15150
- version: this.meta.version,
15151
- status: this.meta.status,
15152
- input: this.inputSchema,
15153
- nodes: this.nodes,
15154
- pipelineInputBindings: this.pipelineInputBindings
14883
+ const gateKey = `${stateKey}__cohortGate`;
14884
+ if (ctx.stateKeys.has(gateKey)) {
14885
+ throw new Error(`Pipeline "${ctx.pipelineKey}": synthesized cohortGate key "${gateKey}" collides with an author-declared state \u2014 rename state "${stateKey}"`);
14886
+ }
14887
+ assertTargetExists(ctx, stateKey, state.next);
14888
+ return {
14889
+ nodeDefinitions: [
14890
+ {
14891
+ nodeKey: stateKey,
14892
+ kind: "fanOut",
14893
+ stepKey: state.step.key,
14894
+ stepName: state.step.name,
14895
+ stepDescription: state.step.description,
14896
+ inputBindingsJson,
14897
+ timeoutSeconds: state.timeout ?? null,
14898
+ overSignalKey: overSignalKeyOf(state.over),
14899
+ advanceEachPolicyDefinition: serializeCohortAdvancementPolicy(advanceEachPolicy),
14900
+ maxConcurrency: state.maxConcurrency ?? null
14901
+ },
14902
+ {
14903
+ nodeKey: gateKey,
14904
+ kind: "cohortGate",
14905
+ advanceAllPolicyDefinition: serializeCohortAdvancementPolicy(advanceAllPolicy),
14906
+ stepSignalsListDefinitions: extractInlineStepSignalsListDefinitions(advanceAllPolicy)
14907
+ }
14908
+ ],
14909
+ edges: [
14910
+ { fromNodeKey: stateKey, toNodeKey: gateKey },
14911
+ { fromNodeKey: gateKey, toNodeKey: state.next }
14912
+ ]
14913
+ };
14914
+ }
14915
+ function compileParallelState(stateKey, state, ctx) {
14916
+ const branchEntries = Object.entries(state.branches);
14917
+ if (branchEntries.length === 0) {
14918
+ throw new Error(`Pipeline "${ctx.pipelineKey}": parallel state "${stateKey}" requires at least one branch`);
14919
+ }
14920
+ const branches = {};
14921
+ for (const [branchKey, branchConfig] of branchEntries) {
14922
+ ctx.registerStep(branchConfig.step);
14923
+ const inputCtx = makeNodeInputCtx();
14924
+ const rawInput = branchConfig.input ? branchConfig.input(inputCtx) : {};
14925
+ branches[branchKey] = {
14926
+ stepKey: branchConfig.step.key,
14927
+ stepName: branchConfig.step.name,
14928
+ stepDescription: branchConfig.step.description,
14929
+ inputBindingsJson: serializeInputBindings(rawInput)
15155
14930
  };
15156
- return buildPipelineSpec(config2);
14931
+ }
14932
+ let advanceAllPolicyDefinition;
14933
+ if (state.advanceAll) {
14934
+ const advanceAllResult = state.advanceAll(makeAdvanceAllCtx());
14935
+ const advanceAllPolicy = {
14936
+ default: advanceAllResult.default,
14937
+ ...advanceAllResult.rules !== undefined ? { rules: advanceAllResult.rules } : {}
14938
+ };
14939
+ advanceAllPolicyDefinition = serializeCohortAdvancementPolicy(advanceAllPolicy);
14940
+ }
14941
+ assertTargetExists(ctx, stateKey, state.next);
14942
+ return {
14943
+ nodeDefinitions: [
14944
+ {
14945
+ nodeKey: stateKey,
14946
+ kind: "parallel",
14947
+ branches,
14948
+ ...advanceAllPolicyDefinition ? { advanceAllPolicyDefinition } : {}
14949
+ }
14950
+ ],
14951
+ edges: [{ fromNodeKey: stateKey, toNodeKey: state.next }]
14952
+ };
14953
+ }
14954
+ function compileLoopState(stateKey, state, ctx) {
14955
+ ctx.registerStep(state.step);
14956
+ const inputCtx = makeNodeInputCtx();
14957
+ const rawInput = state.input ? state.input(inputCtx) : {};
14958
+ assertTargetExists(ctx, stateKey, state.next);
14959
+ assertTargetExists(ctx, stateKey, state.onExhausted);
14960
+ return {
14961
+ nodeDefinitions: [
14962
+ {
14963
+ nodeKey: stateKey,
14964
+ kind: "loop",
14965
+ stepKey: state.step.key,
14966
+ stepName: state.step.name,
14967
+ stepDescription: state.step.description,
14968
+ inputBindingsJson: serializeInputBindings(rawInput),
14969
+ timeoutSeconds: state.timeout ?? null,
14970
+ maxIterations: state.maxIterations,
14971
+ untilConditionJson: serializeCondition(state.until)
14972
+ }
14973
+ ],
14974
+ edges: [
14975
+ { fromNodeKey: stateKey, toNodeKey: state.next, discriminantJson: { loopExit: "next" } },
14976
+ {
14977
+ fromNodeKey: stateKey,
14978
+ toNodeKey: state.onExhausted,
14979
+ discriminantJson: { loopExit: "onExhausted" }
14980
+ }
14981
+ ]
14982
+ };
14983
+ }
14984
+ function compileTerminalState(stateKey, kind) {
14985
+ return { nodeDefinitions: [{ nodeKey: stateKey, kind }], edges: [] };
14986
+ }
14987
+ function assertNoIllegalConvergentEdges(pipelineKey, nodeKindByKey, edges) {
14988
+ const incoming = new Map;
14989
+ for (const edge of edges) {
14990
+ const list = incoming.get(edge.toNodeKey) ?? [];
14991
+ list.push(edge);
14992
+ incoming.set(edge.toNodeKey, list);
14993
+ }
14994
+ for (const [targetKey, incomingEdges] of incoming) {
14995
+ if (incomingEdges.length <= 1)
14996
+ continue;
14997
+ const hasInvalidSource = incomingEdges.some((edge) => {
14998
+ const kind = nodeKindByKey.get(edge.fromNodeKey);
14999
+ return kind !== "choice" && kind !== "loop";
15000
+ });
15001
+ if (hasInvalidSource) {
15002
+ throw new Error(`Pipeline "${pipelineKey}": state "${targetKey}" has more than one incoming edge, but not every source is a 'choice'/'loop' state (unconditional convergent edges are not allowed \u2014 see docs/research/flat-pipeline-sdk-and-visual-designer.md \xA76).`);
15003
+ }
15157
15004
  }
15158
15005
  }
15159
15006
 
15160
- class PipelineBuilder {
15161
- inputSchema;
15162
- meta;
15163
- nodes = [];
15164
- pipelineInputBindings;
15165
- pipelineStepInputBindings;
15166
- constructor(meta3) {
15167
- const { additionalPipelineInput, additionalStepInput, ...rest } = meta3;
15168
- this.inputSchema = additionalPipelineInput?.schema ?? exports_external.unknown();
15169
- this.meta = rest;
15170
- if (additionalPipelineInput) {
15171
- const raw = additionalPipelineInput.bindings({
15172
- workItem: WORK_ITEM_ACCESSOR,
15173
- literal: literal2
15174
- });
15175
- if (additionalPipelineInput.schema instanceof exports_external.ZodObject) {
15176
- const validKeys = new Set(Object.keys(additionalPipelineInput.schema.shape));
15177
- const unknown2 = Object.keys(raw).filter((k) => !validKeys.has(k));
15178
- if (unknown2.length > 0) {
15179
- throw new Error(`additionalPipelineInput.bindings returned key${unknown2.length > 1 ? "s" : ""} not in schema: ${unknown2.map((k) => `"${k}"`).join(", ")}`);
15180
- }
15181
- }
15182
- this.pipelineInputBindings = normalizeInputMapping(raw) ?? {};
15183
- } else {
15184
- this.pipelineInputBindings = {};
15185
- }
15186
- this.pipelineStepInputBindings = resolveAdditionalStepInputBindings("additionalStepInput", additionalStepInput);
15007
+ // src/definitions/pipelines/define-pipeline.ts
15008
+ function isWorkingNodeDefinition(node) {
15009
+ return node.kind === "step" || node.kind === "fanOut" || node.kind === "loop";
15010
+ }
15011
+ function definePipeline(config2) {
15012
+ const stateEntries = Object.entries(config2.states);
15013
+ if (stateEntries.length === 0) {
15014
+ throw new Error(`Pipeline "${config2.key}" must declare at least one state`);
15187
15015
  }
15188
- step(step, options) {
15189
- return pushStep(this.inputSchema, this.meta, this.nodes, this.pipelineInputBindings, this.pipelineStepInputBindings, step, options);
15016
+ const startState = config2.states[config2.startAt];
15017
+ if (!startState) {
15018
+ throw new Error(`Pipeline "${config2.key}"'s startAt "${config2.startAt}" does not name a declared state`);
15190
15019
  }
15191
- }
15192
- function pipeline(meta3) {
15193
- return new PipelineBuilder(meta3);
15020
+ if (startState.kind === "choice" || startState.kind === "succeed" || startState.kind === "fail") {
15021
+ throw new Error(`Pipeline "${config2.key}"'s startAt "${config2.startAt}" names a '${startState.kind}' state, which cannot be an entry point`);
15022
+ }
15023
+ const stateKeys = new Set(Object.keys(config2.states));
15024
+ const stepDefMap = new Map;
15025
+ const registerStep = (step) => {
15026
+ const mapKey = `${step.key}@v${String(step.version)}`;
15027
+ if (!stepDefMap.has(mapKey))
15028
+ stepDefMap.set(mapKey, step);
15029
+ };
15030
+ const compileContext = {
15031
+ pipelineKey: config2.key,
15032
+ stateKeys,
15033
+ registerStep
15034
+ };
15035
+ const nodeDefinitions = [];
15036
+ const dependencyEdges = [];
15037
+ for (const [stateKey, state] of stateEntries) {
15038
+ const compiled = state.kind === "step" ? compileStepState(stateKey, state, compileContext) : state.kind === "choice" ? compileChoiceState(stateKey, state, compileContext) : state.kind === "fanOut" ? compileFanOutState(stateKey, state, compileContext) : state.kind === "parallel" ? compileParallelState(stateKey, state, compileContext) : state.kind === "loop" ? compileLoopState(stateKey, state, compileContext) : compileTerminalState(stateKey, state.kind);
15039
+ nodeDefinitions.push(...compiled.nodeDefinitions);
15040
+ dependencyEdges.push(...compiled.edges);
15041
+ }
15042
+ const nodeKindByKey = new Map(nodeDefinitions.map((node) => [node.nodeKey, node.kind]));
15043
+ assertNoIllegalConvergentEdges(config2.key, nodeKindByKey, dependencyEdges);
15044
+ let inputSchemaJson = null;
15045
+ if (config2.input) {
15046
+ try {
15047
+ inputSchemaJson = exports_external.toJSONSchema(config2.input);
15048
+ } catch {
15049
+ inputSchemaJson = null;
15050
+ }
15051
+ }
15052
+ return {
15053
+ key: config2.key,
15054
+ name: config2.name ?? config2.key,
15055
+ description: config2.description ?? null,
15056
+ version: config2.version ?? 1,
15057
+ status: config2.status ?? "active",
15058
+ inputSchemaJson,
15059
+ _stepDefinitions: [...stepDefMap.values()],
15060
+ nodeDefinitions,
15061
+ dependencyEdges
15062
+ };
15194
15063
  }
15195
15064
  // src/generated/core/bodySerializer.gen.ts
15196
15065
  var jsonBodySerializer = {
@@ -16271,29 +16140,6 @@ class PipelineDefinitions extends HeyApiClient {
16271
16140
  unarchivePipelineDefinition(options) {
16272
16141
  return (options.client ?? this.client).put({ url: "/api/pipeline-definitions/{pipelineDefinitionId}/unarchive", ...options });
16273
16142
  }
16274
- addPipelineStep(options) {
16275
- return (options.client ?? this.client).post({
16276
- url: "/api/pipeline-definitions/{pipelineDefinitionId}/steps",
16277
- ...options,
16278
- headers: {
16279
- "Content-Type": "application/json",
16280
- ...options.headers
16281
- }
16282
- });
16283
- }
16284
- removePipelineStep(options) {
16285
- return (options.client ?? this.client).delete({ url: "/api/pipeline-definitions/{pipelineDefinitionId}/steps/{pipelineStepDefinitionId}", ...options });
16286
- }
16287
- updatePipelineStep(options) {
16288
- return (options.client ?? this.client).put({
16289
- url: "/api/pipeline-definitions/{pipelineDefinitionId}/steps/{pipelineStepDefinitionId}",
16290
- ...options,
16291
- headers: {
16292
- "Content-Type": "application/json",
16293
- ...options.headers
16294
- }
16295
- });
16296
- }
16297
16143
  setPipelineStepAdvancementPolicy(options) {
16298
16144
  return (options.client ?? this.client).put({
16299
16145
  url: "/api/pipeline-definitions/{pipelineDefinitionId}/steps/{pipelineStepDefinitionId}/advancement-policy",
@@ -16800,6 +16646,76 @@ function createPipelineDefinitionsClient(baseUrl) {
16800
16646
  const client2 = createClient({ baseUrl });
16801
16647
  return buildPipelineDefinitionsClient(new PipelineDefinitions({ client: client2 }));
16802
16648
  }
16649
+ function resolveStepRef(pipelineKey, nodeKey, stepKey, stepDefMap) {
16650
+ const stepDef = stepDefMap.get(stepKey);
16651
+ if (!stepDef) {
16652
+ throw new Error(`Step "${stepKey}" referenced by node "${nodeKey}" in pipeline "${pipelineKey}" was not found on ` + `the server. Run \`boboddy steps push\` first to push your step definitions.`);
16653
+ }
16654
+ return {
16655
+ stepDefinitionId: stepDef.id,
16656
+ stepDefinitionVersion: stepDef.version
16657
+ };
16658
+ }
16659
+ function buildConfigJson(pipelineKey, node, stepDefMap) {
16660
+ if (node.kind === "choice") {
16661
+ return { choices: node.choices, default: node.default };
16662
+ }
16663
+ if (node.kind === "loop") {
16664
+ return {
16665
+ maxIterations: node.maxIterations,
16666
+ untilConditionJson: node.untilConditionJson
16667
+ };
16668
+ }
16669
+ if (node.kind === "parallel") {
16670
+ const branches = {};
16671
+ for (const [branchKey, branch] of Object.entries(node.branches)) {
16672
+ branches[branchKey] = {
16673
+ ...resolveStepRef(pipelineKey, node.nodeKey, branch.stepKey, stepDefMap),
16674
+ inputBindingsJson: branch.inputBindingsJson
16675
+ };
16676
+ }
16677
+ return {
16678
+ branches,
16679
+ ...node.advanceAllPolicyDefinition ? { advanceAllPolicyDefinition: node.advanceAllPolicyDefinition } : {}
16680
+ };
16681
+ }
16682
+ if (node.kind === "fanOut") {
16683
+ return {
16684
+ overSignalKey: node.overSignalKey,
16685
+ advanceEachPolicyDefinition: node.advanceEachPolicyDefinition,
16686
+ maxConcurrency: node.maxConcurrency
16687
+ };
16688
+ }
16689
+ if (node.kind === "cohortGate") {
16690
+ return {
16691
+ advanceAllPolicyDefinition: node.advanceAllPolicyDefinition,
16692
+ stepSignalsListDefinitions: node.stepSignalsListDefinitions
16693
+ };
16694
+ }
16695
+ return null;
16696
+ }
16697
+ function buildGraphNodeInput(pipelineKey, node, stepDefMap) {
16698
+ const working = isWorkingNodeDefinition(node) ? node : null;
16699
+ const stepRef = working ? resolveStepRef(pipelineKey, node.nodeKey, working.stepKey, stepDefMap) : null;
16700
+ const policy = node.kind === "step" ? node.advancementPolicyDefinition : undefined;
16701
+ return {
16702
+ key: node.nodeKey,
16703
+ kind: node.kind,
16704
+ name: working?.stepName ?? node.nodeKey,
16705
+ ...stepRef ?? {},
16706
+ description: working?.stepDescription ?? null,
16707
+ inputBindingsJson: working ? working.inputBindingsJson : null,
16708
+ timeoutSeconds: working?.timeoutSeconds ?? null,
16709
+ ...policy ? {
16710
+ advancementPolicyRulesJson: policy.rulesJson,
16711
+ advancementPolicyDefaultEventType: policy.defaultEventType,
16712
+ advancementPolicyDefaultEventParamsJson: policy.defaultEventParamsJson,
16713
+ advancementPolicyAllowedEventTypes: policy.allowedEventTypes
16714
+ } : {},
16715
+ configJson: buildConfigJson(pipelineKey, node, stepDefMap),
16716
+ computedSignalDefinitions: node.kind === "step" ? node.computedSignalDefinitions : []
16717
+ };
16718
+ }
16803
16719
  var buildPipelineDefinitionsClient = (pipelineDefinitions) => {
16804
16720
  return {
16805
16721
  listByProjectId: async (projectId, options) => {
@@ -16819,37 +16735,12 @@ var buildPipelineDefinitionsClient = (pipelineDefinitions) => {
16819
16735
  stepDefMap.set(s.key, s);
16820
16736
  }
16821
16737
  }
16822
- const nonStepNode = spec.nodeDefinitions.find((node) => node.kind !== "step");
16823
- if (nonStepNode) {
16824
- throw new Error(`Pipeline "${spec.key}" contains a "${nonStepNode.kind}" node ("${nonStepNode.nodeKey}"), ` + `but fan-out pipelines cannot be pushed via the current wire contract yet. ` + `Only "step"-only (chain) pipelines can be pushed with \`upsertFromSpec\` today.`);
16825
- }
16826
- const ordered = tryOrderChainNodeDefinitions(spec.nodeDefinitions, spec.dependencyEdges);
16827
- if (ordered === null) {
16828
- throw new Error(`Pipeline "${spec.key}" has a malformed step graph: its node and ` + `dependency-edge definitions do not form a single connected, ` + `acyclic chain. This should not happen from the \`pipeline()\` ` + `builder \u2014 check for hand-edited or generated pipeline specs.`);
16829
- }
16830
- const stepDefinitions = ordered.map((node, index) => {
16831
- const stepKey = node.stepKey;
16832
- if (!stepKey) {
16833
- throw new Error(`Node "${node.nodeKey}" in pipeline "${spec.key}" has no stepKey.`);
16834
- }
16835
- const stepDef = stepDefMap.get(stepKey);
16836
- if (!stepDef) {
16837
- throw new Error(`Step "${stepKey}" referenced in pipeline "${spec.key}" was not found on the server. ` + `Run \`boboddy steps push\` first to push your step definitions.`);
16838
- }
16839
- return {
16840
- stepDefinitionId: stepDef.id,
16841
- stepDefinitionVersion: stepDef.version,
16842
- key: node.nodeKey,
16843
- name: node.stepName ?? "",
16844
- description: node.stepDescription ?? null,
16845
- position: index + 1,
16846
- inputBindingsJson: node.inputBindingsJson ?? {},
16847
- timeoutSeconds: node.timeoutSeconds ?? null,
16848
- retryPolicyJson: null,
16849
- advancementPolicyDefinition: node.advancementPolicyDefinition,
16850
- computedSignalDefinitions: node.computedSignalDefinitions ?? []
16851
- };
16852
- });
16738
+ const nodeDefinitions = spec.nodeDefinitions.map((node) => buildGraphNodeInput(spec.key, node, stepDefMap));
16739
+ const dependencyEdges = spec.dependencyEdges.map((edge) => ({
16740
+ fromNodeKey: edge.fromNodeKey,
16741
+ toNodeKey: edge.toNodeKey,
16742
+ discriminantJson: edge.discriminantJson ?? null
16743
+ }));
16853
16744
  const body = {
16854
16745
  projectId,
16855
16746
  key: spec.key,
@@ -16857,7 +16748,8 @@ var buildPipelineDefinitionsClient = (pipelineDefinitions) => {
16857
16748
  description: spec.description,
16858
16749
  status: spec.status,
16859
16750
  inputSchemaJson: spec.inputSchemaJson,
16860
- stepDefinitions
16751
+ nodeDefinitions,
16752
+ dependencyEdges
16861
16753
  };
16862
16754
  const result = await pipelineDefinitions.upsertPipelineDefinition({
16863
16755
  body,
@@ -16892,7 +16784,7 @@ function makeLeaf(fact, path, operator, value) {
16892
16784
  };
16893
16785
  }
16894
16786
  function makeFieldRef(fact, path) {
16895
- return {
16787
+ const untyped = {
16896
16788
  eq: (v) => makeLeaf(fact, path, "equal", v),
16897
16789
  ne: (v) => makeLeaf(fact, path, "notEqual", v),
16898
16790
  gt: (v) => makeLeaf(fact, path, "greaterThan", v),
@@ -16904,18 +16796,28 @@ function makeFieldRef(fact, path) {
16904
16796
  contains: (v) => makeLeaf(fact, path, "contains", v),
16905
16797
  doesNotContain: (v) => makeLeaf(fact, path, "doesNotContain", v)
16906
16798
  };
16799
+ return untyped;
16907
16800
  }
16908
- function makeAssign(pipeline2) {
16909
- if (typeof pipeline2 !== "object" || typeof pipeline2["key"] !== "string" || !Array.isArray(pipeline2["nodeDefinitions"])) {
16910
- throw new Error("assign() requires a pipeline spec produced by pipeline().build(). " + "Pass the default-exported value from a pipeline definition file.");
16801
+ function buildWorkItemAccessor() {
16802
+ const accessor = {
16803
+ field: (name) => makeFieldRef("workItem", `$.${WORK_ITEM_FIELDS_PATH_PREFIX}${name}`)
16804
+ };
16805
+ for (const key of WORK_ITEM_TOP_LEVEL_FIELDS) {
16806
+ accessor[key] = makeFieldRef("workItem", `$.${key}`);
16911
16807
  }
16912
- return { _tag: "assign", pipeline: pipeline2 };
16808
+ return accessor;
16913
16809
  }
16914
- function extractCondition2(ref) {
16810
+ function makeAssign(pipeline) {
16811
+ if (typeof pipeline !== "object" || typeof pipeline["key"] !== "string" || !Array.isArray(pipeline["nodeDefinitions"])) {
16812
+ throw new Error("assign() requires a pipeline spec produced by definePipeline(). " + "Pass the default-exported value from a pipeline definition file.");
16813
+ }
16814
+ return { _tag: "assign", pipeline };
16815
+ }
16816
+ function extractCondition(ref) {
16915
16817
  return ref._condition;
16916
16818
  }
16917
16819
  function makeGroup(mode, refs) {
16918
- const conditions = refs.map(extractCondition2);
16820
+ const conditions = refs.map(extractCondition);
16919
16821
  const condition = { _tag: "group", mode, conditions };
16920
16822
  return {
16921
16823
  _condition: condition,
@@ -16926,9 +16828,7 @@ function makeGroup(mode, refs) {
16926
16828
  }
16927
16829
  function buildCtx() {
16928
16830
  return {
16929
- workItem: {
16930
- field: (name) => makeFieldRef("workItem", `$.fields.${name}`)
16931
- },
16831
+ workItem: buildWorkItemAccessor(),
16932
16832
  context: {
16933
16833
  isNew: makeFieldRef("context", "$.isNew")
16934
16834
  },
@@ -17007,19 +16907,19 @@ function isDefaultPipelineAssignmentSpec(value) {
17007
16907
  return value["_tag"] === "default_pipeline_assignment";
17008
16908
  }
17009
16909
  export {
16910
+ serializeInputBindings,
17010
16911
  serializeDefaultPipelineAssignment,
17011
- pipeline,
17012
- materializeAccessor,
17013
- literal2 as literal,
17014
- isInputAccessor,
16912
+ resolveWorkItemFieldPath,
16913
+ makeNodeInputCtx,
16914
+ makeFanOutNodeInputCtx,
16915
+ isWorkingNodeDefinition,
17015
16916
  isDefaultPipelineAssignmentSpec,
16917
+ definePipeline,
17016
16918
  defaultPipelineAssignment,
17017
16919
  createPipelineDefinitionsClient,
17018
- createInputAccessor,
17019
- buildPipelineSpec,
16920
+ WORK_ITEM_TOP_LEVEL_FIELDS,
16921
+ WORK_ITEM_FIELDS_PATH_PREFIX,
17020
16922
  Rule,
17021
- PipelineStepBuilder,
17022
- PipelineBuilder,
17023
16923
  DEFAULT_PIPELINE_ASSIGNMENT_FILENAME,
17024
16924
  Computed
17025
16925
  };