@boboddy/sdk 0.2.15-alpha → 0.4.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.
@@ -1,10 +1,10 @@
1
1
  import { PipelineDefinitions } from "../../generated/sdk.gen";
2
- import type { PutApiLinearPipelineDefinitionsData } from "../../generated/types.gen";
2
+ import type { PutApiPipelineDefinitionsData } from "../../generated/types.gen";
3
3
  import type { PipelineDefinitionSpec } from "./define-pipeline";
4
4
  type RequestOptions = {
5
5
  headers?: Record<string, unknown> | undefined;
6
6
  };
7
- export type UpsertPipelineDefinitionInput = PutApiLinearPipelineDefinitionsData["body"];
7
+ export type UpsertPipelineDefinitionInput = PutApiPipelineDefinitionsData["body"];
8
8
  export type StepDefinitionRef = {
9
9
  id: string;
10
10
  key: string;
@@ -23,7 +23,7 @@ declare const buildPipelineDefinitionsClient: (pipelineDefinitions: PipelineDefi
23
23
  inputSchemaJson: unknown;
24
24
  stepDefinitions: Array<{
25
25
  id: string;
26
- linearPipelineDefinitionId: string;
26
+ pipelineDefinitionId: string;
27
27
  stepDefinitionId: string;
28
28
  stepDefinitionVersion: number;
29
29
  key: string;
@@ -54,7 +54,7 @@ declare const buildPipelineDefinitionsClient: (pipelineDefinitions: PipelineDefi
54
54
  retryPolicyJson: unknown;
55
55
  advancementPolicyDefinition: {
56
56
  id: string;
57
- linearPipelineStepDefinitionId: string;
57
+ pipelineStepDefinitionId: string;
58
58
  rulesJson: {
59
59
  rules: Array<{
60
60
  conditions: {
@@ -141,7 +141,7 @@ declare const buildPipelineDefinitionsClient: (pipelineDefinitions: PipelineDefi
141
141
  inputSchemaJson: unknown;
142
142
  stepDefinitions: Array<{
143
143
  id: string;
144
- linearPipelineDefinitionId: string;
144
+ pipelineDefinitionId: string;
145
145
  stepDefinitionId: string;
146
146
  stepDefinitionVersion: number;
147
147
  key: string;
@@ -172,7 +172,7 @@ declare const buildPipelineDefinitionsClient: (pipelineDefinitions: PipelineDefi
172
172
  retryPolicyJson: unknown;
173
173
  advancementPolicyDefinition: {
174
174
  id: string;
175
- linearPipelineStepDefinitionId: string;
175
+ pipelineStepDefinitionId: string;
176
176
  rulesJson: {
177
177
  rules: Array<{
178
178
  conditions: {
@@ -49,6 +49,9 @@ type HealthCheck = {
49
49
  /** Full value of a step's `healthChecks` field. */
50
50
  type HealthChecks = HealthCheck[];
51
51
  type SignalTypeStr = "string" | "number" | "boolean" | "object" | "array";
52
+ type Prettify<T> = {
53
+ [K in keyof T]: T[K];
54
+ } & {};
52
55
  export type DotPaths<T, D extends readonly unknown[] = []> = D["length"] extends 4 ? string : unknown extends T ? string : T extends readonly unknown[] ? string : T extends object ? {
53
56
  [K in keyof T & string]: K | (NonNullable<T[K]> extends object ? `${K}.${DotPaths<NonNullable<T[K]>, [...D, unknown]> & string}` : never);
54
57
  }[keyof T & string] : string;
@@ -117,13 +120,14 @@ export type StepDefinitionSpec = {
117
120
  healthChecksJson: HealthChecks | null;
118
121
  };
119
122
  export type SignalTypeStrToTs<T extends SignalTypeStr> = T extends "string" ? string : T extends "number" ? number : T extends "boolean" ? boolean : T extends "array" ? unknown[] : T extends "object" ? object : unknown;
120
- export type SignalTypeMapOf<TSignals extends readonly unknown[], TResult> = {
123
+ export type SignalTypeMapOf<TSignals extends readonly unknown[], TResult> = Prettify<{
121
124
  [S in TSignals[number] as ExtractSignalKey<S>]: S extends {
122
125
  type: infer T extends SignalTypeStr;
123
126
  } ? SignalTypeStrToTs<T> : S extends {
124
127
  sourcePath: infer P extends string;
125
128
  } ? TypeAtPath<TResult, P> : unknown;
126
- };
129
+ }>;
130
+ type EffectiveResult<TResult, TFeatures extends ReadonlyArray<AnyStepFeature>> = Prettify<TResult & FeatureResultExtensions<TFeatures>>;
127
131
  type HasAdditionalInput<T> = 0 extends 1 & T ? boolean : [unknown] extends [T] ? false : true;
128
132
  export type TypedStepDefinitionSpec<TInput = unknown, TResult = unknown, TSignalKeys extends string = string, TSignalTypeMap extends Partial<Record<string, unknown>> = Record<string, unknown>> = StepDefinitionSpec & {
129
133
  readonly __inputType: TInput;
@@ -144,5 +148,5 @@ export declare function defineStep<TInput extends ZodType = ZodType, TResult ext
144
148
  }> = never[], const TFeatures extends ReadonlyArray<AnyStepFeature> = never[]>(config: Omit<DefineStepInput<TInput, TResult>, "signals" | "features"> & {
145
149
  signals?: TSignals & readonly SignalSpecInput<TResult["_output"]>[];
146
150
  features?: TFeatures;
147
- }): TypedStepDefinitionSpec<TInput["_output"], TResult["_output"] & FeatureResultExtensions<TFeatures>, SignalKeysOf<TSignals> | FeatureSignalKeys<TFeatures>, SignalTypeMapOf<TSignals, TResult["_output"]>>;
151
+ }): TypedStepDefinitionSpec<TInput["_output"], EffectiveResult<TResult["_output"], TFeatures>, SignalKeysOf<TSignals> | FeatureSignalKeys<TFeatures>, SignalTypeMapOf<TSignals, TResult["_output"]>>;
148
152
  export {};
@@ -12933,6 +12933,18 @@ class Api extends HeyApiClient {
12933
12933
  }
12934
12934
 
12935
12935
  class Projects extends HeyApiClient {
12936
+ resolveProjectBySlug(options) {
12937
+ return (options.client ?? this.client).get({ url: "/api/projects/resolve", ...options });
12938
+ }
12939
+ listProjectWorkItems(options) {
12940
+ return (options.client ?? this.client).get({ url: "/api/projects/{projectId}/work-items", ...options });
12941
+ }
12942
+ listProjectWorkItemFieldOptions(options) {
12943
+ return (options.client ?? this.client).get({ url: "/api/projects/{projectId}/work-item-field-options", ...options });
12944
+ }
12945
+ getProject(options) {
12946
+ return (options.client ?? this.client).get({ url: "/api/projects/{projectId}", ...options });
12947
+ }
12936
12948
  listProjects(options) {
12937
12949
  return (options?.client ?? this.client).get({ url: "/api/projects", ...options });
12938
12950
  }
@@ -12946,18 +12958,6 @@ class Projects extends HeyApiClient {
12946
12958
  }
12947
12959
  });
12948
12960
  }
12949
- resolveProjectBySlug(options) {
12950
- return (options.client ?? this.client).get({ url: "/api/projects/resolve", ...options });
12951
- }
12952
- listProjectWorkItems(options) {
12953
- return (options.client ?? this.client).get({ url: "/api/projects/{projectId}/work-items", ...options });
12954
- }
12955
- listProjectWorkItemFieldOptions(options) {
12956
- return (options.client ?? this.client).get({ url: "/api/projects/{projectId}/work-item-field-options", ...options });
12957
- }
12958
- getProject(options) {
12959
- return (options.client ?? this.client).get({ url: "/api/projects/{projectId}", ...options });
12960
- }
12961
12961
  updateProjectDefaultPipelineAssignment(options) {
12962
12962
  return (options.client ?? this.client).put({
12963
12963
  url: "/api/projects/{projectId}/default-pipeline-assignment",
@@ -13016,32 +13016,6 @@ class StepDefinitions extends HeyApiClient {
13016
13016
  }
13017
13017
 
13018
13018
  class StepExecutions extends HeyApiClient {
13019
- createArtifactUploadUrl(options) {
13020
- return (options.client ?? this.client).post({
13021
- url: "/api/step-executions/{stepExecutionId}/artifact-upload-url",
13022
- ...options,
13023
- headers: {
13024
- "Content-Type": "application/json",
13025
- ...options.headers
13026
- }
13027
- });
13028
- }
13029
- listStepExecutionArtifacts(options) {
13030
- return (options.client ?? this.client).get({ url: "/api/step-executions/{stepExecutionId}/artifacts", ...options });
13031
- }
13032
- recordStepExecutionArtifact(options) {
13033
- return (options.client ?? this.client).post({
13034
- url: "/api/step-executions/{stepExecutionId}/artifacts",
13035
- ...options,
13036
- headers: {
13037
- "Content-Type": "application/json",
13038
- ...options.headers
13039
- }
13040
- });
13041
- }
13042
- getArtifactDownloadUrl(options) {
13043
- return (options.client ?? this.client).get({ url: "/api/step-executions/{stepExecutionId}/artifacts/{artifactId}/download-url", ...options });
13044
- }
13045
13019
  claimStepExecutions(options) {
13046
13020
  return (options.client ?? this.client).post({
13047
13021
  url: "/api/step-executions/claims",
@@ -13111,9 +13085,6 @@ class StepExecutions extends HeyApiClient {
13111
13085
  extractStepExecutionSignals(options) {
13112
13086
  return (options.client ?? this.client).post({ url: "/api/step-execution-results/{stepExecutionResultId}/signals/extract", ...options });
13113
13087
  }
13114
- getStepExecution(options) {
13115
- return (options.client ?? this.client).get({ url: "/api/step-executions/{stepExecutionId}", ...options });
13116
- }
13117
13088
  readStepExecutionLogs(options) {
13118
13089
  return (options.client ?? this.client).get({ url: "/api/step-executions/{stepExecutionId}/logs", ...options });
13119
13090
  }
@@ -13127,15 +13098,44 @@ class StepExecutions extends HeyApiClient {
13127
13098
  }
13128
13099
  });
13129
13100
  }
13101
+ getStepExecution(options) {
13102
+ return (options.client ?? this.client).get({ url: "/api/step-executions/{stepExecutionId}", ...options });
13103
+ }
13130
13104
  getStepExecutionLogArchive(options) {
13131
13105
  return (options.client ?? this.client).get({ url: "/api/step-executions/{stepExecutionId}/logs/archive", ...options });
13132
13106
  }
13107
+ createArtifactUploadUrl(options) {
13108
+ return (options.client ?? this.client).post({
13109
+ url: "/api/step-executions/{stepExecutionId}/artifact-upload-url",
13110
+ ...options,
13111
+ headers: {
13112
+ "Content-Type": "application/json",
13113
+ ...options.headers
13114
+ }
13115
+ });
13116
+ }
13117
+ listStepExecutionArtifacts(options) {
13118
+ return (options.client ?? this.client).get({ url: "/api/step-executions/{stepExecutionId}/artifacts", ...options });
13119
+ }
13120
+ recordStepExecutionArtifact(options) {
13121
+ return (options.client ?? this.client).post({
13122
+ url: "/api/step-executions/{stepExecutionId}/artifacts",
13123
+ ...options,
13124
+ headers: {
13125
+ "Content-Type": "application/json",
13126
+ ...options.headers
13127
+ }
13128
+ });
13129
+ }
13130
+ getArtifactDownloadUrl(options) {
13131
+ return (options.client ?? this.client).get({ url: "/api/step-executions/{stepExecutionId}/artifacts/{artifactId}/download-url", ...options });
13132
+ }
13133
13133
  }
13134
13134
 
13135
13135
  class PipelineDefinitions extends HeyApiClient {
13136
13136
  createPipelineDefinition(options) {
13137
13137
  return (options.client ?? this.client).post({
13138
- url: "/api/linear-pipeline-definitions",
13138
+ url: "/api/pipeline-definitions",
13139
13139
  ...options,
13140
13140
  headers: {
13141
13141
  "Content-Type": "application/json",
@@ -13145,7 +13145,7 @@ class PipelineDefinitions extends HeyApiClient {
13145
13145
  }
13146
13146
  upsertPipelineDefinition(options) {
13147
13147
  return (options.client ?? this.client).put({
13148
- url: "/api/linear-pipeline-definitions",
13148
+ url: "/api/pipeline-definitions",
13149
13149
  ...options,
13150
13150
  headers: {
13151
13151
  "Content-Type": "application/json",
@@ -13153,21 +13153,15 @@ class PipelineDefinitions extends HeyApiClient {
13153
13153
  }
13154
13154
  });
13155
13155
  }
13156
- getPipelineDefinition(options) {
13157
- return (options.client ?? this.client).get({ url: "/api/linear-pipeline-definitions/{linearPipelineDefinitionId}", ...options });
13158
- }
13159
- listPipelineDefinitions(options) {
13160
- return (options.client ?? this.client).get({ url: "/api/projects/{projectId}/linear-pipeline-definitions", ...options });
13161
- }
13162
13156
  archivePipelineDefinition(options) {
13163
- return (options.client ?? this.client).put({ url: "/api/linear-pipeline-definitions/{linearPipelineDefinitionId}/archive", ...options });
13157
+ return (options.client ?? this.client).put({ url: "/api/pipeline-definitions/{pipelineDefinitionId}/archive", ...options });
13164
13158
  }
13165
13159
  unarchivePipelineDefinition(options) {
13166
- return (options.client ?? this.client).put({ url: "/api/linear-pipeline-definitions/{linearPipelineDefinitionId}/unarchive", ...options });
13160
+ return (options.client ?? this.client).put({ url: "/api/pipeline-definitions/{pipelineDefinitionId}/unarchive", ...options });
13167
13161
  }
13168
13162
  addPipelineStep(options) {
13169
13163
  return (options.client ?? this.client).post({
13170
- url: "/api/linear-pipeline-definitions/{linearPipelineDefinitionId}/steps",
13164
+ url: "/api/pipeline-definitions/{pipelineDefinitionId}/steps",
13171
13165
  ...options,
13172
13166
  headers: {
13173
13167
  "Content-Type": "application/json",
@@ -13176,11 +13170,11 @@ class PipelineDefinitions extends HeyApiClient {
13176
13170
  });
13177
13171
  }
13178
13172
  removePipelineStep(options) {
13179
- return (options.client ?? this.client).delete({ url: "/api/linear-pipeline-definitions/{linearPipelineDefinitionId}/steps/{linearPipelineStepDefinitionId}", ...options });
13173
+ return (options.client ?? this.client).delete({ url: "/api/pipeline-definitions/{pipelineDefinitionId}/steps/{pipelineStepDefinitionId}", ...options });
13180
13174
  }
13181
13175
  updatePipelineStep(options) {
13182
13176
  return (options.client ?? this.client).put({
13183
- url: "/api/linear-pipeline-definitions/{linearPipelineDefinitionId}/steps/{linearPipelineStepDefinitionId}",
13177
+ url: "/api/pipeline-definitions/{pipelineDefinitionId}/steps/{pipelineStepDefinitionId}",
13184
13178
  ...options,
13185
13179
  headers: {
13186
13180
  "Content-Type": "application/json",
@@ -13190,7 +13184,7 @@ class PipelineDefinitions extends HeyApiClient {
13190
13184
  }
13191
13185
  setPipelineStepAdvancementPolicy(options) {
13192
13186
  return (options.client ?? this.client).put({
13193
- url: "/api/linear-pipeline-definitions/{linearPipelineDefinitionId}/steps/{linearPipelineStepDefinitionId}/advancement-policy",
13187
+ url: "/api/pipeline-definitions/{pipelineDefinitionId}/steps/{pipelineStepDefinitionId}/advancement-policy",
13194
13188
  ...options,
13195
13189
  headers: {
13196
13190
  "Content-Type": "application/json",
@@ -13198,15 +13192,21 @@ class PipelineDefinitions extends HeyApiClient {
13198
13192
  }
13199
13193
  });
13200
13194
  }
13195
+ getPipelineDefinition(options) {
13196
+ return (options.client ?? this.client).get({ url: "/api/pipeline-definitions/{pipelineDefinitionId}", ...options });
13197
+ }
13198
+ listPipelineDefinitions(options) {
13199
+ return (options.client ?? this.client).get({ url: "/api/projects/{projectId}/pipeline-definitions", ...options });
13200
+ }
13201
13201
  }
13202
13202
 
13203
13203
  class PipelineExecutions extends HeyApiClient {
13204
13204
  listPipelineExecutions(options) {
13205
- return (options.client ?? this.client).get({ url: "/api/linear-pipeline-executions", ...options });
13205
+ return (options.client ?? this.client).get({ url: "/api/pipeline-executions", ...options });
13206
13206
  }
13207
13207
  createPipelineExecution(options) {
13208
13208
  return (options.client ?? this.client).post({
13209
- url: "/api/linear-pipeline-executions",
13209
+ url: "/api/pipeline-executions",
13210
13210
  ...options,
13211
13211
  headers: {
13212
13212
  "Content-Type": "application/json",
@@ -13215,17 +13215,17 @@ class PipelineExecutions extends HeyApiClient {
13215
13215
  });
13216
13216
  }
13217
13217
  startPipelineExecution(options) {
13218
- return (options.client ?? this.client).put({ url: "/api/linear-pipeline-executions/{linearPipelineExecutionId}/start", ...options });
13218
+ return (options.client ?? this.client).put({ url: "/api/pipeline-executions/{pipelineExecutionId}/start", ...options });
13219
13219
  }
13220
13220
  queueFirstPipelineStepRun(options) {
13221
- return (options.client ?? this.client).post({ url: "/api/linear-pipeline-executions/{linearPipelineExecutionId}/step-runs/first", ...options });
13221
+ return (options.client ?? this.client).post({ url: "/api/pipeline-executions/{pipelineExecutionId}/step-runs/first", ...options });
13222
13222
  }
13223
13223
  markPipelineStepRunRunning(options) {
13224
- return (options.client ?? this.client).put({ url: "/api/linear-pipeline-executions/{linearPipelineExecutionId}/step-runs/{linearPipelineStepRunId}/running", ...options });
13224
+ return (options.client ?? this.client).put({ url: "/api/pipeline-executions/{pipelineExecutionId}/step-runs/{pipelineStepRunId}/running", ...options });
13225
13225
  }
13226
13226
  applyPipelineStepResult(options) {
13227
13227
  return (options.client ?? this.client).post({
13228
- url: "/api/linear-pipeline-executions/{linearPipelineExecutionId}/step-runs/{linearPipelineStepRunId}/results",
13228
+ url: "/api/pipeline-executions/{pipelineExecutionId}/step-runs/{pipelineStepRunId}/results",
13229
13229
  ...options,
13230
13230
  headers: {
13231
13231
  "Content-Type": "application/json",
@@ -13235,7 +13235,17 @@ class PipelineExecutions extends HeyApiClient {
13235
13235
  }
13236
13236
  acceptPipelineStepRun(options) {
13237
13237
  return (options.client ?? this.client).post({
13238
- url: "/api/linear-pipeline-executions/{linearPipelineExecutionId}/step-runs/{linearPipelineStepRunId}/accept",
13238
+ url: "/api/pipeline-executions/{pipelineExecutionId}/step-runs/{pipelineStepRunId}/accept",
13239
+ ...options,
13240
+ headers: {
13241
+ "Content-Type": "application/json",
13242
+ ...options.headers
13243
+ }
13244
+ });
13245
+ }
13246
+ acceptPipelineCohort(options) {
13247
+ return (options.client ?? this.client).post({
13248
+ url: "/api/pipeline-executions/{pipelineExecutionId}/cohorts/{originNodeDefinitionId}/accept",
13239
13249
  ...options,
13240
13250
  headers: {
13241
13251
  "Content-Type": "application/json",
@@ -13245,7 +13255,7 @@ class PipelineExecutions extends HeyApiClient {
13245
13255
  }
13246
13256
  rerunPipelineExecution(options) {
13247
13257
  return (options.client ?? this.client).post({
13248
- url: "/api/linear-pipeline-executions/{linearPipelineExecutionId}/rerun",
13258
+ url: "/api/pipeline-executions/{pipelineExecutionId}/rerun",
13249
13259
  ...options,
13250
13260
  headers: {
13251
13261
  "Content-Type": "application/json",
@@ -13254,23 +13264,32 @@ class PipelineExecutions extends HeyApiClient {
13254
13264
  });
13255
13265
  }
13256
13266
  cancelPipelineExecution(options) {
13257
- return (options.client ?? this.client).put({ url: "/api/linear-pipeline-executions/{linearPipelineExecutionId}/cancel", ...options });
13267
+ return (options.client ?? this.client).put({ url: "/api/pipeline-executions/{pipelineExecutionId}/cancel", ...options });
13258
13268
  }
13259
13269
  getPipelineExecution(options) {
13260
- return (options.client ?? this.client).get({ url: "/api/linear-pipeline-executions/{linearPipelineExecutionId}", ...options });
13270
+ return (options.client ?? this.client).get({ url: "/api/pipeline-executions/{pipelineExecutionId}", ...options });
13271
+ }
13272
+ getPipelineExecutionRoutedChain(options) {
13273
+ return (options.client ?? this.client).get({ url: "/api/pipeline-executions/{pipelineExecutionId}/routed-chain", ...options });
13261
13274
  }
13262
13275
  countPipelineExecutionsByPipeline(options) {
13263
- return (options.client ?? this.client).get({ url: "/api/linear-pipeline-executions/counts/by-pipeline", ...options });
13276
+ return (options.client ?? this.client).get({ url: "/api/pipeline-executions/counts/by-pipeline", ...options });
13264
13277
  }
13265
13278
  listPipelineDefinitionStepRollups(options) {
13266
- return (options.client ?? this.client).get({ url: "/api/linear-pipeline-executions/step-rollups/by-definition/{linearPipelineDefinitionId}", ...options });
13279
+ return (options.client ?? this.client).get({ url: "/api/pipeline-executions/step-rollups/by-definition/{pipelineDefinitionId}", ...options });
13267
13280
  }
13268
13281
  listPipelineDefinitionStepRuns(options) {
13269
- return (options.client ?? this.client).get({ url: "/api/linear-pipeline-executions/step-runs/by-definition/{linearPipelineDefinitionId}", ...options });
13282
+ return (options.client ?? this.client).get({ url: "/api/pipeline-executions/step-runs/by-definition/{pipelineDefinitionId}", ...options });
13270
13283
  }
13271
13284
  }
13272
13285
 
13273
13286
  class WorkItems extends HeyApiClient {
13287
+ deleteWorkItem(options) {
13288
+ return (options.client ?? this.client).delete({ url: "/api/work-items/{workItemId}", ...options });
13289
+ }
13290
+ getWorkItem(options) {
13291
+ return (options.client ?? this.client).get({ url: "/api/work-items/{workItemId}", ...options });
13292
+ }
13274
13293
  createWorkItem(options) {
13275
13294
  return (options.client ?? this.client).post({
13276
13295
  url: "/api/work-items",
@@ -13321,12 +13340,6 @@ class WorkItems extends HeyApiClient {
13321
13340
  }
13322
13341
  });
13323
13342
  }
13324
- deleteWorkItem(options) {
13325
- return (options.client ?? this.client).delete({ url: "/api/work-items/{workItemId}", ...options });
13326
- }
13327
- getWorkItem(options) {
13328
- return (options.client ?? this.client).get({ url: "/api/work-items/{workItemId}", ...options });
13329
- }
13330
13343
  }
13331
13344
 
13332
13345
  class WorkItemComments extends HeyApiClient {
@@ -237,6 +237,67 @@ function resolveSourcePath(schema, sourcePath) {
237
237
  }
238
238
  return { kind: "resolved" };
239
239
  }
240
+ // src/definitions/pipelines/chain-graph.ts
241
+ function tryOrderChainNodeDefinitions(nodeDefinitions, dependencyEdges) {
242
+ const nodesByKey = new Map;
243
+ for (const nodeDefinition of nodeDefinitions) {
244
+ nodesByKey.set(nodeDefinition.nodeKey, nodeDefinition);
245
+ }
246
+ const outgoing = new Map;
247
+ const incomingCount = new Map;
248
+ for (const nodeDefinition of nodeDefinitions) {
249
+ incomingCount.set(nodeDefinition.nodeKey, 0);
250
+ }
251
+ for (const edge of dependencyEdges) {
252
+ if (!nodesByKey.has(edge.fromNodeKey) || !nodesByKey.has(edge.toNodeKey)) {
253
+ return null;
254
+ }
255
+ if (outgoing.has(edge.fromNodeKey))
256
+ return null;
257
+ outgoing.set(edge.fromNodeKey, edge.toNodeKey);
258
+ incomingCount.set(edge.toNodeKey, (incomingCount.get(edge.toNodeKey) ?? 0) + 1);
259
+ }
260
+ for (const count of incomingCount.values()) {
261
+ if (count > 1)
262
+ return null;
263
+ }
264
+ if (nodeDefinitions.length === 0)
265
+ return [];
266
+ const roots = nodeDefinitions.filter((nodeDefinition) => (incomingCount.get(nodeDefinition.nodeKey) ?? 0) === 0);
267
+ if (roots.length !== 1)
268
+ return null;
269
+ const rootNode = roots[0];
270
+ if (!rootNode)
271
+ return null;
272
+ const ordered = [];
273
+ const visited = new Set;
274
+ let currentKey = rootNode.nodeKey;
275
+ while (currentKey !== undefined) {
276
+ if (visited.has(currentKey))
277
+ return null;
278
+ visited.add(currentKey);
279
+ const currentNode = nodesByKey.get(currentKey);
280
+ if (!currentNode)
281
+ return null;
282
+ ordered.push(currentNode);
283
+ currentKey = outgoing.get(currentKey);
284
+ }
285
+ if (ordered.length !== nodeDefinitions.length)
286
+ return null;
287
+ return ordered;
288
+ }
289
+ function buildChainDependencyEdges(orderedNodes) {
290
+ const dependencyEdges = [];
291
+ for (let index = 0;index < orderedNodes.length - 1; index += 1) {
292
+ const from = orderedNodes[index];
293
+ const to = orderedNodes[index + 1];
294
+ if (!from || !to)
295
+ continue;
296
+ dependencyEdges.push({ fromNodeKey: from.nodeKey, toNodeKey: to.nodeKey });
297
+ }
298
+ return dependencyEdges;
299
+ }
300
+
240
301
  // src/definitions/validation/validate-definition-specs.ts
241
302
  function listPaths(paths, limit = 24) {
242
303
  if (paths.length === 0)
@@ -300,6 +361,8 @@ function checkHealthChecks(steps) {
300
361
  return issues;
301
362
  }
302
363
  function routeTargets(policy) {
364
+ if (!policy)
365
+ return [];
303
366
  const keys = [];
304
367
  if (policy.defaultEventType === "route" && typeof policy.defaultEventParamsJson?.["pipelineKey"] === "string") {
305
368
  keys.push(policy.defaultEventParamsJson["pipelineKey"]);
@@ -318,36 +381,42 @@ function checkRouteTargets(pipelines, knownPipelineKeys) {
318
381
  ...knownPipelineKeys
319
382
  ]);
320
383
  for (const pipeline of pipelines) {
321
- for (const step of pipeline.steps) {
322
- for (const target of routeTargets(step.advancementPolicyDefinition)) {
384
+ for (const node of pipeline.nodeDefinitions) {
385
+ for (const target of routeTargets(node.advancementPolicyDefinition)) {
323
386
  if (known.has(target))
324
387
  continue;
325
388
  issues.push({
326
389
  check: "route-target",
327
- message: `Pipeline "${pipeline.key}" step "${step.stepKey}" routes to pipeline ` + `"${target}", but no pipeline with that key was found on the server or ` + `in the current push batch. Push the target pipeline first.`
390
+ message: `Pipeline "${pipeline.key}" step "${node.stepKey ?? node.nodeKey}" routes to pipeline ` + `"${target}", but no pipeline with that key was found on the server or ` + `in the current push batch. Push the target pipeline first.`
328
391
  });
329
392
  }
330
393
  }
331
394
  }
332
395
  return issues;
333
396
  }
334
- function executionRanks(steps) {
335
- const positions = steps.map((step) => step.position);
336
- const usable = positions.every((value) => Number.isInteger(value) && value > 0) && new Set(positions).size === positions.length;
337
- const indexes = steps.map((_, index) => index);
338
- const ordered = usable ? [...indexes].sort((left, right) => (positions[left] ?? 0) - (positions[right] ?? 0)) : indexes;
397
+ function executionRanks(nodeDefinitions, dependencyEdges) {
398
+ const indexes = nodeDefinitions.map((_, index) => index);
399
+ const orderedNodes = tryOrderChainNodeDefinitions(nodeDefinitions, dependencyEdges);
400
+ if (orderedNodes === null) {
401
+ return new Map(indexes.map((index, rank) => [index, rank]));
402
+ }
403
+ const indexByNodeKey = new Map(nodeDefinitions.map((node, index) => [node.nodeKey, index]));
404
+ const ordered = orderedNodes.map((node) => indexByNodeKey.get(node.nodeKey) ?? 0);
339
405
  return new Map(ordered.map((index, rank) => [index, rank]));
340
406
  }
341
407
  function bindingSource(binding) {
342
408
  if (binding.source === "step_signal") {
343
- return { stepKey: binding.stepKey, signalKey: binding.signalKey };
409
+ return { stepKey: binding.stepKey, signalKey: binding.signalKey, kind: "signal" };
344
410
  }
345
411
  if (binding.source === "step_output") {
346
- return { stepKey: binding.stepKey, signalKey: null };
412
+ return { stepKey: binding.stepKey, signalKey: null, kind: "output" };
413
+ }
414
+ if (binding.source === "signals_list") {
415
+ return { stepKey: binding.stepKey, signalKey: null, kind: "signals_list" };
347
416
  }
348
417
  return null;
349
418
  }
350
- function declaredSignalKeys(stepKey, stepsByKey, pipelineSteps) {
419
+ function declaredSignalKeys(stepKey, stepsByKey, pipelineNodeDefinitions) {
351
420
  const specs = stepsByKey.get(stepKey);
352
421
  if (!specs || specs.length === 0)
353
422
  return null;
@@ -356,10 +425,10 @@ function declaredSignalKeys(stepKey, stepsByKey, pipelineSteps) {
356
425
  for (const signal of spec.signalExtractorDefinitions)
357
426
  keys.add(signal.key);
358
427
  }
359
- for (const step of pipelineSteps) {
360
- if (step.stepKey !== stepKey)
428
+ for (const node of pipelineNodeDefinitions) {
429
+ if (node.stepKey !== stepKey)
361
430
  continue;
362
- for (const computed of step.computedSignalDefinitions)
431
+ for (const computed of node.computedSignalDefinitions ?? [])
363
432
  keys.add(computed.key);
364
433
  }
365
434
  return [...keys];
@@ -367,18 +436,18 @@ function declaredSignalKeys(stepKey, stepsByKey, pipelineSteps) {
367
436
  function checkSignalBindings(pipelines, stepsByKey) {
368
437
  const issues = [];
369
438
  for (const pipeline of pipelines) {
370
- const ranks = executionRanks(pipeline.steps);
371
- const order = [...pipeline.steps.keys()].sort((left, right) => (ranks.get(left) ?? 0) - (ranks.get(right) ?? 0)).map((index) => pipeline.steps[index]?.stepKey ?? "");
439
+ const ranks = executionRanks(pipeline.nodeDefinitions, pipeline.dependencyEdges);
440
+ const order = [...pipeline.nodeDefinitions.keys()].sort((left, right) => (ranks.get(left) ?? 0) - (ranks.get(right) ?? 0)).map((index) => pipeline.nodeDefinitions[index]?.stepKey ?? "");
372
441
  const orderHint = `Steps in "${pipeline.key}", in order: ${order.join(" \u2192 ")}.`;
373
- pipeline.steps.forEach((step, index) => {
442
+ pipeline.nodeDefinitions.forEach((node, index) => {
374
443
  const consumerRank = ranks.get(index) ?? index;
375
- const where = `Pipeline "${pipeline.key}" step "${step.stepKey}"`;
376
- for (const [field, binding] of Object.entries(step.inputBindingsJson)) {
444
+ const where = `Pipeline "${pipeline.key}" step "${node.stepKey ?? node.nodeKey}"`;
445
+ for (const [field, binding] of Object.entries(node.inputBindingsJson ?? {})) {
377
446
  const source = bindingSource(binding);
378
447
  if (!source)
379
448
  continue;
380
- const what = source.signalKey ? `binds input "${field}" to signal "${source.signalKey}" of step "${source.stepKey}"` : `binds input "${field}" to the output of step "${source.stepKey}"`;
381
- const producerRanks = pipeline.steps.map((candidate, candidateIndex) => candidate.stepKey === source.stepKey ? ranks.get(candidateIndex) ?? candidateIndex : null).filter((rank) => rank !== null);
449
+ const what = source.kind === "signal" ? `binds input "${field}" to signal "${source.signalKey ?? ""}" of step "${source.stepKey}"` : source.kind === "signals_list" ? `binds input "${field}" to the signals list of fan-out step "${source.stepKey}"` : `binds input "${field}" to the output of step "${source.stepKey}"`;
450
+ const producerRanks = pipeline.nodeDefinitions.map((candidate, candidateIndex) => candidate.stepKey === source.stepKey ? ranks.get(candidateIndex) ?? candidateIndex : null).filter((rank) => rank !== null);
382
451
  if (producerRanks.length === 0) {
383
452
  issues.push({
384
453
  check: "signal-binding",
@@ -395,7 +464,7 @@ function checkSignalBindings(pipelines, stepsByKey) {
395
464
  }
396
465
  if (source.signalKey === null)
397
466
  continue;
398
- const available = declaredSignalKeys(source.stepKey, stepsByKey, pipeline.steps);
467
+ const available = declaredSignalKeys(source.stepKey, stepsByKey, pipeline.nodeDefinitions);
399
468
  if (available === null || available.includes(source.signalKey))
400
469
  continue;
401
470
  issues.push({