@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/api-index.md +138 -138
- package/dist/api-members.md +407 -407
- package/dist/case/compile-cli.js +82 -26
- package/dist/check.js +43 -331
- package/dist/core/actions.d.ts +0 -147
- package/dist/core/actions.js +0 -15
- package/dist/core/expr.d.ts +1 -1
- package/dist/core/expr.js +2 -2
- package/dist/core/nodes/node-type.d.ts +15 -0
- package/dist/core/step-ports.js +7 -23
- package/dist/core/typed-raw-node.js +0 -2
- package/dist/decompile.js +44 -88
- package/dist/flow-node-registry.js +2 -1
- package/dist/flow-node-type.d.ts +59 -0
- package/dist/flow-sdk.d.ts +1 -0
- package/dist/flow-sdk.js +1 -0
- package/dist/flow-step-exits.d.ts +12 -0
- package/dist/flow-step-exits.js +30 -0
- package/dist/nodes/http/flow/check.d.ts +58 -0
- package/dist/nodes/http/flow/check.js +248 -0
- package/dist/nodes/http/flow/factories.d.ts +14 -0
- package/dist/nodes/http/flow/factories.js +20 -0
- package/dist/nodes/http/flow/family.d.ts +8 -0
- package/dist/nodes/http/flow/family.js +13 -0
- package/dist/nodes/http/flow/index.d.ts +3 -0
- package/dist/nodes/http/flow/index.js +3 -0
- package/dist/nodes/http/flow/node-type.d.ts +7 -0
- package/dist/nodes/http/flow/node-type.js +411 -0
- package/dist/nodes/http/flow/spec.d.ts +151 -0
- package/dist/nodes/http/flow/spec.js +1 -0
- package/dist/serialize.d.ts +2 -2
- package/dist/serialize.js +20 -276
- package/package.json +2 -2
package/dist/core/actions.d.ts
CHANGED
|
@@ -10,141 +10,6 @@
|
|
|
10
10
|
import type { Expr } from './expr.js';
|
|
11
11
|
import type { LookupToken } from './lookups.js';
|
|
12
12
|
import { type ConnectorDescriptor, type TriggerDescriptor } from './connectors.js';
|
|
13
|
-
/** One conditional response branch on an HTTP node — a designer-visible side exit. */
|
|
14
|
-
export interface HttpBranch {
|
|
15
|
-
/**
|
|
16
|
-
* The branch's name — it becomes the node's `branch-<name>` source port, so
|
|
17
|
-
* keep it port-safe (letters, digits, `_`, `-`). Route it with
|
|
18
|
-
* `.stepToList('branch-<name>', ...)` after the step; the main path continues
|
|
19
|
-
* from the default port as always.
|
|
20
|
-
*/
|
|
21
|
-
name: string;
|
|
22
|
-
/**
|
|
23
|
-
* When to take this exit, evaluated against the response — e.g.
|
|
24
|
-
* js-tagged: `$vars.fetch.output.statusCode === 429`. Branches are checked in
|
|
25
|
-
* order; the first truthy one wins, else the default port fires.
|
|
26
|
-
*/
|
|
27
|
-
condition: Expr;
|
|
28
|
-
}
|
|
29
|
-
interface HttpInputsBase {
|
|
30
|
-
/**
|
|
31
|
-
* Conditional response branches — extra source ports (`branch-<name>`)
|
|
32
|
-
* beside the default. See {@link HttpBranch}; both HTTP node families
|
|
33
|
-
* declare them.
|
|
34
|
-
*/
|
|
35
|
-
branches?: HttpBranch[];
|
|
36
|
-
method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
37
|
-
url: string | Expr;
|
|
38
|
-
headers?: Record<string, string | Expr>;
|
|
39
|
-
query?: Record<string, string | Expr>;
|
|
40
|
-
body?: string | Expr;
|
|
41
|
-
contentType?: string;
|
|
42
|
-
/**
|
|
43
|
-
* Choose the HTTP node explicitly. `false` emits the standalone
|
|
44
|
-
* `core.action.http`; `true` emits the managed `core.action.http.v2`, routed
|
|
45
|
-
* through Integration Service's HTTP connector.
|
|
46
|
-
*
|
|
47
|
-
* This has no default because these are different platform nodes, not two
|
|
48
|
-
* modes of one node. A silent `false` made an omitted field compile and
|
|
49
|
-
* validate as the wrong node while changing failure routing and connection
|
|
50
|
-
* behavior.
|
|
51
|
-
*
|
|
52
|
-
* It is not a version bump, it changes two things you can see:
|
|
53
|
-
*
|
|
54
|
-
* - **a 4xx/5xx FAILS the step**, so `.onError(…)` fires on it. On the plain
|
|
55
|
-
* node the same 404 comes back on the SUCCESS path as
|
|
56
|
-
* `out('fetch','statusCode')` and no error handler ever runs — which is why
|
|
57
|
-
* an error port only makes sense here (`check` says so: HTTP_ONERROR_V1).
|
|
58
|
-
* The handler can answer the flow (`.return`), stop the run
|
|
59
|
-
* (`.terminate`), or compensate and continue at a step the success path
|
|
60
|
-
* also reaches (`h.stepToRef('<step>')` — see `references/error-handling.md`);
|
|
61
|
-
* - both nodes expose JSON responses as parsed values in the live product;
|
|
62
|
-
* use `returns` to declare fields before reading them. The node choice does
|
|
63
|
-
* not decide whether application/json is parsed.
|
|
64
|
-
*
|
|
65
|
-
* With `managed: true`, omit `connection` and `folder` for the platform's
|
|
66
|
-
* manual/implicit mode, or provide both symbolic names to reuse an Integration
|
|
67
|
-
* Service HTTP connection. A local run remains unauthenticated.
|
|
68
|
-
*
|
|
69
|
-
* @enforcedBy HTTP_ONERROR_V1 `.onError()` on an http step needs `managed: true`; on
|
|
70
|
-
* the standalone node a 4xx arrives on the SUCCESS path and no handler runs.
|
|
71
|
-
*/
|
|
72
|
-
managed: boolean;
|
|
73
|
-
/**
|
|
74
|
-
* The response BODY's top-level fields and their types — e.g.
|
|
75
|
-
* `{ items: 'array' }`. Required for either HTTP node if anything reads a
|
|
76
|
-
* field off a parsed JSON body.
|
|
77
|
-
*
|
|
78
|
-
* Why you have to say: the platform's own definition declares the response as
|
|
79
|
-
* a bare object, because only the API being called knows its shape. Without
|
|
80
|
-
* this, `out('fetch','body','items')` reads from an object with no declared
|
|
81
|
-
* fields, and nothing downstream can tell a real field from a typo. Same rule,
|
|
82
|
-
* and the same word, as
|
|
83
|
-
* `rpaWorkflow`'s `returns`.
|
|
84
|
-
*
|
|
85
|
-
* **Where a declared field is read:** under `body`, never beside it. The
|
|
86
|
-
* response is an envelope — `{ body, statusCode, headers }` — and these are the
|
|
87
|
-
* body's fields, so `returns: { items: 'array' }` is read as
|
|
88
|
-
* `out('fetch', 'body.items')`, which is `$vars.fetch.output.body.items`.
|
|
89
|
-
* `$vars.fetch.output.items` is undefined at run time.
|
|
90
|
-
*
|
|
91
|
-
* @enforcedBy HTTP_READ_UNKNOWN_FIELD A read must be `output.body.<declared field>`,
|
|
92
|
-
* `output.statusCode` or `output.headers`.
|
|
93
|
-
* @enforcedBy HTTP_READ_WITHOUT_RETURNS Reading a body field requires declaring it here.
|
|
94
|
-
*/
|
|
95
|
-
returns?: Record<string, ReturnFieldType>;
|
|
96
|
-
/**
|
|
97
|
-
* How long to wait for the response before giving up, as an **ISO-8601
|
|
98
|
-
* duration** — `'PT30S'` is "give up after 30 seconds", `'PT1M'` one minute,
|
|
99
|
-
* `'PT15M'` fifteen.
|
|
100
|
-
*
|
|
101
|
-
* Both http node types carry this, and both definitions declare the same
|
|
102
|
-
* default (`PT15M`), so leaving it unset is not "no timeout" — it is fifteen
|
|
103
|
-
* minutes. Omitted from the emitted node unless you set it, which keeps a flow
|
|
104
|
-
* that doesn't care byte-identical to the platform's own default shape (~99%
|
|
105
|
-
* of the 808 deployed http nodes are on the defaults).
|
|
106
|
-
*
|
|
107
|
-
* `check` rejects a string the platform cannot parse as a duration —
|
|
108
|
-
* `'30s'`, `'PT'` and `'30'` are all errors that name the expected form.
|
|
109
|
-
*
|
|
110
|
-
* @defaultValue `'PT15M'`
|
|
111
|
-
* @enforcedBy HTTP_TIMEOUT_NOT_DURATION Must be an ISO-8601 duration.
|
|
112
|
-
*/
|
|
113
|
-
timeout?: string;
|
|
114
|
-
/**
|
|
115
|
-
* How many times to RETRY a retryable failure (5xx, 429, a network error) —
|
|
116
|
-
* `0`, the definitions' default, means "try once, don't retry". `2` means up
|
|
117
|
-
* to three attempts in total.
|
|
118
|
-
*
|
|
119
|
-
* Must be a non-negative integer. Above **5** `check` warns rather than
|
|
120
|
-
* errors: the deployed corpus's
|
|
121
|
-
* largest author-set value is 3, and the platform's own ceiling is not
|
|
122
|
-
* measured — so a bigger number may well work, and refusing it outright would
|
|
123
|
-
* fence off something we have no evidence is wrong.
|
|
124
|
-
*
|
|
125
|
-
* @defaultValue `0`
|
|
126
|
-
* @enforcedBy HTTP_RETRY_COUNT_INVALID Must be a non-negative integer.
|
|
127
|
-
*/
|
|
128
|
-
retryCount?: number;
|
|
129
|
-
}
|
|
130
|
-
export type HttpInputs = HttpInputsBase & ({
|
|
131
|
-
managed: false;
|
|
132
|
-
connection?: never;
|
|
133
|
-
folder?: never;
|
|
134
|
-
} | {
|
|
135
|
-
managed: true;
|
|
136
|
-
/** Symbolic HTTP connection name declared in bindings.json. */
|
|
137
|
-
connection?: string;
|
|
138
|
-
/** Symbolic folder name declared in bindings.json. */
|
|
139
|
-
folder?: string;
|
|
140
|
-
/**
|
|
141
|
-
* Connector key whose authentication the HTTP proxy should reuse.
|
|
142
|
-
* Defaults to `uipath-uipath-http`. Set this for a connector-specific
|
|
143
|
-
* fallback endpoint, for example `uipath-salesforce-slack`.
|
|
144
|
-
* Requires both `connection` and `folder`.
|
|
145
|
-
*/
|
|
146
|
-
targetConnector?: string;
|
|
147
|
-
});
|
|
148
13
|
export interface ConnectorOpts {
|
|
149
14
|
/** Connector action version (defaults to the library's newest match). */
|
|
150
15
|
version?: string;
|
|
@@ -1928,10 +1793,6 @@ export interface ContextIndexRef {
|
|
|
1928
1793
|
* whole body rather than an inputs payload.
|
|
1929
1794
|
*/
|
|
1930
1795
|
export interface FlowActionSpecs {
|
|
1931
|
-
/** The spec {@link http} builds. */
|
|
1932
|
-
http: {
|
|
1933
|
-
inputs: HttpInputs;
|
|
1934
|
-
};
|
|
1935
1796
|
/** The spec {@link hitl} builds. */
|
|
1936
1797
|
hitl: {
|
|
1937
1798
|
inputs: HitlInputs;
|
|
@@ -2059,14 +1920,6 @@ export declare function builtinActionSpec<S extends object>(spec: S): S;
|
|
|
2059
1920
|
* @returns The same spec, as a `FlowTrigger` instance.
|
|
2060
1921
|
*/
|
|
2061
1922
|
export declare function builtinTriggerSpec<S extends object>(spec: S): S;
|
|
2062
|
-
/**
|
|
2063
|
-
* Declare an HTTP request action, explicitly choosing standalone or managed.
|
|
2064
|
-
*
|
|
2065
|
-
* @param inputs - The request: `url`, `method`, `body`, the response fields you
|
|
2066
|
-
* read back via `returns`, and the `managed` node choice.
|
|
2067
|
-
* @returns An action spec to pass to `.step(name, …)`.
|
|
2068
|
-
*/
|
|
2069
|
-
export declare function http(inputs: HttpInputs): ActionSpec;
|
|
2070
1923
|
/**
|
|
2071
1924
|
* Declare a human task — a step that pauses for a person to read some values,
|
|
2072
1925
|
* fill others in, and press one of the outcome buttons.
|
package/dist/core/actions.js
CHANGED
|
@@ -88,21 +88,6 @@ export function builtinActionSpec(spec) {
|
|
|
88
88
|
export function builtinTriggerSpec(spec) {
|
|
89
89
|
return new BuiltinTrigger(spec);
|
|
90
90
|
}
|
|
91
|
-
/**
|
|
92
|
-
* Declare an HTTP request action, explicitly choosing standalone or managed.
|
|
93
|
-
*
|
|
94
|
-
* @param inputs - The request: `url`, `method`, `body`, the response fields you
|
|
95
|
-
* read back via `returns`, and the `managed` node choice.
|
|
96
|
-
* @returns An action spec to pass to `.step(name, …)`.
|
|
97
|
-
*/
|
|
98
|
-
export function http(inputs) {
|
|
99
|
-
if (typeof inputs.managed !== 'boolean') {
|
|
100
|
-
throw new Error('http() requires managed: true or managed: false because they emit different platform nodes. '
|
|
101
|
-
+ 'Use true for Managed HTTP Request/core.action.http.v2 or when non-2xx statuses must reach .onError(); '
|
|
102
|
-
+ 'use false for the standalone core.action.http node.');
|
|
103
|
-
}
|
|
104
|
-
return builtinActionSpec({ kind: 'http', inputs });
|
|
105
|
-
}
|
|
106
91
|
/**
|
|
107
92
|
* Declare a human task — a step that pauses for a person to read some values,
|
|
108
93
|
* fill others in, and press one of the outcome buttons.
|
package/dist/core/expr.d.ts
CHANGED
|
@@ -196,7 +196,7 @@ export type ErrorEnvelopeField = 'code' | 'message' | 'detail' | 'category' | 's
|
|
|
196
196
|
*
|
|
197
197
|
* So the author writes one shape, `.error.<field>`, and `serialize` rewrites it
|
|
198
198
|
* to `.output.<field>` for the one family that publishes it there
|
|
199
|
-
* (
|
|
199
|
+
* (a node type's `errorEnvelope`). Do not hand-write either prefix: which
|
|
200
200
|
* one is right is not a property of the expression, it is a property of the node
|
|
201
201
|
* the step happens to be, and only the builder knows that.
|
|
202
202
|
*
|
package/dist/core/expr.js
CHANGED
|
@@ -209,7 +209,7 @@ export function ran(step) {
|
|
|
209
209
|
*
|
|
210
210
|
* So the author writes one shape, `.error.<field>`, and `serialize` rewrites it
|
|
211
211
|
* to `.output.<field>` for the one family that publishes it there
|
|
212
|
-
* (
|
|
212
|
+
* (a node type's `errorEnvelope`). Do not hand-write either prefix: which
|
|
213
213
|
* one is right is not a property of the expression, it is a property of the node
|
|
214
214
|
* the step happens to be, and only the builder knows that.
|
|
215
215
|
*
|
|
@@ -258,7 +258,7 @@ export function ran(step) {
|
|
|
258
258
|
*/
|
|
259
259
|
export function err(step, field) {
|
|
260
260
|
// ONE shape for every family. `serialize` rewrites the prefix for the families
|
|
261
|
-
// that publish the envelope elsewhere — see `
|
|
261
|
+
// that publish the envelope elsewhere — see `FlowNodeType.errorEnvelope`.
|
|
262
262
|
return new Expr(`$vars.${step}.error${field ? '.' + field : ''}`);
|
|
263
263
|
}
|
|
264
264
|
/**
|
|
@@ -45,6 +45,13 @@ export interface OutputRead {
|
|
|
45
45
|
/** The step whose expression contains the read. */
|
|
46
46
|
reader: string;
|
|
47
47
|
}
|
|
48
|
+
/** A read of a node's output, split where a `reader` contract checks it. */
|
|
49
|
+
export interface OutputPathRead extends OutputRead {
|
|
50
|
+
/** The first segment after the step (`output`, `error`, …); undefined for a read of the step itself. */
|
|
51
|
+
field: string | undefined;
|
|
52
|
+
/** The path after `field`, as the reference spells it (with its leading `.`); `''` when there is none. */
|
|
53
|
+
rest: string;
|
|
54
|
+
}
|
|
48
55
|
/**
|
|
49
56
|
* How the artifact words a read of a `fields` output: the code prefix its read
|
|
50
57
|
* diagnostics share (`<PREFIX>_READ_NOT_OUTPUT`, `_READ_WITHOUT_RETURNS`,
|
|
@@ -65,6 +72,11 @@ export interface FieldsRead {
|
|
|
65
72
|
* states the fields a read may name — `undefined` when the author declared none,
|
|
66
73
|
* which makes any field read its own mistake — and `read` keeps the wording of
|
|
67
74
|
* the read rule it replaces, for the same reason. `open` admits any field.
|
|
75
|
+
*
|
|
76
|
+
* `reader` is for an output whose shape no field list states: an HTTP response is
|
|
77
|
+
* an envelope (`body`, `statusCode`, `headers`) whose `body` holds the author's
|
|
78
|
+
* `returns`. The type checks each read itself and reports through its family's
|
|
79
|
+
* catalog, with the codes it had before the port.
|
|
68
80
|
*/
|
|
69
81
|
export type OutputContract = {
|
|
70
82
|
readonly kind: 'none';
|
|
@@ -75,6 +87,9 @@ export type OutputContract = {
|
|
|
75
87
|
readonly fields: Readonly<Record<string, TypeDesc>> | undefined;
|
|
76
88
|
readonly open?: boolean;
|
|
77
89
|
readonly read: FieldsRead;
|
|
90
|
+
} | {
|
|
91
|
+
readonly kind: 'reader';
|
|
92
|
+
read(read: OutputPathRead, report: (code: string, message: string, suggestion?: string) => void): void;
|
|
78
93
|
} | {
|
|
79
94
|
readonly kind: 'opaque';
|
|
80
95
|
};
|
package/dist/core/step-ports.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The exits an action declares that the AUTHOR named — a human task's outcomes
|
|
3
|
-
*
|
|
2
|
+
* The exits an action declares that the AUTHOR named — a human task's outcomes —
|
|
3
|
+
* and the port each one leaves on. A registered node type declares its own
|
|
4
|
+
* (`FlowNodeType.exits`: an HTTP call's response branches); `stepExits` in
|
|
5
|
+
* flow-step-exits.ts asks it first and falls back here.
|
|
4
6
|
*
|
|
5
7
|
* This is what `.stepSwitch()` routes over, and the reason it exists as a table
|
|
6
|
-
* rather than as
|
|
8
|
+
* rather than as more `if (spec.kind === …)` arms: `serialize` has to turn
|
|
7
9
|
* an arm's `value` into a port, `check` has to say which values are legal and
|
|
8
10
|
* which were left out, and `decompile` has to turn a port back into a value.
|
|
9
|
-
* Those three read the same list
|
|
10
|
-
*
|
|
11
|
-
* ports".
|
|
11
|
+
* Those three read the same list instead of each carrying their own copy of
|
|
12
|
+
* "how a human task names its ports".
|
|
12
13
|
*
|
|
13
14
|
* `undefined` means the family has no author-declared fan-out at all, which is
|
|
14
15
|
* what makes `.stepSwitch()` on it an error rather than a no-op.
|
|
@@ -68,23 +69,6 @@ export function declaredExits(spec, pinnedVersion) {
|
|
|
68
69
|
...(e.endsProcess ? { endsProcess: true } : {}),
|
|
69
70
|
}));
|
|
70
71
|
}
|
|
71
|
-
if (kind === 'http') {
|
|
72
|
-
const branches = (spec?.inputs?.branches
|
|
73
|
-
?? []);
|
|
74
|
-
if (branches.length === 0) {
|
|
75
|
-
return {
|
|
76
|
-
reason: 'it declares no response branches',
|
|
77
|
-
suggestion: `branches: [{ name: 'rateLimited', condition: … }]`,
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
// The fall-through is an exit like any other here — it is what `.switch()`
|
|
81
|
-
// spells as its default arm, and leaving it out is the same omission as
|
|
82
|
-
// leaving out a branch.
|
|
83
|
-
return [
|
|
84
|
-
...branches.map((b) => ({ value: String(b?.name ?? ''), port: `branch-${b?.name ?? ''}` })),
|
|
85
|
-
{ value: 'default', port: 'default', isDefault: true },
|
|
86
|
-
];
|
|
87
|
-
}
|
|
88
72
|
return {
|
|
89
73
|
reason: `a ${kind ?? 'custom'} step declares no author-named exits`,
|
|
90
74
|
suggestion: 'Use .step(); route failures with .onError().',
|
|
@@ -21,8 +21,6 @@ import { ownEntry } from './own-entry.js';
|
|
|
21
21
|
* themselves (the Data Fabric verbs, since Phase 3).
|
|
22
22
|
*/
|
|
23
23
|
export const TYPED_FACTORIES = {
|
|
24
|
-
'core.action.http': { factory: 'http({ managed: false })' },
|
|
25
|
-
'core.action.http.v2': { factory: 'http({ managed: true })' },
|
|
26
24
|
'core.control.end': { factory: '.return()' },
|
|
27
25
|
'core.logic.decision': { factory: '.branch()' },
|
|
28
26
|
'core.logic.dowhile': { factory: '.doWhile(name, condition, body, { limit, breakEnabled })' },
|
package/dist/decompile.js
CHANGED
|
@@ -38,6 +38,7 @@ import { commentText } from './core/comment-text.js';
|
|
|
38
38
|
import { tsLiteral, tsNumber, tsText } from './core/ts-literal.js';
|
|
39
39
|
import { contextIndexSlug, parseContextIndexType } from './core/context-index.js';
|
|
40
40
|
import { wireExprBody } from './core/wire-expr.js';
|
|
41
|
+
import { hasExits } from './core/step-ports.js';
|
|
41
42
|
import { parseIxpProjectType } from './core/actions.js';
|
|
42
43
|
import { readFlowGlobals } from './flow-variables.js';
|
|
43
44
|
import { outputBackingGlobal, outputBackingName } from './flow-output-backing.js';
|
|
@@ -236,8 +237,6 @@ const T = {
|
|
|
236
237
|
triggerVoice: 'core.trigger.voice',
|
|
237
238
|
createOutgoingCall: 'uipath.conversational.voice.create-outgoing-call',
|
|
238
239
|
endCall: 'uipath.conversational.voice.end-call',
|
|
239
|
-
http: 'core.action.http',
|
|
240
|
-
httpV2: 'core.action.http.v2',
|
|
241
240
|
decision: 'core.logic.decision',
|
|
242
241
|
switch: 'core.logic.switch',
|
|
243
242
|
merge: 'core.logic.merge',
|
|
@@ -547,21 +546,29 @@ function specValue(raw) {
|
|
|
547
546
|
return raw;
|
|
548
547
|
}
|
|
549
548
|
/**
|
|
550
|
-
*
|
|
551
|
-
*
|
|
552
|
-
*
|
|
553
|
-
* as every built-in family lifts any version — and `verClause` omits a
|
|
554
|
-
* `{ version }` the type does not register, with a warning. `undefined` when the type is not registered, or the node type declines
|
|
555
|
-
* the node; the caller's branches take it from there.
|
|
549
|
+
* The registered implementation a node of this type and version lifts with: its
|
|
550
|
+
* own version's, else the type's default (as every built-in family lifts any
|
|
551
|
+
* version); undefined when the type is not registered.
|
|
556
552
|
*/
|
|
557
|
-
function
|
|
553
|
+
function registeredImpl(node) {
|
|
558
554
|
const entry = typeof node.type === 'string' ? FLOW_NODE_TYPES.byTypeName(node.type) : undefined;
|
|
559
555
|
if (!entry)
|
|
560
556
|
return undefined;
|
|
561
557
|
const version = String(node.typeVersion ?? '');
|
|
562
|
-
|
|
558
|
+
return (Object.hasOwn(entry.type.versions, version)
|
|
563
559
|
? entry.type.versions[version]
|
|
564
560
|
: entry.type.versions[entry.type.defaultVersion]);
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* A node of a registered type (flow-node-registry.ts), lifted to its spec by the
|
|
564
|
+
* type's own `deserialize`: undefined when the type is not registered or declines
|
|
565
|
+
* the node. A node at a version the type does not register is lifted by its
|
|
566
|
+
* default version's implementation, as every built-in family lifts any version.
|
|
567
|
+
*/
|
|
568
|
+
function liftRegistered(node, impl = registeredImpl(node)) {
|
|
569
|
+
if (!impl)
|
|
570
|
+
return undefined;
|
|
571
|
+
const version = String(node.typeVersion ?? '');
|
|
565
572
|
const ctx = {
|
|
566
573
|
nodeId: node.id,
|
|
567
574
|
expr: specValue,
|
|
@@ -574,8 +581,21 @@ function emitRegisteredSpec(node, imp, inputNames) {
|
|
|
574
581
|
warn: warnOnce,
|
|
575
582
|
};
|
|
576
583
|
const spec = impl.deserialize(node, ctx);
|
|
577
|
-
|
|
584
|
+
return spec === undefined ? undefined : { impl, spec };
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Print a node whose type is registered (flow-node-registry.ts): the node type
|
|
588
|
+
* deserializes it to its spec and prints the factory call. A node at a version
|
|
589
|
+
* the type does not register is lifted by its default version's implementation —
|
|
590
|
+
* as every built-in family lifts any version — and `verClause` omits a
|
|
591
|
+
* `{ version }` the type does not register, with a warning. `undefined` when the type is not registered, or the node type declines
|
|
592
|
+
* the node; the caller's branches take it from there.
|
|
593
|
+
*/
|
|
594
|
+
function emitRegisteredSpec(node, imp, inputNames) {
|
|
595
|
+
const lifted = liftRegistered(node);
|
|
596
|
+
if (!lifted)
|
|
578
597
|
return undefined;
|
|
598
|
+
const { impl, spec } = lifted;
|
|
579
599
|
// A spec value as source, recursing into arrays and plain objects so an Expr
|
|
580
600
|
// nested in one (a filter row's value) prints as the helper an author writes —
|
|
581
601
|
// in the `{ k: v }` / `[a, b]` spelling the hand-written printers use.
|
|
@@ -707,10 +727,6 @@ function emitStepSpec(node, imp, inputNames, o, graph) {
|
|
|
707
727
|
['exchangeLimit', num(i.exchangeLimit) === '20' ? undefined : num(i.exchangeLimit)],
|
|
708
728
|
])})`;
|
|
709
729
|
}
|
|
710
|
-
case T.http:
|
|
711
|
-
return emitHttp(node, false, imp, inputNames);
|
|
712
|
-
case T.httpV2:
|
|
713
|
-
return emitHttp(node, true, imp, inputNames);
|
|
714
730
|
default:
|
|
715
731
|
// A connector action node: `uipath.connector.<key>.<action>` (but NOT the
|
|
716
732
|
// event nodes `uipath.connector.event.*` / `.trigger.*`, which are triggers).
|
|
@@ -767,66 +783,6 @@ function emitStepSpec(node, imp, inputNames, o, graph) {
|
|
|
767
783
|
return unsupportedSpec(node, imp, o);
|
|
768
784
|
}
|
|
769
785
|
}
|
|
770
|
-
/**
|
|
771
|
-
* Invert an HTTP node. The plain node (`core.action.http`) keeps its request at
|
|
772
|
-
* the top level (`url` / `method` / `headers` / `queryParams` / `body` /
|
|
773
|
-
* `contentType`); the managed node (`core.action.http.v2`) nests the request
|
|
774
|
-
* inside `detail.bodyParameters` and routes through IS. Request settings
|
|
775
|
-
* (`timeout` / `retryCount`) sit at the top level on both. Emitted only-when-off
|
|
776
|
-
* their definition defaults, exactly as serialize writes them, so the round-trip
|
|
777
|
-
* stays minimal. The response schema (`returns`) is a Phase-2 refinement.
|
|
778
|
-
*/
|
|
779
|
-
function emitHttp(node, managed, imp, inputNames) {
|
|
780
|
-
const inputs = node.inputs ?? {};
|
|
781
|
-
const detail = managed
|
|
782
|
-
? (inputs.detail ?? {})
|
|
783
|
-
: {};
|
|
784
|
-
const req = managed
|
|
785
|
-
? detail.bodyParameters ?? {}
|
|
786
|
-
: inputs;
|
|
787
|
-
const method = typeof req.method === 'string' ? req.method : 'GET';
|
|
788
|
-
const headers = managed ? req.headers : inputs.headers;
|
|
789
|
-
const query = managed ? req.query : inputs.queryParams;
|
|
790
|
-
const bodySrc = req.body !== undefined && req.body !== '' ? emitVal(req.body, imp, inputNames) : undefined;
|
|
791
|
-
const headersSrc = emitValMap(headers, imp, inputNames) || undefined;
|
|
792
|
-
const querySrc = emitValMap(query, imp, inputNames) || undefined;
|
|
793
|
-
const contentType = !managed && typeof inputs.contentType === 'string' && inputs.contentType !== 'application/json'
|
|
794
|
-
? tsLiteral(inputs.contentType) : undefined;
|
|
795
|
-
const timeout = typeof inputs.timeout === 'string' && inputs.timeout !== 'PT15M' ? tsLiteral(inputs.timeout) : undefined;
|
|
796
|
-
const retry = inputs.retryCount !== undefined && Number(inputs.retryCount) !== 0 ? tsNumber(inputs.retryCount) : undefined;
|
|
797
|
-
const branchRows = Array.isArray(inputs.branches) ? inputs.branches : [];
|
|
798
|
-
const branchesSrc = branchRows.length
|
|
799
|
-
? `[${branchRows.map((b) => {
|
|
800
|
-
const cond = unwrapSource(b.conditionExpression) ?? '';
|
|
801
|
-
const expr = emitBareExpr(wireExprBody(cond), imp, inputNames);
|
|
802
|
-
return `{ name: ${tsText(b.name ?? b.id)}, condition: ${expr} }`;
|
|
803
|
-
}).join(', ')}]`
|
|
804
|
-
: undefined;
|
|
805
|
-
const connectionValue = detail.connectionId ?? detail.connectionResourceId ?? req.connection;
|
|
806
|
-
const connection = managed && typeof connectionValue === 'string' && connectionValue !== 'ImplicitConnection'
|
|
807
|
-
? tsLiteral(connectionValue) : undefined;
|
|
808
|
-
const folder = managed && typeof detail.connectionFolderKey === 'string' && detail.connectionFolderKey.length > 0
|
|
809
|
-
? tsLiteral(detail.connectionFolderKey) : undefined;
|
|
810
|
-
const targetConnector = managed && typeof req.targetConnector === 'string'
|
|
811
|
-
&& req.targetConnector !== 'uipath-uipath-http'
|
|
812
|
-
? tsLiteral(req.targetConnector) : undefined;
|
|
813
|
-
const spec = opts([
|
|
814
|
-
['url', emitVal(req.url ?? '', imp, inputNames)],
|
|
815
|
-
['method', method !== 'GET' ? tsLiteral(method) : undefined],
|
|
816
|
-
['headers', headersSrc],
|
|
817
|
-
['query', querySrc],
|
|
818
|
-
['body', bodySrc],
|
|
819
|
-
['contentType', contentType],
|
|
820
|
-
['managed', boolLit(managed)],
|
|
821
|
-
['connection', connection],
|
|
822
|
-
['folder', folder],
|
|
823
|
-
['targetConnector', targetConnector],
|
|
824
|
-
['timeout', timeout],
|
|
825
|
-
['retryCount', retry],
|
|
826
|
-
['branches', branchesSrc],
|
|
827
|
-
]);
|
|
828
|
-
return `${imp.use('http')}(${spec})`;
|
|
829
|
-
}
|
|
830
786
|
/**
|
|
831
787
|
* Split a connector `nodeType` (`uipath.connector.<key>.<action>`) into key +
|
|
832
788
|
* action. Mirrors `core/connectors.ts`'s `splitConnectorNodeType`.
|
|
@@ -2715,9 +2671,9 @@ function outcomeIdsOfNode(node) {
|
|
|
2715
2671
|
* The exits a node declares, read back off the EMITTED artifact rather than off
|
|
2716
2672
|
* an authored spec — `inputs.schema.outcomes` for a base or quick-form human
|
|
2717
2673
|
* task (the product draws one `outcome-<id>` handle per outcome on both, at
|
|
2718
|
-
* every version),
|
|
2719
|
-
*
|
|
2720
|
-
*
|
|
2674
|
+
* every version), and a registered type's own `exits` over the spec its lift
|
|
2675
|
+
* recovers (an HTTP call's `inputs.branches` plus `default`). The authoring-side
|
|
2676
|
+
* twin is `stepExits` in `flow-step-exits.ts`.
|
|
2721
2677
|
*/
|
|
2722
2678
|
function declaredExitsOfNode(node) {
|
|
2723
2679
|
const inputs = (node.inputs ?? {});
|
|
@@ -2729,16 +2685,16 @@ function declaredExitsOfNode(node) {
|
|
|
2729
2685
|
return undefined;
|
|
2730
2686
|
return outcomes.map((o) => ({ value: String(o?.name ?? ''), port: `outcome-${o?.id ?? ''}` }));
|
|
2731
2687
|
}
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
return
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
return
|
|
2688
|
+
// A registered type that declares exits answers from its own spec, lifted off
|
|
2689
|
+
// this node; one that declares none is not lifted at all (this runs per edge).
|
|
2690
|
+
const impl = registeredImpl(node);
|
|
2691
|
+
if (!impl?.exits)
|
|
2692
|
+
return undefined;
|
|
2693
|
+
const lifted = liftRegistered(node, impl);
|
|
2694
|
+
const exits = lifted && impl.exits(lifted.spec);
|
|
2695
|
+
if (!exits || !hasExits(exits))
|
|
2696
|
+
return undefined;
|
|
2697
|
+
return exits.map((e) => ({ value: e.value, port: e.port }));
|
|
2742
2698
|
}
|
|
2743
2699
|
/**
|
|
2744
2700
|
* Split a switch case expression into `<discriminant> === <literal>`, the only
|
|
@@ -11,10 +11,11 @@ import { hasBundledDefinition } from './flow-definitions.js';
|
|
|
11
11
|
import { dataFabricFlowFamily } from './nodes/data-fabric/flow/family.js';
|
|
12
12
|
import { delayFlowFamily } from './nodes/delay/flow/family.js';
|
|
13
13
|
import { documentFlowFamily } from './nodes/document/flow/family.js';
|
|
14
|
+
import { httpFlowFamily } from './nodes/http/flow/family.js';
|
|
14
15
|
import { mockFlowFamily } from './nodes/mock/flow/family.js';
|
|
15
16
|
import { queueFlowFamily } from './nodes/queue/flow/family.js';
|
|
16
17
|
import { scriptFlowFamily } from './nodes/script/flow/family.js';
|
|
17
18
|
import { transformFlowFamily } from './nodes/transform/flow/family.js';
|
|
18
19
|
/** The families, in no significant order. Adding one is the whole of registering it. */
|
|
19
|
-
export const FLOW_NODE_FAMILIES = [dataFabricFlowFamily, delayFlowFamily, documentFlowFamily, mockFlowFamily, queueFlowFamily, scriptFlowFamily, transformFlowFamily];
|
|
20
|
+
export const FLOW_NODE_FAMILIES = [dataFabricFlowFamily, delayFlowFamily, documentFlowFamily, httpFlowFamily, mockFlowFamily, queueFlowFamily, scriptFlowFamily, transformFlowFamily];
|
|
20
21
|
export const FLOW_NODE_TYPES = new NodeTypeRegistry('flow', FLOW_NODE_FAMILIES, { hasBundledDefinition });
|
package/dist/flow-node-type.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ import type { VersionedNodeType } from './core/nodes/versioned.js';
|
|
|
14
14
|
import type { NodeFamily, Placement } from './core/nodes/family.js';
|
|
15
15
|
import type { DefinitionReference, NodeContribution } from './core/node-classes.js';
|
|
16
16
|
import type { CheckOpts } from './check.js';
|
|
17
|
+
import type { DeclaredExit, NoExits } from './core/step-ports.js';
|
|
17
18
|
/**
|
|
18
19
|
* What a Flow node type's `serialize` returns: the node's type-owned fields.
|
|
19
20
|
*
|
|
@@ -81,6 +82,28 @@ export interface FlowSerializeContext {
|
|
|
81
82
|
* pair) or must pick an id that is not taken; add entries through `bind`.
|
|
82
83
|
*/
|
|
83
84
|
readonly bindings: ReadonlyMap<string, Readonly<Record<string, unknown>>>;
|
|
85
|
+
/**
|
|
86
|
+
* A symbolic `connection` or `folder` label resolved through the flow's
|
|
87
|
+
* bindings.json, as a connector step's is: a self-referential label throws the
|
|
88
|
+
* refusal check reports, and a value that cannot be a tenant id is warned about
|
|
89
|
+
* (`CONNECTION_STUB`). `where` names the site in both, e.g. `managed http "fetch"`.
|
|
90
|
+
*/
|
|
91
|
+
resolveBinding(name: string, attribute: 'connection' | 'folder', where: string): string;
|
|
92
|
+
/**
|
|
93
|
+
* Hoist the Integration Service connection pair a definition's `model`
|
|
94
|
+
* references (`<bindings.NAME>` for its connection id and folder key), deduped
|
|
95
|
+
* against the flow's existing entries by name, resource key and attribute. An
|
|
96
|
+
* unresolved connection still gets its entries (no `default`), so the
|
|
97
|
+
* definition's references always close.
|
|
98
|
+
*/
|
|
99
|
+
bindConnection(o: {
|
|
100
|
+
model: unknown;
|
|
101
|
+
connectorKey: string;
|
|
102
|
+
connectionId: string;
|
|
103
|
+
folderKey?: string;
|
|
104
|
+
/** The entries' `resourceKey`; defaults to `connectionId`. */
|
|
105
|
+
resourceKey?: string;
|
|
106
|
+
}): void;
|
|
84
107
|
}
|
|
85
108
|
/** What `deserialize` may ask of the decompiler, for one serialized node. */
|
|
86
109
|
export interface FlowDeserializeContext {
|
|
@@ -146,6 +169,20 @@ export interface FlowCheckContext {
|
|
|
146
169
|
} | undefined;
|
|
147
170
|
/** The options `check` was called with (the connector-library views among them). */
|
|
148
171
|
readonly options: CheckOpts;
|
|
172
|
+
/**
|
|
173
|
+
* Check a step's symbolic `connection` / `folder` labels against bindings.json,
|
|
174
|
+
* as a connector step's are, reporting `BINDING_SELF_NAME` / `BINDING_UNDECLARED`.
|
|
175
|
+
* Those codes are the pipeline's, shared by every family that binds a
|
|
176
|
+
* connection, so they belong to no family catalog. `use` names the connector
|
|
177
|
+
* the connection must belong to, for the cross-step connection-owner rule.
|
|
178
|
+
*/
|
|
179
|
+
bindingLabels(where: string, labels: {
|
|
180
|
+
connection?: unknown;
|
|
181
|
+
folder?: unknown;
|
|
182
|
+
}, use?: {
|
|
183
|
+
id: string;
|
|
184
|
+
connector: string | undefined;
|
|
185
|
+
}): void;
|
|
149
186
|
}
|
|
150
187
|
/** What a family-level `check` may ask of the checker. */
|
|
151
188
|
export interface FlowFamilyCheckContext {
|
|
@@ -199,6 +236,28 @@ export interface FlowNodeType<Spec> extends NodeType<Spec, FlowNodeContribution,
|
|
|
199
236
|
readonly nodeModel?: 'definition' | 'omit';
|
|
200
237
|
/** What `rawNode` reports for a raw node of this type. */
|
|
201
238
|
readonly rawNode?: FlowRawNodeAdvice;
|
|
239
|
+
/**
|
|
240
|
+
* The runtime variable a failed node's envelope is published under, when it is
|
|
241
|
+
* not `error`. `err()` writes one shape for every family
|
|
242
|
+
* (`$vars.<step>.error.<field>`), and serialize rewrites a handler's reads to
|
|
243
|
+
* this variable.
|
|
244
|
+
*
|
|
245
|
+
* Measured on the product, one debug run per family (2026-09-10): six of the
|
|
246
|
+
* seven families probed publish it as `<step>.error`, which is what the
|
|
247
|
+
* definitions declare (`outputDefinition.error.var`). The exception is
|
|
248
|
+
* `core.action.http.v2`, whose `<step>.error` is the boolean `true` and whose
|
|
249
|
+
* envelope is in `<step>.output` (instance 430d43ad-4583-40c0-8f74-b49d2c4904e4).
|
|
250
|
+
*/
|
|
251
|
+
readonly errorEnvelope?: string;
|
|
252
|
+
/**
|
|
253
|
+
* The exits the AUTHOR named on this step — an HTTP call's response branches,
|
|
254
|
+
* and the port each leaves on — or why it has none to route. What
|
|
255
|
+
* `.stepSwitch()` routes over, what an arm's `value` and a `.stepToList` port
|
|
256
|
+
* are checked against, and what decompile reads a fully wired node back as.
|
|
257
|
+
* Omitted: the type has no author-declared fan-out. The `error` port is never
|
|
258
|
+
* one of these (`.onError()` routes it).
|
|
259
|
+
*/
|
|
260
|
+
exits?(spec: Spec): DeclaredExit[] | NoExits;
|
|
202
261
|
}
|
|
203
262
|
/** A Flow node type with several versions. */
|
|
204
263
|
export type FlowVersionedNodeType<Spec> = VersionedNodeType<Spec, FlowNodeContribution, FlowContexts, FlowNodeType<Spec>>;
|
package/dist/flow-sdk.d.ts
CHANGED
|
@@ -21,6 +21,7 @@ export * from './core/actions.js';
|
|
|
21
21
|
export * from './nodes/data-fabric/flow/index.js';
|
|
22
22
|
export * from './nodes/delay/flow/index.js';
|
|
23
23
|
export * from './nodes/document/flow/index.js';
|
|
24
|
+
export * from './nodes/http/flow/index.js';
|
|
24
25
|
export * from './nodes/mock/flow/index.js';
|
|
25
26
|
export * from './nodes/queue/flow/index.js';
|
|
26
27
|
export * from './nodes/script/flow/index.js';
|
package/dist/flow-sdk.js
CHANGED
|
@@ -25,6 +25,7 @@ export * from './core/actions.js';
|
|
|
25
25
|
export * from './nodes/data-fabric/flow/index.js';
|
|
26
26
|
export * from './nodes/delay/flow/index.js';
|
|
27
27
|
export * from './nodes/document/flow/index.js';
|
|
28
|
+
export * from './nodes/http/flow/index.js';
|
|
28
29
|
export * from './nodes/mock/flow/index.js';
|
|
29
30
|
export * from './nodes/queue/flow/index.js';
|
|
30
31
|
export * from './nodes/script/flow/index.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type DeclaredExit, type NoExits } from './core/step-ports.js';
|
|
2
|
+
/**
|
|
3
|
+
* The author-declared exits of a step's spec: a registered type's own `exits`,
|
|
4
|
+
* at the version the step resolves to (its pin, else the type's choice; an
|
|
5
|
+
* unregistered pin falls back to that choice, as check's other rules do), and
|
|
6
|
+
* `declaredExits` for a kind not yet registered. `serialize` and `check` ask
|
|
7
|
+
* here, so they agree on what a port means.
|
|
8
|
+
*/
|
|
9
|
+
export declare function stepExits(spec: {
|
|
10
|
+
kind?: unknown;
|
|
11
|
+
inputs?: unknown;
|
|
12
|
+
} | undefined, pinnedVersion?: string): DeclaredExit[] | NoExits;
|