@uipath/maestro-builder-sdk 6.32.5 → 6.32.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -204,6 +204,8 @@ export interface BuiltTrigger {
204
204
  eventOutputs?: TaskOutputBinding[];
205
205
  /** Event only: a library-resolved Integration Service subscription. */
206
206
  eventSubscription?: EventSubscription;
207
+ /** Event placeholder only: the source object the event watches (see {@link EventTriggerOpts.object}). */
208
+ eventObject?: string;
207
209
  }
208
210
  export interface ManualTriggerOpts {
209
211
  name?: string;
@@ -241,10 +243,25 @@ export interface EventTriggerOpts {
241
243
  description?: string;
242
244
  /**
243
245
  * Stringly resolved subscription. Prefer the descriptor overload when a
244
- * prepared connector module is available. Omit this for the legacy
245
- * `serviceType`-only placeholder.
246
+ * prepared connector module is available. Omit this for a **placeholder**
247
+ * trigger, whose bag carries `serviceType` (plus `context[objectName]` when
248
+ * `object` is set).
246
249
  */
247
250
  subscription?: EventSubscription;
251
+ /**
252
+ * The source OBJECT the event watches — a Data Fabric entity, a Salesforce or
253
+ * ServiceNow object, a database table — for a **placeholder** trigger whose
254
+ * connector and connection are not resolved yet. It is emitted as the
255
+ * trigger's `context[objectName]` row, the same row `uip maestro case sdd
256
+ * convert` writes for an SDD's `| T02 | Intsvc.EventTrigger | <object> | … |`
257
+ * Case Triggers row, so the requested source survives in the plan as data,
258
+ * not only in a label. For example
259
+ * `eventTrigger({ name: 'Invoice created', object: 'aged_invoice_cases' })`.
260
+ *
261
+ * A resolved subscription names its object in `subscription.object` instead;
262
+ * passing both is refused.
263
+ */
264
+ object?: string;
248
265
  /**
249
266
  * Optional event-payload extractions. Each key is a case-variable name read
250
267
  * downstream as `=vars.<name>`; each value is the payload field expression
@@ -253,7 +270,8 @@ export interface EventTriggerOpts {
253
270
  *
254
271
  * @remarks
255
272
  * With **no** outputs the event trigger is a **placeholder** (`data.inputs`
256
- * carries only `serviceType`) — the offline shape for an event on a connector
273
+ * carries `serviceType`, plus `context[objectName]` when `object` is set) —
274
+ * the offline shape for an event on a connector
257
275
  * not yet registered; attach the real connection after registering it.
258
276
  */
259
277
  outputs?: Record<string, string | {
@@ -112,11 +112,21 @@ export function eventTrigger(descriptorOrOpts = {}, descriptorOpts = {}) {
112
112
  const type = (typeof v === 'string' ? 'string' : (v.type ?? 'string'));
113
113
  eventOutputs.push({ var: name, source, type });
114
114
  }
115
+ const object = descriptor ? undefined : opts.object;
116
+ if (object !== undefined) {
117
+ if (opts.subscription)
118
+ throw new Error('eventTrigger: pass the watched object as `subscription.object` on a resolved subscription, not as `object`.');
119
+ // Refuse padding rather than trim it: the value must match the SDD's
120
+ // source object exactly, and a silent trim would hide the typo.
121
+ if (typeof object !== 'string' || !object.trim() || object !== object.trim())
122
+ throw new Error('eventTrigger: `object` must be a non-empty string with no surrounding whitespace.');
123
+ }
115
124
  return {
116
125
  kind: 'event',
117
126
  name: opts.name,
118
127
  description: opts.description,
119
128
  eventOutputs: eventOutputs.length ? eventOutputs : undefined,
129
+ eventObject: object,
120
130
  eventSubscription: descriptor
121
131
  ? subscriptionFrom(descriptor, descriptorOpts)
122
132
  : opts.subscription,
@@ -269,8 +269,8 @@ function syncEntryPoints(caseplan, outPath) {
269
269
  * succeeds with zero warnings when the sidecar is stale or empty.
270
270
  *
271
271
  * Non-connector resources come from root binding pairs and referenced tasks.
272
- * Connector connection and folder bindings have different resource keys, so
273
- * their relationship comes from the context[] that references both binding ids.
272
+ * A connector's connection and folder relationship comes from the context[]
273
+ * that references both binding ids.
274
274
  * No-op when compiling outside a scaffolded project.
275
275
  */
276
276
  function syncBindingsV2(caseplan, outPath) {
@@ -814,7 +814,9 @@ function triggerSource(node, index, plan, refs) {
814
814
  }
815
815
  if (bag.serviceType === 'Intsvc.EventTrigger') {
816
816
  const bridges = bridgeRows(plan, node.id ?? '', bag);
817
- const resolved = bag.context !== undefined || bag.inputs !== undefined || bag.bindings !== undefined;
817
+ const object = placeholderEventObject(bag);
818
+ const resolved = object === undefined
819
+ && (bag.context !== undefined || bag.inputs !== undefined || bag.bindings !== undefined);
818
820
  const outputs = (bag.outputs ?? []).filter((row) => !bridges.has(row) && !isResolvedConnectorOutput(row, node.id ?? '', resolved));
819
821
  const subscription = resolved
820
822
  ? resolvedSubscriptionSource(bag, `event trigger "${label ?? node.id ?? index}"`, 'trigger', refs)
@@ -832,11 +834,28 @@ function triggerSource(node, index, plan, refs) {
832
834
  ['name', name],
833
835
  ['description', description ? tsLiteral(description) : undefined],
834
836
  ['subscription', subscription],
837
+ ['object', object !== undefined ? tsLiteral(object) : undefined],
835
838
  ['outputs', outputShape],
836
839
  ])})`;
837
840
  }
838
841
  throw new Error(`trigger "${label ?? node.id ?? index}" has unsupported serviceType "${bag.serviceType}".`);
839
842
  }
843
+ /**
844
+ * The source object of an unresolved event trigger, when its bag is the
845
+ * placeholder plus one `context[objectName]` row — the shape `eventTrigger({
846
+ * object })` compiles to and `uip maestro case sdd convert` writes. Anything
847
+ * richer (connector key, inputs, bindings) is a resolved subscription.
848
+ */
849
+ function placeholderEventObject(bag) {
850
+ const context = bag.context;
851
+ if (!Array.isArray(context) || context.length !== 1)
852
+ return undefined;
853
+ const row = context[0];
854
+ if (row?.name !== 'objectName' || typeof row.value !== 'string' || !row.value.trim())
855
+ return undefined;
856
+ const empty = (value) => value === undefined || (Array.isArray(value) && value.length === 0);
857
+ return empty(bag.inputs) && empty(bag.bindings) ? row.value : undefined;
858
+ }
840
859
  function caseAppSource(config) {
841
860
  if (typeof config.caseSummary !== 'string')
842
861
  throw new Error('caseAppConfig.caseSummary must be a string.');
@@ -184,7 +184,7 @@ export function serialize(built, opts = {}) {
184
184
  context.push(io('connection', 'string', { value: `=bindings.${connection.id}` }));
185
185
  context.push(io('resourceKey', 'string', { value: connection.resourceKey }));
186
186
  }
187
- const folder = bindingRef(resolver, connector.folder, 'Connection', 'folderKey', 'FolderKey', { ...site, attribute: 'folder' });
187
+ const folder = folderBindingRef(resolver, connector.folder, connection, { ...site, attribute: 'folder' });
188
188
  if (folder)
189
189
  context.push(io('folderKey', 'string', { value: `=bindings.${folder.id}` }));
190
190
  }
@@ -700,7 +700,12 @@ function emitTriggers(triggers, ids, resolver) {
700
700
  // machinery as connector tasks and wait-for-connector bags.
701
701
  const bag = t.eventSubscription
702
702
  ? resolvedSubscriptionBag('trigger', t.eventSubscription, resolver, triggerId, `Event trigger "${label}"`)
703
- : { serviceType: CASE_FORMAT_PROFILE.eventServiceType };
703
+ : {
704
+ serviceType: CASE_FORMAT_PROFILE.eventServiceType,
705
+ // A placeholder that names its source object carries it the way
706
+ // `case sdd convert` does: one `context[objectName]` row.
707
+ ...(t.eventObject ? { context: [io('objectName', 'string', { value: t.eventObject })] } : {}),
708
+ };
704
709
  if (t.eventOutputs?.length) {
705
710
  const outputs = t.eventOutputs.map((o) => {
706
711
  const field = o.source.replace(/^=/, '').split('.').pop() || o.source;
@@ -899,7 +904,7 @@ function resolvedSubscriptionBag(kind, spec, resolver, elementId, where) {
899
904
  context.push(io('connection', 'string', { value: `=bindings.${connection.id}` }));
900
905
  context.push(io('resourceKey', 'string', { value: connection.resourceKey }));
901
906
  }
902
- const folder = bindingRef(resolver, spec.folder, 'Connection', 'folderKey', 'FolderKey', { attribute: 'folder', where, target });
907
+ const folder = folderBindingRef(resolver, spec.folder, connection, { attribute: 'folder', where, target });
903
908
  if (folder)
904
909
  context.push(io('folderKey', 'string', { value: `=bindings.${folder.id}` }));
905
910
  context.push(io('method', 'string', {}), io('path', 'string', {}), io('objectName', 'string', { value: op.objectName ?? spec.event }), io('operation', 'string', { value: op.eventOperation ?? spec.event }), io('metadata', 'json', { body: subscriptionMetadata(rc, op, spec.filters ?? [], elementId) }));
@@ -1095,7 +1100,7 @@ function connectorTaskData(spec, resolver, elementId, where) {
1095
1100
  context.push(io('connection', 'string', { value: `=bindings.${connRef.id}` }));
1096
1101
  context.push(io('resourceKey', 'string', { value: connRef.resourceKey }));
1097
1102
  }
1098
- const folderRef = bindingRef(resolver, spec.folder, 'Connection', 'folderKey', 'FolderKey', { attribute: 'folder', where, target });
1103
+ const folderRef = folderBindingRef(resolver, spec.folder, connRef, { attribute: 'folder', where, target });
1099
1104
  if (folderRef)
1100
1105
  context.push(io('folderKey', 'string', { value: `=bindings.${folderRef.id}` }));
1101
1106
  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) }));
@@ -1143,7 +1148,7 @@ function externalTaskData(kind, spec, resolver, where) {
1143
1148
  throw new Error(`${kind} task mode must be "sync" or "async".`);
1144
1149
  const target = { key: spec.connector.key, action: spec.connector.action };
1145
1150
  const connection = bindingRef(resolver, spec.connector.connection, 'Connection', 'ConnectionId', `${rc.connectorKey} connection`, { attribute: 'connection', where, target });
1146
- const folder = bindingRef(resolver, spec.connector.folder, 'Connection', 'folderKey', 'FolderKey', { attribute: 'folder', where, target });
1151
+ const folder = folderBindingRef(resolver, spec.connector.folder, connection, { attribute: 'folder', where, target });
1147
1152
  if (!connection || !folder)
1148
1153
  throw new Error(`${kind} task requires non-empty connection and folder binding names.`);
1149
1154
  const serviceType = kind === 'external-agent'
@@ -1231,6 +1236,50 @@ function bindingRef(resolver, name, resource, propertyAttribute, displayName, si
1231
1236
  }
1232
1237
  return { id, resourceKey };
1233
1238
  }
1239
+ /**
1240
+ * A connector's folder is a property of its connection:
1241
+ * { resourceKey: <connection key>, default: <folder key>, propertyAttribute: 'folderKey' }.
1242
+ * One folder label on two connections gets one row each: `shared`, `shared_2`.
1243
+ * One connection with two different folders is refused: a connection lives in
1244
+ * one folder, and the syncs group rows by `resourceKey`, so one value would win.
1245
+ * Without a connection the folder binds as a plain binding.
1246
+ */
1247
+ function folderBindingRef(resolver, name, connection, site) {
1248
+ if (!connection)
1249
+ return bindingRef(resolver, name, 'Connection', 'folderKey', 'FolderKey', site);
1250
+ if (!name)
1251
+ return undefined;
1252
+ const refused = bindingLabelRefusal(resolver.bindings, name, site.attribute, site.where, site.target);
1253
+ if (refused)
1254
+ throw refused;
1255
+ const entry = resolver.bindings?.entry(name);
1256
+ const baseId = entry?.id ?? name;
1257
+ const folderKey = entry?.default ?? entry?.resourceKey ?? name;
1258
+ const matches = (row) => row?.resourceKey === connection.resourceKey && row?.default === folderKey
1259
+ && row?.propertyAttribute === 'folderKey';
1260
+ for (const row of resolver.bindingSink.values()) {
1261
+ if (row.resourceKey === connection.resourceKey && row.propertyAttribute === 'folderKey'
1262
+ && row.default !== folderKey)
1263
+ throw new Error(`${site.where}: connection "${connection.resourceKey}" is bound to two folders: `
1264
+ + `"${String(row.name)}" (${String(row.default)}) and "${name}" (${folderKey}). `
1265
+ + `A connection lives in one folder; use the same folder binding for every task on it.`);
1266
+ }
1267
+ let id = baseId;
1268
+ for (let n = 2; resolver.bindingSink.has(id) && !matches(resolver.bindingSink.get(id)); n++)
1269
+ id = `${baseId}_${n}`;
1270
+ if (!resolver.bindingSink.has(id)) {
1271
+ resolver.bindingSink.set(id, {
1272
+ id,
1273
+ name: entry?.name ?? 'FolderKey',
1274
+ type: 'string',
1275
+ resource: 'Connection',
1276
+ resourceKey: connection.resourceKey,
1277
+ default: folderKey,
1278
+ propertyAttribute: 'folderKey',
1279
+ });
1280
+ }
1281
+ return { id };
1282
+ }
1234
1283
  /** The connector `metadata` json blob: the FUNCTIONAL essentialConfiguration +
1235
1284
  * activityTypeId. Designer cosmetics (packageId/activityColor/…) are omitted —
1236
1285
  * the caseplan schema-validates without them (see design §C). */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uipath/maestro-builder-sdk",
3
- "version": "6.32.5",
3
+ "version": "6.32.7",
4
4
  "description": "Build UiPath Flow, Case, and BPMN artifacts by writing TypeScript.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://docs.uipath.com/maestro",
@@ -93,5 +93,5 @@
93
93
  "@types/node": "^22.7.0",
94
94
  "esbuild": "^0.28.1"
95
95
  },
96
- "gitref": "14ac2b3fba98100313a97094685f1e9b5bc3601a"
96
+ "gitref": "25920074d219f5839f57dd1e8ef96af291415168"
97
97
  }