@uipath/maestro-builder-sdk 6.16.14 → 6.17.1
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/README.md +2 -2
- package/dist/api-index.md +115 -114
- package/dist/api-members.md +295 -291
- package/dist/bindings-v2.d.ts +39 -1
- package/dist/bindings-v2.js +289 -9
- package/dist/bpmn/compile-cli.js +11 -2
- package/dist/bpmn/decompile.js +2 -1
- package/dist/bpmn/registry-fallback.js +9 -7
- package/dist/case/compile-cli.js +16 -6
- package/dist/case/decompile-cli.js +2 -1
- package/dist/case/decompile.js +3 -2
- package/dist/case/merge-cli.js +3 -2
- package/dist/check-cli.js +2 -30
- package/dist/check.js +278 -55
- package/dist/cli-library.d.ts +18 -4
- package/dist/cli-library.js +24 -6
- package/dist/cli-result.d.ts +9 -0
- package/dist/cli-result.js +12 -0
- package/dist/compile-cli.js +82 -86
- package/dist/core/actions.d.ts +71 -17
- package/dist/core/agentic-process-forms.d.ts +51 -0
- package/dist/core/agentic-process-forms.js +49 -0
- package/dist/core/binding-messages.d.ts +5 -0
- package/dist/core/cli-library.d.ts +16 -7
- package/dist/core/cli-library.js +53 -19
- package/dist/core/comment-text.d.ts +29 -0
- package/dist/core/comment-text.js +40 -0
- package/dist/core/connector-checks.d.ts +18 -2
- package/dist/core/connector-checks.js +15 -5
- package/dist/core/contribution-bindings.d.ts +73 -0
- package/dist/core/contribution-bindings.js +105 -0
- package/dist/core/error-port.d.ts +25 -0
- package/dist/core/error-port.js +36 -0
- package/dist/core/expr-check.js +7 -2
- package/dist/core/expr.d.ts +11 -5
- package/dist/core/expr.js +9 -3
- package/dist/core/json-file.d.ts +1 -0
- package/dist/core/json-file.js +12 -0
- package/dist/core/library.d.ts +19 -0
- package/dist/core/library.js +22 -6
- package/dist/core/script-return.js +4 -1
- package/dist/core/typed-raw-node.js +1 -0
- package/dist/core/typescript-module.d.ts +2 -0
- package/dist/core/typescript-module.js +18 -0
- package/dist/core-definitions.json +210 -0
- package/dist/decompile-cli.js +2 -1
- package/dist/decompile.js +64 -24
- package/dist/emit.js +4 -3
- package/dist/flow-sdk.d.ts +18 -12
- package/dist/flow-sdk.js +19 -8
- package/dist/flow-step-tree.d.ts +2 -3
- package/dist/flow-step-tree.js +2 -3
- package/dist/load.js +1 -1
- package/dist/merge-cli.js +3 -2
- package/dist/merge.d.ts +2 -1
- package/dist/merge.js +0 -0
- package/dist/path-within.d.ts +33 -0
- package/dist/path-within.js +41 -0
- package/dist/registry/archive/extract.js +2 -5
- package/dist/registry/curated-overlay.js +3 -2
- package/dist/registry/generators/descriptors.js +20 -18
- package/dist/registry/generators/triggers.js +4 -4
- package/dist/registry/prepare/messages.js +2 -1
- package/dist/registry/prepare/source-labels.js +60 -1
- package/dist/registry/prepare-cli.js +14 -4
- package/dist/registry/pull-cli.js +3 -2
- package/dist/registry/uip/client.d.ts +28 -3
- package/dist/registry/uip/client.js +95 -34
- package/dist/registry/uip/host.d.ts +41 -0
- package/dist/registry/uip/host.js +312 -0
- package/dist/serialize.d.ts +7 -0
- package/dist/serialize.js +414 -277
- package/dist/workdir.js +1 -1
- package/package.json +3 -3
package/dist/check.js
CHANGED
|
@@ -7,16 +7,21 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { Expr, SCHEDULE_PRESETS, DELAY_PRESETS, VARIANT_OPERATION, parseIxpProjectType, flatNameOf, flatNameSegmentsOf, FLAT_SEP } from './flow-sdk.js';
|
|
9
9
|
import { FlowNode } from './core/node-classes.js';
|
|
10
|
+
import { planContributionBindings } from './core/contribution-bindings.js';
|
|
11
|
+
import { definitionHasErrorPort, errorPortRefusal } from './core/error-port.js';
|
|
12
|
+
import { resolveContributionDefinition } from './serialize.js';
|
|
10
13
|
import { QUEUE_ITEM_RECORD_SCHEMA } from './core/queue-record.js';
|
|
14
|
+
import { AGENTIC_PROCESS_FORMS } from './core/agentic-process-forms.js';
|
|
11
15
|
import { checkEventResolution, checkEventSubscription, eventParamsFor, } from './core/event-checks.js';
|
|
12
16
|
import { checkCookedEscapes } from './flow-expr-check.js';
|
|
13
17
|
import { FLOW_EXPR_DIALECT, checkBindingLabels, checkBindingPresence, checkConnectorContract as coreCheckConnectorContract, checkConnectorLookups as coreCheckConnectorLookups, checkConnectorSchema as coreCheckConnectorSchema, collectConnectionUses, connectionConnectorConflicts, } from './core/connector-checks.js';
|
|
14
18
|
import { prepareCommand } from './core/cli-spelling.js';
|
|
19
|
+
import { commentText } from './core/comment-text.js';
|
|
15
20
|
import { editDistance } from './core/edit-distance.js';
|
|
16
21
|
import { isAnswerField } from './core/hitl-answers.js';
|
|
17
22
|
import { hitlDerivesOutcomeHandles, hitlExitModel, hitlRoutesPerOutcome } from './core/hitl-routing.js';
|
|
18
23
|
import { declaredExits, hasExits } from './core/step-ports.js';
|
|
19
|
-
import {
|
|
24
|
+
import { stopsAtEnd } from './flow-step-tree.js';
|
|
20
25
|
import { FLOW_SCHEMA_VERSIONS } from './format-profile.js';
|
|
21
26
|
import { compareSchemaVersions, schemaVersionRefusal } from './schema-version.js';
|
|
22
27
|
import { planFlowGlobals, planSharedInputs, sharedInputRoots } from './flow-variables.js';
|
|
@@ -54,9 +59,11 @@ function checkFlow(built, ancestors, opts = {}) {
|
|
|
54
59
|
if (maybeCustomTrigger !== undefined && !('kind' in maybeCustomTrigger) && maybeCustomTrigger instanceof FlowNode) {
|
|
55
60
|
// A custom FlowTrigger subclass reports through its own diagnostics() hook;
|
|
56
61
|
// the built-in trigger rules key on `kind` and don't apply.
|
|
57
|
-
|
|
62
|
+
const own = maybeCustomTrigger.diagnostics();
|
|
63
|
+
for (const d of own) {
|
|
58
64
|
diags.push({ level: d.severity, code: d.code, message: d.message, step: 'trigger' });
|
|
59
65
|
}
|
|
66
|
+
checkContribution(maybeCustomTrigger, built.triggerOptions?.version, 'trigger', own.some((d) => d.severity === 'error'), diags);
|
|
60
67
|
}
|
|
61
68
|
else if (built.trigger !== undefined)
|
|
62
69
|
checkTrigger(built.trigger, diags, opts);
|
|
@@ -251,7 +258,7 @@ function checkFlow(built, ancestors, opts = {}) {
|
|
|
251
258
|
stepNames.add(s.name);
|
|
252
259
|
declared.add(s.name); // a step's output is referenceable by name
|
|
253
260
|
}
|
|
254
|
-
if (s.kind === 'stepToList' && s.port === 'error')
|
|
261
|
+
if ((s.kind === 'stepToList' || s.kind === 'stepToRef') && s.port === 'error')
|
|
255
262
|
checkOnError(s, prevPortSource, diags);
|
|
256
263
|
if ((s.kind === 'stepToList' || s.kind === 'stepToRef') && s.port.startsWith('branch-')) {
|
|
257
264
|
const want = s.port.slice('branch-'.length);
|
|
@@ -366,9 +373,11 @@ function checkFlow(built, ancestors, opts = {}) {
|
|
|
366
373
|
// don't apply, and it reports through its own diagnostics() hook.
|
|
367
374
|
const maybeCustom = s.spec;
|
|
368
375
|
if (!('kind' in maybeCustom) && maybeCustom instanceof FlowNode) {
|
|
369
|
-
|
|
376
|
+
const own = maybeCustom.diagnostics();
|
|
377
|
+
for (const d of own) {
|
|
370
378
|
diags.push({ level: d.severity, code: d.code, message: d.message, step: s.name });
|
|
371
379
|
}
|
|
380
|
+
checkContribution(maybeCustom, s.options?.version, s.name, own.some((d) => d.severity === 'error'), diags);
|
|
372
381
|
}
|
|
373
382
|
if (s.spec.kind === 'transform')
|
|
374
383
|
checkTransform(s.name, s.spec.inputs, diags, typeOf, triggerId);
|
|
@@ -864,9 +873,11 @@ function checkFlow(built, ancestors, opts = {}) {
|
|
|
864
873
|
epIds.add(ep.id);
|
|
865
874
|
const maybeCustomEp = ep.trigger;
|
|
866
875
|
if (!('kind' in maybeCustomEp) && maybeCustomEp instanceof FlowNode) {
|
|
867
|
-
|
|
876
|
+
const own = maybeCustomEp.diagnostics();
|
|
877
|
+
for (const d of own) {
|
|
868
878
|
diags.push({ level: d.severity, code: d.code, message: d.message, step: ep.id });
|
|
869
879
|
}
|
|
880
|
+
checkContribution(maybeCustomEp, ep.options?.version, ep.id, own.some((d) => d.severity === 'error'), diags);
|
|
870
881
|
}
|
|
871
882
|
else {
|
|
872
883
|
checkTrigger(ep.trigger, diags, opts, ep.id);
|
|
@@ -1283,13 +1294,10 @@ function checkFlow(built, ancestors, opts = {}) {
|
|
|
1283
1294
|
}
|
|
1284
1295
|
}
|
|
1285
1296
|
}
|
|
1286
|
-
//
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
const hasTerminal = hasReturn(built.steps);
|
|
1291
|
-
if (!hasTerminal)
|
|
1292
|
-
diags.push({ level: 'warning', code: 'NO_RETURN', message: 'Flow has no return(); a default End node will be appended.' });
|
|
1297
|
+
// The End compile appends when the root path runs out of steps (#941).
|
|
1298
|
+
const fallOff = checkFallOffEnd(built);
|
|
1299
|
+
if (fallOff)
|
|
1300
|
+
diags.push(fallOff);
|
|
1293
1301
|
// Check every child flow with the same rules, in its OWN scope — a child's
|
|
1294
1302
|
// steps never see the parent's variables, so its undeclared references,
|
|
1295
1303
|
// duplicate step names and type mismatches are its own. Diagnostics come back
|
|
@@ -1376,9 +1384,124 @@ function checkLoopListEnvelope(loop, connectors, opts, diags) {
|
|
|
1376
1384
|
suggestion,
|
|
1377
1385
|
});
|
|
1378
1386
|
}
|
|
1379
|
-
/**
|
|
1380
|
-
|
|
1381
|
-
|
|
1387
|
+
/**
|
|
1388
|
+
* NO_RETURN: a path that runs off the end of the flow, where a declared output
|
|
1389
|
+
* is never written (#941).
|
|
1390
|
+
*
|
|
1391
|
+
* It asks serialize's question, not "is there a `.return()` anywhere?".
|
|
1392
|
+
* serialize appends an End exactly when the root walk has tails left
|
|
1393
|
+
* (`if (finalTails.length)`), and `armTails` mirrors that walk tail for tail.
|
|
1394
|
+
* So a `.terminate()` path appends no End, and a branch where one arm returns
|
|
1395
|
+
* and the other falls off DOES append one.
|
|
1396
|
+
*
|
|
1397
|
+
* The appended End maps every output from its own variable
|
|
1398
|
+
* (`result <- $vars.result`), the same as a `.return()` that names no value.
|
|
1399
|
+
* That loses nothing when the flow declares no outputs, or when each output
|
|
1400
|
+
* was set on the way: by a `default`, a `{ shared }` input that every root
|
|
1401
|
+
* feeds, or `{ updates }` on a step of that path. The warning names the outputs
|
|
1402
|
+
* that are not, and the steps the path falls off from.
|
|
1403
|
+
*
|
|
1404
|
+
* Not covered: the private End a `.stepToList` body gets (#742). `armTails`
|
|
1405
|
+
* skips those bodies, and that End is a different emission site with no
|
|
1406
|
+
* output mappings at all.
|
|
1407
|
+
*/
|
|
1408
|
+
function checkFallOffEnd(built) {
|
|
1409
|
+
if (built.outputs.length === 0)
|
|
1410
|
+
return undefined;
|
|
1411
|
+
const from = built.triggerId ?? 'start';
|
|
1412
|
+
if (armTails(built.steps, [{ from }]).length === 0)
|
|
1413
|
+
return undefined;
|
|
1414
|
+
const preset = new Set(built.outputs.filter((o) => o.default !== undefined).map((o) => o.name));
|
|
1415
|
+
// A shared input sets its variable only on runs that enter through a root
|
|
1416
|
+
// feeding it, so it counts as preset only when every root does.
|
|
1417
|
+
const roots = sharedInputRoots(built);
|
|
1418
|
+
for (const t of planSharedInputs({ roots, outputs: built.outputs, vars: built.vars }).targets) {
|
|
1419
|
+
if (t.declaredAs === 'output' && roots.every((r) => t.feeds.some((f) => f.root === r.id)))
|
|
1420
|
+
preset.add(t.name);
|
|
1421
|
+
}
|
|
1422
|
+
const tails = writtenTails(built.steps, [{ from, written: preset }], []);
|
|
1423
|
+
const missing = built.outputs.map((o) => o.name).filter((n) => tails.some((t) => !t.written.has(n)));
|
|
1424
|
+
if (missing.length === 0)
|
|
1425
|
+
return undefined;
|
|
1426
|
+
const steps = [...new Set(tails.filter((t) => missing.some((n) => !t.written.has(n))).map((t) => t.from))];
|
|
1427
|
+
const one = missing.length === 1;
|
|
1428
|
+
return {
|
|
1429
|
+
level: 'warning',
|
|
1430
|
+
code: 'NO_RETURN',
|
|
1431
|
+
message: `Path ending at ${steps.map((x) => `"${x}"`).join(', ')} falls into the End compile appends. `
|
|
1432
|
+
+ `${one ? 'Output' : 'Outputs'} ${missing.map((n) => `"${n}"`).join(', ')} may be unset there. `
|
|
1433
|
+
+ `End the path with .return({ … }) or set ${one ? 'it' : 'them'} with { updates } (a loop body may run zero times).`,
|
|
1434
|
+
step: steps[0],
|
|
1435
|
+
suggestion: `.return({ ${missing.map((n) => `${n}: …`).join(', ')} })`,
|
|
1436
|
+
};
|
|
1437
|
+
}
|
|
1438
|
+
/**
|
|
1439
|
+
* `armTails`, step for step, carrying what each path has surely written. A
|
|
1440
|
+
* `.return()` value is NOT a write here: it lives on that `.return()`'s End,
|
|
1441
|
+
* which is not the End this is about. Where paths meet, only what all of them
|
|
1442
|
+
* wrote counts.
|
|
1443
|
+
*
|
|
1444
|
+
* A `.break()` leaves the enclosing loop with what its path wrote so far, so
|
|
1445
|
+
* its tail goes to `breaks`, and the loop counts it as one of the ways out. A
|
|
1446
|
+
* loop body may run zero times, so it writes nothing for sure. A do-while body
|
|
1447
|
+
* runs at least once, and is left by its end or by a `.break()`, so what all of
|
|
1448
|
+
* those wrote counts. Every `.parallel` arm runs, so what each surely writes
|
|
1449
|
+
* counts.
|
|
1450
|
+
*/
|
|
1451
|
+
function writtenTails(steps, incoming, breaks) {
|
|
1452
|
+
let tails = incoming;
|
|
1453
|
+
for (const st of steps) {
|
|
1454
|
+
if (st.kind === 'stepToList')
|
|
1455
|
+
continue;
|
|
1456
|
+
if (st.kind === 'stepToRef') {
|
|
1457
|
+
if (st.port === 'output')
|
|
1458
|
+
tails = [];
|
|
1459
|
+
continue;
|
|
1460
|
+
}
|
|
1461
|
+
if (st.kind === 'break') {
|
|
1462
|
+
breaks.push(...tails);
|
|
1463
|
+
return [];
|
|
1464
|
+
}
|
|
1465
|
+
if (st.kind === 'return' || st.kind === 'terminate')
|
|
1466
|
+
return [];
|
|
1467
|
+
const before = surelyWritten(tails);
|
|
1468
|
+
const written = new Set([...before, ...Object.keys(st.options?.updates ?? {})]);
|
|
1469
|
+
const arm = (body) => writtenTails(body, [{ from: st.name, written }], breaks);
|
|
1470
|
+
if (st.kind === 'action') {
|
|
1471
|
+
tails = actionTails(st.name, st.spec, st.options?.version)
|
|
1472
|
+
.map((t) => ({ from: t.from, written }));
|
|
1473
|
+
}
|
|
1474
|
+
else if (st.kind === 'stepSwitch') {
|
|
1475
|
+
tails = st.cases.flatMap((c) => arm(c.body));
|
|
1476
|
+
}
|
|
1477
|
+
else if (st.kind === 'branch') {
|
|
1478
|
+
tails = [...arm(st.then), ...arm(st.otherwise)];
|
|
1479
|
+
}
|
|
1480
|
+
else if (st.kind === 'switch') {
|
|
1481
|
+
tails = [...st.cases.flatMap((c) => arm(c.body)), ...(st.default !== undefined ? arm(st.default) : [])];
|
|
1482
|
+
}
|
|
1483
|
+
else if (st.kind === 'doWhile') {
|
|
1484
|
+
const exits = [];
|
|
1485
|
+
exits.push(...writtenTails(st.body, [{ from: st.name, written }], exits));
|
|
1486
|
+
surelyWritten(exits).forEach((n) => written.add(n));
|
|
1487
|
+
tails = [{ from: st.name, written }];
|
|
1488
|
+
}
|
|
1489
|
+
else if (st.kind === 'parallel') {
|
|
1490
|
+
for (const body of st.arms)
|
|
1491
|
+
surelyWritten(arm(body)).forEach((n) => written.add(n));
|
|
1492
|
+
tails = [{ from: st.name, written }];
|
|
1493
|
+
}
|
|
1494
|
+
else {
|
|
1495
|
+
tails = [{ from: st.name, written }];
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
return tails;
|
|
1499
|
+
}
|
|
1500
|
+
/** What every one of `tails` has written; nothing when there are none. */
|
|
1501
|
+
function surelyWritten(tails) {
|
|
1502
|
+
if (tails.length === 0)
|
|
1503
|
+
return new Set();
|
|
1504
|
+
return new Set([...tails[0].written].filter((n) => tails.every((t) => t.written.has(n))));
|
|
1382
1505
|
}
|
|
1383
1506
|
/**
|
|
1384
1507
|
* Closest of `candidates` to `name`: same word ignoring case, one contained in
|
|
@@ -1982,10 +2105,11 @@ function renamedFieldMessage(label, step, oldField) {
|
|
|
1982
2105
|
* - a `key` that is not a GUID. The commonest form of this is passing the
|
|
1983
2106
|
* process's NAME where its release key belongs, which produces a node type
|
|
1984
2107
|
* the platform cannot resolve to anything.
|
|
1985
|
-
* - a `
|
|
1986
|
-
* the
|
|
1987
|
-
*
|
|
1988
|
-
*
|
|
2108
|
+
* - a `name` that looks like a path (contains "/"). The two are swappable, and
|
|
2109
|
+
* the resulting `resourceKey` is wrong in a way that only surfaces as a 400
|
|
2110
|
+
* from Orchestrator ("Folder does not exist"). That is v1's own 2026-06-26
|
|
2111
|
+
* failure mode on this task. A single-segment `folderPath` is NOT decidable:
|
|
2112
|
+
* root folders and personal workspaces are one segment, so it is not flagged.
|
|
1989
2113
|
*/
|
|
1990
2114
|
function checkRpaWorkflow(step, inputs, diags) {
|
|
1991
2115
|
const at = (code, message, suggestion) => {
|
|
@@ -2009,33 +2133,33 @@ function checkRpaWorkflow(step, inputs, diags) {
|
|
|
2009
2133
|
at('RPA_NO_NAME', `RPA step "${step}" has no \`name\`. The runtime starts the job by name + folder, not by the key in `
|
|
2010
2134
|
+ `the node type, so without it the process cannot be resolved and the run fails before dispatch.`, `name: 'RPA Workflow'`);
|
|
2011
2135
|
}
|
|
2012
|
-
|
|
2136
|
+
const inSolution = inputs?.location === 'in-solution';
|
|
2137
|
+
if (!inSolution && blank(inputs?.folderPath)) {
|
|
2013
2138
|
at('RPA_NO_FOLDER', `RPA step "${step}" has no \`folderPath\`. The runtime starts the job by name + folder, so the `
|
|
2014
2139
|
+ `Orchestrator folder holding the process is required.`, `folderPath: 'Shared/uipath-maestro-flow/ProjectEuler RPA'`);
|
|
2015
2140
|
}
|
|
2141
|
+
if (inSolution && blank(inputs?.projectId)) {
|
|
2142
|
+
at('RPA_LOCAL_NO_PROJECT_ID', `In-solution RPA step "${step}" has no \`projectId\`. Read \`resource.projectKey\` from `
|
|
2143
|
+
+ `\`resources/solution_folder/process/process/<project>.json\`.`, `projectId: '<resource.projectKey>'`);
|
|
2144
|
+
}
|
|
2145
|
+
else if (inSolution && !GUID_RE.test(String(inputs.projectId).trim())) {
|
|
2146
|
+
at('RPA_LOCAL_PROJECT_ID_NOT_GUID', `In-solution RPA step "${step}" has projectId ${JSON.stringify(inputs.projectId)}, which is not `
|
|
2147
|
+
+ `the sibling project's GUID. Read \`resource.projectKey\` from the generated resource file.`, `projectId: '<resource.projectKey>'`);
|
|
2148
|
+
}
|
|
2149
|
+
if (inSolution && !blank(inputs?.folderPath)) {
|
|
2150
|
+
at('RPA_LOCAL_HAS_FOLDER', `In-solution RPA step "${step}" also sets \`folderPath\` ${JSON.stringify(inputs.folderPath)}. An `
|
|
2151
|
+
+ `in-solution sibling has no folder until the solution is deployed — the platform's own manifest `
|
|
2152
|
+
+ `writes \`""\` — so the value would be dropped. Remove it, or drop \`location: 'in-solution'\` to `
|
|
2153
|
+
+ `call the published copy.`);
|
|
2154
|
+
}
|
|
2016
2155
|
// The two are swappable by shape, and swapping them is invisible until
|
|
2017
2156
|
// Orchestrator answers "Folder does not exist or the user does not have access".
|
|
2018
2157
|
const name = typeof inputs?.name === 'string' ? inputs.name.trim() : '';
|
|
2019
|
-
const folder = typeof inputs?.folderPath === 'string' ? inputs.folderPath.trim() : '';
|
|
2020
2158
|
if (name.includes('/')) {
|
|
2021
2159
|
at('RPA_NAME_IS_PATH', `RPA step "${step}"'s \`name\` is ${JSON.stringify(inputs.name)}, which is a folder path. \`name\` is `
|
|
2022
2160
|
+ `the process's own name in Orchestrator; the path it lives in goes in \`folderPath\`. Together they `
|
|
2023
2161
|
+ `form the resourceKey "<folderPath>.<name>", so swapping them points the job at nothing.`);
|
|
2024
2162
|
}
|
|
2025
|
-
if (folder && !folder.includes('/') && name && !name.includes('/')) {
|
|
2026
|
-
// A single-segment folder is legal ("Shared"), so this is only worth saying
|
|
2027
|
-
// when the folder ALSO fails to look like one of the tenant's roots.
|
|
2028
|
-
if (!/^(Shared|Personal|My Workspace)$/i.test(folder)) {
|
|
2029
|
-
diags.push({
|
|
2030
|
-
level: 'warning',
|
|
2031
|
-
code: 'RPA_FOLDER_NOT_PATH',
|
|
2032
|
-
message: `RPA step "${step}"'s \`folderPath\` is ${JSON.stringify(inputs.folderPath)} — a single segment with no `
|
|
2033
|
-
+ `"/". Orchestrator folder paths are usually nested (e.g. "Shared/<team>/<solution>"). If this is `
|
|
2034
|
-
+ `the process's name rather than its folder, the two arguments are swapped.`,
|
|
2035
|
-
step,
|
|
2036
|
-
});
|
|
2037
|
-
}
|
|
2038
|
-
}
|
|
2039
2163
|
}
|
|
2040
2164
|
/**
|
|
2041
2165
|
* Check an `apiWorkflow(...)` call.
|
|
@@ -2636,10 +2760,33 @@ function checkAgenticProcess(step, inputs, diags) {
|
|
|
2636
2760
|
+ `the key in the node type, so without it the process cannot be resolved and the run fails before `
|
|
2637
2761
|
+ `dispatch.`, `name: 'ProcurementProcess'`);
|
|
2638
2762
|
}
|
|
2639
|
-
|
|
2763
|
+
const inSolution = inputs?.location === 'in-solution';
|
|
2764
|
+
if (!inSolution && blank(inputs?.folderPath)) {
|
|
2640
2765
|
at('AGENTIC_NO_FOLDER', `Agentic process step "${step}" has no \`folderPath\`. The runtime starts the job by name + folder, so `
|
|
2641
2766
|
+ `the Orchestrator folder holding the process is required.`, `folderPath: 'Shared/uipath-agents/ProcurementProcess'`);
|
|
2642
2767
|
}
|
|
2768
|
+
const form = inputs?.form ?? 'bpmn';
|
|
2769
|
+
if (inSolution && form !== 'flow') {
|
|
2770
|
+
at('AGENTIC_LOCAL_FORM_UNVERIFIED', `In-solution agentic process step "${step}" has \`form: ${JSON.stringify(form)}\`. Only \`form: 'flow'\` `
|
|
2771
|
+
+ `has been run against an in-solution sibling; the ${JSON.stringify(form)} shape is unproven. Call the `
|
|
2772
|
+
+ `published process instead (drop \`location\` and \`projectId\`, set \`folderPath\`), or use `
|
|
2773
|
+
+ `\`form: 'flow'\` if the sibling is a Flow.`, `location: 'published', folderPath: 'Shared/<folder>'`);
|
|
2774
|
+
}
|
|
2775
|
+
if (inSolution && blank(inputs?.projectId)) {
|
|
2776
|
+
const folder = (AGENTIC_PROCESS_FORMS[inputs?.form ?? 'bpmn'] ?? AGENTIC_PROCESS_FORMS.bpmn).solutionFolder;
|
|
2777
|
+
at('AGENTIC_LOCAL_NO_PROJECT_ID', `In-solution agentic process step "${step}" has no \`projectId\`. Read \`resource.projectKey\` from `
|
|
2778
|
+
+ `\`resources/solution_folder/process/${folder}/<project>.json\`.`, `projectId: '<resource.projectKey>'`);
|
|
2779
|
+
}
|
|
2780
|
+
else if (inSolution && !GUID_RE.test(String(inputs.projectId).trim())) {
|
|
2781
|
+
at('AGENTIC_LOCAL_PROJECT_ID_NOT_GUID', `In-solution agentic process step "${step}" has projectId ${JSON.stringify(inputs.projectId)}, which is not `
|
|
2782
|
+
+ `the sibling project's GUID. Read \`resource.projectKey\` from the generated resource file.`, `projectId: '<resource.projectKey>'`);
|
|
2783
|
+
}
|
|
2784
|
+
if (inSolution && !blank(inputs?.folderPath)) {
|
|
2785
|
+
at('AGENTIC_LOCAL_HAS_FOLDER', `In-solution agentic process step "${step}" also sets \`folderPath\` ${JSON.stringify(inputs.folderPath)}. An `
|
|
2786
|
+
+ `in-solution sibling has no folder until the solution is deployed — the platform's own manifest `
|
|
2787
|
+
+ `writes \`""\` — so the value would be dropped. Remove it, or drop \`location: 'in-solution'\` to `
|
|
2788
|
+
+ `call the published copy.`);
|
|
2789
|
+
}
|
|
2643
2790
|
const name = typeof inputs?.name === 'string' ? inputs.name.trim() : '';
|
|
2644
2791
|
if (name.includes('/')) {
|
|
2645
2792
|
at('AGENTIC_NAME_IS_PATH', `Agentic process step "${step}"'s \`name\` is ${JSON.stringify(inputs.name)}, which is a folder path. `
|
|
@@ -3642,7 +3789,7 @@ function checkQueueItem(step, inputs, diags) {
|
|
|
3642
3789
|
+ `Orchestrator rejects a queue item whose property values are not simple: `
|
|
3643
3790
|
+ `"Property values must be simple (like numbers or text) and not complex or composite `
|
|
3644
3791
|
+ `data types (like objects or arrays)". Flatten it, or JSON-encode it into one string `
|
|
3645
|
-
+ `field.`, `item: { ${k}: JSON.stringify(...) } // or ${k}Id, ${k}Name, …`);
|
|
3792
|
+
+ `field.`, `item: { ${k}: JSON.stringify(...) } // or ${commentText(k)}Id, ${commentText(k)}Name, …`);
|
|
3646
3793
|
}
|
|
3647
3794
|
}
|
|
3648
3795
|
}
|
|
@@ -3933,7 +4080,7 @@ function fanInDiag(join, arm, steps, tails) {
|
|
|
3933
4080
|
+ `edge, so the run never gets past "${join}" — with no incident, and \`flow validate\` answers Valid. Add a `
|
|
3934
4081
|
+ `step at the end of the arm${last?.name ? `, after "${last.name}"` : ''}, so the paths meet on that step and `
|
|
3935
4082
|
+ `only its one edge reaches the join, or move human task "${task}" out of the \`.parallel(…)\`.`,
|
|
3936
|
-
suggestion: `….step('record', …) // last step of arm ${arm + 1}`,
|
|
4083
|
+
suggestion: `….step('record', …) // last step of arm ${commentText(arm + 1)}`,
|
|
3937
4084
|
};
|
|
3938
4085
|
}
|
|
3939
4086
|
/**
|
|
@@ -5195,7 +5342,7 @@ function checkOnError(_handler, step, diags) {
|
|
|
5195
5342
|
// A `.loop()` CONTAINER is fine: `core.logic.loop` declares the error handle at
|
|
5196
5343
|
// both bundled versions, and a measured run routed a body failure to it — the
|
|
5197
5344
|
// container's envelope carried the body's message in `detail` and the failing
|
|
5198
|
-
// body step's
|
|
5345
|
+
// body step's label in `element`.
|
|
5199
5346
|
if (step.kind === 'loop')
|
|
5200
5347
|
return;
|
|
5201
5348
|
// `.doWhile()` is not. `core.logic.dowhile@1.0` declares an error VARIABLE and
|
|
@@ -5204,12 +5351,38 @@ function checkOnError(_handler, step, diags) {
|
|
|
5204
5351
|
// declare that handle". The builder refuses this too; this catches a
|
|
5205
5352
|
// hand-built flow and says the same thing.
|
|
5206
5353
|
if (step.kind === 'doWhile') {
|
|
5354
|
+
diags.push(doWhileOnErrorRefusal(step.name));
|
|
5355
|
+
return;
|
|
5356
|
+
}
|
|
5357
|
+
// A custom FlowAction or rawNode has no `kind`: ask its DEFINITION, with the
|
|
5358
|
+
// product's own rule (definitionHasErrorPort), not the kind list (#943).
|
|
5359
|
+
const maybeCustom = step.spec;
|
|
5360
|
+
if (!('kind' in maybeCustom) && maybeCustom instanceof FlowNode) {
|
|
5361
|
+
let def;
|
|
5362
|
+
try {
|
|
5363
|
+
const requestedVersion = step.options?.version;
|
|
5364
|
+
def = resolveContributionDefinition(maybeCustom.contribute(requestedVersion !== undefined ? { requestedVersion } : {}).definition, requestedVersion, `step "${step.name}"`);
|
|
5365
|
+
}
|
|
5366
|
+
catch {
|
|
5367
|
+
// checkContribution already reports a contribution compile cannot lower.
|
|
5368
|
+
return;
|
|
5369
|
+
}
|
|
5370
|
+
// A custom node backed by a typed family's bundled definition gets that
|
|
5371
|
+
// family's refusals: the rules are about the node type, not the SDK kind.
|
|
5372
|
+
if (def?.nodeType === 'core.logic.dowhile') {
|
|
5373
|
+
diags.push(doWhileOnErrorRefusal(step.name));
|
|
5374
|
+
return;
|
|
5375
|
+
}
|
|
5376
|
+
if (def?.nodeType === 'core.action.http') {
|
|
5377
|
+
diags.push(plainHttpOnErrorRefusal(step.name));
|
|
5378
|
+
return;
|
|
5379
|
+
}
|
|
5380
|
+
if (definitionHasErrorPort(def))
|
|
5381
|
+
return;
|
|
5207
5382
|
diags.push({
|
|
5208
5383
|
level: 'error',
|
|
5209
5384
|
code: 'ONERROR_NO_ERROR_PORT',
|
|
5210
|
-
message:
|
|
5211
|
-
+ `(core.logic.dowhile@1.0: input, success, start, continue, break), so the edge would leave a handle the `
|
|
5212
|
-
+ `node does not have. Handle the failure inside the body, on the step that can fail.`,
|
|
5385
|
+
message: errorPortRefusal(step.name, def),
|
|
5213
5386
|
step: step.name,
|
|
5214
5387
|
});
|
|
5215
5388
|
return;
|
|
@@ -5240,19 +5413,33 @@ function checkOnError(_handler, step, diags) {
|
|
|
5240
5413
|
// So this stays an error, and says the second part too: an author who reads
|
|
5241
5414
|
// the old message ("use the managed node if statuses must route") could
|
|
5242
5415
|
// reasonably conclude a transport-failure handler is fine as it is.
|
|
5243
|
-
if (spec.kind === 'http' && !spec.inputs?.managed)
|
|
5244
|
-
diags.push(
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
}
|
|
5416
|
+
if (spec.kind === 'http' && !spec.inputs?.managed)
|
|
5417
|
+
diags.push(plainHttpOnErrorRefusal(step.name));
|
|
5418
|
+
}
|
|
5419
|
+
/** `.onError` after a `core.logic.dowhile` container: it declares no error handle. */
|
|
5420
|
+
function doWhileOnErrorRefusal(stepName) {
|
|
5421
|
+
return {
|
|
5422
|
+
level: 'error',
|
|
5423
|
+
code: 'ONERROR_NO_ERROR_PORT',
|
|
5424
|
+
message: `Step "${stepName}" is a .doWhile() container. It declares an error variable but no error HANDLE `
|
|
5425
|
+
+ `(core.logic.dowhile@1.0: input, success, start, continue, break), so the edge would leave a handle the `
|
|
5426
|
+
+ `node does not have. Handle the failure inside the body, on the step that can fail.`,
|
|
5427
|
+
step: stepName,
|
|
5428
|
+
};
|
|
5429
|
+
}
|
|
5430
|
+
/** `.onError` after a plain `core.action.http` node (see the two measured facts in {@link checkOnError}). */
|
|
5431
|
+
function plainHttpOnErrorRefusal(stepName) {
|
|
5432
|
+
return {
|
|
5433
|
+
level: 'error',
|
|
5434
|
+
code: 'HTTP_ONERROR_V1',
|
|
5435
|
+
message: `Step "${stepName}" handles errors on a plain http() request. A 4xx/5xx does NOT fail that node — it `
|
|
5436
|
+
+ `completes with out('${stepName}', 'statusCode') set — so the handler runs only on a transport failure, `
|
|
5437
|
+
+ `and when it does the node publishes no failure envelope at all (measured: "<step>.error" is the boolean `
|
|
5438
|
+
+ `true and "<step>.output" is null, in 1.0.0 and in the 1.3 flow migrate produces), so err() has nothing `
|
|
5439
|
+
+ `to read. The managed node is the one whose failures route AND carry the envelope.`,
|
|
5440
|
+
step: stepName,
|
|
5441
|
+
suggestion: `http({ url: …, managed: true })`,
|
|
5442
|
+
};
|
|
5256
5443
|
}
|
|
5257
5444
|
/**
|
|
5258
5445
|
* Reading a value that only ONE arm produces (flow-builder-sdk#200).
|
|
@@ -5623,3 +5810,39 @@ function checkSchemaVersion(built, ancestors, diags) {
|
|
|
5623
5810
|
});
|
|
5624
5811
|
}
|
|
5625
5812
|
}
|
|
5813
|
+
/**
|
|
5814
|
+
* Run a custom node's contribution lowering DRY, so `check` reports what
|
|
5815
|
+
* `compile` would throw. For instance, a `rawNode` carrying an in-solution
|
|
5816
|
+
* sibling's manifest with no `values` row for `<bindings.folderPath>` fails here
|
|
5817
|
+
* with the same code compile throws.
|
|
5818
|
+
*
|
|
5819
|
+
* It calls `contribute()`, resolves the definition the way serialize does, and
|
|
5820
|
+
* plans the `bindings[]` entries serialize would build
|
|
5821
|
+
* ({@link planContributionBindings}). A name the plan cannot close is
|
|
5822
|
+
* `CONTRIBUTION_BINDING_UNRESOLVED` — the same code and sentence serialize
|
|
5823
|
+
* throws. A contribution that throws is `CONTRIBUTION_INVALID`, unless
|
|
5824
|
+
* `ownError` says the node's own `diagnostics()` already reported an error (a
|
|
5825
|
+
* raw connector node throws for the reason `RAW_NODE_CONNECTOR` already gives).
|
|
5826
|
+
*/
|
|
5827
|
+
function checkContribution(node, requestedVersion, step, ownError, diags) {
|
|
5828
|
+
let def;
|
|
5829
|
+
let supplied;
|
|
5830
|
+
try {
|
|
5831
|
+
const contribution = node.contribute(requestedVersion !== undefined ? { requestedVersion } : {});
|
|
5832
|
+
def = resolveContributionDefinition(contribution.definition, requestedVersion, `step "${step}"`);
|
|
5833
|
+
supplied = contribution.bindings;
|
|
5834
|
+
}
|
|
5835
|
+
catch (e) {
|
|
5836
|
+
if (ownError)
|
|
5837
|
+
return;
|
|
5838
|
+
diags.push({
|
|
5839
|
+
level: 'error', code: 'CONTRIBUTION_INVALID', step,
|
|
5840
|
+
message: `compile cannot lower step "${step}": ${e instanceof Error ? e.message : String(e)}`,
|
|
5841
|
+
});
|
|
5842
|
+
return;
|
|
5843
|
+
}
|
|
5844
|
+
const plan = planContributionBindings(def, supplied);
|
|
5845
|
+
if (plan.problems.length === 0)
|
|
5846
|
+
return;
|
|
5847
|
+
diags.push({ level: 'error', code: 'CONTRIBUTION_BINDING_UNRESOLVED', step, message: plan.problems.join(' ') });
|
|
5848
|
+
}
|
package/dist/cli-library.d.ts
CHANGED
|
@@ -1,9 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* cli-library —
|
|
2
|
+
* cli-library — Flow's check options, plus the historical re-exports.
|
|
3
3
|
*
|
|
4
4
|
* How a CLI opens the connector library and its `connectors-local/` overlay, and
|
|
5
|
-
* the event verdicts `check` shares with
|
|
6
|
-
* `core/cli-library.ts
|
|
7
|
-
*
|
|
5
|
+
* the connector and event verdicts every family's `check` shares with its
|
|
6
|
+
* `compile`, live in `core/cli-library.ts`. This module keeps the historical
|
|
7
|
+
* `./cli-library.js` import path and adds the one thing that is Flow's own:
|
|
8
|
+
* {@link flowCheckOpts}, the options both `flow check` and `flow compile`'s check
|
|
9
|
+
* pass run on.
|
|
8
10
|
*/
|
|
11
|
+
import type { CheckOpts } from './check.js';
|
|
12
|
+
import type { BindingsView } from './core/binding-messages.js';
|
|
13
|
+
import type { Library } from './core/library.js';
|
|
9
14
|
export { openCliLibrary, connectorCheckOpts, eventResolveErrorFor, byoaCheckOpts } from './core/cli-library.js';
|
|
15
|
+
/**
|
|
16
|
+
* Flow's check options from a library the CLI already opened: the shared
|
|
17
|
+
* connector and event hooks, Flow's own field validator (it renders Flow
|
|
18
|
+
* expressions, as `serialize` does), and the measured list envelopes.
|
|
19
|
+
*
|
|
20
|
+
* One builder for `flow check` and `flow compile`'s check pass, so the two
|
|
21
|
+
* cannot disagree.
|
|
22
|
+
*/
|
|
23
|
+
export declare function flowCheckOpts(library: Library | undefined, bindings?: BindingsView): CheckOpts;
|
package/dist/cli-library.js
CHANGED
|
@@ -1,9 +1,27 @@
|
|
|
1
|
+
import { connectorCheckOpts } from './core/cli-library.js';
|
|
2
|
+
import { connectorInputErrors } from './serialize.js';
|
|
3
|
+
export { openCliLibrary, connectorCheckOpts, eventResolveErrorFor, byoaCheckOpts } from './core/cli-library.js';
|
|
1
4
|
/**
|
|
2
|
-
*
|
|
5
|
+
* Flow's check options from a library the CLI already opened: the shared
|
|
6
|
+
* connector and event hooks, Flow's own field validator (it renders Flow
|
|
7
|
+
* expressions, as `serialize` does), and the measured list envelopes.
|
|
3
8
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* `core/cli-library.ts` when BPMN's `compile` and `check` needed the same things.
|
|
7
|
-
* This shim preserves the historical `./cli-library.js` import path.
|
|
9
|
+
* One builder for `flow check` and `flow compile`'s check pass, so the two
|
|
10
|
+
* cannot disagree.
|
|
8
11
|
*/
|
|
9
|
-
export
|
|
12
|
+
export function flowCheckOpts(library, bindings) {
|
|
13
|
+
const shared = connectorCheckOpts(library, bindings, connectorInputErrors);
|
|
14
|
+
if (!library)
|
|
15
|
+
return shared;
|
|
16
|
+
return {
|
|
17
|
+
...shared,
|
|
18
|
+
listEnvelope: (connector, operation, version, object) => {
|
|
19
|
+
try {
|
|
20
|
+
return library.resolve(connector, operation, version, object).listEnvelope;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return undefined; // an unresolvable operation is connectorResolveError's to report
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
package/dist/cli-result.d.ts
CHANGED
|
@@ -34,3 +34,12 @@ export declare function reportDiagnostics(diags: ReadonlyArray<{
|
|
|
34
34
|
message: string;
|
|
35
35
|
suggestion?: string;
|
|
36
36
|
}>): void;
|
|
37
|
+
/**
|
|
38
|
+
* The error diagnostic for a throw that ends a compile: the error's own string
|
|
39
|
+
* `code` when it carries one, else `COMPILE_FAILED`.
|
|
40
|
+
*/
|
|
41
|
+
export declare function thrownDiagnostic(error: unknown): {
|
|
42
|
+
level: 'error';
|
|
43
|
+
code: string;
|
|
44
|
+
message: string;
|
|
45
|
+
};
|
package/dist/cli-result.js
CHANGED
|
@@ -47,3 +47,15 @@ export function reportDiagnostics(diags) {
|
|
|
47
47
|
diagnostics: diags.map((d) => ({ level: d.level, code: d.code, message: d.message, ...(d.suggestion ? { suggestion: d.suggestion } : {}) })),
|
|
48
48
|
});
|
|
49
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* The error diagnostic for a throw that ends a compile: the error's own string
|
|
52
|
+
* `code` when it carries one, else `COMPILE_FAILED`.
|
|
53
|
+
*/
|
|
54
|
+
export function thrownDiagnostic(error) {
|
|
55
|
+
const code = error?.code;
|
|
56
|
+
return {
|
|
57
|
+
level: 'error',
|
|
58
|
+
code: typeof code === 'string' && code.length > 0 ? code : 'COMPILE_FAILED',
|
|
59
|
+
message: error instanceof Error ? error.message : String(error),
|
|
60
|
+
};
|
|
61
|
+
}
|