@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.
- package/dist/client.js +0 -23
- package/dist/definitions/advancement-policies/define-advancement-policy.d.ts +30 -5
- package/dist/definitions/advancement-policies/index.js +11 -1
- package/dist/definitions/pipelines/bindings.d.ts +62 -0
- package/dist/definitions/pipelines/builder-helpers.d.ts +19 -106
- package/dist/definitions/pipelines/chain-graph.d.ts +15 -14
- package/dist/definitions/pipelines/compile-node-definitions.d.ts +27 -0
- package/dist/definitions/pipelines/define-pipeline.d.ts +101 -154
- package/dist/definitions/pipelines/index.d.ts +0 -2
- package/dist/definitions/pipelines/index.js +470 -615
- package/dist/definitions/pipelines/node-input-ctx.d.ts +31 -0
- package/dist/definitions/pipelines/pipeline-definitions-client.d.ts +18 -4
- package/dist/definitions/pipelines/pipeline-states.d.ts +104 -0
- package/dist/definitions/steps/define-code-step.d.ts +50 -0
- package/dist/definitions/steps/define-step.d.ts +22 -1
- package/dist/definitions/steps/index.d.ts +1 -0
- package/dist/definitions/steps/index.js +41 -24
- package/dist/definitions/steps/step-definitions-client.d.ts +29 -5
- package/dist/definitions/validation/index.js +15148 -94
- package/dist/definitions/validation/validate-definition-specs.d.ts +19 -1
- package/dist/generated/index.d.ts +1 -1
- package/dist/generated/sdk.gen.d.ts +1 -4
- package/dist/generated/types.gen.d.ts +296 -878
- package/dist/index.js +510 -615
- package/dist/push/collect-definitions.d.ts +40 -1
- package/dist/push/index.d.ts +2 -2
- package/dist/push/index.js +788 -738
- package/dist/step-execution-plane-client.d.ts +9 -4
- package/package.json +2 -2
- package/dist/definitions/pipelines/builder.d.ts +0 -80
- package/dist/definitions/pipelines/fan-out-builder.d.ts +0 -66
- 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: [
|
|
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
|
|
14939
|
-
var
|
|
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
|
-
[
|
|
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
|
-
[
|
|
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 (
|
|
14990
|
-
return ref[
|
|
14991
|
-
const group = ref[
|
|
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
|
-
[
|
|
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/
|
|
15103
|
-
function
|
|
15104
|
-
|
|
15105
|
-
|
|
15106
|
-
|
|
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
|
-
|
|
15110
|
-
|
|
15111
|
-
|
|
15112
|
-
|
|
15113
|
-
|
|
15114
|
-
|
|
15115
|
-
|
|
15116
|
-
|
|
15117
|
-
|
|
15118
|
-
const
|
|
15119
|
-
|
|
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
|
-
|
|
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
|
-
|
|
15136
|
-
|
|
15137
|
-
|
|
15138
|
-
}
|
|
15139
|
-
|
|
15140
|
-
|
|
15141
|
-
|
|
15142
|
-
|
|
15143
|
-
|
|
15144
|
-
|
|
15145
|
-
|
|
15146
|
-
|
|
15147
|
-
|
|
15148
|
-
|
|
15149
|
-
|
|
15150
|
-
|
|
15151
|
-
|
|
15152
|
-
|
|
15153
|
-
|
|
15154
|
-
|
|
15155
|
-
|
|
15156
|
-
|
|
15157
|
-
|
|
15158
|
-
|
|
15159
|
-
|
|
15160
|
-
|
|
15161
|
-
|
|
15162
|
-
|
|
15163
|
-
|
|
15164
|
-
|
|
15165
|
-
|
|
15166
|
-
|
|
15167
|
-
|
|
15168
|
-
|
|
15169
|
-
|
|
15170
|
-
|
|
15171
|
-
|
|
15172
|
-
}
|
|
15173
|
-
|
|
15174
|
-
|
|
15175
|
-
|
|
15176
|
-
|
|
15177
|
-
|
|
15178
|
-
|
|
15179
|
-
|
|
15180
|
-
|
|
15181
|
-
|
|
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
|
-
|
|
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
|
-
|
|
15195
|
-
|
|
15196
|
-
|
|
15197
|
-
|
|
15198
|
-
|
|
15199
|
-
|
|
15200
|
-
|
|
15201
|
-
|
|
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
|
-
|
|
15223
|
-
|
|
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
|
-
|
|
15227
|
-
|
|
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
|
|
16857
|
-
|
|
16858
|
-
|
|
16859
|
-
|
|
16860
|
-
|
|
16861
|
-
|
|
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
|
-
|
|
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(
|
|
16953
|
-
if (typeof
|
|
16954
|
-
throw new Error("assign() requires a pipeline spec produced by
|
|
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
|
|
16814
|
+
return { _tag: "assign", pipeline };
|
|
16957
16815
|
}
|
|
16958
|
-
function
|
|
16816
|
+
function extractCondition(ref) {
|
|
16959
16817
|
return ref._condition;
|
|
16960
16818
|
}
|
|
16961
16819
|
function makeGroup(mode, refs) {
|
|
16962
|
-
const conditions = refs.map(
|
|
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
|
-
|
|
17055
|
-
|
|
17056
|
-
|
|
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
|
};
|