@uipath/maestro-builder-sdk 6.21.1 → 6.22.0

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
@@ -19,6 +19,7 @@ import { rawNodeInputProblem, registeredRawType } from './raw-node-advice.js';
19
19
  import { planContributionBindings } from './core/contribution-bindings.js';
20
20
  import { declaredErrorPortRefusal, definitionHasErrorPort, errorPortRefusal } from './core/error-port.js';
21
21
  import { FLOW_NODE_TYPES } from './flow-node-registry.js';
22
+ import { stepExits } from './flow-step-exits.js';
22
23
  import { resolveVersion } from './core/nodes/versioned.js';
23
24
  import { isAnswerField } from './core/hitl-answers.js';
24
25
  import { connectionConnectors } from './bindings-v2.js';
@@ -28,7 +29,7 @@ import { genericEventObjectRefusal } from './core/event-checks.js';
28
29
  import { OUTCOME_HANDLE_NODE_TYPES, assertHitlExitInvariant, hitlExitModel, hitlExitViolation, outcomeIdOf, outcomeSlug } from './core/hitl-routing.js';
29
30
  import { STICKY_NOTE_TYPE, STICKY_NOTE_TYPE_VERSION } from './core/definitionless-node-types.js';
30
31
  import { placeholderPosition } from './node-placement.js';
31
- import { declaredExits, hasExits } from './core/step-ports.js';
32
+ import { hasExits } from './core/step-ports.js';
32
33
  import { stopsAtEnd } from './flow-step-tree.js';
33
34
  import { assertNodeEnvelope } from './core/node-envelope.js';
34
35
  import { buildConfiguration } from './config.js';
@@ -97,8 +98,6 @@ const NODE_TYPE = {
97
98
  conversationalAgent: 'uipath.agent.conversational',
98
99
  createOutgoingCall: 'uipath.conversational.voice.create-outgoing-call',
99
100
  endCall: 'uipath.conversational.voice.end-call',
100
- http: 'core.action.http',
101
- httpV2: 'core.action.http.v2',
102
101
  hitl: 'uipath.human-in-the-loop',
103
102
  // The two other spellings of the SAME human task, both resolvable on this
104
103
  // tenant. `hitl()` emits the base type unless `variant` names one of these;
@@ -3336,27 +3335,6 @@ function subNodeId(obj, nodeId) {
3336
3335
  return JSON.parse(JSON.stringify(obj).split('{nodeId}').join(nodeId));
3337
3336
  }
3338
3337
  const NO_RENAME = { nodeIds: new Map(), errorEnvelopes: new Map() };
3339
- /**
3340
- * Which runtime variable holds a failed node's envelope, by node type.
3341
- *
3342
- * Measured on the product, one debug run per family (2026-09-10). Six of the
3343
- * seven families probed publish it as `<step>.error`, which is what the
3344
- * definitions declare (`outputDefinition.error.var`) and what `err()` writes, so
3345
- * only the exceptions are listed here:
3346
- *
3347
- * - `core.action.http.v2` — `<step>.error` is the boolean `true` and the
3348
- * envelope is in `<step>.output` (instance 430d43ad-4583-40c0-8f74-b49d2c4904e4).
3349
- *
3350
- * `core.action.http` (plain, 1.0.0 and the 1.3 `flow migrate` produces) is NOT
3351
- * an entry: it publishes no envelope anywhere, so there is no variable to name.
3352
- * `check` refuses an error handler on it instead (HTTP_ONERROR_V1).
3353
- *
3354
- * Read with `ownEntry`: the envelope variable for a node type, or undefined when
3355
- * it is the default `error`.
3356
- */
3357
- const ERROR_ENVELOPE_VAR = {
3358
- [NODE_TYPE.httpV2]: 'output',
3359
- };
3360
3338
  /**
3361
3339
  * Append the flow's `.stickyNotes()` as real `stickyNote` nodes.
3362
3340
  *
@@ -3654,12 +3632,11 @@ function describeDeclared(bindings) {
3654
3632
  * agenticProcess, publishedFunction, agent, ixpExtract) and for a spec this SDK
3655
3633
  * does not lower by kind.
3656
3634
  *
3657
- * The http / transform / delay / script emit path reads its type from here too,
3658
- * so the answer `check` gets is the type `serialize` writes.
3635
+ * A registered kind (flow-node-registry.ts) is not listed: its type is the
3636
+ * registry's.
3659
3637
  */
3660
3638
  export function bundledActionNodeType(spec) {
3661
3639
  switch (spec?.kind) {
3662
- case 'http': return spec.inputs?.managed ? NODE_TYPE.httpV2 : NODE_TYPE.http;
3663
3640
  case 'hitl': return hitlNodeType(spec.inputs);
3664
3641
  case 'inlineAgent': return INLINE_AGENT_TYPE;
3665
3642
  case 'subflow':
@@ -5006,8 +4983,6 @@ export function serialize(built, opts = {}) {
5006
4983
  if (!customTrigger)
5007
4984
  root.nodes.push(trigger);
5008
4985
  function successPort(type) {
5009
- if (type === NODE_TYPE.http || type === NODE_TYPE.httpV2)
5010
- return 'default';
5011
4986
  if (type === NODE_TYPE.loop)
5012
4987
  return 'success';
5013
4988
  // Every human-task definition declares one static source handle, `completed`.
@@ -5119,9 +5094,8 @@ export function serialize(built, opts = {}) {
5119
5094
  const id = stepUid(scope, step.name);
5120
5095
  // As for every typed family: record the failure-envelope boundary before any
5121
5096
  // expression renders, so a handler reading this step resolves correctly.
5122
- const envelope = ownEntry(ERROR_ENVELOPE_VAR, impl.typeName);
5123
- if (envelope)
5124
- scope.rename.errorEnvelopes.set(step.name, envelope);
5097
+ if (impl.errorEnvelope)
5098
+ scope.rename.errorEnvelopes.set(step.name, impl.errorEnvelope);
5125
5099
  const ctx = {
5126
5100
  step: step.name,
5127
5101
  version: impl.version,
@@ -5132,6 +5106,17 @@ export function serialize(built, opts = {}) {
5132
5106
  bind: (b) => { bound.push(b); },
5133
5107
  definition: (typeName, version) => bundledDefinition(typeName, version),
5134
5108
  bindings: resourceBindings,
5109
+ resolveBinding: (name, attribute, at) => resolveBinding(opts, name, attribute, at),
5110
+ bindConnection: (c) => {
5111
+ const { entries } = connectionResourceBindings({
5112
+ def: { model: c.model },
5113
+ connectorKey: c.connectorKey,
5114
+ connectionId: c.connectionId,
5115
+ ...(c.folderKey !== undefined ? { folderKey: c.folderKey } : {}),
5116
+ ...(c.resourceKey !== undefined ? { resourceKey: c.resourceKey } : {}),
5117
+ }, resourceBindings);
5118
+ bound.push(...entries);
5119
+ },
5135
5120
  };
5136
5121
  const bound = [];
5137
5122
  const contribution = impl.serialize(spec, ctx);
@@ -6247,43 +6232,7 @@ export function serialize(built, opts = {}) {
6247
6232
  }
6248
6233
  throw new Error(`step "${step.name}": not an action spec — pass a factory result, subflow(), or a FlowAction subclass instance.`);
6249
6234
  }
6250
- if (spec.kind !== 'http') {
6251
- throw new Error(`step "${step.name}": unknown action kind "${spec.kind}".`);
6252
- }
6253
- const type = bundledActionNodeType(spec);
6254
- const id = stepUid(scope, step.name);
6255
- const node = makeNode(type, id, step.name, { parentId, requestedVersion: step.options?.version });
6256
- // Record the failure-envelope boundary BEFORE any expression is rendered, so
6257
- // a handler that reads this step resolves against the right variable. The
6258
- // handler is emitted after the step it guards, so recording it here is early
6259
- // enough.
6260
- const envelope = ownEntry(ERROR_ENVELOPE_VAR, type);
6261
- if (envelope)
6262
- scope.rename.errorEnvelopes.set(step.name, envelope);
6263
- // The guard above leaves http; registered kinds returned at the top.
6264
- node.inputs = actionInputs(spec, scope.rename, opts, step.name);
6265
- if (spec.kind === 'http') {
6266
- node.outputs = httpOutputs(node.outputs, spec.inputs.returns, spec.inputs.managed);
6267
- if (spec.inputs.managed) {
6268
- const binding = resolveManagedHttpBinding(spec.inputs, opts, `managed http "${step.name}"`);
6269
- const { entries } = connectionResourceBindings({
6270
- def: { model: node.model },
6271
- connectorKey: 'uipath-uipath-http',
6272
- connectionId: binding?.connectionId ?? 'ImplicitConnection',
6273
- folderKey: binding?.folderKey,
6274
- // ImplicitConnection is the binding's default, not a remote
6275
- // resource key. Keeping the key empty matches product-authored
6276
- // manual HTTP nodes and lets the runtime supply the debug folder.
6277
- ...(binding ? {} : { resourceKey: '' }),
6278
- }, resourceBindings);
6279
- for (const entry of entries)
6280
- resourceBindings.set(entry.id, entry);
6281
- }
6282
- }
6283
- scope.nodes.push(node);
6284
- for (const t of tails)
6285
- addEdge(scope, t, id);
6286
- return [{ node: id, port: successPort(type) }];
6235
+ throw new Error(`step "${step.name}": unknown action kind "${spec.kind}".`);
6287
6236
  }
6288
6237
  /**
6289
6238
  * Wire a step's `.onError(...)` handler — the edge out of the node's `error`
@@ -6472,8 +6421,8 @@ export function serialize(built, opts = {}) {
6472
6421
  // The exits are resolved BEFORE the node is emitted, because a spec with
6473
6422
  // no routable fan-out (a human task pinned to 1.0, a variant, an http
6474
6423
  // with no branches) must refuse rather than emit a node and then
6475
- // discover it has one port. `declaredExits` carries the reason.
6476
- const exits = declaredExits(step.spec, step.options?.version);
6424
+ // discover it has one port. `stepExits` carries the reason.
6425
+ const exits = stepExits(step.spec, step.options?.version);
6477
6426
  if (!hasExits(exits)) {
6478
6427
  throw new Error(`.stepSwitch("${step.name}"): ${exits.reason}, so there are no exits to route.`
6479
6428
  + (exits.suggestion ? ` ${exits.suggestion}` : ''));
@@ -7174,208 +7123,3 @@ export function assertBindingPlaceholdersResolve(flow) {
7174
7123
  + `"invalid GUID <bindings.…>") and refuses to publish. This is a serializer defect, not an authoring `
7175
7124
  + `error; report it with the flow source.`);
7176
7125
  }
7177
- function actionInputs(spec, rename = NO_RENAME, opts = {}, stepName = '') {
7178
- if (spec.kind === 'http') {
7179
- const i = spec.inputs;
7180
- if (i.managed)
7181
- return managedHttpInputs(i, rename, opts, stepName);
7182
- if (i.connection !== undefined
7183
- || i.folder !== undefined
7184
- || i.targetConnector !== undefined) {
7185
- throw new Error('standalone http cannot use Integration Service connection settings; set managed: true');
7186
- }
7187
- const defaults = jsonClone(defByType.get(NODE_TYPE.http)?.inputDefaults ?? {});
7188
- return {
7189
- ...defaults,
7190
- method: i.method ?? 'GET',
7191
- url: renderValue(i.url, rename),
7192
- headers: renderMap(i.headers, rename),
7193
- queryParams: renderMap(i.query, rename),
7194
- body: i.body !== undefined ? renderValue(i.body, rename) : '',
7195
- contentType: i.contentType ?? 'application/json',
7196
- ...httpRequestSettings(i),
7197
- ...httpBranchRows(i, rename),
7198
- };
7199
- }
7200
- throw new Error(`internal SDK error: no inputs for action kind "${spec.kind}".`);
7201
- }
7202
- /**
7203
- * `timeout` / `retryCount` — the two request settings BOTH http node types carry.
7204
- *
7205
- * **These fields were never MISSING from the emitted node.** Both definitions
7206
- * declare them in `inputDefaults` (`timeout: 'PT15M'`, `retryCount: 0`) and the
7207
- * `...defaults` spread has always carried them through, so every http node this
7208
- * SDK ever emitted already said fifteen minutes and no retries. What the author
7209
- * had no way to do was say anything ELSE — which is the actual gap, and why this
7210
- * spreads AFTER the defaults rather than instead of them.
7211
- *
7212
- * Emitting only-when-set therefore does two things at once: an author's value
7213
- * overrides the definition's, and an author who says nothing gets byte-for-byte
7214
- * what they got before. (~99% of the 808 deployed http nodes are on the
7215
- * defaults, so that is also the faithful shape.)
7216
- *
7217
- * `check` has already validated the FORM of both (`HTTP_TIMEOUT_NOT_DURATION`,
7218
- * `HTTP_RETRY_COUNT_INVALID`), so this writes them through verbatim.
7219
- */
7220
- function httpRequestSettings(i) {
7221
- return {
7222
- ...(i.timeout !== undefined ? { timeout: i.timeout } : {}),
7223
- ...(i.retryCount !== undefined ? { retryCount: i.retryCount } : {}),
7224
- };
7225
- }
7226
- /**
7227
- * The MANAGED HTTP node's inputs (`core.action.http.v2`).
7228
- *
7229
- * The platform routes this one through Integration Service's own HTTP connector,
7230
- * so the request rides inside a connector `detail` envelope instead of sitting at
7231
- * the top level. Every constant below is read off the deployed corpus (384
7232
- * instances, 2026-05-11 → 07-29), not invented:
7233
- *
7234
- * - `uiPathActivityTypeId` — ONE value across all 331 instances that carry it;
7235
- * - `detail.method: 'POST'` + `endpoint: '/http-request'` — 352 of 352. That is
7236
- * how the flow calls the CONNECTOR; the HTTP verb the connector performs
7237
- * lives in `bodyParameters.method` (GET on 309). Two `method`s, one value
7238
- * each, and swapping them silently turns every GET into a POST;
7239
- * - `connectionId: 'ImplicitConnection'` — 290 of 352 (the rest bind an
7240
- * explicit Integration Service connection);
7241
- * - the `configuration` blob, whose `=jsonString:` envelope the platform reads
7242
- * back as the activity's instance parameters.
7243
- */
7244
- /** The `branches` rows both HTTP definitions declare: id/name from the author's name, conditions rendered like a decision's. */
7245
- function httpBranchRows(i, rename) {
7246
- if (!i.branches?.length)
7247
- return {};
7248
- return {
7249
- branches: i.branches.map((b) => ({
7250
- id: b.name,
7251
- name: b.name,
7252
- conditionExpression: renameRefs(b.condition.js, rename),
7253
- })),
7254
- };
7255
- }
7256
- function resolveManagedHttpBinding(i, opts, where) {
7257
- const configured = i.connection !== undefined || i.folder !== undefined;
7258
- if (!configured)
7259
- return undefined;
7260
- if (typeof i.connection !== 'string' || i.connection.trim() === ''
7261
- || typeof i.folder !== 'string' || i.folder.trim() === '') {
7262
- throw new Error('managed http connection mode requires both a non-empty connection and folder');
7263
- }
7264
- // The same resolution a connector step gets: a self-referential binding is an
7265
- // error, a stub is a warning. This used to be the one call site left on the
7266
- // silent `resolve(name) ?? name` spelling.
7267
- return {
7268
- connectionId: resolveBinding(opts, i.connection, 'connection', where),
7269
- folderKey: resolveBinding(opts, i.folder, 'folder', where),
7270
- };
7271
- }
7272
- function managedHttpInputs(i, rename, opts, stepName) {
7273
- const defaults = jsonClone(defByType.get(NODE_TYPE.httpV2)?.inputDefaults ?? {});
7274
- // Resolution is repeated by the caller that hoists the binding pair; only that
7275
- // one carries the `warn` sink, so a stub is reported once, not twice.
7276
- const binding = resolveManagedHttpBinding(i, { bindings: opts.bindings }, `managed http "${stepName}"`);
7277
- if (i.targetConnector !== undefined && !binding) {
7278
- throw new Error('managed http targetConnector requires both a non-empty connection and folder');
7279
- }
7280
- if (i.targetConnector !== undefined
7281
- && (typeof i.targetConnector !== 'string' || i.targetConnector.trim() === '')) {
7282
- throw new Error('managed http targetConnector must be a non-empty connector key');
7283
- }
7284
- const url = renderValue(i.url, rename);
7285
- const bodyParameters = {
7286
- authentication: binding ? 'connector' : 'manual',
7287
- method: i.method ?? 'GET',
7288
- ...(binding ? {
7289
- targetConnector: i.targetConnector ?? 'uipath-uipath-http',
7290
- connection: binding.connectionId,
7291
- path: url,
7292
- } : {}),
7293
- url,
7294
- };
7295
- const headers = renderMap(i.headers, rename);
7296
- if (Object.keys(headers).length > 0)
7297
- bodyParameters.headers = headers;
7298
- const query = renderMap(i.query, rename);
7299
- if (Object.keys(query).length > 0)
7300
- bodyParameters.query = query;
7301
- if (i.body !== undefined)
7302
- bodyParameters.body = renderValue(i.body, rename);
7303
- return {
7304
- ...defaults,
7305
- ...httpBranchRows(i, rename),
7306
- // TOP-LEVEL on the managed node too, NOT inside `detail` — the platform reads
7307
- // the request settings off the node, while `detail` is the connector call it
7308
- // wraps.
7309
- ...httpRequestSettings(i),
7310
- detail: {
7311
- connector: 'uipath-uipath-http',
7312
- connectionId: binding?.connectionId ?? 'ImplicitConnection',
7313
- connectionResourceId: binding?.connectionId ?? null,
7314
- connectionFolderKey: binding?.folderKey ?? null,
7315
- method: 'POST',
7316
- endpoint: '/http-request',
7317
- bodyParameters,
7318
- configuration: '=jsonString:' + JSON.stringify({
7319
- essentialConfiguration: {
7320
- instanceParameters: {
7321
- connectorKey: 'uipath-uipath-http',
7322
- objectName: 'http-request',
7323
- httpMethod: 'POST',
7324
- activityType: 'Curated',
7325
- version: '1.0.0',
7326
- },
7327
- objectName: 'http-request',
7328
- operation: 'create',
7329
- packageVersion: '1.0.0',
7330
- httpMethod: 'POST',
7331
- path: '/http-request',
7332
- unifiedTypesCompatible: true,
7333
- savedJitInputFieldId: 'in_http-request',
7334
- },
7335
- }),
7336
- uiPathActivityTypeId: '5c4cc855-b42a-37e6-b910-de8588998fce',
7337
- errorState: { issues: [] },
7338
- telemetryData: {
7339
- connectorKey: 'uipath-uipath-http',
7340
- connectorName: 'HTTP',
7341
- operationType: 'create',
7342
- objectName: 'http-request',
7343
- objectDisplayName: 'HTTP Request',
7344
- primaryKeyName: '',
7345
- },
7346
- },
7347
- };
7348
- }
7349
- /**
7350
- * An HTTP node's declared parsed-JSON response shape, from the author's `returns`.
7351
- *
7352
- * The platform's own definition declares `output` as a bare object — only the API
7353
- * being called knows its body — so a `body.<field>` read is unresolvable until the
7354
- * author says what is in there. Same rule, same word, as `rpaWorkflow.returns`.
7355
- */
7356
- function httpOutputs(base, returns, managed) {
7357
- if (!returns || Object.keys(returns).length === 0)
7358
- return base;
7359
- const out = jsonClone(base);
7360
- if (!out.output)
7361
- return out;
7362
- // The whole `output` shape lives on the INSTANCE, not in the bundled
7363
- // definition — deliberately. An instance schema may refine a GENERIC definition
7364
- // object but never override one that already declares a
7365
- // shape, so declaring `body`/`statusCode` in the def would lock the author's
7366
- // `returns` out of the very read it exists to license. The definition stays
7367
- // byte-faithful to the platform's (a bare object, because only the API being
7368
- // called knows its body) and the author's declaration is the only source of
7369
- // shape — which is also what makes refusing a read with no `returns` correct.
7370
- out.output.properties = {
7371
- body: {
7372
- type: 'object',
7373
- description: managed
7374
- ? 'Response body, deserialized by Integration Service'
7375
- : 'JSON response body, deserialized by the standalone HTTP runtime',
7376
- properties: Object.fromEntries(Object.entries(returns).map(([name, type]) => [name, { type }])),
7377
- },
7378
- statusCode: { type: 'number', description: 'HTTP status code of the response' },
7379
- };
7380
- return out;
7381
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uipath/maestro-builder-sdk",
3
- "version": "6.21.1",
3
+ "version": "6.22.0",
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",
@@ -92,5 +92,5 @@
92
92
  "@types/node": "^22.7.0",
93
93
  "esbuild": "^0.28.1"
94
94
  },
95
- "gitref": "fb7b702cde7f69674dfc8ed9e4eb171472e8d8e7"
95
+ "gitref": "b090b1119c411ed2ffdefab1d258d629ff624a1f"
96
96
  }