@boboddy/sdk 0.4.3 → 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 (32) 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 +19 -106
  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-pipeline.d.ts +101 -154
  9. package/dist/definitions/pipelines/index.d.ts +0 -2
  10. package/dist/definitions/pipelines/index.js +470 -615
  11. package/dist/definitions/pipelines/node-input-ctx.d.ts +31 -0
  12. package/dist/definitions/pipelines/pipeline-definitions-client.d.ts +18 -4
  13. package/dist/definitions/pipelines/pipeline-states.d.ts +104 -0
  14. package/dist/definitions/steps/define-code-step.d.ts +50 -0
  15. package/dist/definitions/steps/define-step.d.ts +22 -1
  16. package/dist/definitions/steps/index.d.ts +1 -0
  17. package/dist/definitions/steps/index.js +41 -24
  18. package/dist/definitions/steps/step-definitions-client.d.ts +29 -5
  19. package/dist/definitions/validation/index.js +15148 -94
  20. package/dist/definitions/validation/validate-definition-specs.d.ts +19 -1
  21. package/dist/generated/index.d.ts +1 -1
  22. package/dist/generated/sdk.gen.d.ts +1 -4
  23. package/dist/generated/types.gen.d.ts +296 -878
  24. package/dist/index.js +510 -615
  25. package/dist/push/collect-definitions.d.ts +40 -1
  26. package/dist/push/index.d.ts +2 -2
  27. package/dist/push/index.js +788 -738
  28. package/dist/step-execution-plane-client.d.ts +9 -4
  29. package/package.json +2 -2
  30. package/dist/definitions/pipelines/builder.d.ts +0 -80
  31. package/dist/definitions/pipelines/fan-out-builder.d.ts +0 -66
  32. 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,436 +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/work-item-fields.ts
14825
- var WORK_ITEM_TOP_LEVEL_FIELDS = [
14826
- "id",
14827
- "projectId",
14828
- "platform",
14829
- "platformId",
14830
- "platformKey",
14831
- "url",
14832
- "title",
14833
- "description",
14834
- "sourceCreatedAt",
14835
- "sourceUpdatedAt",
14836
- "createdByUserId",
14837
- "parentWorkItemId",
14838
- "createdAt",
14839
- "updatedAt"
14840
- ];
14841
- var WORK_ITEM_FIELDS_PATH_PREFIX = "fields.";
14842
- function resolveWorkItemFieldPath(record2, path) {
14843
- if (typeof record2 !== "object" || record2 === null)
14844
- return;
14845
- const asRecord = record2;
14846
- if (path.startsWith(WORK_ITEM_FIELDS_PATH_PREFIX)) {
14847
- const fieldName = path.slice(WORK_ITEM_FIELDS_PATH_PREFIX.length);
14848
- const fields = asRecord["fields"];
14849
- if (typeof fields !== "object" || fields === null)
14850
- return;
14851
- return fields[fieldName];
14852
- }
14853
- return asRecord[path];
14854
- }
14855
-
14856
- // src/definitions/pipelines/builder-helpers.ts
14857
- var WORK_ITEM_ACCESSOR = Object.freeze({
14858
- ...Object.fromEntries(WORK_ITEM_TOP_LEVEL_FIELDS.map((field) => [
14859
- field,
14860
- Object.freeze({ source: "work_item", field })
14861
- ])),
14862
- field: (fieldName) => Object.freeze({
14863
- source: "work_item",
14864
- field: `${WORK_ITEM_FIELDS_PATH_PREFIX}${fieldName}`
14865
- })
14866
- });
14867
- var WORK_ITEM_FIELD_BINDINGS = {
14868
- workItemTitle: { source: "work_item", field: "title" },
14869
- workItemDescription: { source: "work_item", field: "description" }
14870
- };
14871
- function makeStepInputCtx(inputSchema) {
14872
- const baseAccessor = createInputAccessor(inputSchema);
14873
- const input = new Proxy(baseAccessor, {
14874
- get(target, prop) {
14875
- if (typeof prop === "string" && prop in WORK_ITEM_FIELD_BINDINGS) {
14876
- return WORK_ITEM_FIELD_BINDINGS[prop];
14877
- }
14878
- return target[prop];
14879
- }
14880
- });
14881
- return {
14882
- input,
14883
- signal(step, key) {
14884
- return { source: "step_signal", step, signalKey: key };
14885
- },
14886
- output(step) {
14887
- return { source: "step_output", step };
14888
- },
14889
- literal: literal2,
14890
- signalsList(fanOutStep) {
14891
- return { source: "signals_list", fanOutStep };
14892
- }
14893
- };
14894
- }
14895
- function literal2(value) {
14896
- return { source: "literal", value };
14897
- }
14898
- function normalizeInputMapping(mapping) {
14899
- if (!mapping)
14900
- return;
14901
- const out = {};
14902
- for (const [key, value] of Object.entries(mapping)) {
14903
- if (value === undefined)
14904
- continue;
14905
- out[key] = isInputAccessor(value) ? materializeAccessor(value) : value;
14906
- }
14907
- return out;
14908
- }
14909
- function resolveAdditionalStepInputBindings(label, definition) {
14910
- if (!definition) {
14911
- return {};
14912
- }
14913
- const raw = definition.bindings({
14914
- workItemField: (fieldName) => ({
14915
- source: "work_item",
14916
- field: `${WORK_ITEM_FIELDS_PATH_PREFIX}${fieldName}`
14917
- }),
14918
- literal: literal2
14919
- });
14920
- if (definition.schema instanceof exports_external.ZodObject) {
14921
- const validKeys = new Set(Object.keys(definition.schema.shape));
14922
- const unknown2 = Object.keys(raw).filter((key) => !validKeys.has(key));
14923
- if (unknown2.length > 0) {
14924
- throw new Error(`${label}.bindings returned key${unknown2.length > 1 ? "s" : ""} not in schema: ${unknown2.map((key) => `"${key}"`).join(", ")}`);
14925
- }
14926
- }
14927
- return normalizeInputMapping(raw) ?? {};
14928
- }
14929
- function mergeStepBindings(pipelineBindings, explicitBindings) {
14930
- const merged = {
14931
- ...pipelineBindings,
14932
- ...explicitBindings ?? {}
14933
- };
14934
- return Object.keys(merged).length > 0 ? merged : undefined;
14935
- }
14936
-
14937
14519
  // src/definitions/advancement-policies/cohort-fluent-rules.ts
14938
- var LEAF_BRAND2 = Symbol("boboddy.cohortRule.leaf");
14939
- var GROUP_BRAND2 = Symbol("boboddy.cohortRule.group");
14520
+ var LEAF_BRAND = Symbol("boboddy.cohortRule.leaf");
14521
+ var GROUP_BRAND = Symbol("boboddy.cohortRule.group");
14940
14522
  function createCohortSignalRef(signal2) {
14941
14523
  const leaf = (operator, value) => {
14942
14524
  const condition = {
@@ -14946,7 +14528,7 @@ function createCohortSignalRef(signal2) {
14946
14528
  value
14947
14529
  };
14948
14530
  return {
14949
- [LEAF_BRAND2]: condition,
14531
+ [LEAF_BRAND]: condition,
14950
14532
  then(outcome, paramsJson) {
14951
14533
  return {
14952
14534
  _tag: "rule",
@@ -14973,7 +14555,7 @@ function createCohortSignalRef(signal2) {
14973
14555
  }
14974
14556
  function createCohortLeafFromCondition(condition) {
14975
14557
  return {
14976
- [LEAF_BRAND2]: condition,
14558
+ [LEAF_BRAND]: condition,
14977
14559
  then(outcome, paramsJson) {
14978
14560
  return {
14979
14561
  _tag: "rule",
@@ -14986,15 +14568,15 @@ function createCohortLeafFromCondition(condition) {
14986
14568
  };
14987
14569
  }
14988
14570
  function extractCohortCondition(ref) {
14989
- if (LEAF_BRAND2 in ref)
14990
- return ref[LEAF_BRAND2];
14991
- const group = ref[GROUP_BRAND2];
14571
+ if (LEAF_BRAND in ref)
14572
+ return ref[LEAF_BRAND];
14573
+ const group = ref[GROUP_BRAND];
14992
14574
  return group.mode === "all" ? { _tag: "all", conditions: group.conditions } : { _tag: "any", conditions: group.conditions };
14993
14575
  }
14994
14576
  function createCohortGroup(mode, refs) {
14995
14577
  const conditions = refs.map(extractCohortCondition);
14996
14578
  return {
14997
- [GROUP_BRAND2]: { mode, conditions },
14579
+ [GROUP_BRAND]: { mode, conditions },
14998
14580
  then(outcome, paramsJson) {
14999
14581
  return {
15000
14582
  _tag: "rule",
@@ -15099,132 +14681,385 @@ function makeAdvanceAllCtx() {
15099
14681
  };
15100
14682
  }
15101
14683
 
15102
- // src/definitions/pipelines/fan-out-builder.ts
15103
- function beginFanOut(inputSchema, meta3, nodes, pipelineInputBindings, pipelineStepInputBindings, step, config2) {
15104
- const baseCtx = makeStepInputCtx(inputSchema);
15105
- const ctx = {
15106
- ...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(),
15107
14787
  item: { source: "fan_out_item" }
15108
14788
  };
15109
- const rawInput = config2.input ? config2.input(ctx) : {};
15110
- const input = mergeStepBindings(pipelineStepInputBindings, normalizeInputMapping(rawInput));
15111
- const fanOutNodeConfig = {
15112
- nodeType: "fanOut",
15113
- fanOutStep: step,
15114
- overSignalKey: config2.over,
15115
- ...input ? { input } : {},
15116
- ...config2.timeout !== undefined ? { timeout: config2.timeout } : {}
15117
- };
15118
- const advanceEachCtx = makeAdvanceEachCtx();
15119
- 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());
15120
14874
  const advanceEachPolicy = {
15121
14875
  default: advanceEachResult.default,
15122
14876
  ...advanceEachResult.rules !== undefined ? { rules: advanceEachResult.rules } : {}
15123
14877
  };
15124
- fanOutNodeConfig.advanceEach = advanceEachPolicy;
15125
- const cohortGateNodeConfig = {
15126
- nodeType: "cohortGate",
15127
- nodeKey: `${step.key}__cohortGate`
15128
- };
15129
- const advanceAllCtx = makeAdvanceAllCtx();
15130
- const advanceAllResult = config2.advanceAll(advanceAllCtx);
14878
+ const advanceAllResult = state.advanceAll(makeAdvanceAllCtx());
15131
14879
  const advanceAllPolicy = {
15132
14880
  default: advanceAllResult.default,
15133
14881
  ...advanceAllResult.rules !== undefined ? { rules: advanceAllResult.rules } : {}
15134
14882
  };
15135
- cohortGateNodeConfig.advanceAll = advanceAllPolicy;
15136
- nodes.push(fanOutNodeConfig, cohortGateNodeConfig);
15137
- return new PipelineStepBuilder(inputSchema, meta3, nodes, pipelineInputBindings, pipelineStepInputBindings);
15138
- }
15139
-
15140
- // src/definitions/pipelines/builder.ts
15141
- function pushStep(inputSchema, meta3, nodes, pipelineInputBindings, pipelineStepInputBindings, step, rawOptions) {
15142
- const options = rawOptions;
15143
- const ctx = makeStepInputCtx(inputSchema);
15144
- const rawInput = options.input ? options.input(ctx) : {};
15145
- const input = mergeStepBindings(pipelineStepInputBindings, normalizeInputMapping(rawInput));
15146
- const stepConfig = { step, input };
15147
- if (options.timeout !== undefined)
15148
- stepConfig.timeout = options.timeout;
15149
- const advanceCtx = makeAdvanceCtx();
15150
- const result = options.advance(advanceCtx);
15151
- const policy = {
15152
- defaultOutcome: result.default,
15153
- ...result.rules !== undefined ? { rules: result.rules } : {}
15154
- };
15155
- stepConfig.advancement = policy;
15156
- nodes.push(stepConfig);
15157
- return new PipelineStepBuilder(inputSchema, meta3, nodes, pipelineInputBindings, pipelineStepInputBindings);
15158
- }
15159
-
15160
- class PipelineStepBuilder {
15161
- inputSchema;
15162
- meta;
15163
- nodes;
15164
- pipelineInputBindings;
15165
- pipelineStepInputBindings;
15166
- constructor(inputSchema, meta3, nodes, pipelineInputBindings = {}, pipelineStepInputBindings = {}) {
15167
- this.inputSchema = inputSchema;
15168
- this.meta = meta3;
15169
- this.nodes = nodes;
15170
- this.pipelineInputBindings = pipelineInputBindings;
15171
- this.pipelineStepInputBindings = pipelineStepInputBindings;
15172
- }
15173
- step(step, options) {
15174
- return pushStep(this.inputSchema, this.meta, this.nodes, this.pipelineInputBindings, this.pipelineStepInputBindings, step, options);
15175
- }
15176
- fanOutStep(step, config2) {
15177
- return beginFanOut(this.inputSchema, this.meta, this.nodes, this.pipelineInputBindings, this.pipelineStepInputBindings, step, config2);
15178
- }
15179
- build() {
15180
- const config2 = {
15181
- key: this.meta.key,
15182
- name: this.meta.name,
15183
- description: this.meta.description,
15184
- version: this.meta.version,
15185
- status: this.meta.status,
15186
- input: this.inputSchema,
15187
- nodes: this.nodes,
15188
- 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)
15189
14930
  };
15190
- 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
+ }
15191
15004
  }
15192
15005
  }
15193
15006
 
15194
- class PipelineBuilder {
15195
- inputSchema;
15196
- meta;
15197
- nodes = [];
15198
- pipelineInputBindings;
15199
- pipelineStepInputBindings;
15200
- constructor(meta3) {
15201
- const { additionalPipelineInput, additionalStepInput, ...rest } = meta3;
15202
- this.inputSchema = additionalPipelineInput?.schema ?? exports_external.unknown();
15203
- this.meta = rest;
15204
- if (additionalPipelineInput) {
15205
- const raw = additionalPipelineInput.bindings({
15206
- workItem: WORK_ITEM_ACCESSOR,
15207
- literal: literal2
15208
- });
15209
- if (additionalPipelineInput.schema instanceof exports_external.ZodObject) {
15210
- const validKeys = new Set(Object.keys(additionalPipelineInput.schema.shape));
15211
- const unknown2 = Object.keys(raw).filter((k) => !validKeys.has(k));
15212
- if (unknown2.length > 0) {
15213
- throw new Error(`additionalPipelineInput.bindings returned key${unknown2.length > 1 ? "s" : ""} not in schema: ${unknown2.map((k) => `"${k}"`).join(", ")}`);
15214
- }
15215
- }
15216
- this.pipelineInputBindings = normalizeInputMapping(raw) ?? {};
15217
- } else {
15218
- this.pipelineInputBindings = {};
15219
- }
15220
- 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`);
15221
15015
  }
15222
- step(step, options) {
15223
- 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`);
15224
15019
  }
15225
- }
15226
- function pipeline(meta3) {
15227
- 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
+ };
15228
15063
  }
15229
15064
  // src/generated/core/bodySerializer.gen.ts
15230
15065
  var jsonBodySerializer = {
@@ -16305,29 +16140,6 @@ class PipelineDefinitions extends HeyApiClient {
16305
16140
  unarchivePipelineDefinition(options) {
16306
16141
  return (options.client ?? this.client).put({ url: "/api/pipeline-definitions/{pipelineDefinitionId}/unarchive", ...options });
16307
16142
  }
16308
- addPipelineStep(options) {
16309
- return (options.client ?? this.client).post({
16310
- url: "/api/pipeline-definitions/{pipelineDefinitionId}/steps",
16311
- ...options,
16312
- headers: {
16313
- "Content-Type": "application/json",
16314
- ...options.headers
16315
- }
16316
- });
16317
- }
16318
- removePipelineStep(options) {
16319
- return (options.client ?? this.client).delete({ url: "/api/pipeline-definitions/{pipelineDefinitionId}/steps/{pipelineStepDefinitionId}", ...options });
16320
- }
16321
- updatePipelineStep(options) {
16322
- return (options.client ?? this.client).put({
16323
- url: "/api/pipeline-definitions/{pipelineDefinitionId}/steps/{pipelineStepDefinitionId}",
16324
- ...options,
16325
- headers: {
16326
- "Content-Type": "application/json",
16327
- ...options.headers
16328
- }
16329
- });
16330
- }
16331
16143
  setPipelineStepAdvancementPolicy(options) {
16332
16144
  return (options.client ?? this.client).put({
16333
16145
  url: "/api/pipeline-definitions/{pipelineDefinitionId}/steps/{pipelineStepDefinitionId}/advancement-policy",
@@ -16834,6 +16646,76 @@ function createPipelineDefinitionsClient(baseUrl) {
16834
16646
  const client2 = createClient({ baseUrl });
16835
16647
  return buildPipelineDefinitionsClient(new PipelineDefinitions({ client: client2 }));
16836
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
+ }
16837
16719
  var buildPipelineDefinitionsClient = (pipelineDefinitions) => {
16838
16720
  return {
16839
16721
  listByProjectId: async (projectId, options) => {
@@ -16853,37 +16735,12 @@ var buildPipelineDefinitionsClient = (pipelineDefinitions) => {
16853
16735
  stepDefMap.set(s.key, s);
16854
16736
  }
16855
16737
  }
16856
- const nonStepNode = spec.nodeDefinitions.find((node) => node.kind !== "step");
16857
- if (nonStepNode) {
16858
- 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.`);
16859
- }
16860
- const ordered = tryOrderChainNodeDefinitions(spec.nodeDefinitions, spec.dependencyEdges);
16861
- if (ordered === null) {
16862
- 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.`);
16863
- }
16864
- const stepDefinitions = ordered.map((node, index) => {
16865
- const stepKey = node.stepKey;
16866
- if (!stepKey) {
16867
- throw new Error(`Node "${node.nodeKey}" in pipeline "${spec.key}" has no stepKey.`);
16868
- }
16869
- const stepDef = stepDefMap.get(stepKey);
16870
- if (!stepDef) {
16871
- 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.`);
16872
- }
16873
- return {
16874
- stepDefinitionId: stepDef.id,
16875
- stepDefinitionVersion: stepDef.version,
16876
- key: node.nodeKey,
16877
- name: node.stepName ?? "",
16878
- description: node.stepDescription ?? null,
16879
- position: index + 1,
16880
- inputBindingsJson: node.inputBindingsJson ?? {},
16881
- timeoutSeconds: node.timeoutSeconds ?? null,
16882
- retryPolicyJson: null,
16883
- advancementPolicyDefinition: node.advancementPolicyDefinition,
16884
- computedSignalDefinitions: node.computedSignalDefinitions ?? []
16885
- };
16886
- });
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
+ }));
16887
16744
  const body = {
16888
16745
  projectId,
16889
16746
  key: spec.key,
@@ -16891,7 +16748,8 @@ var buildPipelineDefinitionsClient = (pipelineDefinitions) => {
16891
16748
  description: spec.description,
16892
16749
  status: spec.status,
16893
16750
  inputSchemaJson: spec.inputSchemaJson,
16894
- stepDefinitions
16751
+ nodeDefinitions,
16752
+ dependencyEdges
16895
16753
  };
16896
16754
  const result = await pipelineDefinitions.upsertPipelineDefinition({
16897
16755
  body,
@@ -16949,17 +16807,17 @@ function buildWorkItemAccessor() {
16949
16807
  }
16950
16808
  return accessor;
16951
16809
  }
16952
- function makeAssign(pipeline2) {
16953
- if (typeof pipeline2 !== "object" || typeof pipeline2["key"] !== "string" || !Array.isArray(pipeline2["nodeDefinitions"])) {
16954
- throw new Error("assign() requires a pipeline spec produced by pipeline().build(). " + "Pass the default-exported value from a pipeline definition file.");
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.");
16955
16813
  }
16956
- return { _tag: "assign", pipeline: pipeline2 };
16814
+ return { _tag: "assign", pipeline };
16957
16815
  }
16958
- function extractCondition2(ref) {
16816
+ function extractCondition(ref) {
16959
16817
  return ref._condition;
16960
16818
  }
16961
16819
  function makeGroup(mode, refs) {
16962
- const conditions = refs.map(extractCondition2);
16820
+ const conditions = refs.map(extractCondition);
16963
16821
  const condition = { _tag: "group", mode, conditions };
16964
16822
  return {
16965
16823
  _condition: condition,
@@ -17049,22 +16907,19 @@ function isDefaultPipelineAssignmentSpec(value) {
17049
16907
  return value["_tag"] === "default_pipeline_assignment";
17050
16908
  }
17051
16909
  export {
16910
+ serializeInputBindings,
17052
16911
  serializeDefaultPipelineAssignment,
17053
16912
  resolveWorkItemFieldPath,
17054
- pipeline,
17055
- materializeAccessor,
17056
- literal2 as literal,
17057
- isInputAccessor,
16913
+ makeNodeInputCtx,
16914
+ makeFanOutNodeInputCtx,
16915
+ isWorkingNodeDefinition,
17058
16916
  isDefaultPipelineAssignmentSpec,
16917
+ definePipeline,
17059
16918
  defaultPipelineAssignment,
17060
16919
  createPipelineDefinitionsClient,
17061
- createInputAccessor,
17062
- buildPipelineSpec,
17063
16920
  WORK_ITEM_TOP_LEVEL_FIELDS,
17064
16921
  WORK_ITEM_FIELDS_PATH_PREFIX,
17065
16922
  Rule,
17066
- PipelineStepBuilder,
17067
- PipelineBuilder,
17068
16923
  DEFAULT_PIPELINE_ASSIGNMENT_FILENAME,
17069
16924
  Computed
17070
16925
  };