@uipath/maestro-builder-sdk 6.16.14 → 6.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/api-index.md +115 -114
- package/dist/api-members.md +295 -291
- package/dist/bindings-v2.d.ts +39 -1
- package/dist/bindings-v2.js +289 -9
- package/dist/bpmn/compile-cli.js +11 -2
- package/dist/bpmn/decompile.js +2 -1
- package/dist/bpmn/registry-fallback.js +9 -7
- package/dist/case/compile-cli.js +16 -6
- package/dist/case/decompile-cli.js +2 -1
- package/dist/case/decompile.js +3 -2
- package/dist/case/merge-cli.js +3 -2
- package/dist/check-cli.js +2 -30
- package/dist/check.js +278 -55
- package/dist/cli-library.d.ts +18 -4
- package/dist/cli-library.js +24 -6
- package/dist/cli-result.d.ts +9 -0
- package/dist/cli-result.js +12 -0
- package/dist/compile-cli.js +82 -86
- package/dist/core/actions.d.ts +71 -17
- package/dist/core/agentic-process-forms.d.ts +51 -0
- package/dist/core/agentic-process-forms.js +49 -0
- package/dist/core/binding-messages.d.ts +5 -0
- package/dist/core/cli-library.d.ts +16 -7
- package/dist/core/cli-library.js +53 -19
- package/dist/core/comment-text.d.ts +29 -0
- package/dist/core/comment-text.js +40 -0
- package/dist/core/connector-checks.d.ts +18 -2
- package/dist/core/connector-checks.js +15 -5
- package/dist/core/contribution-bindings.d.ts +73 -0
- package/dist/core/contribution-bindings.js +105 -0
- package/dist/core/error-port.d.ts +25 -0
- package/dist/core/error-port.js +36 -0
- package/dist/core/expr-check.js +7 -2
- package/dist/core/expr.d.ts +11 -5
- package/dist/core/expr.js +9 -3
- package/dist/core/json-file.d.ts +1 -0
- package/dist/core/json-file.js +12 -0
- package/dist/core/library.d.ts +19 -0
- package/dist/core/library.js +22 -6
- package/dist/core/script-return.js +4 -1
- package/dist/core/typed-raw-node.js +1 -0
- package/dist/core/typescript-module.d.ts +2 -0
- package/dist/core/typescript-module.js +18 -0
- package/dist/core-definitions.json +210 -0
- package/dist/decompile-cli.js +2 -1
- package/dist/decompile.js +64 -24
- package/dist/emit.js +4 -3
- package/dist/flow-sdk.d.ts +18 -12
- package/dist/flow-sdk.js +19 -8
- package/dist/flow-step-tree.d.ts +2 -3
- package/dist/flow-step-tree.js +2 -3
- package/dist/load.js +1 -1
- package/dist/merge-cli.js +3 -2
- package/dist/merge.d.ts +2 -1
- package/dist/merge.js +0 -0
- package/dist/path-within.d.ts +33 -0
- package/dist/path-within.js +41 -0
- package/dist/registry/archive/extract.js +2 -5
- package/dist/registry/curated-overlay.js +3 -2
- package/dist/registry/generators/descriptors.js +20 -18
- package/dist/registry/generators/triggers.js +4 -4
- package/dist/registry/prepare/messages.js +2 -1
- package/dist/registry/prepare/source-labels.js +60 -1
- package/dist/registry/prepare-cli.js +14 -4
- package/dist/registry/pull-cli.js +3 -2
- package/dist/registry/uip/client.d.ts +28 -3
- package/dist/registry/uip/client.js +95 -34
- package/dist/registry/uip/host.d.ts +41 -0
- package/dist/registry/uip/host.js +312 -0
- package/dist/serialize.d.ts +7 -0
- package/dist/serialize.js +414 -277
- package/dist/workdir.js +1 -1
- package/package.json +3 -3
package/dist/core/cli-library.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import { existsSync } from 'node:fs';
|
|
18
18
|
import { join } from 'node:path';
|
|
19
|
-
import { Library } from './library.js';
|
|
19
|
+
import { ConnectorResolveError, Library } from './library.js';
|
|
20
20
|
import { resolveLibraryDir } from './library-cache.js';
|
|
21
21
|
import { flagValue } from '../cli-run.js';
|
|
22
22
|
import { defaultOverlayDir } from '../workdir.js';
|
|
@@ -41,19 +41,28 @@ export function openCliLibrary(argv) {
|
|
|
41
41
|
* The connector half of a family's check options, from a library the CLI already
|
|
42
42
|
* opened.
|
|
43
43
|
*
|
|
44
|
-
* Every callback fails OPEN:
|
|
45
|
-
*
|
|
46
|
-
* `check` stay the fast inner-loop rung — a process with no
|
|
47
|
-
* library
|
|
48
|
-
*
|
|
44
|
+
* Every fact callback fails OPEN: no library at all, or an entry the library
|
|
45
|
+
* cannot resolve, means "unknown", and an unknown fact fires no rule. That is
|
|
46
|
+
* what lets `check` stay the fast inner-loop rung — a process with no
|
|
47
|
+
* connectors needs no library. The one exception is the resolution itself:
|
|
48
|
+
* `connectorResolveError` reports the refusal `compile` would throw for an
|
|
49
|
+
* action, the way `eventResolveError` does for an event, so `check` never
|
|
50
|
+
* passes a connector step `compile` refuses (#948).
|
|
51
|
+
*
|
|
52
|
+
* `inputErrors` is the family's field-contract validator. The default speaks
|
|
53
|
+
* the `=`-expression dialect BPMN uses; Flow passes its own, which renders its
|
|
54
|
+
* expressions (see `flowCheckOpts` in `../cli-library.ts`).
|
|
49
55
|
*
|
|
50
56
|
* The `resolutions` are the overlay's: without them every lookup already
|
|
51
57
|
* recorded by `registry prepare --resolve` would be reported as still owed,
|
|
52
58
|
* telling the author to re-run a prepare they already ran.
|
|
53
59
|
*/
|
|
54
|
-
export function connectorCheckOpts(library, bindings) {
|
|
60
|
+
export function connectorCheckOpts(library, bindings, inputErrors = (rc, inputs, resolutions, lookups) => connectorInputErrors(rc, inputs, resolutions, lookups, { dialect: EQUALS_EXPR_DIALECT })) {
|
|
55
61
|
if (!library)
|
|
56
62
|
return bindings ? { bindings } : {};
|
|
63
|
+
// One memoized resolve per connector step, shared by `connectorResolveError`
|
|
64
|
+
// and `connectorInputs`, so the second hook does not resolve again.
|
|
65
|
+
const resolve = connectorResolver(library);
|
|
57
66
|
return {
|
|
58
67
|
eventResolveError: eventResolveErrorFor(library),
|
|
59
68
|
...byoaCheckOpts(library),
|
|
@@ -85,26 +94,51 @@ export function connectorCheckOpts(library, bindings) {
|
|
|
85
94
|
return undefined;
|
|
86
95
|
}
|
|
87
96
|
},
|
|
97
|
+
// The refusal compile throws for an operation it cannot resolve, with its
|
|
98
|
+
// code and text: CONNECTOR_NOT_IN_LIBRARY, CONNECTOR_OBJECT_REQUIRED,
|
|
99
|
+
// CONNECTOR_OBJECT_NOT_GENERIC.
|
|
100
|
+
connectorResolveError: (spec) => {
|
|
101
|
+
const r = resolve(spec);
|
|
102
|
+
return 'error' in r ? r.error : undefined;
|
|
103
|
+
},
|
|
88
104
|
// The field contract compile enforces, from the same validator, so the inner
|
|
89
105
|
// loop and the emit rung cannot disagree about a missing required field, an
|
|
90
|
-
// unknown key or a mistyped value. An operation
|
|
91
|
-
//
|
|
92
|
-
//
|
|
93
|
-
// The `=`-expression dialect, because this bag serves the families that spell
|
|
94
|
-
// an expression that way. Flow binds its own `connectorInputErrors` in
|
|
95
|
-
// `serialize.ts`, which carries `renderDeep` with it, and overrides this.
|
|
106
|
+
// unknown key or a mistyped value. An unresolvable operation is
|
|
107
|
+
// `connectorResolveError`'s to report; here it just means "unknown".
|
|
96
108
|
connectorInputs: (spec, inputs) => {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
return connectorInputErrors(rc, inputs, library.lookupResolutions ?? {}, library.lookupSpecs(spec.key, spec.action, spec.version, spec.object) ?? {}, { dialect: EQUALS_EXPR_DIALECT });
|
|
100
|
-
}
|
|
101
|
-
catch {
|
|
109
|
+
const r = resolve(spec);
|
|
110
|
+
if (!('rc' in r))
|
|
102
111
|
return undefined;
|
|
103
|
-
}
|
|
112
|
+
return inputErrors(r.rc, inputs, library.lookupResolutions ?? {}, library.lookupSpecs(spec.key, spec.action, spec.version, spec.object) ?? {});
|
|
104
113
|
},
|
|
105
114
|
...(bindings ? { bindings } : {}),
|
|
106
115
|
};
|
|
107
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* `library.resolve` for one connector step, memoized per step for the life of
|
|
119
|
+
* one check's options. A {@link ConnectorResolveError} is the refusal compile
|
|
120
|
+
* throws and becomes `error`; anything else thrown is not a verdict about the
|
|
121
|
+
* author's source and stays "unknown", as before.
|
|
122
|
+
*/
|
|
123
|
+
function connectorResolver(library) {
|
|
124
|
+
const memo = new Map();
|
|
125
|
+
return (spec) => {
|
|
126
|
+
const id = JSON.stringify([spec.key, spec.action, spec.version ?? null, spec.object ?? null]);
|
|
127
|
+
let r = memo.get(id);
|
|
128
|
+
if (!r) {
|
|
129
|
+
try {
|
|
130
|
+
r = { rc: library.resolve(spec.key, spec.action, spec.version, spec.object) };
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
r = error instanceof ConnectorResolveError
|
|
134
|
+
? { error: { code: error.code, message: error.message } }
|
|
135
|
+
: { unknown: true };
|
|
136
|
+
}
|
|
137
|
+
memo.set(id, r);
|
|
138
|
+
}
|
|
139
|
+
return r;
|
|
140
|
+
};
|
|
141
|
+
}
|
|
108
142
|
/**
|
|
109
143
|
* `check`'s EVENT_UNKNOWN verdict: the message `library.resolveEvent` throws
|
|
110
144
|
* for a subscription, or `undefined` when it resolves.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text that is safe inside a generated `//` or `/* … *\/` comment.
|
|
3
|
+
*
|
|
4
|
+
* A decompiler or generator that splices an input string into a comment hands that
|
|
5
|
+
* string the rest of the comment: a line terminator ends a `//` comment, `*\/` ends a
|
|
6
|
+
* block, and whatever follows is CODE in a file `compile` later executes. Those are the
|
|
7
|
+
* only two ways out of a JavaScript comment, so replacing both (line terminators — LF,
|
|
8
|
+
* CR, U+2028, U+2029 — with one space, `*\/` with `* /`) is complete, not a denylist.
|
|
9
|
+
* The replacements are the ones registry/generators already used, so their output keeps
|
|
10
|
+
* its bytes. FB006 holds every comment interpolation to this function.
|
|
11
|
+
*
|
|
12
|
+
* The result is ONE line: a multi-line value is flattened, which is right for a `//`
|
|
13
|
+
* line or a single ` * ` body line. To keep a value's line breaks, use `commentLines`
|
|
14
|
+
* (one escaped, prefixed line per input line) or `docComment` (a whole `/** … *\/`).
|
|
15
|
+
*/
|
|
16
|
+
export declare function commentText(value: string | number): string;
|
|
17
|
+
/**
|
|
18
|
+
* `value` split on its line terminators, each line escaped by `commentText` and
|
|
19
|
+
* given `prefix` (`'// '`, `' * '`), trailing whitespace trimmed so a blank line is
|
|
20
|
+
* a bare `//` or ` *`. The lines are joined with `\n` by the caller, so a value's
|
|
21
|
+
* paragraph breaks survive and none of them can end the comment.
|
|
22
|
+
*/
|
|
23
|
+
export declare function commentLines(value: string | number, prefix?: string): string[];
|
|
24
|
+
/**
|
|
25
|
+
* A JSDoc comment holding `value`, at `indent`. A one-line value keeps the
|
|
26
|
+
* one-line form, `/** value *\/`, so its bytes do not change; a multi-line value
|
|
27
|
+
* gets an open block with one ` * ` line per input line.
|
|
28
|
+
*/
|
|
29
|
+
export declare function docComment(value: string | number, indent?: string): string[];
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** The line terminators (LF, CR, CRLF, U+2028, U+2029): the one way out of a `//` comment. */
|
|
2
|
+
const LINE_BREAK = /\r\n?|[\n\u2028\u2029]/g;
|
|
3
|
+
/**
|
|
4
|
+
* Text that is safe inside a generated `//` or `/* … *\/` comment.
|
|
5
|
+
*
|
|
6
|
+
* A decompiler or generator that splices an input string into a comment hands that
|
|
7
|
+
* string the rest of the comment: a line terminator ends a `//` comment, `*\/` ends a
|
|
8
|
+
* block, and whatever follows is CODE in a file `compile` later executes. Those are the
|
|
9
|
+
* only two ways out of a JavaScript comment, so replacing both (line terminators — LF,
|
|
10
|
+
* CR, U+2028, U+2029 — with one space, `*\/` with `* /`) is complete, not a denylist.
|
|
11
|
+
* The replacements are the ones registry/generators already used, so their output keeps
|
|
12
|
+
* its bytes. FB006 holds every comment interpolation to this function.
|
|
13
|
+
*
|
|
14
|
+
* The result is ONE line: a multi-line value is flattened, which is right for a `//`
|
|
15
|
+
* line or a single ` * ` body line. To keep a value's line breaks, use `commentLines`
|
|
16
|
+
* (one escaped, prefixed line per input line) or `docComment` (a whole `/** … *\/`).
|
|
17
|
+
*/
|
|
18
|
+
export function commentText(value) {
|
|
19
|
+
return String(value).replace(LINE_BREAK, ' ').replaceAll('*/', '* /');
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* `value` split on its line terminators, each line escaped by `commentText` and
|
|
23
|
+
* given `prefix` (`'// '`, `' * '`), trailing whitespace trimmed so a blank line is
|
|
24
|
+
* a bare `//` or ` *`. The lines are joined with `\n` by the caller, so a value's
|
|
25
|
+
* paragraph breaks survive and none of them can end the comment.
|
|
26
|
+
*/
|
|
27
|
+
export function commentLines(value, prefix = '') {
|
|
28
|
+
return String(value).split(LINE_BREAK).map((line) => `${prefix}${commentText(line)}`.trimEnd());
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* A JSDoc comment holding `value`, at `indent`. A one-line value keeps the
|
|
32
|
+
* one-line form, `/** value *\/`, so its bytes do not change; a multi-line value
|
|
33
|
+
* gets an open block with one ` * ` line per input line.
|
|
34
|
+
*/
|
|
35
|
+
export function docComment(value, indent = '') {
|
|
36
|
+
const body = commentLines(value);
|
|
37
|
+
if (body.length === 1)
|
|
38
|
+
return [`${indent}/** ${commentText(value)} */`];
|
|
39
|
+
return [`${indent}/**`, ...body.map((line) => `${indent} * ${line}`.trimEnd()), `${indent} */`];
|
|
40
|
+
}
|
|
@@ -113,6 +113,21 @@ export interface ConnectorCheckOpts {
|
|
|
113
113
|
resolutions?: LookupResolutions;
|
|
114
114
|
/** Whether a connector step's schema is materialized locally. */
|
|
115
115
|
schemaReadiness?: (connector: string, action: string, version?: string, object?: string) => SchemaReadiness | undefined;
|
|
116
|
+
/**
|
|
117
|
+
* Why `compile` could not resolve this operation at all (`library.resolve`
|
|
118
|
+
* throws), or `undefined` when it resolves. Checked before
|
|
119
|
+
* {@link ConnectorCheckOpts.connectorInputs}, which answers `undefined` for an
|
|
120
|
+
* unresolvable operation and so cannot tell "not in the library" from "no facts".
|
|
121
|
+
*/
|
|
122
|
+
connectorResolveError?: (spec: {
|
|
123
|
+
key: string;
|
|
124
|
+
action: string;
|
|
125
|
+
version?: string;
|
|
126
|
+
object?: string;
|
|
127
|
+
}) => {
|
|
128
|
+
code: string;
|
|
129
|
+
message: string;
|
|
130
|
+
} | undefined;
|
|
116
131
|
/** What `compile` would refuse these inputs with, or `undefined` when it would accept them. */
|
|
117
132
|
connectorInputs?: (spec: {
|
|
118
133
|
key: string;
|
|
@@ -157,9 +172,10 @@ export declare function checkConnectorLookups(where: string, spec: ConnectorSpec
|
|
|
157
172
|
*/
|
|
158
173
|
export declare function checkConnectorSchema(where: string, spec: ConnectorSpec, opts: ConnectorCheckOpts, dialect: ExprDialect, report: ReportConnector): void;
|
|
159
174
|
/**
|
|
160
|
-
* The field contract and the binding names `compile` enforces,
|
|
175
|
+
* The operation, its field contract and the binding names `compile` enforces,
|
|
176
|
+
* reported here first.
|
|
161
177
|
*
|
|
162
|
-
*
|
|
178
|
+
* Each rule runs only with the facts in hand (a library for the operation and its fields, a
|
|
163
179
|
* bindings.json for the names); without them `check` stays a pure function of the
|
|
164
180
|
* built model and says nothing, as before.
|
|
165
181
|
*/
|
|
@@ -321,18 +321,28 @@ export function checkConnectorSchema(where, spec, opts, dialect, report) {
|
|
|
321
321
|
}
|
|
322
322
|
}
|
|
323
323
|
/**
|
|
324
|
-
* The field contract and the binding names `compile` enforces,
|
|
324
|
+
* The operation, its field contract and the binding names `compile` enforces,
|
|
325
|
+
* reported here first.
|
|
325
326
|
*
|
|
326
|
-
*
|
|
327
|
+
* Each rule runs only with the facts in hand (a library for the operation and its fields, a
|
|
327
328
|
* bindings.json for the names); without them `check` stays a pure function of the
|
|
328
329
|
* built model and says nothing, as before.
|
|
329
330
|
*/
|
|
330
331
|
export function checkConnectorContract(where, spec, opts, report,
|
|
331
332
|
/** The activity's own id, for {@link connectionConnectorConflicts}; omit to record nothing. */
|
|
332
333
|
id) {
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
|
|
334
|
+
const target = { key: spec.key, action: spec.action, version: spec.version, object: spec.object };
|
|
335
|
+
// The operation itself first: an operation compile cannot resolve has no field
|
|
336
|
+
// contract to check, and `connectorInputs` answers "unknown" for it.
|
|
337
|
+
const unresolved = opts.connectorResolveError?.(target);
|
|
338
|
+
if (unresolved) {
|
|
339
|
+
report({ level: 'error', code: unresolved.code, message: `${where}: ${unresolved.message}` });
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
const inputErr = opts.connectorInputs?.(target, spec.inputs ?? {});
|
|
343
|
+
if (inputErr) {
|
|
344
|
+
report({ level: 'error', code: 'CONNECTOR_INPUT', message: `${where}: ${inputErr}` });
|
|
345
|
+
}
|
|
336
346
|
}
|
|
337
347
|
checkBindingLabels(where, spec, opts, (code, message) => report({ level: 'error', code, message }), { key: spec.key, action: spec.action }, id === undefined ? undefined : { id, connector: spec.key });
|
|
338
348
|
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `bindings[]` entries a contribution-lowered node needs and did not supply
|
|
3
|
+
* (flow-builder-sdk#942).
|
|
4
|
+
*
|
|
5
|
+
* A definition's `model.context` names its resource through `<bindings.NAME>`
|
|
6
|
+
* placeholders, and declares each NAME in `model.bindings.values`. The typed
|
|
7
|
+
* emitters (rpa, api-workflow, queue, ixp, connector) close those names by hand.
|
|
8
|
+
* A `rawNode` or a hand-written `FlowAction` returns a definition and inputs, and
|
|
9
|
+
* usually no `bindings` — so before this, nothing closed them, and compile failed
|
|
10
|
+
* at `BINDING_PLACEHOLDER_UNRESOLVED` while `check` passed.
|
|
11
|
+
*
|
|
12
|
+
* For instance, the manifest `registry get --local` returns for a sibling Flow:
|
|
13
|
+
*
|
|
14
|
+
* ```json
|
|
15
|
+
* "model": { "bindings": { "resource": "process", "resourceSubType": "Flow", "resourceKey": "k1",
|
|
16
|
+
* "values": [{ "name": "name", "default": "Notifier" }, { "name": "folderPath", "default": "" }] },
|
|
17
|
+
* "context": [{ "name": "name", "value": "<bindings.name>" }, { "name": "folderPath", "value": "<bindings.folderPath>" }] }
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* needs two `process` entries keyed `k1`: `name` = "Notifier" and `folderPath` = "".
|
|
21
|
+
* {@link planContributionBindings} reads exactly those facts off the definition.
|
|
22
|
+
*
|
|
23
|
+
* `connection` resources are out of scope: a connector definition's entries are
|
|
24
|
+
* keyed by the tenant connection id, which the definition does not carry. A raw
|
|
25
|
+
* connector node is refused for that reason (`connector-raw-node.ts`).
|
|
26
|
+
*
|
|
27
|
+
* Pure: `serialize` lowers with it, and `check` runs it dry so the two agree.
|
|
28
|
+
*/
|
|
29
|
+
/** One `bindings[]` entry, as the flow file carries it. */
|
|
30
|
+
export interface PlannedBinding {
|
|
31
|
+
name: string;
|
|
32
|
+
type: string;
|
|
33
|
+
resource: string;
|
|
34
|
+
resourceKey: string;
|
|
35
|
+
default?: string;
|
|
36
|
+
propertyAttribute: string;
|
|
37
|
+
resourceSubType?: string;
|
|
38
|
+
}
|
|
39
|
+
/** What one definition needs: the entries to build, and the names it cannot close. */
|
|
40
|
+
export interface ContributionBindingPlan {
|
|
41
|
+
/** The resource kind (`model.bindings.resource`), when it is one this plan closes. */
|
|
42
|
+
resource?: string;
|
|
43
|
+
/** The resource key every entry carries (`model.bindings.resourceKey`). */
|
|
44
|
+
resourceKey?: string;
|
|
45
|
+
/** One entry per referenced name the contribution did not supply. */
|
|
46
|
+
entries: PlannedBinding[];
|
|
47
|
+
/** One sentence per referenced name that cannot be closed, and why. Empty when every name closes. */
|
|
48
|
+
problems: string[];
|
|
49
|
+
}
|
|
50
|
+
/** The `<bindings.NAME>` names a definition's `model.context` references, in order, once each. */
|
|
51
|
+
export declare function referencedBindingNames(model: any): string[];
|
|
52
|
+
/**
|
|
53
|
+
* Plan the entries a contribution-lowered node needs: for each `<bindings.NAME>`
|
|
54
|
+
* its definition's `model.context` references and `supplied` does not cover, one
|
|
55
|
+
* entry built from the definition — `resource`, `resourceKey`, `resourceSubType`
|
|
56
|
+
* from `model.bindings`, and `name`, `default`, `propertyAttribute` from the
|
|
57
|
+
* matching `model.bindings.values` row.
|
|
58
|
+
*
|
|
59
|
+
* A supplied entry covers a name when it has the same `resource` and `name`: the
|
|
60
|
+
* contributor's own bindings win, as they always did.
|
|
61
|
+
*
|
|
62
|
+
* A name is a problem (not an entry) when the definition declares no
|
|
63
|
+
* `values` row for it, or carries no `resourceKey` — a per-tenant template such
|
|
64
|
+
* as the bundled `core.action.queue.create` (`resourceKey: ""`), which only a
|
|
65
|
+
* typed factory can fill.
|
|
66
|
+
*
|
|
67
|
+
* @param def - The resolved definition.
|
|
68
|
+
* @param supplied - The bindings the contribution returned.
|
|
69
|
+
*/
|
|
70
|
+
export declare function planContributionBindings(def: any, supplied?: readonly {
|
|
71
|
+
resource?: string;
|
|
72
|
+
name?: string;
|
|
73
|
+
}[]): ContributionBindingPlan;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `bindings[]` entries a contribution-lowered node needs and did not supply
|
|
3
|
+
* (flow-builder-sdk#942).
|
|
4
|
+
*
|
|
5
|
+
* A definition's `model.context` names its resource through `<bindings.NAME>`
|
|
6
|
+
* placeholders, and declares each NAME in `model.bindings.values`. The typed
|
|
7
|
+
* emitters (rpa, api-workflow, queue, ixp, connector) close those names by hand.
|
|
8
|
+
* A `rawNode` or a hand-written `FlowAction` returns a definition and inputs, and
|
|
9
|
+
* usually no `bindings` — so before this, nothing closed them, and compile failed
|
|
10
|
+
* at `BINDING_PLACEHOLDER_UNRESOLVED` while `check` passed.
|
|
11
|
+
*
|
|
12
|
+
* For instance, the manifest `registry get --local` returns for a sibling Flow:
|
|
13
|
+
*
|
|
14
|
+
* ```json
|
|
15
|
+
* "model": { "bindings": { "resource": "process", "resourceSubType": "Flow", "resourceKey": "k1",
|
|
16
|
+
* "values": [{ "name": "name", "default": "Notifier" }, { "name": "folderPath", "default": "" }] },
|
|
17
|
+
* "context": [{ "name": "name", "value": "<bindings.name>" }, { "name": "folderPath", "value": "<bindings.folderPath>" }] }
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* needs two `process` entries keyed `k1`: `name` = "Notifier" and `folderPath` = "".
|
|
21
|
+
* {@link planContributionBindings} reads exactly those facts off the definition.
|
|
22
|
+
*
|
|
23
|
+
* `connection` resources are out of scope: a connector definition's entries are
|
|
24
|
+
* keyed by the tenant connection id, which the definition does not carry. A raw
|
|
25
|
+
* connector node is refused for that reason (`connector-raw-node.ts`).
|
|
26
|
+
*
|
|
27
|
+
* Pure: `serialize` lowers with it, and `check` runs it dry so the two agree.
|
|
28
|
+
*/
|
|
29
|
+
/** The `<bindings.NAME>` names a definition's `model.context` references, in order, once each. */
|
|
30
|
+
export function referencedBindingNames(model) {
|
|
31
|
+
const names = [];
|
|
32
|
+
for (const row of Array.isArray(model?.context) ? model.context : []) {
|
|
33
|
+
const name = typeof row?.value === 'string' ? /^<bindings\.(.+)>$/.exec(row.value)?.[1] : undefined;
|
|
34
|
+
if (name !== undefined && !names.includes(name))
|
|
35
|
+
names.push(name);
|
|
36
|
+
}
|
|
37
|
+
return names;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Plan the entries a contribution-lowered node needs: for each `<bindings.NAME>`
|
|
41
|
+
* its definition's `model.context` references and `supplied` does not cover, one
|
|
42
|
+
* entry built from the definition — `resource`, `resourceKey`, `resourceSubType`
|
|
43
|
+
* from `model.bindings`, and `name`, `default`, `propertyAttribute` from the
|
|
44
|
+
* matching `model.bindings.values` row.
|
|
45
|
+
*
|
|
46
|
+
* A supplied entry covers a name when it has the same `resource` and `name`: the
|
|
47
|
+
* contributor's own bindings win, as they always did.
|
|
48
|
+
*
|
|
49
|
+
* A name is a problem (not an entry) when the definition declares no
|
|
50
|
+
* `values` row for it, or carries no `resourceKey` — a per-tenant template such
|
|
51
|
+
* as the bundled `core.action.queue.create` (`resourceKey: ""`), which only a
|
|
52
|
+
* typed factory can fill.
|
|
53
|
+
*
|
|
54
|
+
* @param def - The resolved definition.
|
|
55
|
+
* @param supplied - The bindings the contribution returned.
|
|
56
|
+
*/
|
|
57
|
+
export function planContributionBindings(def, supplied = []) {
|
|
58
|
+
const model = def?.model;
|
|
59
|
+
const names = referencedBindingNames(model);
|
|
60
|
+
const resource = model?.bindings?.resource;
|
|
61
|
+
// Connection (or undeclared) resources are keyed by a tenant connection id the
|
|
62
|
+
// definition does not carry; the connector paths own them.
|
|
63
|
+
if (names.length === 0 || typeof resource !== 'string' || !resource || resource === 'connection') {
|
|
64
|
+
return { entries: [], problems: [] };
|
|
65
|
+
}
|
|
66
|
+
const open = names.filter((n) => !supplied.some((b) => b?.resource === resource && b?.name === n));
|
|
67
|
+
if (open.length === 0)
|
|
68
|
+
return { resource, entries: [], problems: [] };
|
|
69
|
+
const label = `${def?.nodeType}@${def?.version}`;
|
|
70
|
+
const resourceKey = model.bindings.resourceKey;
|
|
71
|
+
if (typeof resourceKey !== 'string' || !resourceKey) {
|
|
72
|
+
return {
|
|
73
|
+
resource,
|
|
74
|
+
entries: [],
|
|
75
|
+
problems: open.map((n) => `${label} references "<bindings.${n}>", and its model.bindings carries no resourceKey, so no `
|
|
76
|
+
+ `"${resource}" binding can be built for it. This definition is a per-tenant template, not a resolved `
|
|
77
|
+
+ `manifest: use the typed factory for the family, or the manifest \`uip maestro flow registry get `
|
|
78
|
+
+ `${def?.nodeType}\` returns for a real resource, or return the bindings from contribute().`),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const values = Array.isArray(model.bindings.values) ? model.bindings.values : [];
|
|
82
|
+
const subType = model.bindings.resourceSubType;
|
|
83
|
+
const entries = [];
|
|
84
|
+
const problems = [];
|
|
85
|
+
for (const n of open) {
|
|
86
|
+
const row = values.find((r) => r?.name === n);
|
|
87
|
+
if (!row) {
|
|
88
|
+
problems.push(`${label} references "<bindings.${n}>", but its model.bindings.values declares no "${n}" row, so `
|
|
89
|
+
+ `there is no default to bind it to. Pass the manifest exactly as \`uip maestro flow registry get\` `
|
|
90
|
+
+ `returns it, or return the "${n}" binding from contribute().`);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
entries.push({
|
|
94
|
+
name: n,
|
|
95
|
+
type: typeof row.type === 'string' && row.type ? row.type : 'string',
|
|
96
|
+
resource,
|
|
97
|
+
resourceKey,
|
|
98
|
+
...(typeof row.default === 'string' ? { default: row.default } : {}),
|
|
99
|
+
propertyAttribute: typeof row.propertyAttribute === 'string' && row.propertyAttribute
|
|
100
|
+
? row.propertyAttribute : n,
|
|
101
|
+
...(typeof subType === 'string' && subType ? { resourceSubType: subType } : {}),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return { resource, resourceKey, entries, problems };
|
|
105
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Does a node definition have an `error` port? One answer for `check` and
|
|
3
|
+
* `serialize` (flow-builder-sdk#943).
|
|
4
|
+
*
|
|
5
|
+
* The product's rule, read from @uipath/flow-core and @uipath/flow-tool:
|
|
6
|
+
*
|
|
7
|
+
* - the manifest client injects an `error` source handle into every served
|
|
8
|
+
* definition with `supportsErrorHandling: true` that does not declare one
|
|
9
|
+
* (`withErrorHandles` / `nodeSupportsErrorHandling`);
|
|
10
|
+
* - `uip maestro flow validate` does the same when it checks edge handles
|
|
11
|
+
* (`validateEdgeHandlesAgainstCurrentManifests`: `supportsErrorHandling ===
|
|
12
|
+
* true` adds `error` to the node's source handles).
|
|
13
|
+
*
|
|
14
|
+
* So the flag alone grants the port. For instance, the manifest
|
|
15
|
+
* `registry get --local` returns for a sibling Flow or RPA project
|
|
16
|
+
* (`buildNodeManifest`) has `supportsErrorHandling: true` and only `input` +
|
|
17
|
+
* `output` handles, and an `error` edge from it is valid. A definition that
|
|
18
|
+
* declares an `error` source handle without the flag counts too.
|
|
19
|
+
*/
|
|
20
|
+
export declare function definitionHasErrorPort(def: any): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* The ONERROR_NO_ERROR_PORT sentence for a definition-backed node, naming its
|
|
23
|
+
* node type. Shared with serialize, which throws it for the same node.
|
|
24
|
+
*/
|
|
25
|
+
export declare function errorPortRefusal(stepName: string, def: any): string;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Does a node definition have an `error` port? One answer for `check` and
|
|
3
|
+
* `serialize` (flow-builder-sdk#943).
|
|
4
|
+
*
|
|
5
|
+
* The product's rule, read from @uipath/flow-core and @uipath/flow-tool:
|
|
6
|
+
*
|
|
7
|
+
* - the manifest client injects an `error` source handle into every served
|
|
8
|
+
* definition with `supportsErrorHandling: true` that does not declare one
|
|
9
|
+
* (`withErrorHandles` / `nodeSupportsErrorHandling`);
|
|
10
|
+
* - `uip maestro flow validate` does the same when it checks edge handles
|
|
11
|
+
* (`validateEdgeHandlesAgainstCurrentManifests`: `supportsErrorHandling ===
|
|
12
|
+
* true` adds `error` to the node's source handles).
|
|
13
|
+
*
|
|
14
|
+
* So the flag alone grants the port. For instance, the manifest
|
|
15
|
+
* `registry get --local` returns for a sibling Flow or RPA project
|
|
16
|
+
* (`buildNodeManifest`) has `supportsErrorHandling: true` and only `input` +
|
|
17
|
+
* `output` handles, and an `error` edge from it is valid. A definition that
|
|
18
|
+
* declares an `error` source handle without the flag counts too.
|
|
19
|
+
*/
|
|
20
|
+
export function definitionHasErrorPort(def) {
|
|
21
|
+
if (def?.supportsErrorHandling === true)
|
|
22
|
+
return true;
|
|
23
|
+
const groups = Array.isArray(def?.handleConfiguration) ? def.handleConfiguration : [];
|
|
24
|
+
return groups.some((g) => (Array.isArray(g?.handles) ? g.handles : [])
|
|
25
|
+
.some((h) => h?.id === 'error' && h?.type === 'source'));
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The ONERROR_NO_ERROR_PORT sentence for a definition-backed node, naming its
|
|
29
|
+
* node type. Shared with serialize, which throws it for the same node.
|
|
30
|
+
*/
|
|
31
|
+
export function errorPortRefusal(stepName, def) {
|
|
32
|
+
return `Step "${stepName}" is a ${def?.nodeType}@${def?.version} node, and its definition has no error port: `
|
|
33
|
+
+ `it does not set supportsErrorHandling: true and declares no "error" source handle, so the edge would leave a `
|
|
34
|
+
+ `handle the node does not have. Handle the failure downstream instead, or pass the definition exactly as `
|
|
35
|
+
+ `\`uip maestro flow registry get\` returns it.`;
|
|
36
|
+
}
|
package/dist/core/expr-check.js
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
* and gets back diagnostics with no location. The caller stamps the location
|
|
30
30
|
* (which node / task / field) it came from.
|
|
31
31
|
*/
|
|
32
|
-
import
|
|
32
|
+
import { typescript } from './typescript-module.js';
|
|
33
33
|
/**
|
|
34
34
|
* A JSONPath wildcard/filter step — the spelling that reaches for JavaScript and
|
|
35
35
|
* misses. Used only to add a suggestion; the parse decides.
|
|
@@ -47,15 +47,18 @@ const JSONPATH_WILDCARD = /\[\s*(?:\*|\?|'[^']*'|"[^"]*")\s*\]|\.\.[A-Za-z_$]/;
|
|
|
47
47
|
* `ts.createSourceFile` is a parse, not an evaluation — nothing in `expr` runs.
|
|
48
48
|
* TypeScript is already a runtime dependency of this package (see
|
|
49
49
|
* `core/script-return.ts`, which infers a script's return type the same way), so
|
|
50
|
-
* this adds no dependency.
|
|
50
|
+
* this adds no dependency. It is loaded on the first check, not at import
|
|
51
|
+
* (`core/typescript-module.ts`).
|
|
51
52
|
*/
|
|
52
53
|
function syntaxError(expr) {
|
|
54
|
+
const ts = typescript();
|
|
53
55
|
const problems = parseExpression(expr).problems;
|
|
54
56
|
if (problems.length === 0)
|
|
55
57
|
return undefined;
|
|
56
58
|
return ts.flattenDiagnosticMessageText(problems[0].messageText, ' ');
|
|
57
59
|
}
|
|
58
60
|
function parseExpression(expr) {
|
|
61
|
+
const ts = typescript();
|
|
59
62
|
const source = ts.createSourceFile('expression.ts', `(${expr}\n)`, ts.ScriptTarget.ES2020,
|
|
60
63
|
/* setParentNodes */ false);
|
|
61
64
|
// `parseDiagnostics` is where the scanner records syntax problems. It is not on
|
|
@@ -77,6 +80,7 @@ function retype(expr, escapes, keepCooked) {
|
|
|
77
80
|
}
|
|
78
81
|
/** The value a leaf denotes — a name, or a literal's value (a regular expression's is its source). */
|
|
79
82
|
function leafValue(node) {
|
|
83
|
+
const ts = typescript();
|
|
80
84
|
if (ts.isIdentifier(node) || ts.isPrivateIdentifier(node))
|
|
81
85
|
return node.text;
|
|
82
86
|
// NumericLiteral … TemplateTail: every literal and template piece carries `.text`.
|
|
@@ -86,6 +90,7 @@ function leafValue(node) {
|
|
|
86
90
|
return undefined;
|
|
87
91
|
}
|
|
88
92
|
function children(node) {
|
|
93
|
+
const ts = typescript();
|
|
89
94
|
const out = [];
|
|
90
95
|
ts.forEachChild(node, (c) => { out.push(c); });
|
|
91
96
|
return out;
|
package/dist/core/expr.d.ts
CHANGED
|
@@ -145,8 +145,8 @@ export declare function ran(step: string): Expr;
|
|
|
145
145
|
* The first five are what every error-capable node's definition declares
|
|
146
146
|
* (`outputDefinition.error.schema`, `required`, `additionalProperties: false`).
|
|
147
147
|
* `response` and `element` are NOT declared and are present at run time anyway —
|
|
148
|
-
* measured on every family probed (2026-09-10), `element` carrying the
|
|
149
|
-
* step that failed. They are typed here because a field that exists should be
|
|
148
|
+
* measured on every family probed (2026-09-10), `element` carrying the label of
|
|
149
|
+
* the step that failed. They are typed here because a field that exists should be
|
|
150
150
|
* readable; the declared five stay first because those are the contract.
|
|
151
151
|
*/
|
|
152
152
|
export type ErrorEnvelopeField = 'code' | 'message' | 'detail' | 'category' | 'status' | 'response' | 'element';
|
|
@@ -166,15 +166,21 @@ export type ErrorEnvelopeField = 'code' | 'message' | 'detail' | 'category' | 's
|
|
|
166
166
|
* | `category` | string | `'User'` |
|
|
167
167
|
* | `status` | number | `404` |
|
|
168
168
|
* | `response` | unknown | undeclared; `null` in every probe |
|
|
169
|
-
* | `element` | string | undeclared; the
|
|
169
|
+
* | `element` | string | undeclared; the failing step's label |
|
|
170
170
|
*
|
|
171
171
|
* The last two resolve at run time — measured, a container handler reading
|
|
172
|
-
* `element` came back with the failing body step's
|
|
173
|
-
* the declared schema, so `uip maestro flow validate` reports
|
|
172
|
+
* `element` came back with the failing body step's label — but they are absent
|
|
173
|
+
* from the declared schema, so `uip maestro flow validate` reports
|
|
174
174
|
* `EXPRESSION_DIAGNOSTIC: Property 'element' does not exist on type
|
|
175
175
|
* '<Step>_Error'` for them. Valid, and noisy: prefer the declared five unless you
|
|
176
176
|
* specifically need one of these.
|
|
177
177
|
*
|
|
178
|
+
* **`element` is the step's canvas label (`display.label`), not its node id.** The
|
|
179
|
+
* label defaults to the step name, so it matches the name (not always the node
|
|
180
|
+
* id) only while no `label` is set: `.step('failA', …, { label: 'Fail A' })`
|
|
181
|
+
* failing gives `element: 'Fail A'`. Route on `code` / `message`, never on
|
|
182
|
+
* `element`.
|
|
183
|
+
*
|
|
178
184
|
* **Which VARIABLE holds it is per node family, and this helper owns that.**
|
|
179
185
|
* Measured on the product (2026-09-10), one debug run per family:
|
|
180
186
|
*
|
package/dist/core/expr.js
CHANGED
|
@@ -179,15 +179,21 @@ export function ran(step) {
|
|
|
179
179
|
* | `category` | string | `'User'` |
|
|
180
180
|
* | `status` | number | `404` |
|
|
181
181
|
* | `response` | unknown | undeclared; `null` in every probe |
|
|
182
|
-
* | `element` | string | undeclared; the
|
|
182
|
+
* | `element` | string | undeclared; the failing step's label |
|
|
183
183
|
*
|
|
184
184
|
* The last two resolve at run time — measured, a container handler reading
|
|
185
|
-
* `element` came back with the failing body step's
|
|
186
|
-
* the declared schema, so `uip maestro flow validate` reports
|
|
185
|
+
* `element` came back with the failing body step's label — but they are absent
|
|
186
|
+
* from the declared schema, so `uip maestro flow validate` reports
|
|
187
187
|
* `EXPRESSION_DIAGNOSTIC: Property 'element' does not exist on type
|
|
188
188
|
* '<Step>_Error'` for them. Valid, and noisy: prefer the declared five unless you
|
|
189
189
|
* specifically need one of these.
|
|
190
190
|
*
|
|
191
|
+
* **`element` is the step's canvas label (`display.label`), not its node id.** The
|
|
192
|
+
* label defaults to the step name, so it matches the name (not always the node
|
|
193
|
+
* id) only while no `label` is set: `.step('failA', …, { label: 'Fail A' })`
|
|
194
|
+
* failing gives `element: 'Fail A'`. Route on `code` / `message`, never on
|
|
195
|
+
* `element`.
|
|
196
|
+
*
|
|
191
197
|
* **Which VARIABLE holds it is per node family, and this helper owns that.**
|
|
192
198
|
* Measured on the product (2026-09-10), one debug run per family:
|
|
193
199
|
*
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function writeJsonFile(path: string, value: unknown): void;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Write `value` as an emitted JSON artifact: 2-space indent and a trailing newline.
|
|
3
|
+
*
|
|
4
|
+
* Every emitted `.flow`, caseplan, entry-points, bindings_v2 and library file is
|
|
5
|
+
* byte-locked, and twelve call sites each spelled this out by hand; a copy that dropped
|
|
6
|
+
* the `'\n'` would break byte-lock on that one artifact only. FB007 holds pretty-printed
|
|
7
|
+
* JSON writes to this function. Creating the parent directory stays the caller's job.
|
|
8
|
+
*/
|
|
9
|
+
import { writeFileSync } from 'node:fs';
|
|
10
|
+
export function writeJsonFile(path, value) {
|
|
11
|
+
writeFileSync(path, JSON.stringify(value, null, 2) + '\n');
|
|
12
|
+
}
|
package/dist/core/library.d.ts
CHANGED
|
@@ -218,6 +218,25 @@ export interface LibraryOpts {
|
|
|
218
218
|
*/
|
|
219
219
|
overlayDir?: string;
|
|
220
220
|
}
|
|
221
|
+
/** Why {@link Library.resolve} refused a connector action. */
|
|
222
|
+
export type ConnectorResolveCode =
|
|
223
|
+
/** The library carries no such operation (or no such connector, or not at that version). */
|
|
224
|
+
'CONNECTOR_NOT_IN_LIBRARY'
|
|
225
|
+
/** A GENERIC operation (one entry per object) named without an `object`. */
|
|
226
|
+
| 'CONNECTOR_OBJECT_REQUIRED'
|
|
227
|
+
/** An `object` on a single, non-generic operation. */
|
|
228
|
+
| 'CONNECTOR_OBJECT_NOT_GENERIC';
|
|
229
|
+
/**
|
|
230
|
+
* The refusal {@link Library.resolve} throws, with a `code` for each reason.
|
|
231
|
+
*
|
|
232
|
+
* Typed so a caller can tell a refusal from a bug without matching on message
|
|
233
|
+
* text: `check` reports it under this code with this message, and a compile
|
|
234
|
+
* that throws it carries the same code into its `--json` diagnostics (#948).
|
|
235
|
+
*/
|
|
236
|
+
export declare class ConnectorResolveError extends Error {
|
|
237
|
+
readonly code: ConnectorResolveCode;
|
|
238
|
+
constructor(code: ConnectorResolveCode, message: string);
|
|
239
|
+
}
|
|
221
240
|
export declare class Library {
|
|
222
241
|
private layers;
|
|
223
242
|
/** The LIST-ENVELOPE LEDGER, overlay first so a prepared entry can add a row. */
|