@uipath/maestro-builder-sdk 6.70.9 → 6.71.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api-index.md +8 -8
- package/dist/api-members.md +37 -35
- package/dist/check.js +11 -11
- package/dist/core/event-subscription.d.ts +113 -0
- package/dist/core/event-subscription.js +356 -0
- package/dist/core/nodes/registry.d.ts +3 -1
- package/dist/core/nodes/registry.js +22 -3
- package/dist/core/refusals.d.ts +3 -0
- package/dist/core/refusals.js +3 -0
- package/dist/decompile.js +0 -7
- package/dist/flow-node-type.d.ts +25 -0
- package/dist/nodes/connector/flow/event-wait.d.ts +33 -0
- package/dist/nodes/connector/flow/event-wait.js +162 -0
- package/dist/nodes/connector/flow/family.d.ts +1 -1
- package/dist/nodes/connector/flow/family.js +3 -2
- package/dist/nodes/process/flow/check.js +16 -2
- package/dist/nodes/process/flow/node-type.js +19 -10
- package/dist/nodes/process/flow/refusals.js +1 -1
- package/dist/nodes/process/flow/spec.d.ts +28 -2
- package/dist/serialize.js +20 -391
- package/package.json +2 -2
package/dist/serialize.js
CHANGED
|
@@ -22,9 +22,7 @@ import { endOutcomeRefusal, fanInRefusal, hitlEndHazards, hitlFanInto } from './
|
|
|
22
22
|
import { resolveVersionCarried } from './core/nodes/versioned.js';
|
|
23
23
|
import { indexCarriedDefinitions } from './core/carried-definitions.js';
|
|
24
24
|
import { connectionConnectors } from './bindings-v2.js';
|
|
25
|
-
import { BindingRefusal, GUID_RE, bindingLabelRefusal
|
|
26
|
-
import { ByoaRefusal, byoaUnverified } from './core/byoa.js';
|
|
27
|
-
import { genericEventObjectRefusal } from './core/event-checks.js';
|
|
25
|
+
import { BindingRefusal, GUID_RE, bindingLabelRefusal } from './core/binding-messages.js';
|
|
28
26
|
import { OUTCOME_HANDLE_NODE_TYPES, assertHitlExitInvariant, hitlExitViolation } from './core/hitl-routing.js';
|
|
29
27
|
import { STICKY_NOTE_TYPE, STICKY_NOTE_TYPE_VERSION } from './core/definitionless-node-types.js';
|
|
30
28
|
import { placeholderPosition } from './node-placement.js';
|
|
@@ -32,7 +30,6 @@ import { hasExits } from './core/step-ports.js';
|
|
|
32
30
|
import { stopsAtEnd } from './flow-step-tree.js';
|
|
33
31
|
import { assertNodeEnvelope } from './core/node-envelope.js';
|
|
34
32
|
import { fnv1aX4Uuid, stableId } from './core/stable-id.js';
|
|
35
|
-
import { EVENT_FILTER_OPERATORS, readEventFilter, eventFilterProblem, eventFilterJmes, eventFilterTreeLeaf, jmesString, jmesStringProblem } from './core/event-filters.js';
|
|
36
33
|
import { FLOW_EXPR_DIALECT } from './core/connector-checks.js';
|
|
37
34
|
import { connectorInputErrors as coreConnectorInputErrors } from './core/connector-inputs.js';
|
|
38
35
|
/**
|
|
@@ -49,7 +46,7 @@ export function connectorInputErrors(rc, inputs, resolutions = {}, lookups = {})
|
|
|
49
46
|
render: (value) => renderDeep(value, NO_RENAME),
|
|
50
47
|
});
|
|
51
48
|
}
|
|
52
|
-
import { isLookupToken,
|
|
49
|
+
import { isLookupToken, } from './core/lookups.js';
|
|
53
50
|
import { migrateToSchemaVersion } from './migrate.js';
|
|
54
51
|
import { FLOW_SCHEMA_VERSIONS } from './format-profile.js';
|
|
55
52
|
import { resolveSchemaVersion } from './schema-version.js';
|
|
@@ -64,6 +61,7 @@ import { SUBFLOW_START_LABEL } from './core/subflow-start.js';
|
|
|
64
61
|
import { endContentKey } from './flow-end-content.js';
|
|
65
62
|
import { terminateStepClashMessage, terminateTwiceMessage } from './flow-terminate-names.js';
|
|
66
63
|
import { jsonClone } from './core/json-clone.js';
|
|
64
|
+
import { eventDetail, eventTarget, libraryRequiredForEvent, refuseUnverifiedByoa, resolveEvent, } from './core/event-subscription.js';
|
|
67
65
|
import { subNodeId } from './core/node-id-placeholder.js';
|
|
68
66
|
import { JOB_ATTACHMENT_REF, jobAttachmentDefinition } from './core/agent-sidecar.js';
|
|
69
67
|
// core-definitions.json is an object keyed by "<nodeType>@<version>".
|
|
@@ -510,44 +508,6 @@ function connectionStubReason(value) {
|
|
|
510
508
|
return 'not a GUID';
|
|
511
509
|
return undefined;
|
|
512
510
|
}
|
|
513
|
-
/** What `registry prepare` takes for an event subscription: its connector key and curated event name. */
|
|
514
|
-
function eventTarget(sub) {
|
|
515
|
-
return typeof sub.connector === 'string' && sub.connector !== ''
|
|
516
|
-
? { key: sub.connector, ...(typeof sub.event === 'string' && sub.event !== '' ? { action: sub.event } : {}) }
|
|
517
|
-
: undefined;
|
|
518
|
-
}
|
|
519
|
-
/**
|
|
520
|
-
* Throw `check`'s EVENT_BYOA_UNVERIFIED for a subscription whose event only
|
|
521
|
-
* fires on a BYOA connection and whose bound connection `prepare` never checked
|
|
522
|
-
* — the one condition in `core/byoa.ts`, fed from the same library and
|
|
523
|
-
* bindings, so a flow check refuses never compiles.
|
|
524
|
-
*
|
|
525
|
-
* `where` is check's spelling of the site (`trigger` for `onEvent`, entry points
|
|
526
|
-
* included; `waitForEvent "<step>"`), so the two print the same sentence.
|
|
527
|
-
*/
|
|
528
|
-
function refuseUnverifiedByoa(opts, where, sub) {
|
|
529
|
-
const library = opts.library;
|
|
530
|
-
if (!library || typeof library.eventFacts !== 'function')
|
|
531
|
-
return;
|
|
532
|
-
const object = typeof sub.object === 'string' && sub.object !== '' ? sub.object : undefined;
|
|
533
|
-
const message = byoaUnverified(where, { connector: sub.connector, event: sub.event, ...(object ? { object } : {}), connection: sub.connection }, library.eventFacts(sub.connector, sub.event, object), library.byoaVerifications, opts.bindings);
|
|
534
|
-
if (message)
|
|
535
|
-
throw new ByoaRefusal(message);
|
|
536
|
-
}
|
|
537
|
-
/**
|
|
538
|
-
* Refuse a connector-bound node (connector step, event trigger, `.entryPoint`
|
|
539
|
-
* onEvent, `waitForEvent`) that names no `connection` or no `folder` label.
|
|
540
|
-
* (An inline agent's connector tool is #875's: `check` refuses it as
|
|
541
|
-
* INLINE_AGENT_TOOL_CONNECTOR_NO_CONNECTION, and serialize leaves it unbound.)
|
|
542
|
-
* `resolveBinding` returns `undefined` for an absent label, which used to reach
|
|
543
|
-
* the node as `detail.connectionId: null` with no binding — valid to compile,
|
|
544
|
-
* refused by `flow validate` (flow-builder-sdk#890): BINDING_MISSING.
|
|
545
|
-
*/
|
|
546
|
-
function requireBindingPair(where, labels, target) {
|
|
547
|
-
const missing = missingBindingLabels(labels);
|
|
548
|
-
if (missing.length > 0)
|
|
549
|
-
throw new BindingRefusal('BINDING_MISSING', bindingMissingMessage(where, missing, target));
|
|
550
|
-
}
|
|
551
511
|
/**
|
|
552
512
|
* Resolve a symbolic connection/folder name to the resource key that is inlined
|
|
553
513
|
* as `connectionId` / `connectionFolderKey`.
|
|
@@ -627,6 +587,14 @@ function resolveBinding(opts, name, attribute, where, target) {
|
|
|
627
587
|
}
|
|
628
588
|
return value;
|
|
629
589
|
}
|
|
590
|
+
/** What the shared event-subscription emission (`core/event-subscription.ts`) needs from these options. */
|
|
591
|
+
function eventEnv(opts) {
|
|
592
|
+
return {
|
|
593
|
+
...(opts.library !== undefined ? { library: opts.library } : {}),
|
|
594
|
+
...(opts.bindings !== undefined ? { bindings: opts.bindings } : {}),
|
|
595
|
+
resolveBinding: (name, attribute, where, target) => resolveBinding(opts, name, attribute, where, target),
|
|
596
|
+
};
|
|
597
|
+
}
|
|
630
598
|
/** An entry answers to `name` but carries no resourceKey or default — the placeholder route, still a warning. */
|
|
631
599
|
function declaredWithoutKey(bindings, name) {
|
|
632
600
|
return (bindings?.declared?.() ?? []).includes(name) || bindings?.entry?.(name) !== undefined;
|
|
@@ -717,51 +685,6 @@ export function resolveContributionDefinition(ref, requestedVersion, where) {
|
|
|
717
685
|
}
|
|
718
686
|
throw new CompileRefusal('CONTRIBUTION_INVALID', `${where}: unknown DefinitionReference source "${ref.source}".`);
|
|
719
687
|
}
|
|
720
|
-
/**
|
|
721
|
-
* `library.resolveEvent` for one subscription, or EVENT_UNKNOWN: whatever it
|
|
722
|
-
* throws (a connector or event the library does not carry, a version or object
|
|
723
|
-
* it does not resolve) is that one condition, an event compile cannot place.
|
|
724
|
-
* `where` names the site as `check` always has (`trigger`, `waitForEvent "x"`).
|
|
725
|
-
*/
|
|
726
|
-
function resolveEvent(library, kind, sub, where) {
|
|
727
|
-
try {
|
|
728
|
-
return library.resolveEvent(kind, sub.connector, sub.event, sub.version, sub.object);
|
|
729
|
-
}
|
|
730
|
-
catch (error) {
|
|
731
|
-
if (error instanceof Error && error.message.startsWith('internal SDK error:'))
|
|
732
|
-
throw error;
|
|
733
|
-
throw new CompileRefusal('EVENT_UNKNOWN', `${where}: ${error instanceof Error ? error.message : String(error)}`);
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
/**
|
|
737
|
-
* LIBRARY_REQUIRED for an event subscription at `site`, after the refusals that
|
|
738
|
-
* need no library: its binding labels, judged as `eventDetail` judges them, so a
|
|
739
|
-
* run without a library (`check`'s inner loop) still hears about them. The
|
|
740
|
-
* refusal carries the connection the node is bound to, so its collect-mode
|
|
741
|
-
* stand-in still takes part in the file-wide connection rule (`connectionConnectors`).
|
|
742
|
-
*/
|
|
743
|
-
function libraryRequiredForEvent(opts, sub, nodeId, site, call) {
|
|
744
|
-
let use;
|
|
745
|
-
if (sub !== null && typeof sub === 'object') {
|
|
746
|
-
// With no library no parameter is declared, so every `where` key lands in
|
|
747
|
-
// eventParameters and folds into the match expression, exactly as
|
|
748
|
-
// `eventDetail` places an undeclared key. A lookup token is a value only
|
|
749
|
-
// a library resolves; it is not judged here.
|
|
750
|
-
if (sub.where !== null && typeof sub.where === 'object') {
|
|
751
|
-
const scope = Object.fromEntries(Object.entries(sub.where).filter(([, v]) => !isLookupToken(v)));
|
|
752
|
-
eventScopeClauses(flattenWhere(scope, new Set()), nodeId);
|
|
753
|
-
}
|
|
754
|
-
if (Array.isArray(sub.filters))
|
|
755
|
-
eventFilterReads(sub.filters, nodeId);
|
|
756
|
-
requireBindingPair(site, sub, eventTarget(sub));
|
|
757
|
-
const connection = resolveBinding(opts, sub.connection, 'connection', `event node "${nodeId}"`, eventTarget(sub));
|
|
758
|
-
resolveBinding(opts, sub.folder, 'folder', `event node "${nodeId}"`, eventTarget(sub));
|
|
759
|
-
const connector = eventTarget(sub)?.key;
|
|
760
|
-
if (connection !== undefined && connector !== undefined)
|
|
761
|
-
use = { connector, connection };
|
|
762
|
-
}
|
|
763
|
-
return new LibraryRequiredRefusal(`${call} needs a library (pass --library / set $FLOW_SDK_LIBRARY_JSON).`, use);
|
|
764
|
-
}
|
|
765
688
|
/** The trigger kinds a `.trigger()` or `.entryPoint()` spec may carry. */
|
|
766
689
|
const TRIGGER_KINDS = new Set(['manual', 'scheduled', 'event', 'form', 'conversation', 'voice']);
|
|
767
690
|
/**
|
|
@@ -856,272 +779,6 @@ function renderMap(m, rename = NO_RENAME) {
|
|
|
856
779
|
* `contains` is the only operator the deployed corpus uses, and it maps to the
|
|
857
780
|
* designer's `Contains`.
|
|
858
781
|
*/
|
|
859
|
-
/**
|
|
860
|
-
* Flatten a nested `where` onto the DOTTED parameter names the wire uses.
|
|
861
|
-
*
|
|
862
|
-
* The generated `…Where` interface splits a dotted event parameter into an
|
|
863
|
-
* object — `channelData.channel.id` becomes
|
|
864
|
-
* `channelData: ConnectorValue<ChannelDataInput>` — so an author following the
|
|
865
|
-
* types writes the nested shape, while `bucketOf` and the `filterExpression`
|
|
866
|
-
* clause both key on the declared dotted name. Without this the nested shape
|
|
867
|
-
* missed the bucket lookup and then stringified, emitting
|
|
868
|
-
* `channelData == '[object Object]'`: a subscription matching nothing, from a
|
|
869
|
-
* document that compiled clean and passed `check`.
|
|
870
|
-
*
|
|
871
|
-
* Descent STOPS as soon as a path names a declared parameter, so a parameter
|
|
872
|
-
* that genuinely takes an object value is passed through whole rather than
|
|
873
|
-
* shredded. A lookup token is a value, never a branch.
|
|
874
|
-
*/
|
|
875
|
-
function flattenWhere(where, declared) {
|
|
876
|
-
const out = {};
|
|
877
|
-
const walk = (value, path) => {
|
|
878
|
-
if (path && declared.has(path)) {
|
|
879
|
-
out[path] = value;
|
|
880
|
-
return;
|
|
881
|
-
}
|
|
882
|
-
const plain = typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
883
|
-
&& !isLookupToken(value)
|
|
884
|
-
&& (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
|
|
885
|
-
if (plain) {
|
|
886
|
-
for (const [k, v] of Object.entries(value))
|
|
887
|
-
walk(v, path ? `${path}.${k}` : k);
|
|
888
|
-
return;
|
|
889
|
-
}
|
|
890
|
-
if (path)
|
|
891
|
-
out[path] = value;
|
|
892
|
-
};
|
|
893
|
-
walk(where, '');
|
|
894
|
-
return out;
|
|
895
|
-
}
|
|
896
|
-
/**
|
|
897
|
-
* A subscription's `filters`, each leaf read structurally (`readEventFilter`),
|
|
898
|
-
* or the refusal of the first leaf compile cannot lower: no field, no operator
|
|
899
|
-
* or two, a value no operator takes, a backslash JMESPath engines read apart.
|
|
900
|
-
* Needs no library, so a run without one judges the leaves too
|
|
901
|
-
* (`libraryRequiredForEvent`).
|
|
902
|
-
*/
|
|
903
|
-
function eventFilterReads(filters, nodeId) {
|
|
904
|
-
const operators = Object.keys(EVENT_FILTER_OPERATORS).join(', ');
|
|
905
|
-
const at = `event node "${nodeId}": filters`;
|
|
906
|
-
return filters.map((f, i) => {
|
|
907
|
-
const { keys, read } = readEventFilter(f);
|
|
908
|
-
const field = f?.field;
|
|
909
|
-
if (typeof field !== 'string' || field === '') {
|
|
910
|
-
throw new CompileRefusal('EVENT_FILTER_NO_FIELD', `${at}[${i}] has no \`field\` — name a field on the event payload, e.g. 'subject'.`);
|
|
911
|
-
}
|
|
912
|
-
if (keys.length === 0) {
|
|
913
|
-
throw new CompileRefusal('EVENT_FILTER_NO_VALUE', `${at}[${i}] has no operator. Write exactly one of ${operators} with its value — `
|
|
914
|
-
+ `\`contains\` is a case-sensitive substring test, the same one Integration Service applies `
|
|
915
|
-
+ `server-side; \`lessThan\`/\`greaterThan\` order a number or an ISO date.`, `{ field: '${field}', contains: '<text>' }`);
|
|
916
|
-
}
|
|
917
|
-
if (keys.length > 1) {
|
|
918
|
-
throw new CompileRefusal('EVENT_FILTER_MANY_OPERATORS', `${at}[${i}] carries ${keys.length} operators (${keys.join(', ')}); a condition has exactly `
|
|
919
|
-
+ `one. Write two conditions instead — they are ANDed.`);
|
|
920
|
-
}
|
|
921
|
-
if (!read) {
|
|
922
|
-
throw new CompileRefusal('EVENT_FILTER_NO_VALUE', `${at}[${i}] gives \`${keys[0]}\` a value that is not a string, number or boolean.`);
|
|
923
|
-
}
|
|
924
|
-
// An ambiguous backslash first: `eventFilterProblem` would report it too.
|
|
925
|
-
const problem = eventFilterProblem(read);
|
|
926
|
-
const backslash = typeof read.value === 'string' && jmesStringProblem(read.value) !== undefined;
|
|
927
|
-
if (problem) {
|
|
928
|
-
throw new CompileRefusal(backslash ? 'EVENT_FILTER_BACKSLASH' : 'EVENT_FILTER_BAD_VALUE', `${at}[${i}] on \`${read.field}\`: ${problem}`);
|
|
929
|
-
}
|
|
930
|
-
return read;
|
|
931
|
-
});
|
|
932
|
-
}
|
|
933
|
-
/**
|
|
934
|
-
* The match-expression clauses of a subscription's EVENT parameters, one
|
|
935
|
-
* `k == '<value>'` per value, or the refusal of the first value compile cannot
|
|
936
|
-
* write there. The clause compares against a JMESPath string, so the value must
|
|
937
|
-
* be a string, number or boolean: an object or array would be stringified to
|
|
938
|
-
* `'[object Object]'` (or a comma list), a subscription that matches nothing
|
|
939
|
-
* (EVENT_WHERE_NOT_SCALAR). A string with a backslash JMESPath engines read
|
|
940
|
-
* apart is EVENT_FILTER_BACKSLASH. An absent or empty value (`''` or `[]`, so a
|
|
941
|
-
* `where` built from a possibly-empty list) writes no clause.
|
|
942
|
-
*
|
|
943
|
-
* Only event parameters fold into the expression; a query or path parameter is
|
|
944
|
-
* sent with the request that registers the subscription and is never read as
|
|
945
|
-
* JMESPath, so neither rule applies to it.
|
|
946
|
-
*/
|
|
947
|
-
function eventScopeClauses(eventParameters, nodeId) {
|
|
948
|
-
return Object.entries(eventParameters)
|
|
949
|
-
.filter(([, v]) => v !== undefined && v !== null && v !== '' && !(Array.isArray(v) && v.length === 0))
|
|
950
|
-
.map(([k, v]) => {
|
|
951
|
-
if (typeof v !== 'string' && typeof v !== 'number' && typeof v !== 'boolean') {
|
|
952
|
-
throw new CompileRefusal('EVENT_WHERE_NOT_SCALAR', `event node "${nodeId}": \`where.${k}\` is ${Array.isArray(v) ? 'an array' : isLookupToken(v) ? 'an unresolved lookup() nested inside an object' : 'an object'}, `
|
|
953
|
-
+ `and an event parameter is matched as one text value (\`${k} == '<value>'\`): written as it is, `
|
|
954
|
-
+ `the subscription would compare against ${JSON.stringify(String(v))} and match nothing. `
|
|
955
|
-
+ `Give \`${k}\` a string, number or boolean.`, `where: { '${k}': '<value>' }`);
|
|
956
|
-
}
|
|
957
|
-
const problem = jmesStringProblem(String(v));
|
|
958
|
-
if (problem)
|
|
959
|
-
throw new CompileRefusal('EVENT_FILTER_BACKSLASH', `event node "${nodeId}": \`where.${k}\`: ${problem}`);
|
|
960
|
-
return `${k} == ${jmesString(String(v))}`;
|
|
961
|
-
});
|
|
962
|
-
}
|
|
963
|
-
function eventDetail(rc, sub, nodeId, opts, site) {
|
|
964
|
-
requireBindingPair(site, sub, eventTarget(sub));
|
|
965
|
-
const conn = resolveBinding(opts, sub.connection, 'connection', `event node "${nodeId}"`, eventTarget(sub));
|
|
966
|
-
const folder = resolveBinding(opts, sub.folder, 'folder', `event node "${nodeId}"`, eventTarget(sub));
|
|
967
|
-
const op = (rc.entry?.operation ?? {});
|
|
968
|
-
const filters = sub.filters ?? [];
|
|
969
|
-
// A GENERIC event with no `object` would carry `objectName: ""`: it validates
|
|
970
|
-
// and the platform's dispatcher refuses it. Refused here, at the layer that
|
|
971
|
-
// would otherwise emit it, with the text every family's compile shares.
|
|
972
|
-
const objectName = String(op.objectName ?? '');
|
|
973
|
-
const noObject = genericEventObjectRefusal(rc, sub, (o) => `onEvent(…, { object: '${o}' })`);
|
|
974
|
-
if (noObject) {
|
|
975
|
-
// The object an author put in `where` by mistake is the value to move.
|
|
976
|
-
const scopeObject = sub.where && typeof sub.where === 'object'
|
|
977
|
-
? Object.entries(sub.where).find(([k]) => /^(objectName|entityName|object)$/i.test(k))?.[1]
|
|
978
|
-
: undefined;
|
|
979
|
-
throw new CompileRefusal('EVENT_GENERIC_NO_OBJECT', `event node "${nodeId}": ${noObject}`, `object: '${scopeObject !== undefined ? String(scopeObject) : '<Object>'}'`);
|
|
980
|
-
}
|
|
981
|
-
// An unresolved `where` lookup is swapped for its recorded id — the id
|
|
982
|
-
// `prepare --resolve` stored under the EVENT-form node type — or refused.
|
|
983
|
-
// Same rule as connector inputs: emitting a placeholder for a value nobody
|
|
984
|
-
// resolved would subscribe the trigger to the wrong folder/channel/queue.
|
|
985
|
-
const where = resolveEventWhere(sub.where, opts.library?.lookupResolutions ?? {}, `event node "${nodeId}"`);
|
|
986
|
-
// A subscription's parameters do not all travel in the same slot. The
|
|
987
|
-
// connector declares which, and the library bakes it per field as `bucket`:
|
|
988
|
-
// measured against designer-authored triggers, Jira's `project`/`issuetype`
|
|
989
|
-
// and GitHub's `repo` land in `queryParameters`, Asana's `projectId` in
|
|
990
|
-
// `pathParameters` and its `workspaceId` in `queryParameters`, while
|
|
991
|
-
// Outlook's `parentFolderId` — which the connector declares through the
|
|
992
|
-
// field's own `events.<OPERATION>` map rather than as a typed request
|
|
993
|
-
// parameter — lands in `eventParameters`. Emitting all of them as event
|
|
994
|
-
// parameters puts three of those four in a slot the runtime does not read.
|
|
995
|
-
const bucketOf = new Map();
|
|
996
|
-
const declaredOrder = [];
|
|
997
|
-
for (const f of (rc.v1def
|
|
998
|
-
?.eventParameters?.fields ?? [])) {
|
|
999
|
-
if (typeof f?.name !== 'string')
|
|
1000
|
-
continue;
|
|
1001
|
-
declaredOrder.push(f.name);
|
|
1002
|
-
if (typeof f?.bucket === 'string')
|
|
1003
|
-
bucketOf.set(f.name, f.bucket);
|
|
1004
|
-
}
|
|
1005
|
-
const eventParameters = {};
|
|
1006
|
-
const queryParameters = {};
|
|
1007
|
-
const pathParameters = {};
|
|
1008
|
-
// FLATTENED first: everything below keys on the DECLARED name, which is dotted
|
|
1009
|
-
// (`channelData.channel.id`), while the generated `…Where` interface splits
|
|
1010
|
-
// that into an object — so an author following the types writes the nested
|
|
1011
|
-
// shape. Un-flattened it missed `bucketOf` (landing in the wrong slot) and
|
|
1012
|
-
// then stringified into the match expression as
|
|
1013
|
-
// `channelData == '[object Object]'`: a subscription that matches nothing,
|
|
1014
|
-
// compiled clean and passed `check`.
|
|
1015
|
-
for (const [k, v] of Object.entries(flattenWhere(where, new Set(declaredOrder)))) {
|
|
1016
|
-
const slot = bucketOf.get(k);
|
|
1017
|
-
(slot === 'query' ? queryParameters : slot === 'path' ? pathParameters : eventParameters)[k] = v;
|
|
1018
|
-
}
|
|
1019
|
-
// Only EVENT parameters fold into the match expression. They are the
|
|
1020
|
-
// subscription's own scope — the mandatory clause the platform AND-joins —
|
|
1021
|
-
// whereas a query or path parameter is part of the request that registers
|
|
1022
|
-
// the subscription, not a property of the events it matches.
|
|
1023
|
-
const scopeClauses = eventScopeClauses(eventParameters, nodeId);
|
|
1024
|
-
// Each authored filter is read structurally (which operator, which value) and
|
|
1025
|
-
// lowered with the designer's own grammar — see `event-filters.ts` for the
|
|
1026
|
-
// measured table.
|
|
1027
|
-
const conditions = eventFilterReads(filters, nodeId);
|
|
1028
|
-
const filterClauses = conditions.map((c) => `(${eventFilterJmes(c)})`);
|
|
1029
|
-
const filterExpression = [
|
|
1030
|
-
...scopeClauses,
|
|
1031
|
-
...(filterClauses.length > 0 ? [`(${filterClauses.join('&&')})`] : []),
|
|
1032
|
-
].join(' && ');
|
|
1033
|
-
const instanceParameters = {
|
|
1034
|
-
connectorKey: rc.connectorKey,
|
|
1035
|
-
objectName,
|
|
1036
|
-
activityType: op.activityType,
|
|
1037
|
-
version: rc.version,
|
|
1038
|
-
eventOperation: op.eventOperation,
|
|
1039
|
-
eventMode: op.eventMode,
|
|
1040
|
-
supportsStreaming: op.supportsStreaming ?? false,
|
|
1041
|
-
};
|
|
1042
|
-
const tree = conditions.length === 0 ? null : {
|
|
1043
|
-
groupOperator: 0,
|
|
1044
|
-
index: 0,
|
|
1045
|
-
filters: conditions.map((c, i) => ({
|
|
1046
|
-
...eventFilterTreeLeaf(c),
|
|
1047
|
-
// Deterministic, so recompiling the same flow is byte-identical (the
|
|
1048
|
-
// designer mints random uuids here; a random one would churn every build).
|
|
1049
|
-
uiId: stableId(`${nodeId}:${c.field}:${String(c.value)}:${i}`),
|
|
1050
|
-
})),
|
|
1051
|
-
groups: [],
|
|
1052
|
-
uuId: stableId(`${nodeId}:filters`),
|
|
1053
|
-
};
|
|
1054
|
-
// The node's own Property binding: how the platform registers the
|
|
1055
|
-
// subscription, and where `flow debug` reads its query parameters from.
|
|
1056
|
-
// Pinned to designer-authored artifacts — the START form carries every
|
|
1057
|
-
// subscription parameter as `{defaultValue, isExpression}` whatever its
|
|
1058
|
-
// bucket (Jira `project,issuetype`; Asana `workspaceId,projectId`; Outlook
|
|
1059
|
-
// `parentFolderId`), while the mid-flow WAIT form carries an EMPTY value and
|
|
1060
|
-
// empty parameter lists: it joins a subscription the trigger registers,
|
|
1061
|
-
// rather than registering one of its own.
|
|
1062
|
-
const isStartForm = rc.nodeType.includes('.connector.trigger.');
|
|
1063
|
-
const allParameters = {
|
|
1064
|
-
...eventParameters, ...queryParameters, ...pathParameters,
|
|
1065
|
-
};
|
|
1066
|
-
// Declared order, not the order the author happened to write `where` in, so
|
|
1067
|
-
// the same subscription always emits the same bytes.
|
|
1068
|
-
const orderedNames = [
|
|
1069
|
-
...declaredOrder.filter((n) => n in allParameters),
|
|
1070
|
-
...Object.keys(allParameters).filter((n) => !declaredOrder.includes(n)),
|
|
1071
|
-
];
|
|
1072
|
-
const subscriptionValue = {};
|
|
1073
|
-
if (isStartForm) {
|
|
1074
|
-
for (const name of orderedNames) {
|
|
1075
|
-
subscriptionValue[name] = { defaultValue: allParameters[name], isExpression: false };
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1078
|
-
const parameterList = isStartForm ? orderedNames.join(',') : '';
|
|
1079
|
-
const propertyBinding = {
|
|
1080
|
-
resource: 'Property',
|
|
1081
|
-
key: op.eventOperation ?? '',
|
|
1082
|
-
value: subscriptionValue,
|
|
1083
|
-
activityDisplayName: 'connector-activity',
|
|
1084
|
-
metadata: {
|
|
1085
|
-
ActivityName: 'connector-activity',
|
|
1086
|
-
BindingsVersion: '2.2',
|
|
1087
|
-
ObjectName: objectName,
|
|
1088
|
-
// The trigger resource is keyed by the CONNECTION the subscription is
|
|
1089
|
-
// registered against, so two connections keep two trigger resources.
|
|
1090
|
-
...(conn ? { ParentResourceKey: `EventTrigger.${conn}` } : {}),
|
|
1091
|
-
TriggerCreateParameters: parameterList,
|
|
1092
|
-
DebugQueryParameters: parameterList,
|
|
1093
|
-
},
|
|
1094
|
-
};
|
|
1095
|
-
return {
|
|
1096
|
-
connector: rc.connectorKey,
|
|
1097
|
-
...(conn ? { connectionId: conn, connectionResourceId: conn } : {}),
|
|
1098
|
-
...(folder ? { connectionFolderKey: folder } : {}),
|
|
1099
|
-
eventParameters,
|
|
1100
|
-
// Emitted only when populated, mirroring the connector-activity slots:
|
|
1101
|
-
// no archived artifact carries an empty one.
|
|
1102
|
-
...(Object.keys(queryParameters).length ? { queryParameters } : {}),
|
|
1103
|
-
...(Object.keys(pathParameters).length ? { pathParameters } : {}),
|
|
1104
|
-
objectName,
|
|
1105
|
-
eventType: op.eventOperation,
|
|
1106
|
-
eventMode: op.eventMode,
|
|
1107
|
-
filterExpression,
|
|
1108
|
-
configuration: '=jsonString:' + JSON.stringify({
|
|
1109
|
-
essentialConfiguration: {
|
|
1110
|
-
instanceParameters,
|
|
1111
|
-
objectName,
|
|
1112
|
-
packageVersion: rc.version,
|
|
1113
|
-
connectorVersion: null,
|
|
1114
|
-
executionType: null,
|
|
1115
|
-
httpMethod: null,
|
|
1116
|
-
path: null,
|
|
1117
|
-
filter: tree,
|
|
1118
|
-
},
|
|
1119
|
-
}),
|
|
1120
|
-
...(rc.activityTypeId ? { uiPathActivityTypeId: rc.activityTypeId } : {}),
|
|
1121
|
-
bindings: [propertyBinding],
|
|
1122
|
-
errorState: { issues: [] },
|
|
1123
|
-
};
|
|
1124
|
-
}
|
|
1125
782
|
/**
|
|
1126
783
|
* Recursively render Exprs nested inside objects/arrays (for connector inputs).
|
|
1127
784
|
*
|
|
@@ -2458,9 +2115,9 @@ function serializeFlow(built, opts) {
|
|
|
2458
2115
|
? (() => {
|
|
2459
2116
|
const sub = built.trigger.subscription;
|
|
2460
2117
|
if (!opts.library)
|
|
2461
|
-
throw libraryRequiredForEvent(opts, sub, built.triggerId ?? 'start', 'event trigger', 'onEvent()');
|
|
2118
|
+
throw libraryRequiredForEvent(eventEnv(opts), sub, built.triggerId ?? 'start', 'event trigger', 'onEvent()');
|
|
2462
2119
|
const rc = resolveEvent(opts.library, 'trigger', sub, 'trigger');
|
|
2463
|
-
refuseUnverifiedByoa(opts, 'trigger', sub);
|
|
2120
|
+
refuseUnverifiedByoa(eventEnv(opts), 'trigger', sub);
|
|
2464
2121
|
return rc;
|
|
2465
2122
|
})()
|
|
2466
2123
|
: undefined;
|
|
@@ -2513,7 +2170,7 @@ function serializeFlow(built, opts) {
|
|
|
2513
2170
|
// `detail` (see eventDetail).
|
|
2514
2171
|
entryPointId: stableId(`${built.id}:start:entryPoint`),
|
|
2515
2172
|
isDefaultEntryPoint: true,
|
|
2516
|
-
detail: eventDetail(eventTriggerRc, built.trigger.subscription, triggerId, opts, 'event trigger'),
|
|
2173
|
+
detail: eventDetail(eventTriggerRc, built.trigger.subscription, triggerId, eventEnv(opts), 'event trigger'),
|
|
2517
2174
|
}
|
|
2518
2175
|
: built.trigger?.kind === 'scheduled'
|
|
2519
2176
|
? scheduleInputs(built.trigger.inputs, triggerId)
|
|
@@ -2814,6 +2471,7 @@ function serializeFlow(built, opts) {
|
|
|
2814
2471
|
resourceNodeId: (explicit, seed, at) => resourceNodeId(scope, explicit, seed, at),
|
|
2815
2472
|
emitted: (typeName, v) => emittedDefs.get(`${typeName}@${v}`),
|
|
2816
2473
|
library: opts.library,
|
|
2474
|
+
events: eventEnv(opts),
|
|
2817
2475
|
// Rendered once: placement renders the contribution's inputs again, so the
|
|
2818
2476
|
// result is marked as the file's, as `render` marks a `lit`'s copy. A copy,
|
|
2819
2477
|
// so an author object the walk returned as is (a `lit`'s own) stays unmarked
|
|
@@ -3150,7 +2808,8 @@ function serializeFlow(built, opts) {
|
|
|
3150
2808
|
return def === undefined ? undefined : { port: definitionHasErrorPort(def), typeName: def.nodeType, version: def.version };
|
|
3151
2809
|
}
|
|
3152
2810
|
const port = typeof impl.errorPort === 'function' ? impl.errorPort(spec, undefined) : impl.errorPort === true;
|
|
3153
|
-
|
|
2811
|
+
const named = impl.namedNode?.(spec);
|
|
2812
|
+
return { port, typeName: named?.typeName ?? impl.typeName, version: step.options?.version ?? named?.version ?? resolved.version };
|
|
3154
2813
|
}
|
|
3155
2814
|
catch (error) {
|
|
3156
2815
|
if (error instanceof CompileRefusal)
|
|
@@ -3193,36 +2852,6 @@ function serializeFlow(built, opts) {
|
|
|
3193
2852
|
subflows[id] = emitSubflowBody(spec.child, id, step.name);
|
|
3194
2853
|
return [{ node: id, port: successPort(NODE_TYPE.subflow) }];
|
|
3195
2854
|
}
|
|
3196
|
-
if (spec.kind === 'waitEvent') {
|
|
3197
|
-
const sub = spec.subscription;
|
|
3198
|
-
// An event wait resumes or it does not: it has no error port to route.
|
|
3199
|
-
// Recorded before anything can refuse the step, so a stand-in keeps it.
|
|
3200
|
-
declaredErrorPorts.set(scope.pending.get(step.name) ?? step.name, {
|
|
3201
|
-
port: false, typeName: `uipath.connector.event.${sub?.connector}.${sub?.event}`, version: step.options?.version ?? sub?.version ?? '1.0.0',
|
|
3202
|
-
});
|
|
3203
|
-
if (!opts.library) {
|
|
3204
|
-
throw libraryRequiredForEvent(opts, sub, scope.pending.get(step.name) ?? step.name, `waitForEvent "${step.name}"`, `waitForEvent "${step.name}"`);
|
|
3205
|
-
}
|
|
3206
|
-
const rc = resolveEvent(opts.library, 'event', sub, `waitForEvent "${step.name}"`);
|
|
3207
|
-
refuseUnverifiedByoa(opts, `waitForEvent "${step.name}"`, sub);
|
|
3208
|
-
const id = stepUid(scope, step.name);
|
|
3209
|
-
const node = makeNode(rc.nodeType, id, step.name, { parentId, requestedVersion: step.options?.version, def: rc.v1def });
|
|
3210
|
-
declaredErrorPorts.set(id, { port: false, typeName: rc.nodeType, version: String(rc.v1def?.version ?? node.typeVersion) });
|
|
3211
|
-
node.inputs = { detail: eventDetail(rc, sub, id, opts, `waitForEvent "${step.name}"`) };
|
|
3212
|
-
// Same connection-binding closure as the connector branch (G-19).
|
|
3213
|
-
const { entries: waitConnBindings } = connectionResourceBindings({
|
|
3214
|
-
def: rc.v1def,
|
|
3215
|
-
connectorKey: rc.connectorKey,
|
|
3216
|
-
connectionId: resolveBinding(opts, sub.connection, 'connection', `waitForEvent "${step.name}"`, eventTarget(sub)),
|
|
3217
|
-
folderKey: resolveBinding(opts, sub.folder, 'folder', `waitForEvent "${step.name}"`, eventTarget(sub)),
|
|
3218
|
-
}, resourceBindings);
|
|
3219
|
-
for (const b of waitConnBindings)
|
|
3220
|
-
resourceBindings.set(b.id, b);
|
|
3221
|
-
scope.nodes.push(node);
|
|
3222
|
-
for (const t of tails)
|
|
3223
|
-
addEdge(scope, t, id);
|
|
3224
|
-
return [{ node: id, port: successPort(rc.nodeType) }];
|
|
3225
|
-
}
|
|
3226
2855
|
// A custom FlowAction subclass carries no `kind`; it compiles through its
|
|
3227
2856
|
// own contribution (design §4). Anything else without a recognized kind is
|
|
3228
2857
|
// an authoring error — it must NOT fall through into the script branch
|
|
@@ -3963,13 +3592,13 @@ function serializeFlow(built, opts) {
|
|
|
3963
3592
|
else if (epSpec.kind === 'event') {
|
|
3964
3593
|
const sub = epSpec.subscription;
|
|
3965
3594
|
if (!opts.library)
|
|
3966
|
-
throw libraryRequiredForEvent(opts, sub, ep.id, `onEvent() entry point "${ep.id}"`, 'onEvent()');
|
|
3595
|
+
throw libraryRequiredForEvent(eventEnv(opts), sub, ep.id, `onEvent() entry point "${ep.id}"`, 'onEvent()');
|
|
3967
3596
|
const rc = resolveEvent(opts.library, 'trigger', sub, 'trigger');
|
|
3968
|
-
refuseUnverifiedByoa(opts, 'trigger', sub);
|
|
3597
|
+
refuseUnverifiedByoa(eventEnv(opts), 'trigger', sub);
|
|
3969
3598
|
node = makeNode(rc.nodeType, ep.id, epLabel, { def: rc.v1def, requestedVersion });
|
|
3970
3599
|
node.inputs = {
|
|
3971
3600
|
entryPointId: stableId(`${built.id}:${ep.id}:entryPoint`),
|
|
3972
|
-
detail: eventDetail(rc, sub, ep.id, opts, `onEvent() entry point "${ep.id}"`),
|
|
3601
|
+
detail: eventDetail(rc, sub, ep.id, eventEnv(opts), `onEvent() entry point "${ep.id}"`),
|
|
3973
3602
|
};
|
|
3974
3603
|
const { entries } = connectionResourceBindings({
|
|
3975
3604
|
def: rc.v1def,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uipath/maestro-builder-sdk",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.71.1",
|
|
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": "7cd35a2caf9c3ca33c5f5f8c0caae6577d6dc77d"
|
|
104
104
|
}
|