@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/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, bindingMissingMessage, missingBindingLabels } from './core/binding-messages.js';
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, resolveEventWhere, } from './core/lookups.js';
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
- return { port, typeName: impl.typeName, version: resolved.version };
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.70.9",
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": "89c9c37af44dc7763bc2334209b79935aff68e7a"
103
+ "gitref": "7cd35a2caf9c3ca33c5f5f8c0caae6577d6dc77d"
104
104
  }