@ultrst-armada/krnl 1.0.18 → 1.0.19
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/package.json +1 -1
- package/packages/cli/dist/bin/krnl.cjs +145 -143
- package/packages/cli/dist/bin/krnl.js +1 -1
- package/packages/cli/dist/{chunk-OOVZPIMX.js → chunk-FKQ5QRQF.js} +140 -138
- package/packages/cli/dist/index.cjs +140 -138
- package/packages/cli/dist/index.js +1 -1
- package/packages/core/dist/index.cjs +94 -79
- package/packages/core/dist/index.d.cts +7 -15
- package/packages/core/dist/index.d.ts +7 -15
- package/packages/core/dist/index.js +94 -79
- package/packages/validate/dist/index.cjs +51 -41
- package/packages/validate/dist/index.js +48 -38
|
@@ -133,8 +133,60 @@ var LifecycleManager = class {
|
|
|
133
133
|
}
|
|
134
134
|
};
|
|
135
135
|
|
|
136
|
-
// src/telemetry/
|
|
136
|
+
// src/telemetry/TelemetryInternals.ts
|
|
137
137
|
var import_node_crypto = require("crypto");
|
|
138
|
+
var createTelemetryId = (prefix) => `${prefix}_${(0, import_node_crypto.randomUUID)()}`;
|
|
139
|
+
|
|
140
|
+
// src/telemetry/TelemetrySnapshotBuilder.ts
|
|
141
|
+
function percentiles(values) {
|
|
142
|
+
if (!values.length) return { min: 0, mean: 0, p50: 0, p90: 0, p95: 0, p99: 0, max: 0 };
|
|
143
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
144
|
+
const pick = (p) => sorted[Math.min(sorted.length - 1, Math.floor((sorted.length - 1) * p))];
|
|
145
|
+
return {
|
|
146
|
+
min: sorted[0],
|
|
147
|
+
mean: sorted.reduce((sum, value) => sum + value, 0) / sorted.length,
|
|
148
|
+
p50: pick(0.5),
|
|
149
|
+
p90: pick(0.9),
|
|
150
|
+
p95: pick(0.95),
|
|
151
|
+
p99: pick(0.99),
|
|
152
|
+
max: sorted[sorted.length - 1]
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function buildTelemetrySnapshot(input) {
|
|
156
|
+
const invocations = input.invocations.slice();
|
|
157
|
+
const durations = invocations.map((item) => item.durationMs);
|
|
158
|
+
const targetMap = /* @__PURE__ */ new Map();
|
|
159
|
+
for (const invocation of invocations) {
|
|
160
|
+
const key = `${invocation.kind}:${invocation.target}`;
|
|
161
|
+
const group = targetMap.get(key) ?? [];
|
|
162
|
+
group.push(invocation);
|
|
163
|
+
targetMap.set(key, group);
|
|
164
|
+
}
|
|
165
|
+
const targets = [...targetMap.values()].map((group) => ({
|
|
166
|
+
target: group[0].target,
|
|
167
|
+
kind: group[0].kind,
|
|
168
|
+
count: group.length,
|
|
169
|
+
successCount: group.filter((item) => item.status === "completed").length,
|
|
170
|
+
errorCount: group.filter((item) => item.status === "failed").length,
|
|
171
|
+
durationMs: percentiles(group.map((item) => item.durationMs)),
|
|
172
|
+
lastInvocationAt: group[group.length - 1]?.completedAt
|
|
173
|
+
}));
|
|
174
|
+
return {
|
|
175
|
+
serviceId: input.serviceId,
|
|
176
|
+
mode: input.mode,
|
|
177
|
+
capturedAt: Date.now(),
|
|
178
|
+
status: input.status,
|
|
179
|
+
totals: {
|
|
180
|
+
invocationCount: input.totalInvocationCount,
|
|
181
|
+
successCount: input.totalSuccessCount,
|
|
182
|
+
errorCount: input.totalErrorCount,
|
|
183
|
+
durationMs: percentiles(durations)
|
|
184
|
+
},
|
|
185
|
+
targets,
|
|
186
|
+
activeInvocations: input.activeInvocations,
|
|
187
|
+
recentInvocations: invocations.slice(-input.maxRecentInvocations)
|
|
188
|
+
};
|
|
189
|
+
}
|
|
138
190
|
|
|
139
191
|
// src/telemetry/TelemetryResources.ts
|
|
140
192
|
var runtimeProcess = typeof globalThis !== "undefined" ? globalThis.process : void 0;
|
|
@@ -174,21 +226,6 @@ function deltaResources(start, end) {
|
|
|
174
226
|
}
|
|
175
227
|
|
|
176
228
|
// src/telemetry/TelemetryController.ts
|
|
177
|
-
var id = (prefix) => `${prefix}_${(0, import_node_crypto.randomUUID)()}`;
|
|
178
|
-
function percentiles(values) {
|
|
179
|
-
if (!values.length) return { min: 0, mean: 0, p50: 0, p90: 0, p95: 0, p99: 0, max: 0 };
|
|
180
|
-
const sorted = [...values].sort((a, b) => a - b);
|
|
181
|
-
const pick = (p) => sorted[Math.min(sorted.length - 1, Math.floor((sorted.length - 1) * p))];
|
|
182
|
-
return {
|
|
183
|
-
min: sorted[0],
|
|
184
|
-
mean: sorted.reduce((sum, value) => sum + value, 0) / sorted.length,
|
|
185
|
-
p50: pick(0.5),
|
|
186
|
-
p90: pick(0.9),
|
|
187
|
-
p95: pick(0.95),
|
|
188
|
-
p99: pick(0.99),
|
|
189
|
-
max: sorted[sorted.length - 1]
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
229
|
var TelemetryController = class {
|
|
193
230
|
constructor(serviceId, options = {}) {
|
|
194
231
|
this.serviceId = serviceId;
|
|
@@ -240,9 +277,9 @@ var TelemetryController = class {
|
|
|
240
277
|
end: () => void 0
|
|
241
278
|
};
|
|
242
279
|
}
|
|
243
|
-
const invocationId =
|
|
244
|
-
const spanId =
|
|
245
|
-
const traceId = parentSpanId ? this.findTraceId(parentSpanId) ??
|
|
280
|
+
const invocationId = createTelemetryId("inv");
|
|
281
|
+
const spanId = createTelemetryId("span");
|
|
282
|
+
const traceId = parentSpanId ? this.findTraceId(parentSpanId) ?? createTelemetryId("trace") : createTelemetryId("trace");
|
|
246
283
|
const active = {
|
|
247
284
|
invocationId,
|
|
248
285
|
traceId,
|
|
@@ -273,39 +310,17 @@ var TelemetryController = class {
|
|
|
273
310
|
this.lastInvocationAt = void 0;
|
|
274
311
|
}
|
|
275
312
|
snapshot() {
|
|
276
|
-
|
|
277
|
-
const durations = invocations.map((item) => item.durationMs);
|
|
278
|
-
const targetMap = /* @__PURE__ */ new Map();
|
|
279
|
-
for (const invocation of invocations) {
|
|
280
|
-
const key = `${invocation.kind}:${invocation.target}`;
|
|
281
|
-
const group = targetMap.get(key) ?? [];
|
|
282
|
-
group.push(invocation);
|
|
283
|
-
targetMap.set(key, group);
|
|
284
|
-
}
|
|
285
|
-
const targets = [...targetMap.values()].map((group) => ({
|
|
286
|
-
target: group[0].target,
|
|
287
|
-
kind: group[0].kind,
|
|
288
|
-
count: group.length,
|
|
289
|
-
successCount: group.filter((item) => item.status === "completed").length,
|
|
290
|
-
errorCount: group.filter((item) => item.status === "failed").length,
|
|
291
|
-
durationMs: percentiles(group.map((item) => item.durationMs)),
|
|
292
|
-
lastInvocationAt: group[group.length - 1]?.completedAt
|
|
293
|
-
}));
|
|
294
|
-
return {
|
|
313
|
+
return buildTelemetrySnapshot({
|
|
295
314
|
serviceId: this.serviceId,
|
|
296
315
|
mode: this.mode,
|
|
297
|
-
|
|
316
|
+
invocations: this.samples,
|
|
298
317
|
status: this.status(),
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
errorCount: this.totalErrorCount,
|
|
303
|
-
durationMs: percentiles(durations)
|
|
304
|
-
},
|
|
305
|
-
targets,
|
|
318
|
+
totalInvocationCount: this.totalInvocationCount,
|
|
319
|
+
totalSuccessCount: this.totalSuccessCount,
|
|
320
|
+
totalErrorCount: this.totalErrorCount,
|
|
306
321
|
activeInvocations: this.active.size,
|
|
307
|
-
|
|
308
|
-
};
|
|
322
|
+
maxRecentInvocations: this.maxRecentInvocations
|
|
323
|
+
});
|
|
309
324
|
}
|
|
310
325
|
functionality(name) {
|
|
311
326
|
return this.snapshot().targets.find((target) => target.kind === "functionality" && target.target === name);
|
|
@@ -709,22 +724,22 @@ var FunctionalityFacade = class {
|
|
|
709
724
|
definition;
|
|
710
725
|
eventBus;
|
|
711
726
|
events;
|
|
712
|
-
constructor(
|
|
713
|
-
if (!
|
|
727
|
+
constructor(id, definition, options = {}) {
|
|
728
|
+
if (!id || typeof id !== "string") {
|
|
714
729
|
throw new Error("[FunctionalityFacade] Functionality id must be a non-empty string.");
|
|
715
730
|
}
|
|
716
731
|
if (!definition || typeof definition.execute !== "function") {
|
|
717
|
-
throw new Error(`[FunctionalityFacade:${
|
|
732
|
+
throw new Error(`[FunctionalityFacade:${id}] Functionality must define execute().`);
|
|
718
733
|
}
|
|
719
|
-
this.id =
|
|
720
|
-
this.name = definition.name ||
|
|
734
|
+
this.id = id;
|
|
735
|
+
this.name = definition.name || id;
|
|
721
736
|
this.description = definition.description || "";
|
|
722
737
|
this.bubbleEvents = options.bubbleEvents ?? definition.bubbleEvents ?? true;
|
|
723
738
|
this.definition = definition;
|
|
724
739
|
this.eventBus = new EventBus();
|
|
725
740
|
for (const reserved of ["triggered", "completed", "failed"]) {
|
|
726
741
|
if (definition.events && reserved in definition.events) {
|
|
727
|
-
throw new Error(`[FunctionalityFacade:${
|
|
742
|
+
throw new Error(`[FunctionalityFacade:${id}] Event '${reserved}' is reserved for functionality lifecycle.`);
|
|
728
743
|
}
|
|
729
744
|
}
|
|
730
745
|
const eventNames = [
|
|
@@ -838,11 +853,11 @@ var PriorityQueue = class {
|
|
|
838
853
|
return item.run;
|
|
839
854
|
}
|
|
840
855
|
enqueue(run, options) {
|
|
841
|
-
const { priority = 0, id
|
|
856
|
+
const { priority = 0, id } = options ?? {};
|
|
842
857
|
const { size } = this;
|
|
843
858
|
const element = {
|
|
844
859
|
priority,
|
|
845
|
-
id
|
|
860
|
+
id,
|
|
846
861
|
run
|
|
847
862
|
};
|
|
848
863
|
if (size === 0) {
|
|
@@ -859,16 +874,16 @@ var PriorityQueue = class {
|
|
|
859
874
|
const index = lowerBound(this.#queue, element, (a, b) => a.priority === b.priority ? 0 : b.priority - a.priority);
|
|
860
875
|
this.#queue.splice(index, 0, element);
|
|
861
876
|
}
|
|
862
|
-
setPriority(
|
|
863
|
-
const index = this.#findIndex((element) => element.id ===
|
|
877
|
+
setPriority(id, priority) {
|
|
878
|
+
const index = this.#findIndex((element) => element.id === id);
|
|
864
879
|
if (index === -1) {
|
|
865
|
-
throw new ReferenceError(`No promise function with the id "${
|
|
880
|
+
throw new ReferenceError(`No promise function with the id "${id}" exists in the queue.`);
|
|
866
881
|
}
|
|
867
882
|
if (this.#queue[index].priority === priority) {
|
|
868
883
|
return;
|
|
869
884
|
}
|
|
870
885
|
const [item] = this.#queue.splice(index, 1);
|
|
871
|
-
this.enqueue(item.run, { priority, id
|
|
886
|
+
this.enqueue(item.run, { priority, id });
|
|
872
887
|
}
|
|
873
888
|
remove(idOrRun) {
|
|
874
889
|
const index = this.#findIndex((element) => (typeof idOrRun === "string" ? element.id : element.run) === idOrRun);
|
|
@@ -1284,17 +1299,17 @@ var PQueue = class extends EventTarget {
|
|
|
1284
1299
|
}
|
|
1285
1300
|
}
|
|
1286
1301
|
async #add(function_, options, waitingTask) {
|
|
1287
|
-
const
|
|
1302
|
+
const id = options.id ?? (this.#idAssigner++).toString();
|
|
1288
1303
|
options = {
|
|
1289
1304
|
timeout: this.#timeout,
|
|
1290
1305
|
...options,
|
|
1291
|
-
id
|
|
1306
|
+
id
|
|
1292
1307
|
};
|
|
1293
1308
|
validateTimeout(options.timeout);
|
|
1294
1309
|
if (options.priority !== void 0 && (typeof options.priority !== "number" || Number.isNaN(options.priority))) {
|
|
1295
1310
|
throw new TypeError(`Expected \`priority\` to be a number, got \`${String(options.priority)}\` (${typeof options.priority})`);
|
|
1296
1311
|
}
|
|
1297
|
-
waitingTask.id =
|
|
1312
|
+
waitingTask.id = id;
|
|
1298
1313
|
waitingTask.priority = options.priority ?? 0;
|
|
1299
1314
|
return new Promise((resolve, reject) => {
|
|
1300
1315
|
if (options.signal?.aborted) {
|
|
@@ -1311,7 +1326,7 @@ var PQueue = class extends EventTarget {
|
|
|
1311
1326
|
}
|
|
1312
1327
|
this.#pending++;
|
|
1313
1328
|
const runningTask = {
|
|
1314
|
-
id
|
|
1329
|
+
id,
|
|
1315
1330
|
priority: waitingTask.priority,
|
|
1316
1331
|
startTime: Date.now(),
|
|
1317
1332
|
timeout: options.timeout
|
|
@@ -1378,7 +1393,7 @@ var PQueue = class extends EventTarget {
|
|
|
1378
1393
|
if (this.#queue instanceof PriorityQueue) {
|
|
1379
1394
|
this.#queue.remove(run);
|
|
1380
1395
|
} else {
|
|
1381
|
-
this.#queue.remove(
|
|
1396
|
+
this.#queue.remove(id);
|
|
1382
1397
|
}
|
|
1383
1398
|
reject(signal.reason);
|
|
1384
1399
|
this.#processQueue();
|
|
@@ -1454,18 +1469,18 @@ var PQueue = class extends EventTarget {
|
|
|
1454
1469
|
// '🦀' runs last
|
|
1455
1470
|
```
|
|
1456
1471
|
*/
|
|
1457
|
-
setPriority(
|
|
1472
|
+
setPriority(id, priority) {
|
|
1458
1473
|
if (typeof priority !== "number" || !Number.isFinite(priority)) {
|
|
1459
1474
|
throw new TypeError(`Expected \`priority\` to be a finite number, got \`${priority}\` (${typeof priority})`);
|
|
1460
1475
|
}
|
|
1461
1476
|
for (const waitingTask of this.#waitingTasks) {
|
|
1462
|
-
if (waitingTask.id ===
|
|
1463
|
-
this.#queue.setPriority(
|
|
1477
|
+
if (waitingTask.id === id) {
|
|
1478
|
+
this.#queue.setPriority(id, priority);
|
|
1464
1479
|
waitingTask.priority = priority;
|
|
1465
1480
|
return;
|
|
1466
1481
|
}
|
|
1467
1482
|
}
|
|
1468
|
-
throw new ReferenceError(`No promise function with the id "${
|
|
1483
|
+
throw new ReferenceError(`No promise function with the id "${id}" exists in the queue.`);
|
|
1469
1484
|
}
|
|
1470
1485
|
/**
|
|
1471
1486
|
Adds a sync or async task to the queue.
|
|
@@ -1810,7 +1825,7 @@ var TimeoutError = class extends DOMException {
|
|
|
1810
1825
|
// src/orchestration/canonical/KrnlQ.ts
|
|
1811
1826
|
var import_node_crypto2 = require("crypto");
|
|
1812
1827
|
|
|
1813
|
-
// src/orchestration/canonical/
|
|
1828
|
+
// src/orchestration/canonical/dagValidation.ts
|
|
1814
1829
|
function validateOrchestrationDAG(steps) {
|
|
1815
1830
|
const errors = [];
|
|
1816
1831
|
const stepMap = /* @__PURE__ */ new Map();
|
|
@@ -1875,8 +1890,8 @@ function validateOrchestrationDAG(steps) {
|
|
|
1875
1890
|
}
|
|
1876
1891
|
}
|
|
1877
1892
|
const queue = [];
|
|
1878
|
-
for (const [
|
|
1879
|
-
if (deg === 0) queue.push(
|
|
1893
|
+
for (const [id, deg] of inDegree.entries()) {
|
|
1894
|
+
if (deg === 0) queue.push(id);
|
|
1880
1895
|
}
|
|
1881
1896
|
const order = [];
|
|
1882
1897
|
while (queue.length > 0) {
|
|
@@ -2080,9 +2095,9 @@ var KrnlQueue = class {
|
|
|
2080
2095
|
if (this.jobs.size <= this.maxRetainedJobs) return;
|
|
2081
2096
|
const excess = this.jobs.size - this.maxRetainedJobs;
|
|
2082
2097
|
let pruned = 0;
|
|
2083
|
-
for (const [
|
|
2098
|
+
for (const [id, record] of this.jobs.entries()) {
|
|
2084
2099
|
if (record.status === "completed" || record.status === "failed" || record.status === "cancelled") {
|
|
2085
|
-
this.jobs.delete(
|
|
2100
|
+
this.jobs.delete(id);
|
|
2086
2101
|
pruned++;
|
|
2087
2102
|
if (pruned >= excess) break;
|
|
2088
2103
|
}
|
|
@@ -3647,9 +3662,9 @@ var ServiceRuntime = class {
|
|
|
3647
3662
|
// src/discovery/ServiceDiscovery.ts
|
|
3648
3663
|
var ServiceDiscovery = class {
|
|
3649
3664
|
peers = /* @__PURE__ */ new Map();
|
|
3650
|
-
registerPeer(
|
|
3651
|
-
this.peers.set(
|
|
3652
|
-
id
|
|
3665
|
+
registerPeer(id, name, endpoints) {
|
|
3666
|
+
this.peers.set(id, {
|
|
3667
|
+
id,
|
|
3653
3668
|
name,
|
|
3654
3669
|
endpoints,
|
|
3655
3670
|
lastSeen: Date.now()
|
|
@@ -3658,8 +3673,8 @@ var ServiceDiscovery = class {
|
|
|
3658
3673
|
getPeers() {
|
|
3659
3674
|
return Array.from(this.peers.values());
|
|
3660
3675
|
}
|
|
3661
|
-
findPeer(
|
|
3662
|
-
return this.peers.get(
|
|
3676
|
+
findPeer(id) {
|
|
3677
|
+
return this.peers.get(id);
|
|
3663
3678
|
}
|
|
3664
3679
|
};
|
|
3665
3680
|
|
|
@@ -214,11 +214,6 @@ declare function telemetryNow(): number;
|
|
|
214
214
|
declare function sampleResources(): TelemetryResourceSample;
|
|
215
215
|
declare function deltaResources(start: TelemetryResourceSample, end: TelemetryResourceSample): TelemetryResourceSample;
|
|
216
216
|
|
|
217
|
-
/**
|
|
218
|
-
* @file TelemetryController.ts
|
|
219
|
-
* @description Per-service telemetry recorder and public control surface.
|
|
220
|
-
*/
|
|
221
|
-
|
|
222
217
|
type ActiveInvocation = {
|
|
223
218
|
invocationId: string;
|
|
224
219
|
traceId: string;
|
|
@@ -231,6 +226,12 @@ type ActiveInvocation = {
|
|
|
231
226
|
startedAt: number;
|
|
232
227
|
resourcesStart?: ReturnType<typeof sampleResources>;
|
|
233
228
|
};
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* @file TelemetryController.ts
|
|
232
|
+
* @description Per-service telemetry recorder and public control surface.
|
|
233
|
+
*/
|
|
234
|
+
|
|
234
235
|
declare class TelemetryController {
|
|
235
236
|
private readonly serviceId;
|
|
236
237
|
private mode;
|
|
@@ -615,21 +616,12 @@ interface OrchestrationResult<T = unknown> {
|
|
|
615
616
|
readonly completedAt: number;
|
|
616
617
|
readonly executionMetadata: Record<string, unknown>;
|
|
617
618
|
}
|
|
619
|
+
|
|
618
620
|
interface DAGValidationResult {
|
|
619
621
|
readonly valid: boolean;
|
|
620
622
|
readonly order: readonly string[];
|
|
621
623
|
readonly errors: readonly string[];
|
|
622
624
|
}
|
|
623
|
-
/**
|
|
624
|
-
* Validates DAG structure & semantic policies:
|
|
625
|
-
* - Duplicate step IDs
|
|
626
|
-
* - Missing dependencies
|
|
627
|
-
* - Cycles / circular dependencies (topological sort via Kahn's algorithm)
|
|
628
|
-
* - Negative or invalid timeouts
|
|
629
|
-
* - Invalid retry policies (attempts < 1, negative backoff)
|
|
630
|
-
* - Empty step targets
|
|
631
|
-
* - Concurrency bounds
|
|
632
|
-
*/
|
|
633
625
|
declare function validateOrchestrationDAG(steps: readonly OrchestrationStep[]): DAGValidationResult;
|
|
634
626
|
|
|
635
627
|
/**
|
|
@@ -214,11 +214,6 @@ declare function telemetryNow(): number;
|
|
|
214
214
|
declare function sampleResources(): TelemetryResourceSample;
|
|
215
215
|
declare function deltaResources(start: TelemetryResourceSample, end: TelemetryResourceSample): TelemetryResourceSample;
|
|
216
216
|
|
|
217
|
-
/**
|
|
218
|
-
* @file TelemetryController.ts
|
|
219
|
-
* @description Per-service telemetry recorder and public control surface.
|
|
220
|
-
*/
|
|
221
|
-
|
|
222
217
|
type ActiveInvocation = {
|
|
223
218
|
invocationId: string;
|
|
224
219
|
traceId: string;
|
|
@@ -231,6 +226,12 @@ type ActiveInvocation = {
|
|
|
231
226
|
startedAt: number;
|
|
232
227
|
resourcesStart?: ReturnType<typeof sampleResources>;
|
|
233
228
|
};
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* @file TelemetryController.ts
|
|
232
|
+
* @description Per-service telemetry recorder and public control surface.
|
|
233
|
+
*/
|
|
234
|
+
|
|
234
235
|
declare class TelemetryController {
|
|
235
236
|
private readonly serviceId;
|
|
236
237
|
private mode;
|
|
@@ -615,21 +616,12 @@ interface OrchestrationResult<T = unknown> {
|
|
|
615
616
|
readonly completedAt: number;
|
|
616
617
|
readonly executionMetadata: Record<string, unknown>;
|
|
617
618
|
}
|
|
619
|
+
|
|
618
620
|
interface DAGValidationResult {
|
|
619
621
|
readonly valid: boolean;
|
|
620
622
|
readonly order: readonly string[];
|
|
621
623
|
readonly errors: readonly string[];
|
|
622
624
|
}
|
|
623
|
-
/**
|
|
624
|
-
* Validates DAG structure & semantic policies:
|
|
625
|
-
* - Duplicate step IDs
|
|
626
|
-
* - Missing dependencies
|
|
627
|
-
* - Cycles / circular dependencies (topological sort via Kahn's algorithm)
|
|
628
|
-
* - Negative or invalid timeouts
|
|
629
|
-
* - Invalid retry policies (attempts < 1, negative backoff)
|
|
630
|
-
* - Empty step targets
|
|
631
|
-
* - Concurrency bounds
|
|
632
|
-
*/
|
|
633
625
|
declare function validateOrchestrationDAG(steps: readonly OrchestrationStep[]): DAGValidationResult;
|
|
634
626
|
|
|
635
627
|
/**
|