@uipath/maestro-builder-sdk 6.33.2 → 6.34.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/api-index.md +26 -24
- package/dist/api-members.md +141 -136
- package/dist/case/case-sdk.d.ts +52 -1
- package/dist/case/case-sdk.js +37 -2
- package/dist/case/check.js +30 -0
- package/dist/case/compile-cli.js +6 -1
- package/dist/case/decompile.js +50 -3
- package/dist/case/format-profile.d.ts +1 -1
- package/dist/case/format-profile.js +7 -3
- package/dist/case/serialize.js +93 -9
- package/dist/schema-version.js +6 -1
- package/package.json +2 -2
package/dist/case/case-sdk.d.ts
CHANGED
|
@@ -372,7 +372,7 @@ export interface BuiltCaseExitCondition {
|
|
|
372
372
|
marksCaseComplete?: boolean;
|
|
373
373
|
rules: CaseRule[][];
|
|
374
374
|
}
|
|
375
|
-
export type TaskKind = 'process' | 'agent' | 'rpa' | 'api-workflow' | 'case-management' | 'flow-process' | 'external-agent' | 'external-workflow' | 'action' | 'connector' | 'wait-for-timer' | 'wait-for-connector';
|
|
375
|
+
export type TaskKind = 'process' | 'agent' | 'rpa' | 'api-workflow' | 'case-management' | 'flow-process' | 'business-rule' | 'external-agent' | 'external-workflow' | 'action' | 'connector' | 'wait-for-timer' | 'wait-for-connector';
|
|
376
376
|
/** Published-resource task kinds that the Case schema permits as unresolved skeletons. */
|
|
377
377
|
export type UnresolvedReferenceTaskKind = 'process' | 'agent' | 'rpa' | 'api-workflow' | 'case-management';
|
|
378
378
|
/**
|
|
@@ -428,6 +428,25 @@ export interface TaskRef {
|
|
|
428
428
|
name: string;
|
|
429
429
|
folderPath: string;
|
|
430
430
|
}
|
|
431
|
+
/**
|
|
432
|
+
* Options for {@link TaskBuilder.businessRule}.
|
|
433
|
+
*/
|
|
434
|
+
export interface BusinessRuleOptions {
|
|
435
|
+
/** The Orchestrator folder the rule is deployed in, e.g. `Shared`. */
|
|
436
|
+
folder: string;
|
|
437
|
+
/**
|
|
438
|
+
* The rule's whole result schema, as `uip maestro case tasks describe --type
|
|
439
|
+
* business-rule` returns it on the `output` row (`_jsonSchema`): one object
|
|
440
|
+
* keyed by decision name, each holding that decision's columns. Optional; it
|
|
441
|
+
* is copied onto the `output` row so the designer can show the columns.
|
|
442
|
+
*/
|
|
443
|
+
resultSchema?: unknown;
|
|
444
|
+
}
|
|
445
|
+
/** Normalized business-rule configuration stored on a built task. */
|
|
446
|
+
export interface BusinessRuleSpecData {
|
|
447
|
+
/** The rule's decision-keyed result schema, when the author supplied it. */
|
|
448
|
+
resultSchema?: unknown;
|
|
449
|
+
}
|
|
431
450
|
/**
|
|
432
451
|
* Action-task recipient type. `2` = a single user by email — the only value the
|
|
433
452
|
* platform corpus exercises for case action tasks; `0`/`1`/`3` are reserved for
|
|
@@ -520,6 +539,8 @@ export interface BuiltTask {
|
|
|
520
539
|
name: string;
|
|
521
540
|
kind: TaskKind;
|
|
522
541
|
ref?: TaskRef;
|
|
542
|
+
/** business-rule task: the rule's decision-keyed result schema, when known. */
|
|
543
|
+
businessRule?: BusinessRuleSpecData;
|
|
523
544
|
action?: ActionSpecData;
|
|
524
545
|
connector?: ConnectorSpecData;
|
|
525
546
|
/** Descriptor-resolved external agent/workflow configuration. */
|
|
@@ -718,6 +739,7 @@ declare class TaskBuilder {
|
|
|
718
739
|
private readonly _name;
|
|
719
740
|
private _kind?;
|
|
720
741
|
private _ref?;
|
|
742
|
+
private _businessRule?;
|
|
721
743
|
private _action?;
|
|
722
744
|
private _connector?;
|
|
723
745
|
private _external?;
|
|
@@ -808,6 +830,35 @@ declare class TaskBuilder {
|
|
|
808
830
|
flowProcess(name: string, opts?: {
|
|
809
831
|
folder?: string;
|
|
810
832
|
}): this;
|
|
833
|
+
/**
|
|
834
|
+
* Evaluate a deployed **business rule** (a DMN decision package) and read its
|
|
835
|
+
* decisions back.
|
|
836
|
+
*
|
|
837
|
+
* @remarks
|
|
838
|
+
* Emits a `business-rule` task at `version: 'v3'` (below v3 the engine cannot
|
|
839
|
+
* run the `.uirule` package a BusinessRules project deploys). The rule is named
|
|
840
|
+
* through a `name` + `folderPath` pair of root bindings with
|
|
841
|
+
* `resource: 'BusinessRule'` and `resourceKey: '<folder>.<name>'`, the shape
|
|
842
|
+
* Studio Web and `uip maestro case bindings sync` write.
|
|
843
|
+
*
|
|
844
|
+
* The task always carries the two outputs every business-rule task has: `output`
|
|
845
|
+
* (`source: '=result'`, the whole decision-keyed result) and `Error`. To store
|
|
846
|
+
* one decision column in a case variable, add an extract with `.outputs()`
|
|
847
|
+
* whose source names the decision and column directly — `=<Decision>.<column>`,
|
|
848
|
+
* never `=result.…` or `=output.…`:
|
|
849
|
+
*
|
|
850
|
+
* ```ts
|
|
851
|
+
* .task('Score Credit Risk', t => t
|
|
852
|
+
* .businessRule('CreditRisk', { folder: 'Shared' })
|
|
853
|
+
* .inputs({ creditScore: { value: '=vars.creditScore', type: 'number' } })
|
|
854
|
+
* .outputs({ riskBand: { source: '=RiskDecision.riskBand', type: 'string' } }))
|
|
855
|
+
* ```
|
|
856
|
+
*
|
|
857
|
+
* @param name - The deployed rule's name.
|
|
858
|
+
* @param opts - `folder` (required) and the optional `resultSchema`.
|
|
859
|
+
* @returns This builder, so calls chain.
|
|
860
|
+
*/
|
|
861
|
+
businessRule(name: string, opts: BusinessRuleOptions): this;
|
|
811
862
|
private external;
|
|
812
863
|
/**
|
|
813
864
|
* Invoke an external agent through its generated Integration Service descriptor.
|
package/dist/case/case-sdk.js
CHANGED
|
@@ -160,6 +160,7 @@ class TaskBuilder {
|
|
|
160
160
|
_name;
|
|
161
161
|
_kind;
|
|
162
162
|
_ref;
|
|
163
|
+
_businessRule;
|
|
163
164
|
_action;
|
|
164
165
|
_connector;
|
|
165
166
|
_external;
|
|
@@ -263,6 +264,39 @@ class TaskBuilder {
|
|
|
263
264
|
flowProcess(name, opts) {
|
|
264
265
|
return this.reference('flow-process', name, opts);
|
|
265
266
|
}
|
|
267
|
+
/**
|
|
268
|
+
* Evaluate a deployed **business rule** (a DMN decision package) and read its
|
|
269
|
+
* decisions back.
|
|
270
|
+
*
|
|
271
|
+
* @remarks
|
|
272
|
+
* Emits a `business-rule` task at `version: 'v3'` (below v3 the engine cannot
|
|
273
|
+
* run the `.uirule` package a BusinessRules project deploys). The rule is named
|
|
274
|
+
* through a `name` + `folderPath` pair of root bindings with
|
|
275
|
+
* `resource: 'BusinessRule'` and `resourceKey: '<folder>.<name>'`, the shape
|
|
276
|
+
* Studio Web and `uip maestro case bindings sync` write.
|
|
277
|
+
*
|
|
278
|
+
* The task always carries the two outputs every business-rule task has: `output`
|
|
279
|
+
* (`source: '=result'`, the whole decision-keyed result) and `Error`. To store
|
|
280
|
+
* one decision column in a case variable, add an extract with `.outputs()`
|
|
281
|
+
* whose source names the decision and column directly — `=<Decision>.<column>`,
|
|
282
|
+
* never `=result.…` or `=output.…`:
|
|
283
|
+
*
|
|
284
|
+
* ```ts
|
|
285
|
+
* .task('Score Credit Risk', t => t
|
|
286
|
+
* .businessRule('CreditRisk', { folder: 'Shared' })
|
|
287
|
+
* .inputs({ creditScore: { value: '=vars.creditScore', type: 'number' } })
|
|
288
|
+
* .outputs({ riskBand: { source: '=RiskDecision.riskBand', type: 'string' } }))
|
|
289
|
+
* ```
|
|
290
|
+
*
|
|
291
|
+
* @param name - The deployed rule's name.
|
|
292
|
+
* @param opts - `folder` (required) and the optional `resultSchema`.
|
|
293
|
+
* @returns This builder, so calls chain.
|
|
294
|
+
*/
|
|
295
|
+
businessRule(name, opts) {
|
|
296
|
+
this.reference('business-rule', name, { folder: opts.folder });
|
|
297
|
+
this._businessRule = opts.resultSchema === undefined ? {} : { resultSchema: opts.resultSchema };
|
|
298
|
+
return this;
|
|
299
|
+
}
|
|
266
300
|
external(kind, descriptor, opts) {
|
|
267
301
|
this.setKind(kind);
|
|
268
302
|
this._external = {
|
|
@@ -448,15 +482,16 @@ class TaskBuilder {
|
|
|
448
482
|
// Task I/O binding is reference-mode only — process/agent/rpa/api-workflow,
|
|
449
483
|
// case-management, and flow-process. Connector tasks derive their own
|
|
450
484
|
// inputs/outputs from the operation schema.
|
|
451
|
-
const REF_IO = new Set(['process', 'agent', 'rpa', 'api-workflow', 'case-management', 'flow-process']);
|
|
485
|
+
const REF_IO = new Set(['process', 'agent', 'rpa', 'api-workflow', 'case-management', 'flow-process', 'business-rule']);
|
|
452
486
|
if ((this._inputs || this._outputs) && !REF_IO.has(this._kind))
|
|
453
|
-
throw new Error(`task "${this._name}": .inputs()/.outputs() are only supported on reference-mode tasks (process/agent/rpa/api-workflow/case-management/flow-process), not "${this._kind}".`);
|
|
487
|
+
throw new Error(`task "${this._name}": .inputs()/.outputs() are only supported on reference-mode tasks (process/agent/rpa/api-workflow/case-management/flow-process/business-rule), not "${this._kind}".`);
|
|
454
488
|
if (!this._ref && (this._inputs || this._outputs))
|
|
455
489
|
throw new Error(`task "${this._name}": an unresolved reference task cannot declare inputs or outputs.`);
|
|
456
490
|
return {
|
|
457
491
|
name: this._name,
|
|
458
492
|
kind: this._kind,
|
|
459
493
|
ref: this._ref,
|
|
494
|
+
businessRule: this._businessRule,
|
|
460
495
|
action: this._action,
|
|
461
496
|
connector: this._connector,
|
|
462
497
|
external: this._external,
|
package/dist/case/check.js
CHANGED
|
@@ -483,6 +483,36 @@ function checkStage(stage, diags, refStage, refPlacement) {
|
|
|
483
483
|
message: `Task "${t.name}" binding "${'var' in invalidBinding ? invalidBinding.var : invalidBinding.name}" has unsupported type ${JSON.stringify(invalidBinding.type)}. Use a type name such as "string" or "jsonSchema"; jsonSchema(...) is only for declaring a structured case variable.`,
|
|
484
484
|
where: t.name,
|
|
485
485
|
});
|
|
486
|
+
if (t.kind === 'business-rule') {
|
|
487
|
+
if (!t.ref || !t.ref.name.trim() || !t.ref.folderPath.trim())
|
|
488
|
+
diags.push({
|
|
489
|
+
level: 'error',
|
|
490
|
+
code: 'BUSINESS_RULE_EMPTY_DATA',
|
|
491
|
+
message: `Business-rule task "${t.name}" must name its deployed rule and the Orchestrator folder it is deployed in: .businessRule('<rule>', { folder: '<folder>' }).`,
|
|
492
|
+
where: t.name,
|
|
493
|
+
});
|
|
494
|
+
for (const o of t.outputs ?? []) {
|
|
495
|
+
const wrapped = /^=\s*(result|output)\./.exec(o.source);
|
|
496
|
+
if (wrapped)
|
|
497
|
+
diags.push({
|
|
498
|
+
level: 'error',
|
|
499
|
+
code: 'BUSINESS_RULE_OUTPUT_SOURCE',
|
|
500
|
+
message: `Business-rule task "${t.name}" output "${o.var}" reads "${o.source}". An extract reads a field of the rule's result directly — write "=${o.source.replace(/^=\s*(result|output)\./, '')}" (\`=<Decision>.<column>\`). The whole result is already the task's own \`output\` row (\`=result\`); \`=${wrapped[1]}.…\` names a field the result does not have.`,
|
|
501
|
+
where: t.name,
|
|
502
|
+
});
|
|
503
|
+
// An extract row is NAMED after its source's last segment (`emitTaskOutput`),
|
|
504
|
+
// so `=Decision.output` writes a second row named `output` beside the
|
|
505
|
+
// task's own. The case variable it stores into collides with nothing.
|
|
506
|
+
const rowName = o.source.replace(/^=/, '').split('.').pop();
|
|
507
|
+
if (rowName === 'output' || rowName === 'Error')
|
|
508
|
+
diags.push({
|
|
509
|
+
level: 'error',
|
|
510
|
+
code: 'BUSINESS_RULE_OUTPUT_NAME',
|
|
511
|
+
message: `Business-rule task "${t.name}" output "${o.var}" reads "${o.source}", which writes an output row named "${rowName}" — the name of the task's own ${rowName === 'output' ? '`output` row (the whole result, `=result`)' : '`Error` row (`=Error`)'}. Two rows with one name are ambiguous to the designer; rename the decision column.`,
|
|
512
|
+
where: t.name,
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
}
|
|
486
516
|
if (t.kind === 'flow-process' && (!t.ref || !t.ref.name.trim()))
|
|
487
517
|
diags.push({
|
|
488
518
|
level: 'error',
|
package/dist/case/compile-cli.js
CHANGED
|
@@ -364,7 +364,12 @@ function syncBindingsV2(caseplan, outPath) {
|
|
|
364
364
|
resource: group.resource,
|
|
365
365
|
key: group.key,
|
|
366
366
|
value: group.value,
|
|
367
|
-
|
|
367
|
+
// A BusinessRule entry carries the bindings version deploy needs to
|
|
368
|
+
// override its folder — the metadata `uip maestro case bindings sync`
|
|
369
|
+
// writes for it (no subType).
|
|
370
|
+
metadata: group.subType
|
|
371
|
+
? { subType: group.subType }
|
|
372
|
+
: group.resource === 'BusinessRule' ? { BindingsVersion: '2.2' } : {},
|
|
368
373
|
});
|
|
369
374
|
}
|
|
370
375
|
resources.push(...connectionResources);
|
package/dist/case/decompile.js
CHANGED
|
@@ -579,6 +579,8 @@ function emitTaskKind(task, refs, library) {
|
|
|
579
579
|
const folder = folderPath ? `, ${opts([['folder', tsLiteral(folderPath)]])}` : '';
|
|
580
580
|
return `.${method}(${tsLiteral(name ?? '')}${folder})`;
|
|
581
581
|
}
|
|
582
|
+
if (isAuthorableBusinessRule(task))
|
|
583
|
+
return businessRuleCall(task, refs);
|
|
582
584
|
if (kind === 'action') {
|
|
583
585
|
let recipient;
|
|
584
586
|
if (data.recipient) {
|
|
@@ -616,7 +618,12 @@ function emitTaskKind(task, refs, library) {
|
|
|
616
618
|
const spec = waitConnectorSpec(data, `wait-for-connector task "${task.displayName ?? task.id ?? '?'}"`, refs);
|
|
617
619
|
return spec === undefined ? '.waitForConnector()' : `.waitForConnector(${spec})`;
|
|
618
620
|
}
|
|
619
|
-
const message =
|
|
621
|
+
const message = kind === 'business-rule'
|
|
622
|
+
// The converter reads a missing version as v2, whose result shape differs
|
|
623
|
+
// from v3's decision-keyed one; recompiling it as v3 would change what its
|
|
624
|
+
// extracts read. Keep the task as data instead.
|
|
625
|
+
? `business-rule task "${task.displayName ?? task.id ?? '?'}" has ${data.version === undefined ? 'no version (the converter reads it as v2)' : `version "${String(data.version)}"`}; only v3 business-rule tasks are authorable.`
|
|
626
|
+
: `unsupported task kind "${kind}" for task "${task.displayName ?? task.id ?? '?'}".`;
|
|
620
627
|
diagnose(refs, {
|
|
621
628
|
code: 'UNSUPPORTED_TASK_KIND',
|
|
622
629
|
message,
|
|
@@ -624,6 +631,29 @@ function emitTaskKind(task, refs, library) {
|
|
|
624
631
|
});
|
|
625
632
|
return `.__UNRESOLVED_TASK_KIND__(${tsLiteral(kind)}, ${tsLiteral(data)})`;
|
|
626
633
|
}
|
|
634
|
+
/** A business-rule task `.businessRule()` can rebuild: v3 only. */
|
|
635
|
+
function isAuthorableBusinessRule(task) {
|
|
636
|
+
return task.type === 'business-rule' && task.data?.version === 'v3';
|
|
637
|
+
}
|
|
638
|
+
/** The two outputs every business-rule task carries, which `.businessRule()` re-emits itself. */
|
|
639
|
+
function isBusinessRuleOwnOutput(row) {
|
|
640
|
+
return (row.name === 'output' && row.source === '=result') || (row.name === 'Error' && row.source === '=Error');
|
|
641
|
+
}
|
|
642
|
+
function businessRuleCall(task, refs) {
|
|
643
|
+
const data = task.data ?? {};
|
|
644
|
+
const owner = `business-rule task "${task.displayName ?? task.id ?? '?'}"`;
|
|
645
|
+
const name = bindingDefault(data.name, refs);
|
|
646
|
+
const folderPath = bindingDefault(data.folderPath, refs);
|
|
647
|
+
if (typeof name !== 'string' || !name || typeof folderPath !== 'string')
|
|
648
|
+
throw new Error(`${owner} must name its rule and folder (data.name / data.folderPath).`);
|
|
649
|
+
const outputRow = (Array.isArray(data.outputs) ? data.outputs : [])
|
|
650
|
+
.find((row) => row.name === 'output' && row.source === '=result');
|
|
651
|
+
const resultSchema = outputRow?._jsonSchema;
|
|
652
|
+
return `.businessRule(${tsLiteral(name)}, ${opts([
|
|
653
|
+
['folder', tsLiteral(folderPath)],
|
|
654
|
+
['resultSchema', resultSchema !== undefined ? tsLiteral(resultSchema) : undefined],
|
|
655
|
+
])})`;
|
|
656
|
+
}
|
|
627
657
|
function ioArg(rows, kind) {
|
|
628
658
|
const valueField = kind === 'inputs' ? 'value' : 'source';
|
|
629
659
|
const entries = rows.map((row) => {
|
|
@@ -647,6 +677,14 @@ function emitTask(out, depth, task, lane, refs, library) {
|
|
|
647
677
|
if (Array.isArray(data.outputs) && data.outputs.length)
|
|
648
678
|
out.line(inner, `.outputs(${ioArg(data.outputs, 'outputs')})`);
|
|
649
679
|
}
|
|
680
|
+
if (isAuthorableBusinessRule(task)) {
|
|
681
|
+
const data = task.data ?? {};
|
|
682
|
+
const extracts = (Array.isArray(data.outputs) ? data.outputs : []).filter((row) => !isBusinessRuleOwnOutput(row));
|
|
683
|
+
if (Array.isArray(data.inputs) && data.inputs.length)
|
|
684
|
+
out.line(inner, `.inputs(${ioArg(data.inputs, 'inputs')})`);
|
|
685
|
+
if (extracts.length)
|
|
686
|
+
out.line(inner, `.outputs(${ioArg(extracts, 'outputs')})`);
|
|
687
|
+
}
|
|
650
688
|
if (task.isRequired !== undefined)
|
|
651
689
|
out.line(inner, task.isRequired ? '.required()' : '.required(false)');
|
|
652
690
|
if (task.shouldRunOnlyOnce !== undefined)
|
|
@@ -749,11 +787,20 @@ function producedVariableNames(plan) {
|
|
|
749
787
|
if (!isStage(node))
|
|
750
788
|
continue;
|
|
751
789
|
for (const lane of node.data?.tasks ?? [])
|
|
752
|
-
for (const task of lane)
|
|
753
|
-
if (ownEntry(TASK_KIND_METHOD, task.type))
|
|
790
|
+
for (const task of lane) {
|
|
791
|
+
if (ownEntry(TASK_KIND_METHOD, task.type)) {
|
|
754
792
|
for (const row of task.data?.outputs ?? [])
|
|
755
793
|
if (row.var)
|
|
756
794
|
produced.add(row.var);
|
|
795
|
+
}
|
|
796
|
+
else if (isAuthorableBusinessRule(task)) {
|
|
797
|
+
// A business-rule extract registers its case variable on recompile, as
|
|
798
|
+
// a reference-task output does; the task's own rows do not.
|
|
799
|
+
for (const row of task.data?.outputs ?? [])
|
|
800
|
+
if (row.var && !isBusinessRuleOwnOutput(row))
|
|
801
|
+
produced.add(row.var);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
757
804
|
}
|
|
758
805
|
return produced;
|
|
759
806
|
}
|
|
@@ -40,7 +40,7 @@ export declare const CASE_FORMAT_PROFILE: Readonly<CaseFormatProfile>;
|
|
|
40
40
|
* Which Case JSON schema versions `.schemaVersion()` may declare.
|
|
41
41
|
*
|
|
42
42
|
* ONE, and that is the honest answer rather than a placeholder. Case is a
|
|
43
|
-
* closed, whole-document schema: `@uipath/case-schema` ships a chain of
|
|
43
|
+
* closed, whole-document schema: `@uipath/case-schema` ships a chain of
|
|
44
44
|
* grammars (`case-schema-census.json`'s `versionChain`), each with its own
|
|
45
45
|
* forward migration, and a version is a claim that the entire document matches
|
|
46
46
|
* that grammar. This SDK emits the V30 grammar natively — the V30 rule schemas
|
|
@@ -28,16 +28,20 @@ export const CASE_FORMAT_PROFILE = {
|
|
|
28
28
|
{ featureFlag: 'canvas-useExplicitEntryExitConditions', fromVersion: '12.0.0' },
|
|
29
29
|
{ featureFlag: 'canvas-caseUnifiedSchema', fromVersion: '20.0.0' },
|
|
30
30
|
],
|
|
31
|
+
// The validation pin (the `@uipath/case-schema` devDependency in
|
|
32
|
+
// typescript/package.json; the census records it as `generatedFrom.version`)
|
|
33
|
+
// and the newest Case JSON version that package reads. The writer stays at V30 (`writeVersion`): V31+ is read
|
|
34
|
+
// and migrated by the platform, not emitted here.
|
|
31
35
|
validationCeiling: {
|
|
32
|
-
caseSchemaVersion: '0.
|
|
33
|
-
formatVersion: '
|
|
36
|
+
caseSchemaVersion: '0.1173.0',
|
|
37
|
+
formatVersion: '32.0.4',
|
|
34
38
|
},
|
|
35
39
|
};
|
|
36
40
|
/**
|
|
37
41
|
* Which Case JSON schema versions `.schemaVersion()` may declare.
|
|
38
42
|
*
|
|
39
43
|
* ONE, and that is the honest answer rather than a placeholder. Case is a
|
|
40
|
-
* closed, whole-document schema: `@uipath/case-schema` ships a chain of
|
|
44
|
+
* closed, whole-document schema: `@uipath/case-schema` ships a chain of
|
|
41
45
|
* grammars (`case-schema-census.json`'s `versionChain`), each with its own
|
|
42
46
|
* forward migration, and a version is a claim that the entire document matches
|
|
43
47
|
* that grammar. This SDK emits the V30 grammar natively — the V30 rule schemas
|
package/dist/case/serialize.js
CHANGED
|
@@ -491,8 +491,18 @@ function applyPreservedIdentities(result, preservation) {
|
|
|
491
491
|
take(task, taskIdentity.id);
|
|
492
492
|
takeConditions(task?.entryConditions, taskIdentity.entryConditions);
|
|
493
493
|
(taskIdentity.inputs ?? []).forEach((row, index) => take(task?.data?.inputs?.[index], row.id));
|
|
494
|
-
|
|
495
|
-
|
|
494
|
+
const outputRows = task?.data?.outputs ?? [];
|
|
495
|
+
const wantedRows = taskIdentity.outputs ?? [];
|
|
496
|
+
// Match by name when unique on both sides, else by position.
|
|
497
|
+
const unique = (names, name) => names.filter((n) => n === name).length === 1;
|
|
498
|
+
const currentNames = outputRows.map((r) => r?.name);
|
|
499
|
+
const wantedNames = wantedRows.map((r) => r.name);
|
|
500
|
+
const named = new Set(wantedRows.filter((r) => unique(wantedNames, r.name) && unique(currentNames, r.name)).map((r) => r.name));
|
|
501
|
+
wantedRows.forEach((row, index) => {
|
|
502
|
+
const target = named.has(row.name)
|
|
503
|
+
? outputRows.find((r) => r?.name === row.name)
|
|
504
|
+
// A positional match never takes a row a name match owns.
|
|
505
|
+
: named.has(outputRows[index]?.name) ? undefined : outputRows[index];
|
|
496
506
|
const currentId = target?.id;
|
|
497
507
|
take(target, row.id);
|
|
498
508
|
if (typeof currentId === 'string' && typeof row.id === 'string' && target?.value === currentId) {
|
|
@@ -839,6 +849,8 @@ function taskData(task, resolver, taskId, stageId, ids) {
|
|
|
839
849
|
data.outputs = task.outputs.map((o, i) => emitTaskOutput(o, elementId, ids, `${elementId}:out:${i}:${o.var}`, resolver));
|
|
840
850
|
return data;
|
|
841
851
|
}
|
|
852
|
+
case 'business-rule':
|
|
853
|
+
return businessRuleTaskData(task, resolver, `${stageId}-${taskId}`, ids);
|
|
842
854
|
case 'action': {
|
|
843
855
|
const a = task.action ?? {};
|
|
844
856
|
const data = {};
|
|
@@ -1094,6 +1106,76 @@ function emitTaskOutput(o, elementId, ids, seed, resolver) {
|
|
|
1094
1106
|
elementId,
|
|
1095
1107
|
};
|
|
1096
1108
|
}
|
|
1109
|
+
// ─── Business-rule task ───────────────────────────────────────────────────────
|
|
1110
|
+
/** The version a business-rule task carries: below v3 the engine cannot run the
|
|
1111
|
+
* `.uirule` package a BusinessRules project deploys (the case converter falls
|
|
1112
|
+
* back to v2 when the field is missing). Same constant as the CLI's
|
|
1113
|
+
* `BUSINESS_RULE_TASK_VERSION`. */
|
|
1114
|
+
const BUSINESS_RULE_TASK_VERSION = 'v3';
|
|
1115
|
+
/** The binding `resource` a business rule is bound by — the CLI's and Studio
|
|
1116
|
+
* Web's spelling. `businessRule` (the registry cache category / BPMN binding
|
|
1117
|
+
* pattern) is a different namespace, and a binding that uses it is not a
|
|
1118
|
+
* BusinessRule resource to the bindings_v2 reader. */
|
|
1119
|
+
const BUSINESS_RULE_RESOURCE = 'BusinessRule';
|
|
1120
|
+
/** Mint (once per resourceKey + attribute) one root `BusinessRule` binding. */
|
|
1121
|
+
function businessRuleBinding(resolver, ids, resourceKey, propertyAttribute, value) {
|
|
1122
|
+
for (const entry of resolver.bindingSink.values()) {
|
|
1123
|
+
if (entry.resource === BUSINESS_RULE_RESOURCE && entry.resourceKey === resourceKey
|
|
1124
|
+
&& entry.propertyAttribute === propertyAttribute)
|
|
1125
|
+
return entry.id;
|
|
1126
|
+
}
|
|
1127
|
+
const id = ids.make('b', 8, `binding:${BUSINESS_RULE_RESOURCE}:${resourceKey}:${propertyAttribute}`);
|
|
1128
|
+
resolver.bindingSink.set(id, {
|
|
1129
|
+
id,
|
|
1130
|
+
name: propertyAttribute,
|
|
1131
|
+
type: 'string',
|
|
1132
|
+
resource: BUSINESS_RULE_RESOURCE,
|
|
1133
|
+
resourceKey,
|
|
1134
|
+
default: value,
|
|
1135
|
+
propertyAttribute,
|
|
1136
|
+
});
|
|
1137
|
+
return id;
|
|
1138
|
+
}
|
|
1139
|
+
/**
|
|
1140
|
+
* The `data` of a `business-rule` task, as Studio Web writes it and as the
|
|
1141
|
+
* CLI's `tasks describe --type business-rule` + splice produce it:
|
|
1142
|
+
*
|
|
1143
|
+
* - `name` / `folderPath` are `=bindings.<id>` references to a `BusinessRule`
|
|
1144
|
+
* binding pair keyed `<folder>.<name>` (the runtime resolves the rule through
|
|
1145
|
+
* them; `validate --strict` refuses literals);
|
|
1146
|
+
* - `version: 'v3'`;
|
|
1147
|
+
* - `outputs` always starts with `output` (`source: '=result'`, the whole
|
|
1148
|
+
* decision-keyed result) and `Error` (`source: '=Error'`), followed by the
|
|
1149
|
+
* author's extract rows, whose sources read a field of the result
|
|
1150
|
+
* (`=<Decision>.<column>`).
|
|
1151
|
+
*/
|
|
1152
|
+
function businessRuleTaskData(task, resolver, elementId, ids) {
|
|
1153
|
+
const ref = task.ref;
|
|
1154
|
+
const resourceKey = `${ref.folderPath}.${ref.name}`;
|
|
1155
|
+
const nameId = businessRuleBinding(resolver, ids, resourceKey, 'name', ref.name);
|
|
1156
|
+
const folderId = businessRuleBinding(resolver, ids, resourceKey, 'folderPath', ref.folderPath);
|
|
1157
|
+
const ownRow = (name, source, seed, extra = {}) => {
|
|
1158
|
+
const slot = ids.make('v', 8, `${elementId}:${seed}`);
|
|
1159
|
+
return { name, type: 'jsonSchema', id: slot, var: slot, value: slot, source, target: `=${slot}`, elementId, ...extra };
|
|
1160
|
+
};
|
|
1161
|
+
const resultSchema = task.businessRule?.resultSchema;
|
|
1162
|
+
const outputs = [
|
|
1163
|
+
ownRow('output', '=result', 'br:output', resultSchema === undefined ? {} : { _jsonSchema: resultSchema }),
|
|
1164
|
+
// The CLI's `buildErrorOutput()` row after `addVarIdsToInputsOutputs`:
|
|
1165
|
+
// `displayName`, and the error schema as both `_jsonSchema` and `body`.
|
|
1166
|
+
ownRow('Error', '=Error', 'br:error', {
|
|
1167
|
+
displayName: 'Error', _jsonSchema: structuredClone(ERROR_OUTPUT_SCHEMA), body: structuredClone(ERROR_OUTPUT_SCHEMA),
|
|
1168
|
+
}),
|
|
1169
|
+
...(task.outputs ?? []).map((o, i) => emitTaskOutput(o, elementId, ids, `${elementId}:out:${i}:${o.var}`, resolver)),
|
|
1170
|
+
];
|
|
1171
|
+
return {
|
|
1172
|
+
name: `=bindings.${nameId}`,
|
|
1173
|
+
folderPath: `=bindings.${folderId}`,
|
|
1174
|
+
version: BUSINESS_RULE_TASK_VERSION,
|
|
1175
|
+
inputs: (task.inputs ?? []).map((inp, i) => emitTaskInput(inp, elementId, ids, `${elementId}:in:${i}:${inp.name}`)),
|
|
1176
|
+
outputs,
|
|
1177
|
+
};
|
|
1178
|
+
}
|
|
1097
1179
|
// ─── Connector task (execute-connector-activity) ──────────────────────────────
|
|
1098
1180
|
/**
|
|
1099
1181
|
* Build the `execute-connector-activity` `data` payload for an IS connector task,
|
|
@@ -1353,6 +1435,14 @@ function connectorOutputVar(resolver, base) {
|
|
|
1353
1435
|
resolver.connectorOutputCounts.set(base, occurrence);
|
|
1354
1436
|
return occurrence === 1 ? base : `${base}${occurrence}`;
|
|
1355
1437
|
}
|
|
1438
|
+
/** The `Error` output's schema: the designer's (and the CLI's) `ERROR_OUTPUT_SCHEMA`. */
|
|
1439
|
+
const ERROR_OUTPUT_SCHEMA = {
|
|
1440
|
+
type: 'object',
|
|
1441
|
+
properties: {
|
|
1442
|
+
code: { type: 'string' }, message: { type: 'string' }, detail: { type: 'string' },
|
|
1443
|
+
category: { type: 'string' }, status: { type: 'number' }, element: { type: 'string' },
|
|
1444
|
+
},
|
|
1445
|
+
};
|
|
1356
1446
|
function connectorOutputs(rc, elementId, resolver) {
|
|
1357
1447
|
const responseSchema = rc.entry.outputSchema
|
|
1358
1448
|
? schemaFromFields(rc.entry.outputSchema.fields ?? [])
|
|
@@ -1367,13 +1457,7 @@ function connectorOutputs(rc, elementId, resolver) {
|
|
|
1367
1457
|
},
|
|
1368
1458
|
{
|
|
1369
1459
|
name: 'Error', displayName: 'Error', type: 'jsonSchema', source: '=Error',
|
|
1370
|
-
body:
|
|
1371
|
-
type: 'object',
|
|
1372
|
-
properties: {
|
|
1373
|
-
code: { type: 'string' }, message: { type: 'string' }, detail: { type: 'string' },
|
|
1374
|
-
category: { type: 'string' }, status: { type: 'number' }, element: { type: 'string' },
|
|
1375
|
-
},
|
|
1376
|
-
},
|
|
1460
|
+
body: structuredClone(ERROR_OUTPUT_SCHEMA),
|
|
1377
1461
|
var: errorVar, id: errorVar, value: errorVar, target: `=${errorVar}`, elementId,
|
|
1378
1462
|
},
|
|
1379
1463
|
];
|
package/dist/schema-version.js
CHANGED
|
@@ -106,11 +106,16 @@ export function schemaVersionRefusal(policy, requested) {
|
|
|
106
106
|
if (isWritableSchemaVersion(policy, requested))
|
|
107
107
|
return undefined;
|
|
108
108
|
const writable = writableSchemaVersions(policy);
|
|
109
|
+
const newestWritable = writable.at(-1);
|
|
109
110
|
const direction = policy.latestKnown !== undefined && schemaVersionAtLeast(requested, policy.latestKnown)
|
|
110
111
|
? compareSchemaVersions(requested, policy.latestKnown) > 0
|
|
111
112
|
? `The platform's newest known ${family} schema version is ${policy.latestKnown}, so ${requested} is newer than anything this SDK has read.`
|
|
112
113
|
: `${requested} is the platform's current ${family} schema version, but this SDK build has not been taught to write it.`
|
|
113
|
-
:
|
|
114
|
+
: newestWritable !== undefined && compareSchemaVersions(requested, newestWritable) > 0
|
|
115
|
+
? `${requested} is a platform ${family} schema version newer than this build writes`
|
|
116
|
+
+ (policy.latestKnown !== undefined ? ` (the platform's current is ${policy.latestKnown})` : '')
|
|
117
|
+
+ '; this SDK build has not been taught to write it.'
|
|
118
|
+
: `${requested} is older than the ${writable.length === 1 ? 'one version' : 'versions'} this build writes.`;
|
|
114
119
|
return (`${method}("${requested}"): this SDK build writes ${family} schema ${writable.join(' / ')}. ${direction} `
|
|
115
120
|
+ `A document's version claims that the WHOLE document matches that schema, so declaring one this build cannot emit `
|
|
116
121
|
+ `would write a false claim rather than a different document. ${policy.migration}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uipath/maestro-builder-sdk",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.34.0",
|
|
4
4
|
"description": "Build UiPath Flow, Case, and BPMN artifacts by writing TypeScript.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://docs.uipath.com/maestro",
|
|
@@ -93,5 +93,5 @@
|
|
|
93
93
|
"@types/node": "^22.7.0",
|
|
94
94
|
"esbuild": "^0.28.1"
|
|
95
95
|
},
|
|
96
|
-
"gitref": "
|
|
96
|
+
"gitref": "aa9dc9a7c6f6adc8edbf4c20d0681307073bb53b"
|
|
97
97
|
}
|