@uipath/maestro-builder-sdk 6.68.6 → 6.68.7
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 +33 -33
- package/dist/api-members.md +158 -158
- package/dist/bpmn/intsvc.js +10 -0
- package/dist/case/case-sdk.d.ts +22 -17
- package/dist/case/case-sdk.js +1 -1
- package/dist/case/check.d.ts +19 -0
- package/dist/case/check.js +20 -15
- package/dist/case/cli-library.js +12 -1
- package/dist/case/decompile.js +16 -3
- package/dist/case/external.d.ts +46 -0
- package/dist/case/external.js +79 -1
- package/dist/case/serialize.js +14 -12
- package/dist/core/refusals.d.ts +1 -0
- package/dist/core/refusals.js +1 -0
- package/dist/registry/library-build/enrich.d.ts +20 -0
- package/dist/registry/library-build/enrich.js +40 -0
- package/dist/registry/model/library.d.ts +10 -0
- package/package.json +2 -2
package/dist/bpmn/intsvc.js
CHANGED
|
@@ -191,6 +191,16 @@ export function createExternalTask(ctx, n) {
|
|
|
191
191
|
`${n.key}/${n.action} is "${String(op.subType ?? 'untyped')}". ` +
|
|
192
192
|
`The shipped library has very few of these — ${wanted === 'AgentExecution' ? '2' : '1'} operation(s).`);
|
|
193
193
|
}
|
|
194
|
+
// The object's execution type, when the library records it (#1369): a `mode`
|
|
195
|
+
// that contradicts it compiles the other contract, which validate accepts and
|
|
196
|
+
// the run gets wrong. Studio Web runs `hybrid` as `async`.
|
|
197
|
+
const recorded = op.executionType;
|
|
198
|
+
if (recorded === 'sync' || recorded === 'async' || recorded === 'hybrid') {
|
|
199
|
+
const runs = recorded === 'sync' ? 'sync' : 'async';
|
|
200
|
+
if (n.mode !== runs)
|
|
201
|
+
throw new CompileRefusal('EXTERNAL_TASK_MODE_MISMATCH', `external ${n.family} "${n.id}" has mode "${n.mode}", but the connector library records ${n.key}/${n.action}'s ` +
|
|
202
|
+
`executionType as "${recorded}", which runs ${runs}; the node would run the wrong contract. Use mode: "${runs}".`);
|
|
203
|
+
}
|
|
194
204
|
const conn = connectorBindingRef(ctx, n.connection, 'Connection', 'ConnectionId', `${rc.connectorKey} connection`);
|
|
195
205
|
const folder = connectorBindingRef(ctx, n.folder, 'Connection', 'folderKey', 'FolderKey', conn?.resourceKey);
|
|
196
206
|
if (!conn || !folder) {
|
package/dist/case/case-sdk.d.ts
CHANGED
|
@@ -430,9 +430,12 @@ export type ConnectorSpecData = Extract<ActionSpec, {
|
|
|
430
430
|
* reports it for the connector object.
|
|
431
431
|
*
|
|
432
432
|
* @remarks
|
|
433
|
-
* This is a property of the connector object, not a choice about the case
|
|
434
|
-
* it
|
|
435
|
-
*
|
|
433
|
+
* This is a property of the connector object, not a choice about the case. The
|
|
434
|
+
* connector library records it for the object when it was built or prepared
|
|
435
|
+
* from Integration Service metadata that reports it, and compile then takes it
|
|
436
|
+
* from there: leave `mode` out. Otherwise copy it from the activity's `case spec`
|
|
437
|
+
* result (`Data.EssentialConfiguration.essentialConfiguration.executionType`).
|
|
438
|
+
* A `mode` the library contradicts is refused (EXTERNAL_TASK_MODE_MISMATCH). The Case
|
|
436
439
|
* Designer saves `sync` as the `Sync…Execution` service type and both `async`
|
|
437
440
|
* and `hybrid` as `Async…Execution`, and writes the value itself into the task's
|
|
438
441
|
* `executionType` context.
|
|
@@ -457,10 +460,10 @@ export type ExternalExecutionMode = 'sync' | 'async' | 'hybrid';
|
|
|
457
460
|
* the Case Designer reads it from the object's metadata (its first event mode
|
|
458
461
|
* and that mode's first event type) and saves it as the task's `operation` and
|
|
459
462
|
* `eventMode` context rows, and as `eventType` / `eventMode` in the metadata's
|
|
460
|
-
* `activityPropertyConfiguration`.
|
|
461
|
-
*
|
|
462
|
-
*
|
|
463
|
-
* example, the Power Automate "Invoke a Flow" object (`hybrid`) answers with
|
|
463
|
+
* `activityPropertyConfiguration`. Like `mode`, compile takes it from the
|
|
464
|
+
* connector library when the library records it; otherwise copy it from the same
|
|
465
|
+
* two rows of the activity's `case spec` result (`caseShape.context`).
|
|
466
|
+
* `decompile` lifts it from a saved task. For example, the Power Automate "Invoke a Flow" object (`hybrid`) answers with
|
|
464
467
|
* `{ operation: 'TRIGGER_CREATED', mode: 'polling' }`.
|
|
465
468
|
*/
|
|
466
469
|
export interface ExternalEventPair {
|
|
@@ -476,16 +479,18 @@ export interface ExternalTaskOptions<I extends Record<string, unknown>> {
|
|
|
476
479
|
/** Symbolic Orchestrator folder binding name declared in `bindings.json`. */
|
|
477
480
|
folder: string;
|
|
478
481
|
/**
|
|
479
|
-
* The connector object's `executionType
|
|
480
|
-
*
|
|
481
|
-
* `
|
|
482
|
+
* The connector object's `executionType`. Leave it out when the connector
|
|
483
|
+
* library records it (compile reads it from there); otherwise copy it from the
|
|
484
|
+
* `case spec` result. Compile refuses a task with no mode from either
|
|
485
|
+
* (EXTERNAL_TASK_MODE), and one the library contradicts
|
|
486
|
+
* (EXTERNAL_TASK_MODE_MISMATCH). Not whether the stage waits: that is
|
|
482
487
|
* `.required(false)`. See {@link ExternalExecutionMode}.
|
|
483
488
|
*/
|
|
484
|
-
mode
|
|
489
|
+
mode?: ExternalExecutionMode;
|
|
485
490
|
/**
|
|
486
|
-
* The event an `async` or `hybrid` object answers with.
|
|
487
|
-
*
|
|
488
|
-
* {@link ExternalEventPair}.
|
|
491
|
+
* The event an `async` or `hybrid` object answers with. Leave it out when the
|
|
492
|
+
* connector library records it. A `hybrid` task needs one from either place;
|
|
493
|
+
* a `sync` one refuses it, since it answers inline. See {@link ExternalEventPair}.
|
|
489
494
|
*/
|
|
490
495
|
event?: ExternalEventPair;
|
|
491
496
|
/** Inputs statically checked by the generated connector descriptor. */
|
|
@@ -493,9 +498,9 @@ export interface ExternalTaskOptions<I extends Record<string, unknown>> {
|
|
|
493
498
|
}
|
|
494
499
|
/** Normalized descriptor and execution mode stored on a built external task. */
|
|
495
500
|
export interface ExternalTaskSpecData {
|
|
496
|
-
/** The connector object's `executionType
|
|
497
|
-
mode
|
|
498
|
-
/** The event an `async` or `hybrid` object answers with, when
|
|
501
|
+
/** The connector object's `executionType`, when authored (else the library's). */
|
|
502
|
+
mode?: ExternalExecutionMode;
|
|
503
|
+
/** The event an `async` or `hybrid` object answers with, when authored (else the library's). */
|
|
499
504
|
event?: ExternalEventPair;
|
|
500
505
|
/** Shared connector action identity, inputs, and symbolic bindings. */
|
|
501
506
|
connector: ConnectorSpecData;
|
package/dist/case/case-sdk.js
CHANGED
|
@@ -333,7 +333,7 @@ class TaskBuilder {
|
|
|
333
333
|
external(kind, descriptor, opts) {
|
|
334
334
|
this.setKind(kind);
|
|
335
335
|
this._external = {
|
|
336
|
-
mode: opts.mode,
|
|
336
|
+
...(opts.mode !== undefined ? { mode: opts.mode } : {}),
|
|
337
337
|
...(opts.event !== undefined ? { event: { ...opts.event } } : {}),
|
|
338
338
|
connector: makeConnector(descriptor, opts.inputs, {
|
|
339
339
|
connection: opts.connection,
|
package/dist/case/check.d.ts
CHANGED
|
@@ -52,6 +52,25 @@ export type CaseCheckOpts = Pick<ConnectorCheckOpts, 'connectorResolveError' | '
|
|
|
52
52
|
version?: string;
|
|
53
53
|
object?: string;
|
|
54
54
|
}) => string | undefined;
|
|
55
|
+
/**
|
|
56
|
+
* What Case `compile` would refuse an External Agent / External Workflow
|
|
57
|
+
* task's mode and event with, judged against what the library records for
|
|
58
|
+
* the object (`externalExecution`): EXTERNAL_TASK_MODE (no mode from the
|
|
59
|
+
* author or the library), EXTERNAL_TASK_MODE_MISMATCH, EXTERNAL_TASK_EVENT.
|
|
60
|
+
* `undefined` when they are fine, or the descriptor does not resolve.
|
|
61
|
+
*/
|
|
62
|
+
externalExecutionError?: (owner: string, descriptor: {
|
|
63
|
+
key: string;
|
|
64
|
+
action: string;
|
|
65
|
+
version?: string;
|
|
66
|
+
object?: string;
|
|
67
|
+
}, authored: {
|
|
68
|
+
mode?: unknown;
|
|
69
|
+
event?: unknown;
|
|
70
|
+
}) => {
|
|
71
|
+
code: string;
|
|
72
|
+
message: string;
|
|
73
|
+
} | undefined;
|
|
55
74
|
subscriptionError?: (kind: 'trigger' | 'event', subscription: EventSubscription) => {
|
|
56
75
|
code: string;
|
|
57
76
|
message: string;
|
package/dist/case/check.js
CHANGED
|
@@ -7,7 +7,7 @@ import { schemaVersionRefusal } from '../schema-version.js';
|
|
|
7
7
|
import { caseJsonPreservation, caseJsonPreservationErrors, preservedBindings } from './preserve.js';
|
|
8
8
|
import { EQUALS_EXPR_DIALECT, checkBindingLabels, checkConnectorContract, checkConnectorLookups, checkConnectorSchema, } from '../core/connector-checks.js';
|
|
9
9
|
import { checkEventResolution } from '../core/event-checks.js';
|
|
10
|
-
import { EXTERNAL_TASK_DESCRIPTOR_CONTRACT,
|
|
10
|
+
import { EXTERNAL_TASK_DESCRIPTOR_CONTRACT, externalExecution } from './external.js';
|
|
11
11
|
import { isResourceLabelRefusal, resolveResourceRef } from './resource-identity.js';
|
|
12
12
|
import { taskShapeProblems } from './task-shape.js';
|
|
13
13
|
import { isConnectorPlaceholder } from './connector-placeholder.js';
|
|
@@ -303,7 +303,7 @@ export function check(built, opts = {}) {
|
|
|
303
303
|
// positive that blocks emit (this gate runs before serialization), so it must be
|
|
304
304
|
// re-derived from the serializer rather than from remembered probe results.
|
|
305
305
|
for (const stage of built.stages) {
|
|
306
|
-
checkStage(stage, diags, refStage, refPlacement, opts.bindings);
|
|
306
|
+
checkStage(stage, diags, refStage, refPlacement, opts.bindings, opts.externalExecutionError !== undefined);
|
|
307
307
|
stage.slaRules.forEach((s, i) => checkSla(s, `stage "${stage.label}" SLA #${i + 1}`, diags));
|
|
308
308
|
}
|
|
309
309
|
built.slaRules.forEach((s, i) => checkSla(s, `case SLA #${i + 1}`, diags));
|
|
@@ -325,7 +325,9 @@ export function check(built, opts = {}) {
|
|
|
325
325
|
* CONNECTOR_OBJECT_REQUIRED, CONNECTOR_OBJECT_NOT_GENERIC; then their inputs
|
|
326
326
|
* (`buildConnectorInputs`): CONNECTOR_INPUT, LOOKUP_UNRESOLVED;
|
|
327
327
|
* - an external task's resolved descriptor (`externalDescriptorRefusal`):
|
|
328
|
-
* EXTERNAL_TASK_DESCRIPTOR_CONTRACT;
|
|
328
|
+
* EXTERNAL_TASK_DESCRIPTOR_CONTRACT; and its mode and event against what the
|
|
329
|
+
* library records for the object (`externalExecution`): EXTERNAL_TASK_MODE,
|
|
330
|
+
* EXTERNAL_TASK_MODE_MISMATCH, EXTERNAL_TASK_EVENT;
|
|
329
331
|
* - an event trigger, a wait-for-connector task and a wait-for-connector rule
|
|
330
332
|
* resolve their subscription (`resolveCaseSubscription`): EVENT_UNKNOWN,
|
|
331
333
|
* EVENT_GENERIC_NO_OBJECT.
|
|
@@ -391,6 +393,9 @@ function checkLibraryConnectors(built, opts, diags) {
|
|
|
391
393
|
const refused = opts.externalDescriptorError?.(t.kind, spec);
|
|
392
394
|
if (refused !== undefined)
|
|
393
395
|
diags.push({ level: 'error', code: EXTERNAL_TASK_DESCRIPTOR_CONTRACT, message: `${where}: ${refused}`, where: t.name });
|
|
396
|
+
const execution = opts.externalExecutionError?.(where, spec, t.external);
|
|
397
|
+
if (execution !== undefined)
|
|
398
|
+
diags.push({ level: 'error', code: execution.code, message: execution.message, where: t.name });
|
|
394
399
|
}
|
|
395
400
|
if (t.kind === 'wait-for-connector' && isSubscription(t.waitConnector))
|
|
396
401
|
subscription('event', t.waitConnector, `Wait-for-connector task "${t.name}"`, t.name);
|
|
@@ -441,7 +446,9 @@ function isNilOrEmpty(value) {
|
|
|
441
446
|
return Object.keys(value).length === 0;
|
|
442
447
|
return false;
|
|
443
448
|
}
|
|
444
|
-
function checkStage(stage, diags, refStage, refPlacement, bindings
|
|
449
|
+
function checkStage(stage, diags, refStage, refPlacement, bindings,
|
|
450
|
+
/** A library judges external tasks' mode and event (`externalExecutionError`). */
|
|
451
|
+
externalJudge) {
|
|
445
452
|
const where = `stage "${stage.label}"`;
|
|
446
453
|
if (stage.exception && stage.required !== false)
|
|
447
454
|
diags.push({
|
|
@@ -622,17 +629,15 @@ function checkStage(stage, diags, refStage, refPlacement, bindings) {
|
|
|
622
629
|
where: t.name,
|
|
623
630
|
});
|
|
624
631
|
else {
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
});
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
if (refused)
|
|
635
|
-
diags.push({ level: 'error', code: EXTERNAL_TASK_EVENT, message: refused, where: t.name });
|
|
632
|
+
// The authored mode and event alone. With a library at hand, the
|
|
633
|
+
// library pass judges them against the object instead (and reports a
|
|
634
|
+
// missing mode), so they are judged here only without one.
|
|
635
|
+
const libraryJudges = externalJudge
|
|
636
|
+
&& !!t.external.connector?.key?.trim() && !!t.external.connector?.action?.trim();
|
|
637
|
+
if (!libraryJudges) {
|
|
638
|
+
const judged = externalExecution(`${family} task "${t.name}"`, t.external, undefined);
|
|
639
|
+
if (judged?.code !== undefined)
|
|
640
|
+
diags.push({ level: 'error', code: judged.code, message: judged.message, where: t.name });
|
|
636
641
|
}
|
|
637
642
|
if (!t.external.connector?.key?.trim() || !t.external.connector?.action?.trim())
|
|
638
643
|
diags.push({
|
package/dist/case/cli-library.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* both `case check` and `case compile`'s check pass call.
|
|
9
9
|
*/
|
|
10
10
|
import { connectorCheckOpts } from '../core/cli-library.js';
|
|
11
|
-
import { externalDescriptorRefusal } from './external.js';
|
|
11
|
+
import { externalDescriptorRefusal, externalExecution } from './external.js';
|
|
12
12
|
import { EVENT_GENERIC_NO_OBJECT, GenericEventNoObjectError, resolveCaseSubscription } from './subscription.js';
|
|
13
13
|
/**
|
|
14
14
|
* Case's check options from a library the CLI already opened, or `{}` without one.
|
|
@@ -48,6 +48,17 @@ export function caseCheckOpts(library, bindings) {
|
|
|
48
48
|
}
|
|
49
49
|
return externalDescriptorRefusal(kind, rc);
|
|
50
50
|
},
|
|
51
|
+
externalExecutionError: (owner, d, authored) => {
|
|
52
|
+
let rc;
|
|
53
|
+
try {
|
|
54
|
+
rc = library.resolve(d.key, d.action, d.version, d.object);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return undefined; // connectorResolveError's to report
|
|
58
|
+
}
|
|
59
|
+
const judged = externalExecution(owner, authored, rc.entry?.operation ?? {});
|
|
60
|
+
return judged?.code !== undefined ? { code: judged.code, message: judged.message } : undefined;
|
|
61
|
+
},
|
|
51
62
|
subscriptionError: (kind, sub) => {
|
|
52
63
|
try {
|
|
53
64
|
resolveCaseSubscription(library, kind, sub);
|
package/dist/case/decompile.js
CHANGED
|
@@ -2,7 +2,7 @@ import { commentText } from '../core/comment-text.js';
|
|
|
2
2
|
import { implicitInArgTrigger } from './in-arg-binding.js';
|
|
3
3
|
import { tsLiteral, tsNumber } from '../core/ts-literal.js';
|
|
4
4
|
import { CASE_FORMAT_PROFILE, CASE_SCHEMA_VERSIONS } from './format-profile.js';
|
|
5
|
-
import { EXTERNAL_TASK_CONTEXT, EXTERNAL_TASK_EVENT_CONTEXT, externalDescriptorRefusal, externalEventRefusal, externalServiceType, isExternalExecutionMode } from './external.js';
|
|
5
|
+
import { EXTERNAL_TASK_CONTEXT, EXTERNAL_TASK_EVENT_CONTEXT, externalDescriptorRefusal, externalEventRefusal, externalServiceType, isExternalExecutionMode, libraryExecution } from './external.js';
|
|
6
6
|
import { preserveSchemaVersion } from '../schema-version.js';
|
|
7
7
|
import { ownEntry } from '../core/own-entry.js';
|
|
8
8
|
import { isUnrestorableSlotId, taskFingerprint } from './preserve.js';
|
|
@@ -676,8 +676,8 @@ function externalCall(task, refs, library) {
|
|
|
676
676
|
const serviceType = externalServiceType(kind, mode);
|
|
677
677
|
if (data.serviceType !== serviceType)
|
|
678
678
|
throw new Error(`${owner} has serviceType "${String(data.serviceType ?? '')}", but its executionType "${mode}" saves as "${serviceType}".`);
|
|
679
|
-
// The event the object answers with, as saved
|
|
680
|
-
//
|
|
679
|
+
// The event the object answers with, as saved, judged by compile's event rule
|
|
680
|
+
// here, and against the library's record below (`externalExecution` in compile).
|
|
681
681
|
const event = eventRows.length ? { operation: stringValue('operation'), mode: stringValue('eventMode') } : undefined;
|
|
682
682
|
// A saved plan has no `event` option to drop, so a sync task with event rows
|
|
683
683
|
// gets its own text naming the rows; every other case is compile's rule.
|
|
@@ -699,6 +699,19 @@ function externalCall(task, refs, library) {
|
|
|
699
699
|
const refused = externalDescriptorRefusal(kind, resolved);
|
|
700
700
|
if (refused)
|
|
701
701
|
throw new Error(`${owner}: ${refused}`);
|
|
702
|
+
// Compile refuses a mode or event the library contradicts (#1369), so a task
|
|
703
|
+
// saved against a different record would lift to source that does not compile
|
|
704
|
+
// back: refuse it here, by name, before the author edits anything.
|
|
705
|
+
const recorded = libraryExecution(resolved.entry?.operation);
|
|
706
|
+
if (recorded.mode !== undefined && recorded.mode !== mode)
|
|
707
|
+
throw new Error(`${owner} is saved with executionType "${mode}", but the connector library records the object's ` +
|
|
708
|
+
`executionType as "${recorded.mode}", so the lifted source would not compile back. Re-save the task in Studio Web, ` +
|
|
709
|
+
`or rebuild the library (registry prepare) if the object changed.`);
|
|
710
|
+
if (event !== undefined && recorded.event !== undefined
|
|
711
|
+
&& (event.operation !== recorded.event.operation || event.mode !== recorded.event.mode))
|
|
712
|
+
throw new Error(`${owner} is saved with event ${JSON.stringify(event)}, but the connector library records the object's ` +
|
|
713
|
+
`event as ${JSON.stringify(recorded.event)}, so the lifted source would not compile back. Re-save the task in Studio Web, ` +
|
|
714
|
+
`or rebuild the library (registry prepare) if the object changed.`);
|
|
702
715
|
if (!Array.isArray(data.inputs))
|
|
703
716
|
throw new Error(`${owner} inputs must be an array.`);
|
|
704
717
|
const inputs = connectorInputs(data.inputs, resolved, owner);
|
package/dist/case/external.d.ts
CHANGED
|
@@ -58,6 +58,52 @@ export declare function isExternalExecutionMode(value: unknown): value is Extern
|
|
|
58
58
|
* @returns The service type.
|
|
59
59
|
*/
|
|
60
60
|
export declare function externalServiceType(kind: 'external-agent' | 'external-workflow', mode: ExternalExecutionMode): string;
|
|
61
|
+
/** Check's and compile's code when an authored `mode` disagrees with the library. */
|
|
62
|
+
export declare const EXTERNAL_TASK_MODE_MISMATCH = "EXTERNAL_TASK_MODE_MISMATCH";
|
|
63
|
+
/** A judged execution: the task's mode and event, or why it cannot be written. */
|
|
64
|
+
export type ExternalExecution = {
|
|
65
|
+
mode: ExternalExecutionMode;
|
|
66
|
+
event?: ExternalEventPair;
|
|
67
|
+
code?: undefined;
|
|
68
|
+
} | {
|
|
69
|
+
code: string;
|
|
70
|
+
message: string;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* The execution facts the connector library records for the object
|
|
74
|
+
* (`operation.executionType` and `operation.executionEvent`, from
|
|
75
|
+
* `registry build-library` / `registry prepare`, #1369). A value the SDK does
|
|
76
|
+
* not know is ignored, as if it were absent.
|
|
77
|
+
*/
|
|
78
|
+
export declare function libraryExecution(operation: unknown): {
|
|
79
|
+
mode?: ExternalExecutionMode;
|
|
80
|
+
event?: ExternalEventPair;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* The mode and event an external task is written with: what the author passed,
|
|
84
|
+
* else what the connector library records for the object. `check` and
|
|
85
|
+
* `serialize` both call this, so they refuse the same tasks with the same text.
|
|
86
|
+
*
|
|
87
|
+
* - `mode` comes from the author or the library. With neither, the task is
|
|
88
|
+
* refused (EXTERNAL_TASK_MODE): a guessed default would compile an `async`
|
|
89
|
+
* object to the sync contract without a word (#1370 was closed for that).
|
|
90
|
+
* - An authored `mode` the library contradicts is refused
|
|
91
|
+
* (EXTERNAL_TASK_MODE_MISMATCH): the plan would run the wrong contract.
|
|
92
|
+
* - `event` comes from the author or, for an `async` / `hybrid` object, the
|
|
93
|
+
* library; an authored one the library contradicts is refused
|
|
94
|
+
* (EXTERNAL_TASK_EVENT), and so is any pair {@link externalEventRefusal} refuses.
|
|
95
|
+
*
|
|
96
|
+
* @param owner - The task as the message names it, e.g. `External Workflow task "Run"`.
|
|
97
|
+
* @param authored - The task's authored `mode` and `event`.
|
|
98
|
+
* @param operation - The resolved library entry's `operation`, or `undefined`
|
|
99
|
+
* when no library is at hand (model-only `check`, which then judges only what
|
|
100
|
+
* was authored and reports no missing mode).
|
|
101
|
+
* @returns The mode and event, or the refusal.
|
|
102
|
+
*/
|
|
103
|
+
export declare function externalExecution(owner: string, authored: {
|
|
104
|
+
mode?: unknown;
|
|
105
|
+
event?: unknown;
|
|
106
|
+
}, operation: unknown): ExternalExecution | undefined;
|
|
61
107
|
/** Check's code for {@link externalDescriptorRefusal}. */
|
|
62
108
|
export declare const EXTERNAL_TASK_DESCRIPTOR_CONTRACT = "EXTERNAL_TASK_DESCRIPTOR_CONTRACT";
|
|
63
109
|
/**
|
package/dist/case/external.js
CHANGED
|
@@ -45,7 +45,8 @@ export function externalEventRefusal(owner, mode, event) {
|
|
|
45
45
|
return undefined;
|
|
46
46
|
return (`${owner} is on a "hybrid" object, which answers through an event: pass the event the object reports as ` +
|
|
47
47
|
`event: { operation, mode } (for example { operation: "TRIGGER_CREATED", mode: "polling" }, ` +
|
|
48
|
-
`the "operation" and "eventMode" rows of the case spec result's caseShape.context)
|
|
48
|
+
`the "operation" and "eventMode" rows of the case spec result's caseShape.context), or prepare the connector so the ` +
|
|
49
|
+
`library records it. Without it the task has nothing to wait on.`);
|
|
49
50
|
}
|
|
50
51
|
if (mode === 'sync')
|
|
51
52
|
return `${owner} is on a "sync" object, which answers inline and has no event; drop event, or fix mode.`;
|
|
@@ -79,6 +80,83 @@ export function externalServiceType(kind, mode) {
|
|
|
79
80
|
return sync ? CASE_FORMAT_PROFILE.externalAgentSyncServiceType : CASE_FORMAT_PROFILE.externalAgentAsyncServiceType;
|
|
80
81
|
return sync ? CASE_FORMAT_PROFILE.externalWorkflowSyncServiceType : CASE_FORMAT_PROFILE.externalWorkflowAsyncServiceType;
|
|
81
82
|
}
|
|
83
|
+
/** Check's and compile's code when an authored `mode` disagrees with the library. */
|
|
84
|
+
export const EXTERNAL_TASK_MODE_MISMATCH = 'EXTERNAL_TASK_MODE_MISMATCH';
|
|
85
|
+
/**
|
|
86
|
+
* The execution facts the connector library records for the object
|
|
87
|
+
* (`operation.executionType` and `operation.executionEvent`, from
|
|
88
|
+
* `registry build-library` / `registry prepare`, #1369). A value the SDK does
|
|
89
|
+
* not know is ignored, as if it were absent.
|
|
90
|
+
*/
|
|
91
|
+
export function libraryExecution(operation) {
|
|
92
|
+
const op = (operation ?? {});
|
|
93
|
+
const mode = isExternalExecutionMode(op.executionType) ? op.executionType : undefined;
|
|
94
|
+
const raw = op.executionEvent;
|
|
95
|
+
const event = mode !== undefined && mode !== 'sync' && typeof raw?.operation === 'string' && raw.operation
|
|
96
|
+
&& isExternalEventMode(raw.mode)
|
|
97
|
+
? { operation: raw.operation, mode: raw.mode }
|
|
98
|
+
: undefined;
|
|
99
|
+
return { ...(mode ? { mode } : {}), ...(event ? { event } : {}) };
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The mode and event an external task is written with: what the author passed,
|
|
103
|
+
* else what the connector library records for the object. `check` and
|
|
104
|
+
* `serialize` both call this, so they refuse the same tasks with the same text.
|
|
105
|
+
*
|
|
106
|
+
* - `mode` comes from the author or the library. With neither, the task is
|
|
107
|
+
* refused (EXTERNAL_TASK_MODE): a guessed default would compile an `async`
|
|
108
|
+
* object to the sync contract without a word (#1370 was closed for that).
|
|
109
|
+
* - An authored `mode` the library contradicts is refused
|
|
110
|
+
* (EXTERNAL_TASK_MODE_MISMATCH): the plan would run the wrong contract.
|
|
111
|
+
* - `event` comes from the author or, for an `async` / `hybrid` object, the
|
|
112
|
+
* library; an authored one the library contradicts is refused
|
|
113
|
+
* (EXTERNAL_TASK_EVENT), and so is any pair {@link externalEventRefusal} refuses.
|
|
114
|
+
*
|
|
115
|
+
* @param owner - The task as the message names it, e.g. `External Workflow task "Run"`.
|
|
116
|
+
* @param authored - The task's authored `mode` and `event`.
|
|
117
|
+
* @param operation - The resolved library entry's `operation`, or `undefined`
|
|
118
|
+
* when no library is at hand (model-only `check`, which then judges only what
|
|
119
|
+
* was authored and reports no missing mode).
|
|
120
|
+
* @returns The mode and event, or the refusal.
|
|
121
|
+
*/
|
|
122
|
+
export function externalExecution(owner, authored, operation) {
|
|
123
|
+
if (authored.mode !== undefined && !isExternalExecutionMode(authored.mode))
|
|
124
|
+
return {
|
|
125
|
+
code: 'EXTERNAL_TASK_MODE',
|
|
126
|
+
message: `${owner} mode must be the connector object's executionType: "sync", "async" or "hybrid".`,
|
|
127
|
+
};
|
|
128
|
+
const library = operation === undefined ? {} : libraryExecution(operation);
|
|
129
|
+
if (authored.mode !== undefined && library.mode !== undefined && authored.mode !== library.mode)
|
|
130
|
+
return {
|
|
131
|
+
code: EXTERNAL_TASK_MODE_MISMATCH,
|
|
132
|
+
message: `${owner} has mode "${authored.mode}", but the connector library records the object's executionType as ` +
|
|
133
|
+
`"${library.mode}"; the plan would run the wrong contract. Drop mode to use the library's, or fix it.`,
|
|
134
|
+
};
|
|
135
|
+
const mode = authored.mode ?? library.mode;
|
|
136
|
+
if (mode === undefined) {
|
|
137
|
+
if (operation === undefined)
|
|
138
|
+
return undefined; // model-only check: the library decides
|
|
139
|
+
return {
|
|
140
|
+
code: 'EXTERNAL_TASK_MODE',
|
|
141
|
+
message: `${owner} has no mode, and the connector library records no executionType for the object. ` +
|
|
142
|
+
`Pass mode: the object's executionType from its case spec result ` +
|
|
143
|
+
`(Data.EssentialConfiguration.essentialConfiguration.executionType), or rebuild the library with registry prepare.`,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
const authoredEvent = authored.event;
|
|
147
|
+
if (authoredEvent !== undefined && library.event !== undefined
|
|
148
|
+
&& (authoredEvent?.operation !== library.event.operation || authoredEvent?.mode !== library.event.mode))
|
|
149
|
+
return {
|
|
150
|
+
code: EXTERNAL_TASK_EVENT,
|
|
151
|
+
message: `${owner} has event ${JSON.stringify(authoredEvent)}, but the connector library records the object's event as ` +
|
|
152
|
+
`${JSON.stringify(library.event)}. Drop event to use the library's, or fix it.`,
|
|
153
|
+
};
|
|
154
|
+
const event = authoredEvent ?? (mode !== 'sync' ? library.event : undefined);
|
|
155
|
+
const refused = externalEventRefusal(owner, mode, event);
|
|
156
|
+
if (refused)
|
|
157
|
+
return { code: EXTERNAL_TASK_EVENT, message: refused };
|
|
158
|
+
return { mode, ...(event !== undefined ? { event } : {}) };
|
|
159
|
+
}
|
|
82
160
|
/** Check's code for {@link externalDescriptorRefusal}. */
|
|
83
161
|
export const EXTERNAL_TASK_DESCRIPTOR_CONTRACT = 'EXTERNAL_TASK_DESCRIPTOR_CONTRACT';
|
|
84
162
|
/**
|
package/dist/case/serialize.js
CHANGED
|
@@ -19,7 +19,7 @@ import { bindingLabelRefusal } from '../core/binding-messages.js';
|
|
|
19
19
|
import { resolveEventWhere } from '../core/lookups.js';
|
|
20
20
|
import { resolveCaseSubscription } from './subscription.js';
|
|
21
21
|
import { dedupeConditionNames } from './rule-names.js';
|
|
22
|
-
import { EXTERNAL_TASK_DESCRIPTOR_CONTRACT,
|
|
22
|
+
import { EXTERNAL_TASK_DESCRIPTOR_CONTRACT, externalDescriptorRefusal, externalExecution, externalServiceType, } from './external.js';
|
|
23
23
|
import { CASE_FORMAT_PROFILE, CASE_SCHEMA_VERSIONS, caseVersionMismatch } from './format-profile.js';
|
|
24
24
|
import { isResourceLabelRefusal, resolveResourceRef, resourceIdentity } from './resource-identity.js';
|
|
25
25
|
import { ownEntry } from '../core/own-entry.js';
|
|
@@ -1828,24 +1828,26 @@ function externalTaskData(kind, spec, resolver, elementId, where) {
|
|
|
1828
1828
|
const refused = externalDescriptorRefusal(kind, rc);
|
|
1829
1829
|
if (refused)
|
|
1830
1830
|
throw new CompileRefusal(EXTERNAL_TASK_DESCRIPTOR_CONTRACT, refused);
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1831
|
+
// The authored mode and event, else the library's (#1369): the same call check makes.
|
|
1832
|
+
const execution = externalExecution(where, spec, rc.entry?.operation ?? {});
|
|
1833
|
+
if (!execution)
|
|
1834
|
+
throw new Error(`internal SDK error: ${where} was judged without its library operation.`);
|
|
1835
|
+
if (execution.code !== undefined)
|
|
1836
|
+
throw new CompileRefusal(execution.code, execution.message);
|
|
1837
|
+
const { mode, event } = execution;
|
|
1836
1838
|
if (!spec.connector.connection || !spec.connector.folder)
|
|
1837
1839
|
throw new CompileRefusal(spec.connector.connection ? 'EXTERNAL_TASK_FOLDER' : 'EXTERNAL_TASK_CONNECTION', `${kind} task requires non-empty connection and folder binding names.`);
|
|
1838
|
-
const data = connectorTaskData(spec.connector, resolver, elementId, where,
|
|
1840
|
+
const data = connectorTaskData(spec.connector, resolver, elementId, where, mode, event);
|
|
1839
1841
|
const context = data.context;
|
|
1840
1842
|
const metadataAt = context.findIndex((row) => row.name === 'metadata');
|
|
1841
1843
|
// The Designer's order: the event pair (when the object answers through one),
|
|
1842
1844
|
// then the execution type, just before `metadata`.
|
|
1843
|
-
context.splice(metadataAt, 0, ...(
|
|
1844
|
-
io('operation', 'string', { value:
|
|
1845
|
-
io('eventMode', 'string', { value:
|
|
1846
|
-
] : []), io('executionType', 'string', { value:
|
|
1845
|
+
context.splice(metadataAt, 0, ...(event ? [
|
|
1846
|
+
io('operation', 'string', { value: event.operation }),
|
|
1847
|
+
io('eventMode', 'string', { value: event.mode }),
|
|
1848
|
+
] : []), io('executionType', 'string', { value: mode }));
|
|
1847
1849
|
context.push(io('activityConfigurationVersion', 'string', { value: 'v2' }));
|
|
1848
|
-
return { ...data, serviceType: externalServiceType(kind,
|
|
1850
|
+
return { ...data, serviceType: externalServiceType(kind, mode) };
|
|
1849
1851
|
}
|
|
1850
1852
|
/** A context/output name/value entry (the caseplan `InputOutput` shape). */
|
|
1851
1853
|
function io(name, type, extra) {
|
package/dist/core/refusals.d.ts
CHANGED
|
@@ -278,6 +278,7 @@ export declare const REFUSALS: {
|
|
|
278
278
|
readonly EXTERNAL_TASK_EVENT: "lowering";
|
|
279
279
|
readonly EXTERNAL_TASK_FOLDER: "lowering";
|
|
280
280
|
readonly EXTERNAL_TASK_MODE: "lowering";
|
|
281
|
+
readonly EXTERNAL_TASK_MODE_MISMATCH: "lowering";
|
|
281
282
|
readonly EXTRACT_SCHEMA_SHAPE: "lint";
|
|
282
283
|
readonly FAKE_JOIN: "lint";
|
|
283
284
|
readonly FILE_NOT_FOUND: "lowering";
|
package/dist/core/refusals.js
CHANGED
|
@@ -329,6 +329,7 @@ export const REFUSALS = {
|
|
|
329
329
|
EXTERNAL_TASK_EVENT: 'lowering',
|
|
330
330
|
EXTERNAL_TASK_FOLDER: 'lowering',
|
|
331
331
|
EXTERNAL_TASK_MODE: 'lowering',
|
|
332
|
+
EXTERNAL_TASK_MODE_MISMATCH: 'lowering',
|
|
332
333
|
EXTRACT_SCHEMA_SHAPE: 'lint',
|
|
333
334
|
FAKE_JOIN: 'lint',
|
|
334
335
|
FILE_NOT_FOUND: 'lowering',
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { LibraryEntry } from "../model/library.js";
|
|
2
2
|
import { type BuildContext } from "./context.js";
|
|
3
|
+
import { type Dict } from "./py.js";
|
|
3
4
|
/**
|
|
4
5
|
* Registry `httpMethod` (e.g. `GETBYID`) → a guess at the `is resources`
|
|
5
6
|
* operation name, for an entry whose canonical `operation.name` is empty.
|
|
@@ -18,6 +19,25 @@ export declare function discoverOperationName(ctx: BuildContext, entry: LibraryE
|
|
|
18
19
|
* payload; `objectDisplayName` and `display.operationLabel` fill gaps only.
|
|
19
20
|
*/
|
|
20
21
|
export declare function applyDescribe(entry: LibraryEntry, data: unknown): LibraryEntry;
|
|
22
|
+
/**
|
|
23
|
+
* Record an external agent's or automation's execution facts on its operation,
|
|
24
|
+
* from the describe payload (#1369, #1387).
|
|
25
|
+
*
|
|
26
|
+
* Integration Service keeps them on the object's metadata, not in the registry
|
|
27
|
+
* node: `executionType` (`sync`, `async` or `hybrid`) and, for an `async` or
|
|
28
|
+
* `hybrid` object, the event it answers with. `uip is resources describe`
|
|
29
|
+
* reports them as `ExecutionType`, `EventType` and `EventMode` (uip#5702,
|
|
30
|
+
* read with the same `externalExecutionOf` as `case spec`). They become
|
|
31
|
+
* `operation.executionType` and `operation.executionEvent` (`{ operation, mode }`),
|
|
32
|
+
* which Case and BPMN derive the task's `mode` and `event` from. The event is
|
|
33
|
+
* kept apart from `eventOperation` / `eventMode`, which mark a connector EVENT
|
|
34
|
+
* entry (a trigger) and which `identifyEvent` matches on.
|
|
35
|
+
*
|
|
36
|
+
* Only an `AgentExecution` / `ProcessExecution` operation gets them, and only
|
|
37
|
+
* what the payload states (an execution type outside the three is not stored): a describe from a CLI that does not report them
|
|
38
|
+
* leaves the entry as it was, so an older build stays byte-identical.
|
|
39
|
+
*/
|
|
40
|
+
export declare function applyExternalExecution(operation: Dict, data: unknown): void;
|
|
21
41
|
/**
|
|
22
42
|
* `enrich_entry`: augment a canonical entry with `is resources describe` data.
|
|
23
43
|
* On any failure the entry is returned as it was, so the pipeline degrades
|
|
@@ -78,6 +78,7 @@ export function applyDescribe(entry, data) {
|
|
|
78
78
|
const opCurated = pick(opData, "Curated", "curated");
|
|
79
79
|
if (pyTruthy(opCurated) && !pyTruthy(get(display, "operationLabel")))
|
|
80
80
|
display.operationLabel = opCurated;
|
|
81
|
+
applyExternalExecution(operation, data);
|
|
81
82
|
// Parameters (path / query) — raw shape, camelCase keys.
|
|
82
83
|
const params = pyOr(pick(data, "Parameters", "parameters"), []);
|
|
83
84
|
if (pyTruthy(params))
|
|
@@ -92,6 +93,45 @@ export function applyDescribe(entry, data) {
|
|
|
92
93
|
e.outputSchema = { fields: normalizeFieldKeys(responseFields) };
|
|
93
94
|
return entry;
|
|
94
95
|
}
|
|
96
|
+
/** The operation subtypes Case's and BPMN's external agent / workflow tasks run. */
|
|
97
|
+
const EXTERNAL_SUBTYPES = new Set(["AgentExecution", "ProcessExecution"]);
|
|
98
|
+
/** The execution types Integration Service reports, as Case and BPMN read them. */
|
|
99
|
+
const EXECUTION_TYPES = new Set(["sync", "async", "hybrid"]);
|
|
100
|
+
/**
|
|
101
|
+
* Record an external agent's or automation's execution facts on its operation,
|
|
102
|
+
* from the describe payload (#1369, #1387).
|
|
103
|
+
*
|
|
104
|
+
* Integration Service keeps them on the object's metadata, not in the registry
|
|
105
|
+
* node: `executionType` (`sync`, `async` or `hybrid`) and, for an `async` or
|
|
106
|
+
* `hybrid` object, the event it answers with. `uip is resources describe`
|
|
107
|
+
* reports them as `ExecutionType`, `EventType` and `EventMode` (uip#5702,
|
|
108
|
+
* read with the same `externalExecutionOf` as `case spec`). They become
|
|
109
|
+
* `operation.executionType` and `operation.executionEvent` (`{ operation, mode }`),
|
|
110
|
+
* which Case and BPMN derive the task's `mode` and `event` from. The event is
|
|
111
|
+
* kept apart from `eventOperation` / `eventMode`, which mark a connector EVENT
|
|
112
|
+
* entry (a trigger) and which `identifyEvent` matches on.
|
|
113
|
+
*
|
|
114
|
+
* Only an `AgentExecution` / `ProcessExecution` operation gets them, and only
|
|
115
|
+
* what the payload states (an execution type outside the three is not stored): a describe from a CLI that does not report them
|
|
116
|
+
* leaves the entry as it was, so an older build stays byte-identical.
|
|
117
|
+
*/
|
|
118
|
+
export function applyExternalExecution(operation, data) {
|
|
119
|
+
if (!EXTERNAL_SUBTYPES.has(String(get(operation, "subType") ?? "")))
|
|
120
|
+
return;
|
|
121
|
+
// Stored only as one of the three values Case and BPMN read, lowercased: a
|
|
122
|
+
// `Hybrid` kept verbatim would be ignored downstream and read as "no record".
|
|
123
|
+
const reported = pick(data, "ExecutionType", "executionType");
|
|
124
|
+
const executionType = typeof reported === "string" ? reported.trim().toLowerCase() : "";
|
|
125
|
+
if (!EXECUTION_TYPES.has(executionType))
|
|
126
|
+
return;
|
|
127
|
+
operation.executionType = executionType;
|
|
128
|
+
if (executionType === "sync")
|
|
129
|
+
return;
|
|
130
|
+
const eventType = pick(data, "EventType", "eventType");
|
|
131
|
+
const eventMode = pick(data, "EventMode", "eventMode");
|
|
132
|
+
if (typeof eventType === "string" && eventType && typeof eventMode === "string" && eventMode)
|
|
133
|
+
operation.executionEvent = { operation: eventType, mode: eventMode };
|
|
134
|
+
}
|
|
95
135
|
/**
|
|
96
136
|
* `enrich_entry`: augment a canonical entry with `is resources describe` data.
|
|
97
137
|
* On any failure the entry is returned as it was, so the pipeline degrades
|
|
@@ -85,6 +85,16 @@ export interface EntryOperation {
|
|
|
85
85
|
objectFromDiscovery?: boolean;
|
|
86
86
|
eventOperation?: string;
|
|
87
87
|
eventMode?: string;
|
|
88
|
+
/**
|
|
89
|
+
* An external agent's or automation's `executionType` (`sync`, `async`,
|
|
90
|
+
* `hybrid`), on an `AgentExecution` / `ProcessExecution` operation only.
|
|
91
|
+
*/
|
|
92
|
+
executionType?: string;
|
|
93
|
+
/** The event an `async` / `hybrid` external object answers with. */
|
|
94
|
+
executionEvent?: {
|
|
95
|
+
operation: string;
|
|
96
|
+
mode: string;
|
|
97
|
+
};
|
|
88
98
|
schemaAction?: SchemaAction | null;
|
|
89
99
|
dispatchStyle?: string;
|
|
90
100
|
paramGrammars?: unknown;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uipath/maestro-builder-sdk",
|
|
3
|
-
"version": "6.68.
|
|
3
|
+
"version": "6.68.7",
|
|
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",
|
|
@@ -100,5 +100,5 @@
|
|
|
100
100
|
"@types/node": "^22.7.0",
|
|
101
101
|
"esbuild": "^0.28.1"
|
|
102
102
|
},
|
|
103
|
-
"gitref": "
|
|
103
|
+
"gitref": "436dbc08c3130fcde3197adec572df61116f4ede"
|
|
104
104
|
}
|