@uipath/maestro-builder-sdk 6.47.1 → 6.47.2
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 +32 -32
- package/dist/api-members.md +153 -153
- package/dist/case/case-sdk.d.ts +31 -6
- package/dist/case/case-sdk.js +2 -2
- package/dist/case/check.js +10 -3
- package/dist/case/decompile.js +73 -59
- package/dist/case/external.d.ts +41 -2
- package/dist/case/external.js +56 -2
- package/dist/case/serialize.js +31 -58
- package/package.json +2 -2
package/dist/case/case-sdk.d.ts
CHANGED
|
@@ -412,22 +412,47 @@ export type WaitConnectorSpec = WaitConnectorPlaceholderSpec | EventSubscription
|
|
|
412
412
|
export type ConnectorSpecData = Extract<ActionSpec, {
|
|
413
413
|
kind: 'connector';
|
|
414
414
|
}>;
|
|
415
|
-
/**
|
|
416
|
-
|
|
415
|
+
/**
|
|
416
|
+
* The external agent's or automation's `executionType`, as Integration Service
|
|
417
|
+
* reports it for the connector object.
|
|
418
|
+
*
|
|
419
|
+
* @remarks
|
|
420
|
+
* This is a property of the connector object, not a choice about the case: copy
|
|
421
|
+
* it from the activity's `case spec` result
|
|
422
|
+
* (`Data.EssentialConfiguration.essentialConfiguration.executionType`). The Case
|
|
423
|
+
* Designer saves `sync` as the `Sync…Execution` service type and both `async`
|
|
424
|
+
* and `hybrid` as `Async…Execution`, and writes the value itself into the task's
|
|
425
|
+
* `executionType` context.
|
|
426
|
+
*
|
|
427
|
+
* `hybrid` is refused for now (EXTERNAL_TASK_HYBRID_UNSUPPORTED): the Designer
|
|
428
|
+
* also writes an event pair for it (`operation`, `eventMode`) that the connector
|
|
429
|
+
* library does not carry (#1387). Add a task on a hybrid object in Studio Web.
|
|
430
|
+
*
|
|
431
|
+
* It does not decide whether the stage waits for the task. A task the stage must
|
|
432
|
+
* not wait on is `.required(false)`, whatever its execution type. For example, a
|
|
433
|
+
* Snowflake Cortex Interact Agent is `sync` even when the stage moves on without
|
|
434
|
+
* it.
|
|
435
|
+
*/
|
|
436
|
+
export type ExternalExecutionMode = 'sync' | 'async' | 'hybrid';
|
|
417
437
|
/** Required wiring and typed inputs for an external agent/workflow invocation. */
|
|
418
438
|
export interface ExternalTaskOptions<I extends Record<string, unknown>> {
|
|
419
439
|
/** Symbolic Integration Service connection name declared in `bindings.json`. */
|
|
420
440
|
connection: string;
|
|
421
441
|
/** Symbolic Orchestrator folder binding name declared in `bindings.json`. */
|
|
422
442
|
folder: string;
|
|
423
|
-
/**
|
|
443
|
+
/**
|
|
444
|
+
* The connector object's `executionType` from its `case spec` result. Required:
|
|
445
|
+
* the connector library does not carry it yet (#1369), and a wrong value passes
|
|
446
|
+
* `validate` but runs the wrong contract. Not whether the stage waits: that is
|
|
447
|
+
* `.required(false)`. See {@link ExternalExecutionMode}.
|
|
448
|
+
*/
|
|
424
449
|
mode: ExternalExecutionMode;
|
|
425
450
|
/** Inputs statically checked by the generated connector descriptor. */
|
|
426
451
|
inputs: I;
|
|
427
452
|
}
|
|
428
453
|
/** Normalized descriptor and execution mode stored on a built external task. */
|
|
429
454
|
export interface ExternalTaskSpecData {
|
|
430
|
-
/**
|
|
455
|
+
/** The connector object's `executionType`. */
|
|
431
456
|
mode: ExternalExecutionMode;
|
|
432
457
|
/** Shared connector action identity, inputs, and symbolic bindings. */
|
|
433
458
|
connector: ConnectorSpecData;
|
|
@@ -934,7 +959,7 @@ declare class TaskBuilder {
|
|
|
934
959
|
* Invoke an external agent through its generated Integration Service descriptor.
|
|
935
960
|
*
|
|
936
961
|
* @param descriptor - An `AgentExecution` operation from a generated connector module.
|
|
937
|
-
* @param opts - Required connection/folder bindings,
|
|
962
|
+
* @param opts - Required connection/folder bindings, the object's execution type, and descriptor-typed inputs.
|
|
938
963
|
* @returns This builder, so calls chain.
|
|
939
964
|
*/
|
|
940
965
|
externalAgent<I extends Record<string, unknown>, O>(descriptor: ConnectorDescriptor<I, O>, opts: ExternalTaskOptions<I>): this;
|
|
@@ -942,7 +967,7 @@ declare class TaskBuilder {
|
|
|
942
967
|
* Invoke an external workflow through its generated Integration Service descriptor.
|
|
943
968
|
*
|
|
944
969
|
* @param descriptor - A `ProcessExecution` operation from a generated connector module.
|
|
945
|
-
* @param opts - Required connection/folder bindings,
|
|
970
|
+
* @param opts - Required connection/folder bindings, the object's execution type, and descriptor-typed inputs.
|
|
946
971
|
* @returns This builder, so calls chain.
|
|
947
972
|
*/
|
|
948
973
|
externalWorkflow<I extends Record<string, unknown>, O>(descriptor: ConnectorDescriptor<I, O>, opts: ExternalTaskOptions<I>): this;
|
package/dist/case/case-sdk.js
CHANGED
|
@@ -328,7 +328,7 @@ class TaskBuilder {
|
|
|
328
328
|
* Invoke an external agent through its generated Integration Service descriptor.
|
|
329
329
|
*
|
|
330
330
|
* @param descriptor - An `AgentExecution` operation from a generated connector module.
|
|
331
|
-
* @param opts - Required connection/folder bindings,
|
|
331
|
+
* @param opts - Required connection/folder bindings, the object's execution type, and descriptor-typed inputs.
|
|
332
332
|
* @returns This builder, so calls chain.
|
|
333
333
|
*/
|
|
334
334
|
externalAgent(descriptor, opts) {
|
|
@@ -338,7 +338,7 @@ class TaskBuilder {
|
|
|
338
338
|
* Invoke an external workflow through its generated Integration Service descriptor.
|
|
339
339
|
*
|
|
340
340
|
* @param descriptor - A `ProcessExecution` operation from a generated connector module.
|
|
341
|
-
* @param opts - Required connection/folder bindings,
|
|
341
|
+
* @param opts - Required connection/folder bindings, the object's execution type, and descriptor-typed inputs.
|
|
342
342
|
* @returns This builder, so calls chain.
|
|
343
343
|
*/
|
|
344
344
|
externalWorkflow(descriptor, opts) {
|
package/dist/case/check.js
CHANGED
|
@@ -6,7 +6,7 @@ import { schemaVersionRefusal } from '../schema-version.js';
|
|
|
6
6
|
import { caseJsonPreservation, caseJsonPreservationErrors } from './preserve.js';
|
|
7
7
|
import { EQUALS_EXPR_DIALECT, checkBindingLabels, checkConnectorContract, checkConnectorLookups, checkConnectorSchema, } from '../core/connector-checks.js';
|
|
8
8
|
import { checkEventResolution } from '../core/event-checks.js';
|
|
9
|
-
import { EXTERNAL_TASK_DESCRIPTOR_CONTRACT } from './external.js';
|
|
9
|
+
import { EXTERNAL_TASK_DESCRIPTOR_CONTRACT, EXTERNAL_TASK_HYBRID_UNSUPPORTED, externalHybridRefusal, isExternalExecutionMode } from './external.js';
|
|
10
10
|
import { isResourceLabelRefusal, resolveResourceRef } from './resource-identity.js';
|
|
11
11
|
const TYPE_NAMES = new Set(Object.values(types));
|
|
12
12
|
// audit-case-coverage: rule-slot table start
|
|
@@ -571,11 +571,18 @@ function checkStage(stage, diags, refStage, refPlacement, bindings) {
|
|
|
571
571
|
where: t.name,
|
|
572
572
|
});
|
|
573
573
|
else {
|
|
574
|
-
if (t.external.mode
|
|
574
|
+
if (!isExternalExecutionMode(t.external.mode))
|
|
575
575
|
diags.push({
|
|
576
576
|
level: 'error',
|
|
577
577
|
code: 'EXTERNAL_TASK_MODE',
|
|
578
|
-
message: `${family} task "${t.name}" mode must be "sync"
|
|
578
|
+
message: `${family} task "${t.name}" mode must be the connector object's executionType: "sync", "async" or "hybrid".`,
|
|
579
|
+
where: t.name,
|
|
580
|
+
});
|
|
581
|
+
else if (t.external.mode === 'hybrid')
|
|
582
|
+
diags.push({
|
|
583
|
+
level: 'error',
|
|
584
|
+
code: EXTERNAL_TASK_HYBRID_UNSUPPORTED,
|
|
585
|
+
message: externalHybridRefusal(`${family} task "${t.name}"`),
|
|
579
586
|
where: t.name,
|
|
580
587
|
});
|
|
581
588
|
if (!t.external.connector?.key?.trim() || !t.external.connector?.action?.trim())
|
package/dist/case/decompile.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { commentText } from '../core/comment-text.js';
|
|
2
2
|
import { tsLiteral, tsNumber } from '../core/ts-literal.js';
|
|
3
3
|
import { CASE_FORMAT_PROFILE, CASE_SCHEMA_VERSIONS } from './format-profile.js';
|
|
4
|
+
import { EXTERNAL_TASK_CONTEXT, externalDescriptorRefusal, externalHybridRefusal, externalServiceType, isExternalExecutionMode } from './external.js';
|
|
4
5
|
import { preserveSchemaVersion } from '../schema-version.js';
|
|
5
6
|
import { ownEntry } from '../core/own-entry.js';
|
|
6
7
|
import { isUnrestorableSlotId } from './preserve.js';
|
|
@@ -523,6 +524,42 @@ function connectorVersion(context) {
|
|
|
523
524
|
function toCamel(value) {
|
|
524
525
|
return value.replace(/_([a-z0-9])/gi, (_match, char) => String(char).toUpperCase());
|
|
525
526
|
}
|
|
527
|
+
/**
|
|
528
|
+
* A connector activity's authored inputs, lifted from its `pathParameters` /
|
|
529
|
+
* `queryParameters` / `body` input containers. A `body` key is the authored
|
|
530
|
+
* name; a path or query key is the camelCased wire name, mapped back to the
|
|
531
|
+
* operation's parameter name. Shared by the plain connector lift and the
|
|
532
|
+
* external task lift, so the two cannot drift.
|
|
533
|
+
*
|
|
534
|
+
* With `owner`, the lift is strict (the external task shape): a row that is not
|
|
535
|
+
* one of the three containers, or a container whose body is not an object, is
|
|
536
|
+
* refused. Without it, such rows are skipped, as the connector lift always did.
|
|
537
|
+
*/
|
|
538
|
+
function connectorInputs(slots, resolved, owner) {
|
|
539
|
+
const parameterByWireName = new Map();
|
|
540
|
+
for (const parameter of resolved.entry.operation?.parameters ?? [])
|
|
541
|
+
parameterByWireName.set(toCamel(String(parameter.name)), String(parameter.name));
|
|
542
|
+
const inputs = {};
|
|
543
|
+
for (const slot of slots) {
|
|
544
|
+
const name = String(slot?.name ?? '');
|
|
545
|
+
if (owner && !CONNECTOR_INPUT_CONTAINERS.has(name))
|
|
546
|
+
throw new Error(`${owner} has unsupported input row "${name}".`);
|
|
547
|
+
const body = slot?.body;
|
|
548
|
+
if (owner && body === undefined)
|
|
549
|
+
continue;
|
|
550
|
+
if (!body || typeof body !== 'object' || Array.isArray(body)) {
|
|
551
|
+
if (owner)
|
|
552
|
+
throw new Error(`${owner} input container "${name}" must carry an object body.`);
|
|
553
|
+
continue;
|
|
554
|
+
}
|
|
555
|
+
for (const [wireName, value] of Object.entries(body)) {
|
|
556
|
+
const authoredName = name === 'body' ? wireName : (parameterByWireName.get(wireName) ?? wireName);
|
|
557
|
+
inputs[authoredName] = value;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
return inputs;
|
|
561
|
+
}
|
|
562
|
+
const CONNECTOR_INPUT_CONTAINERS = new Set(['pathParameters', 'queryParameters', 'body']);
|
|
526
563
|
function connectorCall(task, refs, library) {
|
|
527
564
|
if (!library)
|
|
528
565
|
throw new Error(`connector task "${task.displayName ?? task.id ?? '?'}" needs the connector library; pass DecompileOptions.library or --library.`);
|
|
@@ -542,19 +579,7 @@ function connectorCall(task, refs, library) {
|
|
|
542
579
|
version: connectorVersion(context),
|
|
543
580
|
});
|
|
544
581
|
const resolved = library.resolve(identity.key, identity.action, identity.version, identity.object);
|
|
545
|
-
const
|
|
546
|
-
for (const parameter of resolved.entry.operation?.parameters ?? [])
|
|
547
|
-
parameterByWireName.set(toCamel(String(parameter.name)), String(parameter.name));
|
|
548
|
-
const inputs = {};
|
|
549
|
-
for (const slot of Array.isArray(data.inputs) ? data.inputs : []) {
|
|
550
|
-
const body = slot?.body;
|
|
551
|
-
if (!body || typeof body !== 'object' || Array.isArray(body))
|
|
552
|
-
continue;
|
|
553
|
-
for (const [wireName, value] of Object.entries(body)) {
|
|
554
|
-
const authoredName = slot.name === 'body' ? wireName : (parameterByWireName.get(wireName) ?? wireName);
|
|
555
|
-
inputs[authoredName] = value;
|
|
556
|
-
}
|
|
557
|
-
}
|
|
582
|
+
const inputs = connectorInputs(Array.isArray(data.inputs) ? data.inputs : [], resolved);
|
|
558
583
|
const connection = bindingName(context.get('connection')?.value, refs);
|
|
559
584
|
const folder = bindingName(context.get('folderKey')?.value, refs);
|
|
560
585
|
const options = opts([
|
|
@@ -565,6 +590,14 @@ function connectorCall(task, refs, library) {
|
|
|
565
590
|
]);
|
|
566
591
|
return `.connector(${tsLiteral(identity.key)}, ${tsLiteral(identity.action)}, ${tsLiteral(inputs)}${options ? `, ${options}` : ''})`;
|
|
567
592
|
}
|
|
593
|
+
/**
|
|
594
|
+
* Lift an External Agent / External Workflow task saved in the Case Designer's
|
|
595
|
+
* shape (the one `serialize` emits): a connector activity's context and input
|
|
596
|
+
* containers plus the object's `executionType`, which becomes `mode`. The
|
|
597
|
+
* service type must be the one that execution type gives, so a plan whose two
|
|
598
|
+
* disagree is refused rather than lifted to a source that would compile to
|
|
599
|
+
* something else.
|
|
600
|
+
*/
|
|
568
601
|
function externalCall(task, refs, library) {
|
|
569
602
|
const kind = task.type;
|
|
570
603
|
const owner = `${kind} task "${task.displayName ?? task.id ?? '?'}"`;
|
|
@@ -575,33 +608,24 @@ function externalCall(task, refs, library) {
|
|
|
575
608
|
const unknownData = Object.keys(data).find((name) => !allowed.has(name));
|
|
576
609
|
if (unknownData)
|
|
577
610
|
throw new Error(`${owner} has unsupported data field "${unknownData}".`);
|
|
578
|
-
if (!Array.isArray(data.bindings) || data.bindings.length !== 0)
|
|
611
|
+
if (data.bindings !== undefined && (!Array.isArray(data.bindings) || data.bindings.length !== 0))
|
|
579
612
|
throw new Error(`${owner} data.bindings must be an empty array; bindings live at case root.`);
|
|
580
|
-
const modes = kind === 'external-agent'
|
|
581
|
-
? new Map([
|
|
582
|
-
[CASE_FORMAT_PROFILE.externalAgentSyncServiceType, 'sync'],
|
|
583
|
-
[CASE_FORMAT_PROFILE.externalAgentAsyncServiceType, 'async'],
|
|
584
|
-
])
|
|
585
|
-
: new Map([
|
|
586
|
-
[CASE_FORMAT_PROFILE.externalWorkflowSyncServiceType, 'sync'],
|
|
587
|
-
[CASE_FORMAT_PROFILE.externalWorkflowAsyncServiceType, 'async'],
|
|
588
|
-
]);
|
|
589
|
-
const mode = modes.get(data.serviceType);
|
|
590
|
-
if (!mode)
|
|
591
|
-
throw new Error(`${owner} has unsupported serviceType "${String(data.serviceType ?? '')}".`);
|
|
592
613
|
if (!Array.isArray(data.context))
|
|
593
614
|
throw new Error(`${owner} requires a resolved context array.`);
|
|
594
|
-
// A
|
|
595
|
-
//
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
const
|
|
602
|
-
if (
|
|
603
|
-
throw new Error(`${owner}
|
|
604
|
-
const
|
|
615
|
+
// A hybrid task carries an event pair the SDK cannot write back (#1387): refuse
|
|
616
|
+
// it by name, before its extra context rows are reported as unknown.
|
|
617
|
+
if (data.context.some((row) => row?.name === 'executionType' && row.value === 'hybrid'))
|
|
618
|
+
throw new Error(externalHybridRefusal(owner));
|
|
619
|
+
// Exactly the context rows serialize writes (the Designer's set): an unknown
|
|
620
|
+
// or repeated row would be dropped by the lift and lost on recompile.
|
|
621
|
+
const contextNames = data.context.map((row) => String(row?.name ?? ''));
|
|
622
|
+
const unknownContext = contextNames.find((name, at) => !EXTERNAL_TASK_CONTEXT.includes(name) || contextNames.indexOf(name) !== at);
|
|
623
|
+
if (unknownContext !== undefined)
|
|
624
|
+
throw new Error(`${owner} has unsupported or repeated context row "${unknownContext}".`);
|
|
625
|
+
const absentContext = EXTERNAL_TASK_CONTEXT.find((name) => !contextNames.includes(name));
|
|
626
|
+
if (absentContext)
|
|
627
|
+
throw new Error(`${owner} is missing context row "${absentContext}".`);
|
|
628
|
+
const context = contextMap(data);
|
|
605
629
|
const stringValue = (name) => {
|
|
606
630
|
const row = context.get(name);
|
|
607
631
|
if (row?.type !== 'string' || typeof row.value !== 'string' || !row.value)
|
|
@@ -617,36 +641,26 @@ function externalCall(task, refs, library) {
|
|
|
617
641
|
throw new Error(`${owner} context ${name} references missing root binding "${id}".`);
|
|
618
642
|
return bindingLabel(refs, id);
|
|
619
643
|
};
|
|
644
|
+
const mode = stringValue('executionType');
|
|
645
|
+
if (!isExternalExecutionMode(mode))
|
|
646
|
+
throw new Error(`${owner} has unsupported executionType "${mode}".`);
|
|
647
|
+
const serviceType = externalServiceType(kind, mode);
|
|
648
|
+
if (data.serviceType !== serviceType)
|
|
649
|
+
throw new Error(`${owner} has serviceType "${String(data.serviceType ?? '')}", but its executionType "${mode}" saves as "${serviceType}".`);
|
|
620
650
|
const identity = library.identifyAction({
|
|
621
651
|
connectorKey: stringValue('connectorKey'),
|
|
622
652
|
httpMethod: stringValue('method'),
|
|
623
653
|
endpoint: stringValue('path'),
|
|
654
|
+
objectName: stringValue('objectName'),
|
|
655
|
+
version: connectorVersion(context),
|
|
624
656
|
});
|
|
625
657
|
const resolved = library.resolve(identity.key, identity.action, identity.version, identity.object);
|
|
626
|
-
const
|
|
627
|
-
if (
|
|
628
|
-
throw new Error(`${owner}
|
|
629
|
-
if (stringValue('activity') !== resolved.activityTypeId)
|
|
630
|
-
throw new Error(`${owner} activity does not match its descriptor.`);
|
|
658
|
+
const refused = externalDescriptorRefusal(kind, resolved);
|
|
659
|
+
if (refused)
|
|
660
|
+
throw new Error(`${owner}: ${refused}`);
|
|
631
661
|
if (!Array.isArray(data.inputs))
|
|
632
662
|
throw new Error(`${owner} inputs must be an array.`);
|
|
633
|
-
const
|
|
634
|
-
const inputs = {};
|
|
635
|
-
for (const row of data.inputs) {
|
|
636
|
-
const name = String(row?.name ?? '');
|
|
637
|
-
if (!name || row.id !== name || row.target !== name || !fields.has(name))
|
|
638
|
-
throw new Error(`${owner} has unsupported input row "${name}".`);
|
|
639
|
-
inputs[name] = row.value;
|
|
640
|
-
}
|
|
641
|
-
const missing = resolved.fields.find((field) => field.required && !(field.name in inputs));
|
|
642
|
-
if (missing)
|
|
643
|
-
throw new Error(`${owner} is missing required input "${missing.name}".`);
|
|
644
|
-
if (!Array.isArray(data.outputs) || data.outputs.length !== 1)
|
|
645
|
-
throw new Error(`${owner} must carry exactly one response output.`);
|
|
646
|
-
const output = data.outputs[0];
|
|
647
|
-
if (output.name !== 'response' || output.type !== 'json' || output.source !== '.'
|
|
648
|
-
|| typeof output.var !== 'string' || output.id !== output.var)
|
|
649
|
-
throw new Error(`${owner} has an unsupported response output.`);
|
|
663
|
+
const inputs = connectorInputs(data.inputs, resolved, owner);
|
|
650
664
|
const descriptor = `{ nodeType: ${tsLiteral(resolved.nodeType)}, version: ${tsLiteral(resolved.version)} }`;
|
|
651
665
|
const options = opts([
|
|
652
666
|
['connection', tsLiteral(binding('connection'))],
|
package/dist/case/external.d.ts
CHANGED
|
@@ -8,6 +8,45 @@
|
|
|
8
8
|
* `buildConnectorInputs`, which `check` already runs as `connectorInputs`.
|
|
9
9
|
*/
|
|
10
10
|
import type { ResolvedConnector } from '../core/library.js';
|
|
11
|
+
import type { ExternalExecutionMode } from './case-sdk.js';
|
|
12
|
+
/**
|
|
13
|
+
* The context rows `serialize` writes on an external task: the set the Case
|
|
14
|
+
* Designer saves for a sync object (`uip`'s
|
|
15
|
+
* `tests/fixtures/external-tasks/designer-saved.json`, the Snowflake Cortex
|
|
16
|
+
* agent). `decompile` refuses a task with any other row, since the lift would
|
|
17
|
+
* drop it without a word. A `hybrid` task (which also carries `operation` and
|
|
18
|
+
* `eventMode`) is refused before this check; see {@link externalHybridRefusal}.
|
|
19
|
+
*/
|
|
20
|
+
export declare const EXTERNAL_TASK_CONTEXT: readonly string[];
|
|
21
|
+
/** Check's code for {@link externalHybridRefusal}. */
|
|
22
|
+
export declare const EXTERNAL_TASK_HYBRID_UNSUPPORTED = "EXTERNAL_TASK_HYBRID_UNSUPPORTED";
|
|
23
|
+
/**
|
|
24
|
+
* Why an external task on a `hybrid` object cannot be compiled or decompiled
|
|
25
|
+
* yet. The Case Designer saves such a task with an event pair (context
|
|
26
|
+
* `operation`, e.g. `TRIGGER_CREATED`, and `eventMode`, e.g. `polling`, also in
|
|
27
|
+
* the metadata's `activityPropertyConfiguration`) that it reads from live
|
|
28
|
+
* Integration Service metadata. The connector library does not carry that pair
|
|
29
|
+
* (#1387), so the SDK cannot write the task faithfully, and a guessed pair could
|
|
30
|
+
* deploy a task that never completes. `check`, `serialize` and `decompile` all
|
|
31
|
+
* refuse with this text.
|
|
32
|
+
*
|
|
33
|
+
* @param owner - The task as the message names it, e.g. `External Workflow task "Run"`.
|
|
34
|
+
* @returns The refusal.
|
|
35
|
+
*/
|
|
36
|
+
export declare function externalHybridRefusal(owner: string): string;
|
|
37
|
+
/** The execution types an external task accepts: the values Integration Service reports. */
|
|
38
|
+
export declare function isExternalExecutionMode(value: unknown): value is ExternalExecutionMode;
|
|
39
|
+
/**
|
|
40
|
+
* The `data.serviceType` the Case Designer saves for an external task of this
|
|
41
|
+
* execution type. Studio Web runs `hybrid` as `async` (`determineActualIntsvcType`),
|
|
42
|
+
* so both save as the `Async…Execution` type; the CLI's `externalServiceType`
|
|
43
|
+
* and its strict validator read the same table.
|
|
44
|
+
*
|
|
45
|
+
* @param kind - The task kind.
|
|
46
|
+
* @param mode - The connector object's `executionType`.
|
|
47
|
+
* @returns The service type.
|
|
48
|
+
*/
|
|
49
|
+
export declare function externalServiceType(kind: 'external-agent' | 'external-workflow', mode: ExternalExecutionMode): string;
|
|
11
50
|
/** Check's code for {@link externalDescriptorRefusal}. */
|
|
12
51
|
export declare const EXTERNAL_TASK_DESCRIPTOR_CONTRACT = "EXTERNAL_TASK_DESCRIPTOR_CONTRACT";
|
|
13
52
|
/**
|
|
@@ -17,8 +56,8 @@ export declare const EXTERNAL_TASK_DESCRIPTOR_CONTRACT = "EXTERNAL_TASK_DESCRIPT
|
|
|
17
56
|
* Workflow task a `ProcessExecution` one: the service type the task emits
|
|
18
57
|
* (`Intsvc.SyncAgentExecution`, …) is chosen by the family, and a descriptor of
|
|
19
58
|
* the other kind (or a plain connector action) would run the wrong contract.
|
|
20
|
-
* Both need the operation's `uiPathActivityTypeId`, which the task
|
|
21
|
-
*
|
|
59
|
+
* Both need the operation's `uiPathActivityTypeId`, which the task's `metadata`
|
|
60
|
+
* context carries.
|
|
22
61
|
*
|
|
23
62
|
* @param kind - The task kind.
|
|
24
63
|
* @param rc - What `library.resolve` returned for the task's descriptor.
|
package/dist/case/external.js
CHANGED
|
@@ -1,3 +1,57 @@
|
|
|
1
|
+
import { CASE_FORMAT_PROFILE } from './format-profile.js';
|
|
2
|
+
/**
|
|
3
|
+
* The context rows `serialize` writes on an external task: the set the Case
|
|
4
|
+
* Designer saves for a sync object (`uip`'s
|
|
5
|
+
* `tests/fixtures/external-tasks/designer-saved.json`, the Snowflake Cortex
|
|
6
|
+
* agent). `decompile` refuses a task with any other row, since the lift would
|
|
7
|
+
* drop it without a word. A `hybrid` task (which also carries `operation` and
|
|
8
|
+
* `eventMode`) is refused before this check; see {@link externalHybridRefusal}.
|
|
9
|
+
*/
|
|
10
|
+
export const EXTERNAL_TASK_CONTEXT = [
|
|
11
|
+
'connectorKey', 'connection', 'resourceKey', 'folderKey', 'objectName', 'method', 'path',
|
|
12
|
+
'executionType', 'metadata', 'activityConfigurationVersion',
|
|
13
|
+
];
|
|
14
|
+
/** Check's code for {@link externalHybridRefusal}. */
|
|
15
|
+
export const EXTERNAL_TASK_HYBRID_UNSUPPORTED = 'EXTERNAL_TASK_HYBRID_UNSUPPORTED';
|
|
16
|
+
/**
|
|
17
|
+
* Why an external task on a `hybrid` object cannot be compiled or decompiled
|
|
18
|
+
* yet. The Case Designer saves such a task with an event pair (context
|
|
19
|
+
* `operation`, e.g. `TRIGGER_CREATED`, and `eventMode`, e.g. `polling`, also in
|
|
20
|
+
* the metadata's `activityPropertyConfiguration`) that it reads from live
|
|
21
|
+
* Integration Service metadata. The connector library does not carry that pair
|
|
22
|
+
* (#1387), so the SDK cannot write the task faithfully, and a guessed pair could
|
|
23
|
+
* deploy a task that never completes. `check`, `serialize` and `decompile` all
|
|
24
|
+
* refuse with this text.
|
|
25
|
+
*
|
|
26
|
+
* @param owner - The task as the message names it, e.g. `External Workflow task "Run"`.
|
|
27
|
+
* @returns The refusal.
|
|
28
|
+
*/
|
|
29
|
+
export function externalHybridRefusal(owner) {
|
|
30
|
+
return (`${owner} is on a "hybrid" object, which Case cannot compile yet: the connector library does not carry ` +
|
|
31
|
+
`the event pair the Case Designer writes for it (operation, e.g. "TRIGGER_CREATED", and eventMode, e.g. "polling"), ` +
|
|
32
|
+
`so the task cannot be written faithfully. Add this task in Studio Web for now; ` +
|
|
33
|
+
`https://github.com/UiPath/builder-sdk/issues/1387 tracks the library change.`);
|
|
34
|
+
}
|
|
35
|
+
/** The execution types an external task accepts: the values Integration Service reports. */
|
|
36
|
+
export function isExternalExecutionMode(value) {
|
|
37
|
+
return value === 'sync' || value === 'async' || value === 'hybrid';
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The `data.serviceType` the Case Designer saves for an external task of this
|
|
41
|
+
* execution type. Studio Web runs `hybrid` as `async` (`determineActualIntsvcType`),
|
|
42
|
+
* so both save as the `Async…Execution` type; the CLI's `externalServiceType`
|
|
43
|
+
* and its strict validator read the same table.
|
|
44
|
+
*
|
|
45
|
+
* @param kind - The task kind.
|
|
46
|
+
* @param mode - The connector object's `executionType`.
|
|
47
|
+
* @returns The service type.
|
|
48
|
+
*/
|
|
49
|
+
export function externalServiceType(kind, mode) {
|
|
50
|
+
const sync = mode === 'sync';
|
|
51
|
+
if (kind === 'external-agent')
|
|
52
|
+
return sync ? CASE_FORMAT_PROFILE.externalAgentSyncServiceType : CASE_FORMAT_PROFILE.externalAgentAsyncServiceType;
|
|
53
|
+
return sync ? CASE_FORMAT_PROFILE.externalWorkflowSyncServiceType : CASE_FORMAT_PROFILE.externalWorkflowAsyncServiceType;
|
|
54
|
+
}
|
|
1
55
|
/** Check's code for {@link externalDescriptorRefusal}. */
|
|
2
56
|
export const EXTERNAL_TASK_DESCRIPTOR_CONTRACT = 'EXTERNAL_TASK_DESCRIPTOR_CONTRACT';
|
|
3
57
|
/**
|
|
@@ -7,8 +61,8 @@ export const EXTERNAL_TASK_DESCRIPTOR_CONTRACT = 'EXTERNAL_TASK_DESCRIPTOR_CONTR
|
|
|
7
61
|
* Workflow task a `ProcessExecution` one: the service type the task emits
|
|
8
62
|
* (`Intsvc.SyncAgentExecution`, …) is chosen by the family, and a descriptor of
|
|
9
63
|
* the other kind (or a plain connector action) would run the wrong contract.
|
|
10
|
-
* Both need the operation's `uiPathActivityTypeId`, which the task
|
|
11
|
-
*
|
|
64
|
+
* Both need the operation's `uiPathActivityTypeId`, which the task's `metadata`
|
|
65
|
+
* context carries.
|
|
12
66
|
*
|
|
13
67
|
* @param kind - The task kind.
|
|
14
68
|
* @param rc - What `library.resolve` returned for the task's descriptor.
|
package/dist/case/serialize.js
CHANGED
|
@@ -16,7 +16,7 @@ import { EQUALS_EXPR_DIALECT } from '../core/connector-checks.js';
|
|
|
16
16
|
import { bindingLabelRefusal } from '../core/binding-messages.js';
|
|
17
17
|
import { resolveEventWhere } from '../core/lookups.js';
|
|
18
18
|
import { resolveCaseSubscription } from './subscription.js';
|
|
19
|
-
import { externalDescriptorRefusal } from './external.js';
|
|
19
|
+
import { externalDescriptorRefusal, externalHybridRefusal, externalServiceType, isExternalExecutionMode } from './external.js';
|
|
20
20
|
import { CASE_FORMAT_PROFILE, CASE_SCHEMA_VERSIONS } from './format-profile.js';
|
|
21
21
|
import { isResourceLabelRefusal, resolveResourceRef, resourceIdentity } from './resource-identity.js';
|
|
22
22
|
import { ownEntry } from '../core/own-entry.js';
|
|
@@ -971,7 +971,7 @@ function taskData(task, resolver, taskId, stageId, ids) {
|
|
|
971
971
|
return connectorTaskData(task.connector, resolver, taskId, `Connector task "${task.name}"`);
|
|
972
972
|
case 'external-agent':
|
|
973
973
|
case 'external-workflow':
|
|
974
|
-
return externalTaskData(task.kind, task.external, resolver, `${task.kind === 'external-agent' ? 'External Agent' : 'External Workflow'} task "${task.name}"`);
|
|
974
|
+
return externalTaskData(task.kind, task.external, resolver, taskId, `${task.kind === 'external-agent' ? 'External Agent' : 'External Workflow'} task "${task.name}"`);
|
|
975
975
|
case 'wait-for-timer': {
|
|
976
976
|
if (task.timer?.duration)
|
|
977
977
|
return { timerType: 'timeDuration', timeDuration: task.timer.duration };
|
|
@@ -1360,7 +1360,7 @@ function businessRuleTaskData(task, resolver, elementId, ids) {
|
|
|
1360
1360
|
* the op's output schema. Connection/folder resolve through `bindings` and are
|
|
1361
1361
|
* referenced as `=bindings.<id>`, with the binding entry collected at case root.
|
|
1362
1362
|
*/
|
|
1363
|
-
function connectorTaskData(spec, resolver, elementId, where) {
|
|
1363
|
+
function connectorTaskData(spec, resolver, elementId, where, executionType) {
|
|
1364
1364
|
if (!resolver.library)
|
|
1365
1365
|
throw new Error(`connector task needs the connector library — pass { library } to serialize or use uip maestro case compile --library.`);
|
|
1366
1366
|
const rc = resolver.library.resolve(spec.key, spec.action, spec.version, spec.object);
|
|
@@ -1378,7 +1378,7 @@ function connectorTaskData(spec, resolver, elementId, where) {
|
|
|
1378
1378
|
const folderRef = folderBindingRef(resolver, spec.folder, connRef, { attribute: 'folder', where, target });
|
|
1379
1379
|
if (folderRef)
|
|
1380
1380
|
context.push(io('folderKey', 'string', { value: `=bindings.${folderRef.id}` }));
|
|
1381
|
-
context.push(io('objectName', 'string', { value: op.objectName ?? spec.action }), io('method', 'string', { value: transportHttpMethod(rc.httpMethod) }), io('path', 'string', { value: rc.endpoint }), io('metadata', 'json', { body: connectorMetadata(rc, op) }));
|
|
1381
|
+
context.push(io('objectName', 'string', { value: op.objectName ?? spec.action }), io('method', 'string', { value: transportHttpMethod(rc.httpMethod) }), io('path', 'string', { value: rc.endpoint }), io('metadata', 'json', { body: connectorMetadata(rc, op, executionType) }));
|
|
1382
1382
|
// inputs: the shared validator (`core/connector-inputs.ts`), the one Flow's and
|
|
1383
1383
|
// BPMN's serializers and every family's `check` run. It refuses a missing
|
|
1384
1384
|
// required field, an unknown or mistyped input, and swaps a `lookup()` token for
|
|
@@ -1412,66 +1412,35 @@ function connectorTaskData(spec, resolver, elementId, where) {
|
|
|
1412
1412
|
const outputs = connectorOutputs(rc, elementId, resolver);
|
|
1413
1413
|
return { serviceType: CASE_FORMAT_PROFILE.connectorActivityServiceType, context, inputs, outputs, bindings: [] };
|
|
1414
1414
|
}
|
|
1415
|
-
|
|
1415
|
+
/**
|
|
1416
|
+
* An External Agent / External Workflow task, in the shape the Case Designer
|
|
1417
|
+
* saves one (`uip`'s `tests/fixtures/external-tasks/designer-saved.json`, alpha
|
|
1418
|
+
* 2026-10-16): a connector activity's `data` — `connectorKey`, `connection`,
|
|
1419
|
+
* `resourceKey`, `folderKey`, `objectName`, `method`, `path`, `metadata`
|
|
1420
|
+
* context; `pathParameters` / `queryParameters` / `body` input containers;
|
|
1421
|
+
* `response` + `Error` outputs — plus the object's `executionType` (in the
|
|
1422
|
+
* context and in the metadata's configuration), `activityConfigurationVersion:
|
|
1423
|
+
* "v2"`, and the sync or async service type that execution type gives.
|
|
1424
|
+
*/
|
|
1425
|
+
function externalTaskData(kind, spec, resolver, elementId, where) {
|
|
1416
1426
|
if (!resolver.library)
|
|
1417
1427
|
throw new Error(`${kind} task needs the connector library — pass { library } to serialize or use uip maestro case compile --library.`);
|
|
1418
1428
|
const rc = resolver.library.resolve(spec.connector.key, spec.connector.action, spec.connector.version, spec.connector.object);
|
|
1419
1429
|
const refused = externalDescriptorRefusal(kind, rc);
|
|
1420
1430
|
if (refused)
|
|
1421
1431
|
throw new Error(refused);
|
|
1422
|
-
if (spec.mode
|
|
1423
|
-
throw new Error(`${kind} task mode must be "sync" or "
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
if (!connection || !folder)
|
|
1432
|
+
if (!isExternalExecutionMode(spec.mode))
|
|
1433
|
+
throw new Error(`${kind} task mode must be the connector object's executionType: "sync", "async" or "hybrid".`);
|
|
1434
|
+
if (spec.mode === 'hybrid')
|
|
1435
|
+
throw new Error(externalHybridRefusal(where));
|
|
1436
|
+
if (!spec.connector.connection || !spec.connector.folder)
|
|
1428
1437
|
throw new Error(`${kind} task requires non-empty connection and folder binding names.`);
|
|
1429
|
-
const
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
: CASE_FORMAT_PROFILE.externalWorkflowAsyncServiceType);
|
|
1436
|
-
// The inputs: the shared validator every connector activity runs (unknown,
|
|
1437
|
-
// missing required or mistyped input; a `lookup()` swapped for its recorded id,
|
|
1438
|
-
// or refused). Case `check` reports the same through `connectorInputs`.
|
|
1439
|
-
const fields = new Map(rc.fields.map((field) => [field.name, field]));
|
|
1440
|
-
const slots = buildConnectorInputs(rc, spec.connector.inputs, {
|
|
1441
|
-
dialect: EQUALS_EXPR_DIALECT,
|
|
1442
|
-
resolutions: resolver.library.lookupResolutions,
|
|
1443
|
-
lookups: resolver.library.lookupSpecs(spec.connector.key, spec.connector.action, spec.connector.version, spec.connector.object),
|
|
1444
|
-
});
|
|
1445
|
-
const resolved = {
|
|
1446
|
-
...slots.bodyParameters, ...slots.pathParameters, ...slots.queryParameters,
|
|
1447
|
-
};
|
|
1448
|
-
const responseVar = connectorOutputVar(resolver, 'response');
|
|
1449
|
-
return {
|
|
1450
|
-
serviceType,
|
|
1451
|
-
context: [
|
|
1452
|
-
io('activity', 'string', { value: rc.activityTypeId }),
|
|
1453
|
-
io('connectorKey', 'string', { value: rc.connectorKey }),
|
|
1454
|
-
io('connection', 'string', { value: `=bindings.${connection.id}` }),
|
|
1455
|
-
io('folderKey', 'string', { value: `=bindings.${folder.id}` }),
|
|
1456
|
-
io('method', 'string', { value: transportHttpMethod(rc.httpMethod) }),
|
|
1457
|
-
io('path', 'string', { value: rc.endpoint }),
|
|
1458
|
-
],
|
|
1459
|
-
inputs: Object.entries(spec.connector.inputs).map(([name, value]) => ({
|
|
1460
|
-
id: name,
|
|
1461
|
-
name,
|
|
1462
|
-
type: jsonType(fields.get(name)?.type),
|
|
1463
|
-
value: name in resolved ? resolved[name] : value,
|
|
1464
|
-
target: name,
|
|
1465
|
-
})),
|
|
1466
|
-
outputs: [{
|
|
1467
|
-
id: responseVar,
|
|
1468
|
-
name: 'response',
|
|
1469
|
-
type: 'json',
|
|
1470
|
-
source: '.',
|
|
1471
|
-
var: responseVar,
|
|
1472
|
-
}],
|
|
1473
|
-
bindings: [],
|
|
1474
|
-
};
|
|
1438
|
+
const data = connectorTaskData(spec.connector, resolver, elementId, where, spec.mode);
|
|
1439
|
+
const context = data.context;
|
|
1440
|
+
const metadataAt = context.findIndex((row) => row.name === 'metadata');
|
|
1441
|
+
context.splice(metadataAt, 0, io('executionType', 'string', { value: spec.mode }));
|
|
1442
|
+
context.push(io('activityConfigurationVersion', 'string', { value: 'v2' }));
|
|
1443
|
+
return { ...data, serviceType: externalServiceType(kind, spec.mode) };
|
|
1475
1444
|
}
|
|
1476
1445
|
/** A context/output name/value entry (the caseplan `InputOutput` shape). */
|
|
1477
1446
|
function io(name, type, extra) {
|
|
@@ -1579,7 +1548,7 @@ function folderBindingRef(resolver, name, connection, site) {
|
|
|
1579
1548
|
/** The connector `metadata` json blob: the FUNCTIONAL essentialConfiguration +
|
|
1580
1549
|
* activityTypeId. Designer cosmetics (packageId/activityColor/…) are omitted —
|
|
1581
1550
|
* the caseplan schema-validates without them (see design §C). */
|
|
1582
|
-
function connectorMetadata(rc, op) {
|
|
1551
|
+
function connectorMetadata(rc, op, executionType) {
|
|
1583
1552
|
const instanceParameters = {
|
|
1584
1553
|
connectorKey: rc.connectorKey,
|
|
1585
1554
|
objectName: op.objectName ?? rc.nodeType.split('.').pop(),
|
|
@@ -1596,6 +1565,9 @@ function connectorMetadata(rc, op) {
|
|
|
1596
1565
|
httpMethod: transportHttpMethod(rc.httpMethod),
|
|
1597
1566
|
path: rc.endpoint,
|
|
1598
1567
|
packageVersion: rc.version,
|
|
1568
|
+
// An external task's object states how it runs; the Designer saves it here
|
|
1569
|
+
// and beside the configuration. A plain connector activity has none.
|
|
1570
|
+
...(executionType ? { executionType } : {}),
|
|
1599
1571
|
},
|
|
1600
1572
|
};
|
|
1601
1573
|
return {
|
|
@@ -1603,6 +1575,7 @@ function connectorMetadata(rc, op) {
|
|
|
1603
1575
|
configuration: `=jsonString:${JSON.stringify(configuration)}`,
|
|
1604
1576
|
uiPathActivityTypeId: rc.activityTypeId ?? '',
|
|
1605
1577
|
errorState: { issues: [] },
|
|
1578
|
+
...(executionType ? { executionType } : {}),
|
|
1606
1579
|
},
|
|
1607
1580
|
activityMetadata: {
|
|
1608
1581
|
activity: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uipath/maestro-builder-sdk",
|
|
3
|
-
"version": "6.47.
|
|
3
|
+
"version": "6.47.2",
|
|
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": "16b96902c3da22af8e0fc3cfc8a53edcc832f04c"
|
|
97
97
|
}
|