@uipath/maestro-builder-sdk 6.51.3 → 6.52.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/check.d.ts +8 -0
- package/dist/check.js +33 -2
- package/dist/cli/commands/flow.js +6 -0
- package/dist/cli-run.d.ts +2 -0
- package/dist/cli-run.js +8 -0
- package/dist/core/nodes/extensions.d.ts +23 -0
- package/dist/core/nodes/extensions.js +18 -0
- package/dist/core/nodes/family.d.ts +13 -0
- package/dist/core/nodes/node-type.d.ts +19 -1
- package/dist/core/nodes/package-definition.d.ts +82 -0
- package/dist/core/nodes/package-definition.js +162 -0
- package/dist/core/nodes/registry.d.ts +14 -2
- package/dist/core/nodes/registry.js +68 -25
- package/dist/decompile-cli.d.ts +1 -1
- package/dist/decompile-cli.js +14 -4
- package/dist/decompile.d.ts +14 -0
- package/dist/decompile.js +77 -9
- package/dist/extend.d.ts +81 -0
- package/dist/extend.js +56 -0
- package/dist/flow-node-registry.d.ts +7 -0
- package/dist/flow-node-registry.js +14 -0
- package/dist/merge-cli.js +12 -2
- package/dist/merge-compile.js +14 -1
- package/dist/node-packages.d.ts +68 -0
- package/dist/node-packages.js +279 -0
- package/dist/serialize.d.ts +2 -1
- package/dist/serialize.js +10 -3
- package/package.json +6 -2
package/dist/check.d.ts
CHANGED
|
@@ -52,3 +52,11 @@ export declare const SCHEDULE_PATTERN: string;
|
|
|
52
52
|
* and day names, and the Quartz specials `L W LW ? * #`.
|
|
53
53
|
*/
|
|
54
54
|
export declare const SCHEDULE_CRON_PATTERN: string;
|
|
55
|
+
/**
|
|
56
|
+
* The one thing `check` says about runtimes: a flow with a node from a node-type
|
|
57
|
+
* package does not run on the UiPath platform, which runs exactly its registry.
|
|
58
|
+
* Reported once per flow, naming the steps and their packages, as a WARNING: the
|
|
59
|
+
* flow is still a correct workflow for a runtime that loads the package (the
|
|
60
|
+
* local engine), it just cannot be validated or published through `uip`.
|
|
61
|
+
*/
|
|
62
|
+
export declare const PACKAGE_NODES_NOT_PLATFORM = "PACKAGE_NODES_NOT_PLATFORM";
|
package/dist/check.js
CHANGED
|
@@ -892,6 +892,7 @@ function checkFlow(built, ancestors, opts = {}, ledger = newResourceIdLedger())
|
|
|
892
892
|
}
|
|
893
893
|
reportUnreachableHitlOutcomes(hitlChoiceNoPorts, exprs, diags);
|
|
894
894
|
checkRegisteredFamilies(registeredSteps, unresolvedSteps, stepNames, diags);
|
|
895
|
+
checkPackageNodes(registeredSteps, diags);
|
|
895
896
|
// The ids this scope's other nodes get, for the file-wide nodeId check in `check`.
|
|
896
897
|
for (const n of stepNames)
|
|
897
898
|
if (!ledger.taken.has(n))
|
|
@@ -2819,6 +2820,36 @@ function catalogued(entry, step, code, message, suggestion) {
|
|
|
2819
2820
|
// Key order as the per-family rules always wrote it — `check --json` prints it.
|
|
2820
2821
|
return { level: known.severity, code, step, message, ...(suggestion !== undefined ? { suggestion } : {}) };
|
|
2821
2822
|
}
|
|
2823
|
+
/**
|
|
2824
|
+
* The one thing `check` says about runtimes: a flow with a node from a node-type
|
|
2825
|
+
* package does not run on the UiPath platform, which runs exactly its registry.
|
|
2826
|
+
* Reported once per flow, naming the steps and their packages, as a WARNING: the
|
|
2827
|
+
* flow is still a correct workflow for a runtime that loads the package (the
|
|
2828
|
+
* local engine), it just cannot be validated or published through `uip`.
|
|
2829
|
+
*/
|
|
2830
|
+
export const PACKAGE_NODES_NOT_PLATFORM = 'PACKAGE_NODES_NOT_PLATFORM';
|
|
2831
|
+
function checkPackageNodes(steps, diags) {
|
|
2832
|
+
const byPackage = new Map();
|
|
2833
|
+
let first;
|
|
2834
|
+
for (const [name, placed] of steps) {
|
|
2835
|
+
const origin = placed.entry.family.package;
|
|
2836
|
+
if (origin === undefined)
|
|
2837
|
+
continue;
|
|
2838
|
+
first ??= name;
|
|
2839
|
+
const list = byPackage.get(origin.name) ?? [];
|
|
2840
|
+
list.push(`"${name}" (${placed.impl.typeName})`);
|
|
2841
|
+
byPackage.set(origin.name, list);
|
|
2842
|
+
}
|
|
2843
|
+
if (first === undefined)
|
|
2844
|
+
return;
|
|
2845
|
+
const packages = [...byPackage].map(([pkg, names]) => `${pkg}: ${names.join(', ')}`).join('; ');
|
|
2846
|
+
diags.push({
|
|
2847
|
+
level: 'warning', code: PACKAGE_NODES_NOT_PLATFORM, step: first,
|
|
2848
|
+
message: `This flow uses node types from a node-type package (${packages}). The UiPath platform runs only its own registry, `
|
|
2849
|
+
+ 'so `uip maestro flow validate` refuses the file and it cannot be published; it runs on a runtime that loads the package, '
|
|
2850
|
+
+ 'such as the local engine (`flow-debug`).',
|
|
2851
|
+
});
|
|
2852
|
+
}
|
|
2822
2853
|
/** Run each registered family's own rules over all of its placements in this flow. */
|
|
2823
2854
|
function checkRegisteredFamilies(steps, unresolved, stepNames, diags) {
|
|
2824
2855
|
const byFamily = new Map();
|
|
@@ -2969,7 +3000,7 @@ placed, opts, carried) {
|
|
|
2969
3000
|
if (!placed)
|
|
2970
3001
|
return;
|
|
2971
3002
|
const { impl } = placed;
|
|
2972
|
-
if (impl.definition
|
|
3003
|
+
if (impl.definition !== 'bundled' && placed.carried !== undefined) {
|
|
2973
3004
|
// At a carried version the carried definition answers, as serialize asks
|
|
2974
3005
|
// it: the type's declaration covers only the versions it registers.
|
|
2975
3006
|
if (!definitionHasErrorPort(placed.carried)) {
|
|
@@ -2977,7 +3008,7 @@ placed, opts, carried) {
|
|
|
2977
3008
|
return;
|
|
2978
3009
|
}
|
|
2979
3010
|
}
|
|
2980
|
-
else if (impl.definition
|
|
3011
|
+
else if (impl.definition !== 'bundled') {
|
|
2981
3012
|
// The definition serialize will be supplied, when check's options can name
|
|
2982
3013
|
// it (a connector's, from the library); the type answers without it otherwise.
|
|
2983
3014
|
const def = impl.checkDefinition?.(placed.spec, opts);
|
|
@@ -92,6 +92,7 @@ export function registerFlowCommands(program) {
|
|
|
92
92
|
.option('--import <specifier>', 'SDK import specifier in generated source')
|
|
93
93
|
.option('--strict', 'fail on unsupported constructs')
|
|
94
94
|
.option('--no-pipeline', 'do not emit a brownfield pipeline helper')
|
|
95
|
+
.option('--package <name...>', 'trust and load this node-type package (repeatable); otherwise package.json "maestroBuilderSdk".nodePackages decides')
|
|
95
96
|
.action(async (input, options) => {
|
|
96
97
|
const argv = [input];
|
|
97
98
|
addValue(argv, '-o', options.output);
|
|
@@ -100,6 +101,8 @@ export function registerFlowCommands(program) {
|
|
|
100
101
|
argv.push('--strict');
|
|
101
102
|
if (options.pipeline === false)
|
|
102
103
|
argv.push('--no-pipeline');
|
|
104
|
+
for (const name of options.package ?? [])
|
|
105
|
+
argv.push('--package', name);
|
|
103
106
|
await invoke('flow decompile', () => import('../../decompile-cli.js'), argv);
|
|
104
107
|
});
|
|
105
108
|
flow.command('merge')
|
|
@@ -112,6 +115,7 @@ export function registerFlowCommands(program) {
|
|
|
112
115
|
.option('--library <dir>', 'connector library, for compiling with --baseline-from or a .flow.ts edited source')
|
|
113
116
|
.option('--bindings <file>', 'bindings.json, for the same compiles')
|
|
114
117
|
.option('--strict', 'refuse when the no-edit round trip (the baseline) differs from the original')
|
|
118
|
+
.option('--package <name...>', 'trust and load this node-type package for --baseline-from (repeatable)')
|
|
115
119
|
.allowExcessArguments()
|
|
116
120
|
.action(async (_edited, options, command) => {
|
|
117
121
|
const pair = namedOrLegacySecond(command, {
|
|
@@ -129,6 +133,8 @@ export function registerFlowCommands(program) {
|
|
|
129
133
|
addValue(argv, '--bindings', options.bindings);
|
|
130
134
|
if (options.strict)
|
|
131
135
|
argv.push('--strict');
|
|
136
|
+
for (const name of options.package ?? [])
|
|
137
|
+
argv.push('--package', name);
|
|
132
138
|
await invoke('flow merge', () => import('../../merge-cli.js'), argv);
|
|
133
139
|
});
|
|
134
140
|
}
|
package/dist/cli-run.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export type CliExitCode = 0 | 1 | 2;
|
|
2
2
|
export declare function runWhenInvokedDirectly(moduleUrl: string, label: string, run: (argv: string[]) => Promise<CliExitCode> | CliExitCode): void;
|
|
3
3
|
/** The value after `name` in `argv`, or `undefined`. */
|
|
4
|
+
/** Every value of a repeatable flag, in order: `--package a --package b` → `['a', 'b']`. */
|
|
5
|
+
export declare function flagValues(argv: readonly string[], flag: string): string[];
|
|
4
6
|
export declare function flagValue(argv: readonly string[], name: string): string | undefined;
|
package/dist/cli-run.js
CHANGED
|
@@ -51,6 +51,14 @@ export function runWhenInvokedDirectly(moduleUrl, label, run) {
|
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
53
|
/** The value after `name` in `argv`, or `undefined`. */
|
|
54
|
+
/** Every value of a repeatable flag, in order: `--package a --package b` → `['a', 'b']`. */
|
|
55
|
+
export function flagValues(argv, flag) {
|
|
56
|
+
const out = [];
|
|
57
|
+
for (let i = 0; i < argv.length - 1; i++)
|
|
58
|
+
if (argv[i] === flag)
|
|
59
|
+
out.push(argv[i + 1]);
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
54
62
|
export function flagValue(argv, name) {
|
|
55
63
|
const i = argv.indexOf(name);
|
|
56
64
|
return i >= 0 ? argv[i + 1] : undefined;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The hand-off between a node-type package and the artifact's registry.
|
|
3
|
+
*
|
|
4
|
+
* `@uipath/maestro-builder-sdk/extend` is a builder entry and stays light at
|
|
5
|
+
* import (FB009): it must not load the Flow registry, which pulls the bundled
|
|
6
|
+
* definitions in. So a package's family is CONTRIBUTED here, and the registry
|
|
7
|
+
* ADOPTS whatever was contributed when it loads — at compile time, before any
|
|
8
|
+
* flow is built — and installs itself as the sink for every later contribution,
|
|
9
|
+
* which it then registers at once. A refusal (a kind a built-in family owns, a
|
|
10
|
+
* type that is not `definition: 'package'`) surfaces at adoption, still before
|
|
11
|
+
* the first node is serialized.
|
|
12
|
+
*/
|
|
13
|
+
import type { ArtifactContexts } from './node-type.js';
|
|
14
|
+
import type { NodeFamily } from './family.js';
|
|
15
|
+
type Sink = (family: NodeFamily<ArtifactContexts>) => void;
|
|
16
|
+
/** Hand a package's family to the artifact's registry, now or when it loads. */
|
|
17
|
+
export declare function contributeFamily(family: NodeFamily<ArtifactContexts>): void;
|
|
18
|
+
/**
|
|
19
|
+
* The registry calls this once at load: it receives every family contributed so
|
|
20
|
+
* far and every one contributed after. Families are adopted in contribution order.
|
|
21
|
+
*/
|
|
22
|
+
export declare function adoptContributedFamilies(adopt: Sink): void;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const pending = [];
|
|
2
|
+
let sink;
|
|
3
|
+
/** Hand a package's family to the artifact's registry, now or when it loads. */
|
|
4
|
+
export function contributeFamily(family) {
|
|
5
|
+
if (sink !== undefined)
|
|
6
|
+
sink(family);
|
|
7
|
+
else
|
|
8
|
+
pending.push(family);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The registry calls this once at load: it receives every family contributed so
|
|
12
|
+
* far and every one contributed after. Families are adopted in contribution order.
|
|
13
|
+
*/
|
|
14
|
+
export function adoptContributedFamilies(adopt) {
|
|
15
|
+
sink = adopt;
|
|
16
|
+
for (const family of pending.splice(0))
|
|
17
|
+
adopt(family);
|
|
18
|
+
}
|
|
@@ -25,12 +25,25 @@ export interface Placement<Spec = unknown> {
|
|
|
25
25
|
/** The version the node will be emitted at. */
|
|
26
26
|
readonly version: string;
|
|
27
27
|
}
|
|
28
|
+
/** The npm package a node family comes from, when it is not built into the SDK. */
|
|
29
|
+
export interface PackageOrigin {
|
|
30
|
+
/** The package name an author imports, e.g. `'@uipath/flow-local-nodes'`. */
|
|
31
|
+
readonly name: string;
|
|
32
|
+
/** The package's version, when it knows it; written into each definition's provenance. */
|
|
33
|
+
readonly version?: string;
|
|
34
|
+
}
|
|
28
35
|
export interface NodeFamily<Ctx extends ArtifactContexts> {
|
|
29
36
|
/** Stable id, e.g. `'data-fabric'`. Unique within the artifact's registry. */
|
|
30
37
|
readonly id: string;
|
|
31
38
|
readonly title: string;
|
|
32
39
|
readonly types: readonly AnyNodeType<Ctx>[];
|
|
33
40
|
readonly diagnostics: DiagnosticCatalog;
|
|
41
|
+
/**
|
|
42
|
+
* Set on a family registered from a node-type package. Every type of such a
|
|
43
|
+
* family declares `definition: 'package'`, and only such a family may; a
|
|
44
|
+
* built-in family never sets this.
|
|
45
|
+
*/
|
|
46
|
+
readonly package?: PackageOrigin;
|
|
34
47
|
/** Rules over every placement of this family's types, after the per-node checks. */
|
|
35
48
|
check?(placements: readonly Placement[], ctx: Ctx['familyCheck']): void;
|
|
36
49
|
}
|
|
@@ -25,7 +25,19 @@ import type { TypeDesc } from '../expr.js';
|
|
|
25
25
|
* its declared inputs) is read from. `per-tenant`: built per tenant or per call —
|
|
26
26
|
* there is no bundled entry to ask, so the node type declares those answers itself.
|
|
27
27
|
*/
|
|
28
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Where a node type's definition comes from.
|
|
30
|
+
*
|
|
31
|
+
* - `bundled`: the SDK's bundled registry snapshot has it, so the node carries no
|
|
32
|
+
* definition and the bundle answers `errorPort`.
|
|
33
|
+
* - `per-tenant`: a connector-shaped type the tenant defines; the type supplies its
|
|
34
|
+
* definition at serialize time and declares `errorPort`.
|
|
35
|
+
* - `package`: a type from a node-type package (`@uipath/maestro-builder-sdk/extend`);
|
|
36
|
+
* the package ships the definition, the type writes it into the file with its
|
|
37
|
+
* provenance, and the UiPath platform does not run it. A built-in family may not
|
|
38
|
+
* declare one — the registry refuses it (see `NodeTypeRegistry`).
|
|
39
|
+
*/
|
|
40
|
+
export type DefinitionSource = 'bundled' | 'per-tenant' | 'package';
|
|
29
41
|
/**
|
|
30
42
|
* One place a spec carries a value the artifact evaluates against its scope.
|
|
31
43
|
* `value` is walked deeply for expressions; `code` is a script body whose
|
|
@@ -104,6 +116,12 @@ export type OutputContract = {
|
|
|
104
116
|
*/
|
|
105
117
|
export interface FactoryCall {
|
|
106
118
|
readonly factory: string;
|
|
119
|
+
/**
|
|
120
|
+
* The module the factory is imported from, when it is not the SDK: a node-type
|
|
121
|
+
* package's own name. Decompile defaults it to the type's family `package.name`,
|
|
122
|
+
* so a `print` implementation sets it only to import from somewhere else.
|
|
123
|
+
*/
|
|
124
|
+
readonly module?: string;
|
|
107
125
|
readonly positional?: readonly string[];
|
|
108
126
|
readonly options?: ReadonlyArray<readonly [name: string, source: string | undefined]>;
|
|
109
127
|
/** A note for the reader, written as a block comment after the call (the artifact escapes it). */
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The node definition a node-type package writes into a compiled `.flow`.
|
|
3
|
+
*
|
|
4
|
+
* A package type has no platform definition — neither the SDK's bundled snapshot
|
|
5
|
+
* nor the tenant has one — so the file has to carry everything a reader needs:
|
|
6
|
+
* the designer's display and handles, the input and output schemas, and the
|
|
7
|
+
* `model.expansion` template the `.flow` → BPMN converter expands.
|
|
8
|
+
*
|
|
9
|
+
* ## Why one-node expansion
|
|
10
|
+
*
|
|
11
|
+
* The product's converter (vendored in `local-engine`) resolves a node's
|
|
12
|
+
* definition as `manifestDef ?? fileDef` and reads a node's per-instance input
|
|
13
|
+
* VALUES only through a definition's `model.expansion`: a `context` entry's
|
|
14
|
+
* `source: 'node.data.inputs.<name>'` is read off each placed node while the
|
|
15
|
+
* template is expanded. So every package definition expands to exactly one
|
|
16
|
+
* `bpmn:ServiceTask` that REPLACES the node under its own id, carries
|
|
17
|
+
* `<uipath:type value="<serviceType>">`, its inputs as context, and its
|
|
18
|
+
* `=response` / `=Error` output rows — the element shape a runtime's dispatch
|
|
19
|
+
* lane reads for a connector. Expansion drops the node's original edges, so the
|
|
20
|
+
* template re-creates the `success` edge and, when the author wired `.onError`,
|
|
21
|
+
* an error boundary with the `error` edge.
|
|
22
|
+
*
|
|
23
|
+
* The input NAMES are the contract with the runtime half of the package: a
|
|
24
|
+
* handler reads them off `TaskContext.inputs`. A `string` context entry is
|
|
25
|
+
* emitted as `value` and a `json` one as a JSON `body`; the converter turns a
|
|
26
|
+
* falsy `string` into `""` and a falsy `json` into `{}`, so a package encodes
|
|
27
|
+
* booleans and numbers as `=js:` expressions rather than relying on either.
|
|
28
|
+
*/
|
|
29
|
+
/** One authored input of a package node. */
|
|
30
|
+
export interface PackageInputField {
|
|
31
|
+
readonly type: 'string' | 'boolean' | 'number' | 'array' | 'object';
|
|
32
|
+
readonly description: string;
|
|
33
|
+
readonly required?: boolean;
|
|
34
|
+
readonly enum?: readonly string[];
|
|
35
|
+
readonly default?: unknown;
|
|
36
|
+
}
|
|
37
|
+
/** One field of a package node's `output`. */
|
|
38
|
+
export interface PackageOutputField {
|
|
39
|
+
readonly type: 'string' | 'boolean' | 'number' | 'array' | 'object';
|
|
40
|
+
readonly description: string;
|
|
41
|
+
}
|
|
42
|
+
/** What a package declares about one node; `defineNodeDefinition` does the rest. */
|
|
43
|
+
export interface PackageNodeShape {
|
|
44
|
+
/** The `.flow` node type, e.g. `acme.ledger.post`. */
|
|
45
|
+
readonly nodeType: string;
|
|
46
|
+
/** The BPMN service type a runtime dispatches on, e.g. `Acme.Ledger.Post`. */
|
|
47
|
+
readonly serviceType: string;
|
|
48
|
+
/** The definition version; the node's `typeVersion`. Default `1.0`. */
|
|
49
|
+
readonly version?: string;
|
|
50
|
+
readonly label: string;
|
|
51
|
+
readonly description: string;
|
|
52
|
+
/** A Lucide icon name the designer draws, e.g. `file-text`. */
|
|
53
|
+
readonly icon: string;
|
|
54
|
+
/** The designer's category for the add-node panel. Default `package`. */
|
|
55
|
+
readonly category?: string;
|
|
56
|
+
readonly tags?: readonly string[];
|
|
57
|
+
readonly inputs: Readonly<Record<string, PackageInputField>>;
|
|
58
|
+
readonly outputs: Readonly<Record<string, PackageOutputField>>;
|
|
59
|
+
}
|
|
60
|
+
export declare const DEFAULT_PACKAGE_DEFINITION_VERSION = "1.0";
|
|
61
|
+
/**
|
|
62
|
+
* The definition `defineNodeDefinition` returns: the complete manifest, with the
|
|
63
|
+
* fields a package's node type reads back typed — `version` is the type's
|
|
64
|
+
* `version` and the snapshot reference's, `model.serviceType` is what the runtime
|
|
65
|
+
* half claims.
|
|
66
|
+
*/
|
|
67
|
+
export interface PackageNodeDefinition extends Record<string, unknown> {
|
|
68
|
+
readonly nodeType: string;
|
|
69
|
+
readonly version: string;
|
|
70
|
+
readonly model: Record<string, unknown> & {
|
|
71
|
+
readonly type: 'bpmn:ServiceTask';
|
|
72
|
+
readonly serviceType: string;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Build a package node's definition from its shape: the complete manifest a
|
|
77
|
+
* compiled flow carries as a `snapshot` reference, with the one-node expansion
|
|
78
|
+
* described above. Provenance (`source.package`) is stamped at serialize time
|
|
79
|
+
* from the family's `package`, not here, so a shape stays free of the package's
|
|
80
|
+
* own name.
|
|
81
|
+
*/
|
|
82
|
+
export declare function defineNodeDefinition(shape: PackageNodeShape): PackageNodeDefinition;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The node definition a node-type package writes into a compiled `.flow`.
|
|
3
|
+
*
|
|
4
|
+
* A package type has no platform definition — neither the SDK's bundled snapshot
|
|
5
|
+
* nor the tenant has one — so the file has to carry everything a reader needs:
|
|
6
|
+
* the designer's display and handles, the input and output schemas, and the
|
|
7
|
+
* `model.expansion` template the `.flow` → BPMN converter expands.
|
|
8
|
+
*
|
|
9
|
+
* ## Why one-node expansion
|
|
10
|
+
*
|
|
11
|
+
* The product's converter (vendored in `local-engine`) resolves a node's
|
|
12
|
+
* definition as `manifestDef ?? fileDef` and reads a node's per-instance input
|
|
13
|
+
* VALUES only through a definition's `model.expansion`: a `context` entry's
|
|
14
|
+
* `source: 'node.data.inputs.<name>'` is read off each placed node while the
|
|
15
|
+
* template is expanded. So every package definition expands to exactly one
|
|
16
|
+
* `bpmn:ServiceTask` that REPLACES the node under its own id, carries
|
|
17
|
+
* `<uipath:type value="<serviceType>">`, its inputs as context, and its
|
|
18
|
+
* `=response` / `=Error` output rows — the element shape a runtime's dispatch
|
|
19
|
+
* lane reads for a connector. Expansion drops the node's original edges, so the
|
|
20
|
+
* template re-creates the `success` edge and, when the author wired `.onError`,
|
|
21
|
+
* an error boundary with the `error` edge.
|
|
22
|
+
*
|
|
23
|
+
* The input NAMES are the contract with the runtime half of the package: a
|
|
24
|
+
* handler reads them off `TaskContext.inputs`. A `string` context entry is
|
|
25
|
+
* emitted as `value` and a `json` one as a JSON `body`; the converter turns a
|
|
26
|
+
* falsy `string` into `""` and a falsy `json` into `{}`, so a package encodes
|
|
27
|
+
* booleans and numbers as `=js:` expressions rather than relying on either.
|
|
28
|
+
*/
|
|
29
|
+
export const DEFAULT_PACKAGE_DEFINITION_VERSION = '1.0';
|
|
30
|
+
const ERROR_SCHEMA = {
|
|
31
|
+
$schema: 'http://json-schema.org/draft-07/schema#',
|
|
32
|
+
type: 'object',
|
|
33
|
+
required: ['code', 'message', 'detail', 'category', 'status'],
|
|
34
|
+
properties: {
|
|
35
|
+
code: { type: 'string', description: 'Error code as a string' },
|
|
36
|
+
message: { type: 'string', description: 'High-level error message' },
|
|
37
|
+
detail: { type: 'string', description: 'Detailed error description' },
|
|
38
|
+
category: { type: 'string', description: 'Error category' },
|
|
39
|
+
status: { type: 'integer', description: 'HTTP status code' },
|
|
40
|
+
},
|
|
41
|
+
additionalProperties: false,
|
|
42
|
+
};
|
|
43
|
+
/** The context entry type the converter emits for a field: structured values ride as a JSON body. */
|
|
44
|
+
function contextType(field) {
|
|
45
|
+
return field.type === 'array' || field.type === 'object' ? 'json' : 'string';
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Build a package node's definition from its shape: the complete manifest a
|
|
49
|
+
* compiled flow carries as a `snapshot` reference, with the one-node expansion
|
|
50
|
+
* described above. Provenance (`source.package`) is stamped at serialize time
|
|
51
|
+
* from the family's `package`, not here, so a shape stays free of the package's
|
|
52
|
+
* own name.
|
|
53
|
+
*/
|
|
54
|
+
export function defineNodeDefinition(shape) {
|
|
55
|
+
const version = shape.version ?? DEFAULT_PACKAGE_DEFINITION_VERSION;
|
|
56
|
+
const context = Object.entries(shape.inputs).map(([name, field]) => ({
|
|
57
|
+
name,
|
|
58
|
+
type: contextType(field),
|
|
59
|
+
source: `node.data.inputs.${name}`,
|
|
60
|
+
}));
|
|
61
|
+
const properties = Object.fromEntries(Object.entries(shape.inputs).map(([name, field]) => [name, {
|
|
62
|
+
type: field.type,
|
|
63
|
+
description: field.description,
|
|
64
|
+
...(field.enum ? { enum: [...field.enum] } : {}),
|
|
65
|
+
}]));
|
|
66
|
+
const required = Object.entries(shape.inputs).filter(([, f]) => f.required).map(([name]) => name);
|
|
67
|
+
const inputDefaults = Object.fromEntries(Object.entries(shape.inputs).filter(([, f]) => f.default !== undefined).map(([name, f]) => [name, f.default]));
|
|
68
|
+
return {
|
|
69
|
+
nodeType: shape.nodeType,
|
|
70
|
+
version,
|
|
71
|
+
category: shape.category ?? 'package',
|
|
72
|
+
description: shape.description,
|
|
73
|
+
tags: shape.tags ? [...shape.tags] : ['package', ...shape.nodeType.split('.').slice(1)],
|
|
74
|
+
sortOrder: 90,
|
|
75
|
+
supportsErrorHandling: true,
|
|
76
|
+
display: { label: shape.label, icon: shape.icon },
|
|
77
|
+
handleConfiguration: [
|
|
78
|
+
{ position: 'left', handles: [{ id: 'input', type: 'target', handleType: 'input' }] },
|
|
79
|
+
{
|
|
80
|
+
position: 'right',
|
|
81
|
+
handles: [
|
|
82
|
+
{ id: 'success', type: 'source', handleType: 'output' },
|
|
83
|
+
{
|
|
84
|
+
id: 'error', label: 'Error', type: 'source', handleType: 'output',
|
|
85
|
+
visible: '{inputs.errorHandlingEnabled}', constraints: { maxConnections: 1 },
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
debug: { runtime: 'bpmnEngine' },
|
|
91
|
+
model: {
|
|
92
|
+
type: 'bpmn:ServiceTask',
|
|
93
|
+
serviceType: shape.serviceType,
|
|
94
|
+
version: 'v1',
|
|
95
|
+
expansion: {
|
|
96
|
+
nodes: [
|
|
97
|
+
{
|
|
98
|
+
id: '{nodeId}',
|
|
99
|
+
type: 'bpmn:ServiceTask',
|
|
100
|
+
replaceOriginal: true,
|
|
101
|
+
position: { x: 0, y: 0 },
|
|
102
|
+
data: {
|
|
103
|
+
label: '{node.data.label}',
|
|
104
|
+
model: {
|
|
105
|
+
serviceType: shape.serviceType,
|
|
106
|
+
version: 'v1',
|
|
107
|
+
context,
|
|
108
|
+
outputs: [
|
|
109
|
+
{ name: 'output', type: 'object', source: '=response', var: 'output' },
|
|
110
|
+
{ name: 'error', type: 'object', source: '=Error', var: 'error' },
|
|
111
|
+
],
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
condition: "hasEdgeFromHandle('error')",
|
|
117
|
+
id: '_Implicit_BoundaryError_{nodeId}',
|
|
118
|
+
type: 'bpmn:BoundaryEvent',
|
|
119
|
+
parentId: null,
|
|
120
|
+
position: { x: 0, y: 0 },
|
|
121
|
+
data: {
|
|
122
|
+
label: 'Error',
|
|
123
|
+
attachedToId: '{nodeId}',
|
|
124
|
+
eventDefinition: { type: 'bpmn:ErrorEventDefinition', id: '_Implicit_BoundaryError_{nodeId}_Error' },
|
|
125
|
+
// The `=Error` envelope is written by the BOUNDARY's output row when it
|
|
126
|
+
// fires, not by the failed task's own row — without this, `.onError`
|
|
127
|
+
// handlers read `<step>.error` as undefined. `custom: true` keeps the var
|
|
128
|
+
// as written: the converter would otherwise prefix it with the boundary's id.
|
|
129
|
+
model: { outputs: [{ name: 'error', type: 'object', source: '=Error', var: '{nodeId}.error', custom: true }] },
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
edges: [
|
|
134
|
+
{ matchOriginalEdgeByHandle: 'success', preserveEdgeId: true, source: '{nodeId}', type: 'bpmn:SequenceFlow' },
|
|
135
|
+
{
|
|
136
|
+
condition: "hasEdgeFromHandle('error')",
|
|
137
|
+
matchOriginalEdgeByHandle: 'error',
|
|
138
|
+
preserveEdgeId: true,
|
|
139
|
+
source: '_Implicit_BoundaryError_{nodeId}',
|
|
140
|
+
type: 'bpmn:SequenceFlow',
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
inputDefinition: { type: 'object', properties, required },
|
|
146
|
+
inputDefaults,
|
|
147
|
+
outputDefinition: {
|
|
148
|
+
output: {
|
|
149
|
+
type: 'object',
|
|
150
|
+
description: `What ${shape.label} produced`,
|
|
151
|
+
source: '=response',
|
|
152
|
+
var: 'output',
|
|
153
|
+
schema: {
|
|
154
|
+
$schema: 'http://json-schema.org/draft-07/schema#',
|
|
155
|
+
type: 'object',
|
|
156
|
+
properties: Object.fromEntries(Object.entries(shape.outputs).map(([k, v]) => [k, { type: v.type, description: v.description }])),
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
error: { type: 'object', description: 'Error information if the step fails', source: '=Error', var: 'error', schema: ERROR_SCHEMA },
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
}
|
|
@@ -35,13 +35,25 @@ export interface NodeTypeRegistryOptions {
|
|
|
35
35
|
export declare class NodeTypeRegistry<Ctx extends ArtifactContexts> {
|
|
36
36
|
#private;
|
|
37
37
|
readonly artifact: string;
|
|
38
|
-
readonly families: readonly NodeFamily<Ctx>[];
|
|
39
38
|
/**
|
|
40
39
|
* @param artifact - The artifact's name, for messages (`'flow'`).
|
|
41
|
-
* @param families - Every family this artifact supports, in no significant order.
|
|
40
|
+
* @param families - Every built-in family this artifact supports, in no significant order.
|
|
42
41
|
* @param options - What the artifact knows that the contract does not.
|
|
43
42
|
*/
|
|
44
43
|
constructor(artifact: string, families: readonly NodeFamily<Ctx>[], options: NodeTypeRegistryOptions);
|
|
44
|
+
/** Every family the registry knows: the built-in ones, then the registered packages' in registration order. */
|
|
45
|
+
get families(): readonly NodeFamily<Ctx>[];
|
|
46
|
+
/**
|
|
47
|
+
* Register a node-type package's family (`@uipath/maestro-builder-sdk/extend`).
|
|
48
|
+
*
|
|
49
|
+
* The whole registry is re-indexed with the new family last, under the same
|
|
50
|
+
* rules construction applies, so a package cannot take a kind, a type name, a
|
|
51
|
+
* prefix or a diagnostic code a built-in family owns, nor one another package
|
|
52
|
+
* registered first. A refusal names the package and leaves the live index as
|
|
53
|
+
* it was. Registering the same family object twice is a no-op: an ESM module
|
|
54
|
+
* runs once per process, but a test may import a package through two paths.
|
|
55
|
+
*/
|
|
56
|
+
register(family: NodeFamily<Ctx>): void;
|
|
45
57
|
/**
|
|
46
58
|
* The node type for a spec, by its kind, or undefined when the kind is not
|
|
47
59
|
* registered. When several types share the kind, the one whose `matches(spec)`
|