@uipath/maestro-builder-sdk 6.24.0 → 6.25.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/api-index.md +115 -115
- package/dist/api-members.md +351 -351
- package/dist/check.js +1 -392
- package/dist/core/actions.d.ts +0 -304
- package/dist/core/actions.js +0 -54
- package/dist/core/form-field-type.d.ts +16 -0
- package/dist/core/form-field-type.js +33 -0
- package/dist/core/hitl-routing.d.ts +17 -3
- package/dist/core/stable-id.d.ts +9 -0
- package/dist/core/stable-id.js +16 -0
- package/dist/core/step-ports.d.ts +25 -1
- package/dist/core/step-ports.js +6 -47
- package/dist/core/typed-raw-node.js +0 -8
- package/dist/decompile.js +7 -191
- package/dist/flow-node-registry.js +2 -1
- package/dist/flow-node-type.d.ts +45 -1
- package/dist/flow-sdk.d.ts +1 -0
- package/dist/flow-sdk.js +1 -0
- package/dist/flow-step-exits.js +1 -1
- package/dist/nodes/hitl/flow/check.d.ts +38 -0
- package/dist/nodes/hitl/flow/check.js +357 -0
- package/dist/nodes/hitl/flow/factories.d.ts +58 -0
- package/dist/nodes/hitl/flow/factories.js +59 -0
- package/dist/nodes/hitl/flow/family.d.ts +3 -0
- package/dist/nodes/hitl/flow/family.js +8 -0
- package/dist/nodes/hitl/flow/index.d.ts +3 -0
- package/dist/nodes/hitl/flow/index.js +3 -0
- package/dist/nodes/hitl/flow/node-type.d.ts +7 -0
- package/dist/nodes/hitl/flow/node-type.js +601 -0
- package/dist/nodes/hitl/flow/spec.d.ts +265 -0
- package/dist/nodes/hitl/flow/spec.js +1 -0
- package/dist/serialize.d.ts +2 -4
- package/dist/serialize.js +35 -344
- package/package.json +2 -2
package/dist/serialize.js
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
* the platform emits, so the result passes `uip maestro flow validate`.
|
|
8
8
|
*/
|
|
9
9
|
import { readFileSync } from 'node:fs';
|
|
10
|
-
import { createHash } from 'node:crypto';
|
|
11
10
|
import { fileURLToPath } from 'node:url';
|
|
12
11
|
import { dirname, join } from 'node:path';
|
|
13
12
|
import { BUNDLED_DEFINITIONS, bundledVersions } from './flow-definitions.js';
|
|
@@ -21,19 +20,19 @@ import { declaredErrorPortRefusal, definitionHasErrorPort, errorPortRefusal } fr
|
|
|
21
20
|
import { FLOW_NODE_TYPES } from './flow-node-registry.js';
|
|
22
21
|
import { stepExits } from './flow-step-exits.js';
|
|
23
22
|
import { resolveVersion } from './core/nodes/versioned.js';
|
|
24
|
-
import {
|
|
23
|
+
import { FORM_FIELD_JSON_TYPE } from './core/form-field-type.js';
|
|
25
24
|
import { connectionConnectors } from './bindings-v2.js';
|
|
26
25
|
import { BindingRefusal, GUID_RE, bindingLabelRefusal, bindingMissingMessage, missingBindingLabels } from './core/binding-messages.js';
|
|
27
26
|
import { ByoaRefusal, byoaUnverified } from './core/byoa.js';
|
|
28
27
|
import { genericEventObjectRefusal } from './core/event-checks.js';
|
|
29
|
-
import { OUTCOME_HANDLE_NODE_TYPES, assertHitlExitInvariant,
|
|
28
|
+
import { OUTCOME_HANDLE_NODE_TYPES, assertHitlExitInvariant, hitlExitViolation, outcomeSlug } from './core/hitl-routing.js';
|
|
30
29
|
import { STICKY_NOTE_TYPE, STICKY_NOTE_TYPE_VERSION } from './core/definitionless-node-types.js';
|
|
31
30
|
import { placeholderPosition } from './node-placement.js';
|
|
32
31
|
import { hasExits } from './core/step-ports.js';
|
|
33
32
|
import { stopsAtEnd } from './flow-step-tree.js';
|
|
34
33
|
import { assertNodeEnvelope } from './core/node-envelope.js';
|
|
35
34
|
import { buildConfiguration } from './config.js';
|
|
36
|
-
import { fnv1aX4Uuid, stableId } from './core/stable-id.js';
|
|
35
|
+
import { fnv1aX4Uuid, schemaId, stableId } from './core/stable-id.js';
|
|
37
36
|
import { readEventFilter, eventFilterProblem, eventFilterJmes, eventFilterTreeLeaf, jmesString, jmesStringProblem } from './core/event-filters.js';
|
|
38
37
|
import { FLOW_EXPR_DIALECT } from './core/connector-checks.js';
|
|
39
38
|
import { buildConnectorInputs, connectorInputErrors as coreConnectorInputErrors, multipartBodyFieldName, transportHttpMethod } from './core/connector-inputs.js';
|
|
@@ -95,16 +94,12 @@ const NODE_TYPE = {
|
|
|
95
94
|
conversationalAgent: 'uipath.agent.conversational',
|
|
96
95
|
createOutgoingCall: 'uipath.conversational.voice.create-outgoing-call',
|
|
97
96
|
endCall: 'uipath.conversational.voice.end-call',
|
|
98
|
-
hitl: 'uipath.human-in-the-loop',
|
|
99
97
|
// The two other spellings of the SAME human task, both resolvable on this
|
|
100
98
|
// tenant. `hitl()` emits the base type unless `variant` names one of these;
|
|
101
99
|
// all three share the model (`bpmn:UserTask` / `Actions.HITL`), the single
|
|
102
100
|
// `completed` handle and the `output`/`status` output pair, so only the type
|
|
103
101
|
// string and the form's OWNER differ. (A third, `….document-validation`, is
|
|
104
102
|
// `AvailableOnTenant: false` — no definition resolves, so it is not here.)
|
|
105
|
-
hitlQuickForm: 'uipath.human-in-the-loop.quick-form',
|
|
106
|
-
hitlActionApp: 'uipath.human-in-the-loop.coded-action-app',
|
|
107
|
-
hitlDocValidation: 'uipath.human-in-the-loop.document-validation',
|
|
108
103
|
// The PLATFORM's placeholder — "a real node goes here later". Not the engine's
|
|
109
104
|
// fixture-returning `kind: 'mock'` test construct, which shares only the name
|
|
110
105
|
// (#125). The definition declares no `inputDefinition` and one output whose
|
|
@@ -2998,245 +2993,6 @@ function scheduleInputs(inputs, nodeId) {
|
|
|
2998
2993
|
...(isPreset ? {} : { timerValue: every }),
|
|
2999
2994
|
};
|
|
3000
2995
|
}
|
|
3001
|
-
/** JSON-Schema type per form-field type, as flow-v1's form serializer maps them (quick-form escalations and human tasks). */
|
|
3002
|
-
const FORM_FIELD_JSON_TYPE = {
|
|
3003
|
-
text: { type: 'string' },
|
|
3004
|
-
number: { type: 'number' },
|
|
3005
|
-
boolean: { type: 'boolean' },
|
|
3006
|
-
'date-time': { type: 'string', format: 'date-time' },
|
|
3007
|
-
};
|
|
3008
|
-
/**
|
|
3009
|
-
* A human task's inputs, and the outputs its form implies.
|
|
3010
|
-
*
|
|
3011
|
-
* Three things the author does not state and the platform needs:
|
|
3012
|
-
*
|
|
3013
|
-
* 1. **`type: 'quick'`** — the node type carries both an inline quick form and an
|
|
3014
|
-
* App-backed task, selected by this field. flow-v1's serializer defaults an
|
|
3015
|
-
* absent value to `quick`, but a reader cannot rely on that default, so the
|
|
3016
|
-
* serializer writes it (the same "the encoding is the serializer's job" call as
|
|
3017
|
-
* the scheduled trigger's `timerPreset`/`timerValue` split). **Only on the base
|
|
3018
|
-
* node type**: on either suffixed variant the node TYPE is the choice, so no
|
|
3019
|
-
* `inputs.type` is written — 165 of the 175 deployed `.quick-form` instances
|
|
3020
|
-
* omit it, neither variant's definition declares it, and flow-v1's serializer
|
|
3021
|
-
* DERIVES its `hitlType` from the node type rather than reading the field
|
|
3022
|
-
* (`hitl-serialization.ts:140-146`).
|
|
3023
|
-
* 2. **`recipient`** — who gets the task. Emitted from the definition's own
|
|
3024
|
-
* `inputDefaults`: Email + Action Center, assigned to a group. That is what
|
|
3025
|
-
* 203 of 233 deployed, debug-green v1 human tasks carry, unchanged.
|
|
3026
|
-
* 3. **`schema.schemaId`** — the stable id the backend caches the form under
|
|
3027
|
-
* (229 of those 233 flows have one). Derived from the flow and node ids so the
|
|
3028
|
-
* emitted `.flow` is byte-stable across builds.
|
|
3029
|
-
*
|
|
3030
|
-
* And the outputs, which the DEFINITION cannot declare: a quick form's result keys
|
|
3031
|
-
* are its own answer fields, so `uipath.human-in-the-loop@1.0` says only
|
|
3032
|
-
* `output: { type: 'object' }` and the instance carries the shape — `properties`
|
|
3033
|
-
* per answer field plus `Action` enumerated over the outcome names, and `status`
|
|
3034
|
-
* (the platform's `=result.Action` projection) enumerated the same way. This is
|
|
3035
|
-
* exactly what deployed v1 flows carry, and it is what lets `gen-tests` synthesize
|
|
3036
|
-
* a replay fixture a downstream read can actually use.
|
|
3037
|
-
*/
|
|
3038
|
-
function hitlInputs(inputs, nodeId, flowId, label, rename) {
|
|
3039
|
-
const nodeType = hitlNodeType(inputs);
|
|
3040
|
-
const isApp = nodeType === NODE_TYPE.hitlActionApp;
|
|
3041
|
-
const fields = (inputs?.fields ?? []).map((f) => {
|
|
3042
|
-
const base = {
|
|
3043
|
-
id: f.id,
|
|
3044
|
-
label: f.label ?? f.id,
|
|
3045
|
-
type: f.type,
|
|
3046
|
-
direction: f.direction,
|
|
3047
|
-
};
|
|
3048
|
-
if (f.direction === 'input') {
|
|
3049
|
-
// The platform reads a field's `binding` as a variable PATH (`vars.…`),
|
|
3050
|
-
// not as an expression — so the Expr's `$vars.x` form is rewritten here
|
|
3051
|
-
// rather than asked of the author.
|
|
3052
|
-
base.binding = bindingPath(f.value, rename);
|
|
3053
|
-
}
|
|
3054
|
-
else if (f.direction === 'inOut') {
|
|
3055
|
-
// Pre-filled AND editable: `binding` is the canonical pre-fill (the data
|
|
3056
|
-
// contract flow-v1's serializer reads), and the WRITE target is the field
|
|
3057
|
-
// id itself — deliberately decoupled from the binding, so no `variable`.
|
|
3058
|
-
base.binding = bindingPath(f.value, rename);
|
|
3059
|
-
if (f.required)
|
|
3060
|
-
base.required = true;
|
|
3061
|
-
}
|
|
3062
|
-
else {
|
|
3063
|
-
// The answer's landing variable. The platform falls back to the field id
|
|
3064
|
-
// when this is absent; naming it keeps the emitted flow explicit and
|
|
3065
|
-
// matches what the designer writes.
|
|
3066
|
-
base.variable = `vars.${f.id}`;
|
|
3067
|
-
if (f.required)
|
|
3068
|
-
base.required = true;
|
|
3069
|
-
}
|
|
3070
|
-
return base;
|
|
3071
|
-
});
|
|
3072
|
-
const outcomes = (inputs?.outcomes ?? []).map((o, i) => {
|
|
3073
|
-
const name = typeof o === 'string' ? o : o?.name;
|
|
3074
|
-
const action = typeof o === 'string' ? 'Continue' : (o?.action ?? 'Continue');
|
|
3075
|
-
return { id: outcomeIdOf(o, i), name, type: 'string', isPrimary: i === 0, action };
|
|
3076
|
-
});
|
|
3077
|
-
const properties = {};
|
|
3078
|
-
for (const f of inputs?.fields ?? []) {
|
|
3079
|
-
// inOut fields land in the answers too — their reviewed value flows back.
|
|
3080
|
-
if (!isAnswerField(f))
|
|
3081
|
-
continue;
|
|
3082
|
-
properties[f.id] = { ...ownEntry(FORM_FIELD_JSON_TYPE, String(f.type)) };
|
|
3083
|
-
}
|
|
3084
|
-
const names = outcomes.map((o) => o.name).filter((n) => typeof n === 'string');
|
|
3085
|
-
if (names.length > 0) {
|
|
3086
|
-
properties.Action = { type: 'string', enum: names, default: names[0] };
|
|
3087
|
-
}
|
|
3088
|
-
// The app reference and its input map, for the `action-app` variant only. The
|
|
3089
|
-
// keys are flow-v1's own app-picker names (`name`/`key`/`folderPath`, plus the
|
|
3090
|
-
// `appSystemName` that stays null until an app's first deployment); the
|
|
3091
|
-
// bindings map the app's OWN parameter names to `=`-prefixed expressions,
|
|
3092
|
-
// which is the form v1's serializer turns into `HitlTaskArguments`.
|
|
3093
|
-
const app = inputs?.app;
|
|
3094
|
-
const appInputBindings = {};
|
|
3095
|
-
for (const [name, value] of Object.entries(app?.inputs ?? {})) {
|
|
3096
|
-
appInputBindings[name] = appBindingExpr(value, rename);
|
|
3097
|
-
}
|
|
3098
|
-
// The author's recipient when given; the definition's own default otherwise
|
|
3099
|
-
// (unchanged — that default is what 203 of 233 deployed v1 tasks carry).
|
|
3100
|
-
const defaultRecipient = jsonClone(defByType.get(nodeType)?.inputDefaults?.recipient ?? {});
|
|
3101
|
-
const r = inputs?.recipient;
|
|
3102
|
-
const recipient = r
|
|
3103
|
-
? {
|
|
3104
|
-
channels: r.channels ?? (defaultRecipient.channels ?? []),
|
|
3105
|
-
// Preserve the default's shape: quick-form's default carries an empty
|
|
3106
|
-
// `connections` map, the others none — keep whichever, unless the
|
|
3107
|
-
// author supplies their own.
|
|
3108
|
-
...(r.connections !== undefined
|
|
3109
|
-
? { connections: r.connections }
|
|
3110
|
-
: 'connections' in defaultRecipient ? { connections: defaultRecipient.connections } : {}),
|
|
3111
|
-
assignee: {
|
|
3112
|
-
type: r.assignee.type,
|
|
3113
|
-
...(r.assignee.value !== undefined ? { value: r.assignee.value } : {}),
|
|
3114
|
-
...(r.assignee.displayName !== undefined ? { displayName: r.assignee.displayName } : {}),
|
|
3115
|
-
},
|
|
3116
|
-
}
|
|
3117
|
-
: defaultRecipient;
|
|
3118
|
-
// Document Validation carries the station's own inputs instead of a form; the
|
|
3119
|
-
// expressions ride as `=js:` strings, EV-wrapped by the profile migration like
|
|
3120
|
-
// any other input (the family is not in UNWRAPPED_INPUTS).
|
|
3121
|
-
// The station's expression fields ride as PLAIN `$vars.…` strings — the
|
|
3122
|
-
// property panel's own placeholder shape, and what the platform validator
|
|
3123
|
-
// reads (it string-checks them directly; an ExpressionValue envelope fails
|
|
3124
|
-
// with "extractionResult?.trim is not a function").
|
|
3125
|
-
const docPath = (v) => {
|
|
3126
|
-
const e = toExpr(v);
|
|
3127
|
-
return e.literal ? String(e.value) : renameRefs(e.js, rename);
|
|
3128
|
-
};
|
|
3129
|
-
const doc = inputs?.document;
|
|
3130
|
-
const docvalInputs = nodeType === NODE_TYPE.hitlDocValidation && doc
|
|
3131
|
-
? {
|
|
3132
|
-
validationRenderType: doc.render ?? 'standard',
|
|
3133
|
-
extractionResult: docPath(doc.extractionResult),
|
|
3134
|
-
...(doc.storageBucket !== undefined ? { storageBucket: doc.storageBucket } : {}),
|
|
3135
|
-
...(doc.documentId !== undefined ? { documentId: doc.documentId } : {}),
|
|
3136
|
-
...(doc.taxonomy !== undefined ? { taxonomy: docPath(doc.taxonomy) } : {}),
|
|
3137
|
-
}
|
|
3138
|
-
: {};
|
|
3139
|
-
// 1.2's error output, verbatim from the bundled definition — the instance
|
|
3140
|
-
// outputs replace the definition's (see the caller), so the slot is re-added
|
|
3141
|
-
// here when the author asked for it.
|
|
3142
|
-
const errorOutput = inputs?.exposeError
|
|
3143
|
-
? DEFS['uipath.human-in-the-loop@1.2']?.outputDefinition?.error
|
|
3144
|
-
: undefined;
|
|
3145
|
-
return {
|
|
3146
|
-
inputs: {
|
|
3147
|
-
// The base node type alone needs the discriminator — see the doc block.
|
|
3148
|
-
...(nodeType === NODE_TYPE.hitl ? { type: 'quick' } : {}),
|
|
3149
|
-
title: inputs?.title ?? label,
|
|
3150
|
-
priority: inputs?.priority ?? 'Low',
|
|
3151
|
-
...(inputs?.labels !== undefined ? { labels: inputs.labels } : {}),
|
|
3152
|
-
recipient,
|
|
3153
|
-
...docvalInputs,
|
|
3154
|
-
...((isApp || (nodeType === NODE_TYPE.hitlDocValidation && doc?.render === 'custom')) && app
|
|
3155
|
-
? {
|
|
3156
|
-
app: {
|
|
3157
|
-
displayName: app.name,
|
|
3158
|
-
name: app.name,
|
|
3159
|
-
key: app.key,
|
|
3160
|
-
folderPath: app.folderPath,
|
|
3161
|
-
...(app.appSystemName !== undefined ? { appSystemName: app.appSystemName } : {}),
|
|
3162
|
-
},
|
|
3163
|
-
...(Object.keys(appInputBindings).length > 0 ? { appInputBindings } : {}),
|
|
3164
|
-
}
|
|
3165
|
-
: {}),
|
|
3166
|
-
// The app variant still carries a `schema` — with NO fields (the app owns
|
|
3167
|
-
// the form) but WITH the outcomes, because the flow's own routing and its
|
|
3168
|
-
// `Action`/`status` outputs are derived from them. Both of flow-v1's
|
|
3169
|
-
// app-task node references write exactly this shape.
|
|
3170
|
-
schema: { schemaId: schemaId(flowId, nodeId), fields, outcomes },
|
|
3171
|
-
},
|
|
3172
|
-
outputs: {
|
|
3173
|
-
output: {
|
|
3174
|
-
type: 'object',
|
|
3175
|
-
description: 'Task result data',
|
|
3176
|
-
source: '=result',
|
|
3177
|
-
var: 'output',
|
|
3178
|
-
...(Object.keys(properties).length > 0 ? { properties } : {}),
|
|
3179
|
-
},
|
|
3180
|
-
status: {
|
|
3181
|
-
type: 'string',
|
|
3182
|
-
description: 'Task completion status',
|
|
3183
|
-
source: '=result.Action',
|
|
3184
|
-
var: 'status',
|
|
3185
|
-
...(names.length > 0 ? { enum: names, default: names[0] } : {}),
|
|
3186
|
-
},
|
|
3187
|
-
...(errorOutput !== undefined ? { error: jsonClone(errorOutput) } : {}),
|
|
3188
|
-
},
|
|
3189
|
-
};
|
|
3190
|
-
}
|
|
3191
|
-
/**
|
|
3192
|
-
* Which of the three human-task node types this step emits.
|
|
3193
|
-
*
|
|
3194
|
-
* `undefined` is deliberately the base type and not an alias for `.quick-form`:
|
|
3195
|
-
* the default emission must not change, so a flow authored before `variant`
|
|
3196
|
-
* existed compiles to the same bytes it always did.
|
|
3197
|
-
*/
|
|
3198
|
-
function hitlNodeType(inputs) {
|
|
3199
|
-
if (inputs?.variant === 'quick-form')
|
|
3200
|
-
return NODE_TYPE.hitlQuickForm;
|
|
3201
|
-
if (inputs?.variant === 'action-app')
|
|
3202
|
-
return NODE_TYPE.hitlActionApp;
|
|
3203
|
-
if (inputs?.variant === 'document-validation')
|
|
3204
|
-
return NODE_TYPE.hitlDocValidation;
|
|
3205
|
-
return NODE_TYPE.hitl;
|
|
3206
|
-
}
|
|
3207
|
-
/**
|
|
3208
|
-
* One `appInputBindings` value: the expression sent to a deployed app's input.
|
|
3209
|
-
*
|
|
3210
|
-
* flow-v1 writes these `=`-prefixed and WITHOUT `js:` (`"=vars.<node>.output.<f>"`
|
|
3211
|
-
* — `hitl-node-apptask.md`), and its serializer normalizes each to `=js:<body>`
|
|
3212
|
-
* when it builds `HitlTaskArguments`. So the flow-level form is the bare
|
|
3213
|
-
* `=`-prefixed path, which is what our own `$vars.` expressions become once the
|
|
3214
|
-
* prefix is dropped. A plain string passes through as written.
|
|
3215
|
-
*/
|
|
3216
|
-
function appBindingExpr(value, rename) {
|
|
3217
|
-
if (!(value instanceof Expr))
|
|
3218
|
-
return String(value ?? '');
|
|
3219
|
-
const js = renameRefs(value.js, rename).trim();
|
|
3220
|
-
const path = js.startsWith('$vars.') ? js.slice('$vars.'.length) : js;
|
|
3221
|
-
return path.startsWith('=') ? path : `=${path.startsWith('vars.') ? path : `vars.${path}`}`;
|
|
3222
|
-
}
|
|
3223
|
-
/**
|
|
3224
|
-
* A shown field's `binding`: the platform resolves it as a path against the
|
|
3225
|
-
* workflow's variables (`vars.<flowInput>`, `vars.<node>.output.<field>`), so the
|
|
3226
|
-
* `$vars.` prefix our expressions carry is dropped. A computed expression cannot
|
|
3227
|
-
* be a path — `check` rejects one (HITL_FIELD_VALUE_NOT_PATH) before we get here.
|
|
3228
|
-
*/
|
|
3229
|
-
function bindingPath(value, rename) {
|
|
3230
|
-
if (!(value instanceof Expr))
|
|
3231
|
-
return String(value ?? '');
|
|
3232
|
-
const js = renameRefs(value.js, rename).trim();
|
|
3233
|
-
const path = js.startsWith('$vars.') ? js.slice('$vars.'.length) : js;
|
|
3234
|
-
// `vars.`-prefixed, which is what 526 of 528 bound fields in deployed v1 flows
|
|
3235
|
-
// carry. flow-v1's serializer does prefix a bare identifier itself
|
|
3236
|
-
// (`hitl-serialization.ts`), but only for `HitlTaskArguments` — the
|
|
3237
|
-
// `__hitlInputBindings` the designer reads back stores the binding verbatim.
|
|
3238
|
-
return path.startsWith('vars.') ? path : `vars.${path}`;
|
|
3239
|
-
}
|
|
3240
2996
|
/**
|
|
3241
2997
|
* `Approve` → `approve`; a name that slugifies to nothing falls back to its index.
|
|
3242
2998
|
* The same rule that names the `outcome-<id>` ports (`outcomeSlug`), so an id
|
|
@@ -3245,22 +3001,6 @@ function bindingPath(value, rename) {
|
|
|
3245
3001
|
function outcomeId(name, index) {
|
|
3246
3002
|
return outcomeSlug(name, index);
|
|
3247
3003
|
}
|
|
3248
|
-
/**
|
|
3249
|
-
* A deterministic UUID for the form schema, derived from the flow and node ids.
|
|
3250
|
-
*
|
|
3251
|
-
* The platform uses `schemaId` to identify and cache a form, so it has to be
|
|
3252
|
-
* stable across builds of the same flow — a random one would make every rebuild a
|
|
3253
|
-
* different form and every emitted `.flow` a different file. Shaped as a v5 UUID
|
|
3254
|
-
* (SHA-1 based, version + variant bits set) because that is what the field holds.
|
|
3255
|
-
*/
|
|
3256
|
-
function schemaId(flowId, nodeId) {
|
|
3257
|
-
const h = createHash('sha1').update(`uipath.human-in-the-loop:${flowId}:${nodeId}`).digest();
|
|
3258
|
-
const b = Buffer.from(h.subarray(0, 16));
|
|
3259
|
-
b[6] = (b[6] & 0x0f) | 0x50;
|
|
3260
|
-
b[8] = (b[8] & 0x3f) | 0x80;
|
|
3261
|
-
const hex = b.toString('hex');
|
|
3262
|
-
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
3263
|
-
}
|
|
3264
3004
|
/**
|
|
3265
3005
|
* `serialize`, plus the extra files the flow needs on disk beside it.
|
|
3266
3006
|
*
|
|
@@ -3629,7 +3369,6 @@ function describeDeclared(bindings) {
|
|
|
3629
3369
|
*/
|
|
3630
3370
|
export function bundledActionNodeType(spec) {
|
|
3631
3371
|
switch (spec?.kind) {
|
|
3632
|
-
case 'hitl': return hitlNodeType(spec.inputs);
|
|
3633
3372
|
case 'inlineAgent': return INLINE_AGENT_TYPE;
|
|
3634
3373
|
case 'subflow':
|
|
3635
3374
|
case 'createOutgoingCall':
|
|
@@ -3686,10 +3425,8 @@ export function perCallDefinition(spec) {
|
|
|
3686
3425
|
* The definition version serialize emits for a typed action step that is not
|
|
3687
3426
|
* yet on the node-type registry: the author's `{ version }` when given,
|
|
3688
3427
|
* otherwise the version the step's inputs select, otherwise `undefined` (the
|
|
3689
|
-
* pinned default).
|
|
3690
|
-
*
|
|
3691
|
-
* - `hitl`: `exposeError` selects `@1.2`, per-outcome routing selects `@1.1`;
|
|
3692
|
-
* - `inlineAgent`: the newest bundled version, not the first bundled entry.
|
|
3428
|
+
* pinned default). One such family picks a version itself: `inlineAgent`
|
|
3429
|
+
* takes the newest bundled version, not the first bundled entry.
|
|
3693
3430
|
*
|
|
3694
3431
|
* The emit paths read their version here, and `check` resolves the definition
|
|
3695
3432
|
* it asks about with this same version (#1041), so the two cannot pick
|
|
@@ -3704,23 +3441,10 @@ export function actionVersion(spec, explicit) {
|
|
|
3704
3441
|
// Keyed by the node type `bundledActionNodeType` already picks, so the
|
|
3705
3442
|
// version rule adds no second dispatch on the step's kind.
|
|
3706
3443
|
const type = bundledActionNodeType(spec);
|
|
3707
|
-
if (type === NODE_TYPE.hitl)
|
|
3708
|
-
return hitlNeededVersion(spec?.inputs);
|
|
3709
3444
|
if (type === INLINE_AGENT_TYPE)
|
|
3710
3445
|
return INLINE_AGENT_DEFAULT_VERSION;
|
|
3711
3446
|
return undefined;
|
|
3712
3447
|
}
|
|
3713
|
-
/**
|
|
3714
|
-
* The base human task version a task's inputs need when nothing is pinned:
|
|
3715
|
-
* `exposeError` needs 1.2 (it adds the `error` output), and a task that
|
|
3716
|
-
* routes per outcome needs 1.1. Only the base task reaches here: a variant
|
|
3717
|
-
* (quick-form, app task) has its own node type and one definition.
|
|
3718
|
-
*/
|
|
3719
|
-
function hitlNeededVersion(inputs) {
|
|
3720
|
-
if (inputs?.exposeError)
|
|
3721
|
-
return '1.2';
|
|
3722
|
-
return hitlExitModel(inputs, undefined).shape === 'per-outcome' ? '1.1' : undefined;
|
|
3723
|
-
}
|
|
3724
3448
|
/**
|
|
3725
3449
|
* The bundled definition of `nodeType` that `makeNode` resolves: the author's
|
|
3726
3450
|
* exact `{ version }` when given, otherwise the pinned default (the first
|
|
@@ -4972,14 +4696,6 @@ export function serialize(built, opts = {}) {
|
|
|
4972
4696
|
function successPort(type) {
|
|
4973
4697
|
if (type === NODE_TYPE.loop)
|
|
4974
4698
|
return 'success';
|
|
4975
|
-
// Every human-task definition declares one static source handle, `completed`.
|
|
4976
|
-
// It is the real exit only where the product draws it: action-app,
|
|
4977
|
-
// document-validation, and a task with no outcomes. A base or quick-form task
|
|
4978
|
-
// with outcomes leaves on `outcome-<id>` instead (`hitlExitModel`), and never
|
|
4979
|
-
// reaches this function for its tail.
|
|
4980
|
-
if (type === NODE_TYPE.hitl || type === NODE_TYPE.hitlQuickForm || type === NODE_TYPE.hitlActionApp
|
|
4981
|
-
|| type === NODE_TYPE.hitlDocValidation)
|
|
4982
|
-
return 'completed';
|
|
4983
4699
|
// The inline agent's forward handle is `success`, not `output` — its definition
|
|
4984
4700
|
// declares `success` (with `isDefaultForType`) + `error` on the right, and 29 of
|
|
4985
4701
|
// 29 deployed instances wire the outgoing edge to `success`. The PUBLISHED agent
|
|
@@ -5049,7 +4765,12 @@ export function serialize(built, opts = {}) {
|
|
|
5049
4765
|
delete node.model;
|
|
5050
4766
|
node.inputs = renderDeep(contribution.inputs ?? {}, scope.rename);
|
|
5051
4767
|
if (contribution.outputs) {
|
|
5052
|
-
|
|
4768
|
+
// Replaced outputs are the instance's own, written verbatim: a human task's
|
|
4769
|
+
// come from its form, where a literal `{nodeId}` in an outcome name or a
|
|
4770
|
+
// field id is the author's text, not a template.
|
|
4771
|
+
node.outputs = contribution.replaceOutputs
|
|
4772
|
+
? jsonClone(contribution.outputs)
|
|
4773
|
+
: { ...(node.outputs ?? {}), ...subNodeId(jsonClone(contribution.outputs), id) };
|
|
5053
4774
|
}
|
|
5054
4775
|
// A bundled registered type returns no definition; its bindings still close
|
|
5055
4776
|
// against the bundled one (#942), counting what it bound through the context
|
|
@@ -5057,8 +4778,17 @@ export function serialize(built, opts = {}) {
|
|
|
5057
4778
|
const def = o.def ?? bundledDefinition(o.typeName, o.requestedVersion);
|
|
5058
4779
|
hoistContributionBindings(def, [...(o.bound ?? []), ...(contribution.bindings ?? [])], o.where);
|
|
5059
4780
|
scope.nodes.push(node);
|
|
4781
|
+
// A typed human task whose exits the product derives from its outcomes: every
|
|
4782
|
+
// edge out of it is held to that rule (`hitlExitViolation`, in addEdge), and
|
|
4783
|
+
// the step list treats its tails as outcome edges. A rawNode of the type is
|
|
4784
|
+
// not one: it routes by the port lists its author wrote.
|
|
4785
|
+
if (o.trackOutcomes && OUTCOME_HANDLE_NODE_TYPES.has(o.typeName))
|
|
4786
|
+
hitlNodes.set(id, node);
|
|
5060
4787
|
for (const t of o.tails)
|
|
5061
4788
|
addEdge(scope, t, id);
|
|
4789
|
+
if (contribution.fanOut) {
|
|
4790
|
+
return contribution.fanOut.map((f) => ({ node: id, port: f.port, ...(f.endsRun ? { endsRun: true } : {}) }));
|
|
4791
|
+
}
|
|
5062
4792
|
const port = contribution.port ?? contributionPort(def);
|
|
5063
4793
|
if (port === undefined) {
|
|
5064
4794
|
// Only templated exits: no main path leaves this node. Remember it so a
|
|
@@ -5085,7 +4815,10 @@ export function serialize(built, opts = {}) {
|
|
|
5085
4815
|
scope.rename.errorEnvelopes.set(step.name, impl.errorEnvelope);
|
|
5086
4816
|
const ctx = {
|
|
5087
4817
|
step: step.name,
|
|
4818
|
+
nodeId: id,
|
|
4819
|
+
flowId: built.id,
|
|
5088
4820
|
version: impl.version,
|
|
4821
|
+
pinnedVersion: step.options?.version,
|
|
5089
4822
|
render: (value) => renderValue(value, scope.rename),
|
|
5090
4823
|
renameRefs: (js) => renameRefs(js, scope.rename),
|
|
5091
4824
|
stepNodeId: (name) => scope.stepNodeId.get(name) ?? name,
|
|
@@ -5131,12 +4864,21 @@ export function serialize(built, opts = {}) {
|
|
|
5131
4864
|
}
|
|
5132
4865
|
declaredErrorPorts.set(id, { port, typeName: impl.typeName, version: impl.version });
|
|
5133
4866
|
}
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
4867
|
+
// A forward port is a handle the definition declares, one of the type's
|
|
4868
|
+
// author-named exits, or one the product derives (`derivesPort`: a human
|
|
4869
|
+
// task's `outcome-<id>` handles, where the definition lists only `completed`).
|
|
4870
|
+
const exits = impl.exits?.(spec, step.options?.version);
|
|
4871
|
+
const exitPorts = new Set(exits && hasExits(exits) ? exits.map((e) => e.port) : []);
|
|
4872
|
+
for (const p of [...(contribution.port !== undefined ? [contribution.port] : []), ...(contribution.fanOut ?? []).map((f) => f.port)]) {
|
|
4873
|
+
if (exitPorts.has(p) || impl.derivesPort?.(spec, p)
|
|
4874
|
+
|| declaresForwardPort(def ?? bundledDefinition(impl.typeName, impl.version), p))
|
|
4875
|
+
continue;
|
|
4876
|
+
throw new Error(`internal SDK error: ${where}: node type ${impl.typeName}@${impl.version} leaves by port "${p}", `
|
|
4877
|
+
+ 'which its definition declares no source handle for, and the type neither lists as an exit nor derives.');
|
|
5137
4878
|
}
|
|
5138
4879
|
return placeStepNode({
|
|
5139
4880
|
where, stepName: step.name, id, typeName: impl.typeName, requestedVersion: impl.version, def, contribution, bound, tails, scope, parentId,
|
|
4881
|
+
trackOutcomes: true,
|
|
5140
4882
|
});
|
|
5141
4883
|
}
|
|
5142
4884
|
function emitAction(step, tails, scope, parentId) {
|
|
@@ -6082,57 +5824,6 @@ export function serialize(built, opts = {}) {
|
|
|
6082
5824
|
addEdge(scope, t, id);
|
|
6083
5825
|
return [{ node: id, port: successPort(rc.nodeType) }];
|
|
6084
5826
|
}
|
|
6085
|
-
if (spec.kind === 'hitl') {
|
|
6086
|
-
const id = stepUid(scope, step.name);
|
|
6087
|
-
const hitlType = hitlNodeType(spec.inputs);
|
|
6088
|
-
// How the task leaves its node — `hitlExitModel` (core/hitl-routing.ts)
|
|
6089
|
-
// has the product rule and what `.step()` means after each shape.
|
|
6090
|
-
//
|
|
6091
|
-
// Only the BASE node has definition versions to select: routing per
|
|
6092
|
-
// outcome picks 1.1 and `exposeError` picks 1.2 (which adds the `error`
|
|
6093
|
-
// output). quick-form draws the same per-outcome handles on the one
|
|
6094
|
-
// definition it has, so it routes per outcome without moving. An explicit
|
|
6095
|
-
// pin wins over the inferred 1.1 — `flow validate` accepts `outcome-<id>`
|
|
6096
|
-
// edges on base@1.0 — but not over `exposeError`, whose output only 1.2
|
|
6097
|
-
// declares. A zero- or one-outcome task stays on the pinned default.
|
|
6098
|
-
const pinned = step.options?.version;
|
|
6099
|
-
const exitModel = hitlExitModel(spec.inputs, pinned);
|
|
6100
|
-
if (hitlType !== NODE_TYPE.hitl && spec.inputs?.exposeError === true) {
|
|
6101
|
-
throw new Error(`"${step.name}": exposeError needs the base human task's 1.2 definition, which adds the `
|
|
6102
|
-
+ `error output — the '${spec.inputs?.variant}' variant has no such version. Drop the variant or exposeError.`);
|
|
6103
|
-
}
|
|
6104
|
-
if (spec.inputs?.outcomePorts === true && !OUTCOME_HANDLE_NODE_TYPES.has(hitlType)) {
|
|
6105
|
-
throw new Error(`"${step.name}": outcomePorts: true, but the '${spec.inputs?.variant}' variant reads its outcomes `
|
|
6106
|
-
+ `from its app and leaves on its single 'completed' exit. Route on out('${step.name}', 'Action') downstream.`);
|
|
6107
|
-
}
|
|
6108
|
-
if (spec.inputs?.exposeError === true && pinned !== undefined && pinned !== '1.2') {
|
|
6109
|
-
throw new Error(`"${step.name}": exposeError needs the task's 1.2 definition, but { version: '${pinned}' } pins it. `
|
|
6110
|
-
+ `Drop the pin or match it.`);
|
|
6111
|
-
}
|
|
6112
|
-
// The same version `check` resolves the definition at (#1041).
|
|
6113
|
-
const node = makeNode(hitlType, id, step.name, { parentId, requestedVersion: actionVersion(spec, pinned) });
|
|
6114
|
-
const { inputs, outputs } = hitlInputs(spec.inputs, id, built.id, step.name, scope.rename);
|
|
6115
|
-
node.inputs = inputs;
|
|
6116
|
-
// The definition's `outputDefinition` gives the two output SLOTS; the form
|
|
6117
|
-
// gives their shape (see hitlInputs), so the instance's version wins.
|
|
6118
|
-
node.outputs = outputs;
|
|
6119
|
-
scope.nodes.push(node);
|
|
6120
|
-
if (OUTCOME_HANDLE_NODE_TYPES.has(hitlType))
|
|
6121
|
-
hitlNodes.set(id, node);
|
|
6122
|
-
for (const t of tails)
|
|
6123
|
-
addEdge(scope, t, id);
|
|
6124
|
-
if (exitModel.shape === 'per-outcome') {
|
|
6125
|
-
// The PRIMARY (first) outcome continues the main path; the author routes
|
|
6126
|
-
// the rest with .stepToList('outcome-<id>', …) or as .stepSwitch arms.
|
|
6127
|
-
return [{ node: id, port: exitModel.exits[0]?.port ?? `outcome-${outcomeSlug(undefined, 0)}` }];
|
|
6128
|
-
}
|
|
6129
|
-
if (exitModel.shape === 'every-outcome') {
|
|
6130
|
-
// Fan-out: every outcome continues to the next step, each on its own
|
|
6131
|
-
// handle. End outcomes are marked, and `emit` ends them.
|
|
6132
|
-
return exitModel.exits.map((e) => ({ node: id, port: e.port, ...(e.endsProcess ? { endsRun: true } : {}) }));
|
|
6133
|
-
}
|
|
6134
|
-
return [{ node: id, port: successPort(hitlType) }];
|
|
6135
|
-
}
|
|
6136
5827
|
// A custom FlowAction subclass carries no `kind`; it compiles through its
|
|
6137
5828
|
// own contribution (design §4). Anything else without a recognized kind is
|
|
6138
5829
|
// an authoring error — it must NOT fall through into the script branch
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uipath/maestro-builder-sdk",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.25.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": "
|
|
95
|
+
"gitref": "119258f247ce3ff7e3b3b3faf21ab2e2b13eca5a"
|
|
96
96
|
}
|