@uipath/packager-tool-flow 1.204.0-preview.255 → 1.205.0-preview.256
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/agents.d.ts +10 -4
- package/dist/bindings.d.ts +7 -6
- package/dist/entry-point-triggers.d.ts +17 -0
- package/dist/entry-point-triggers.js +25 -0
- package/dist/flow-binding-resources.d.ts +22 -0
- package/dist/flow-io.d.ts +17 -6
- package/dist/flow-tool-factory.d.ts +12 -2
- package/dist/flow-tool.d.ts +4 -1
- package/dist/flow-validation.d.ts +4 -2
- package/dist/index.d.ts +3 -0
- package/dist/index.js +453 -164
- package/dist/inline-entity-bindings.d.ts +87 -0
- package/dist/trigger-node-types.d.ts +30 -0
- package/package.json +8 -7
package/dist/agents.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { IFileSystem, IToolLogger } from "@uipath/solutionpackager-tool-core";
|
|
2
|
+
import type { BindingsResource } from "./bindings.js";
|
|
2
3
|
export interface InlineAgentContract {
|
|
3
4
|
agentJson: Record<string, unknown>;
|
|
4
5
|
bindingsJson: {
|
|
@@ -19,8 +20,13 @@ export declare function buildInlineAgentContract(config: {
|
|
|
19
20
|
outputPath: string;
|
|
20
21
|
}): Promise<InlineAgentContract>;
|
|
21
22
|
/**
|
|
22
|
-
* Build every root-level agent directory into the content folder
|
|
23
|
-
*
|
|
24
|
-
*
|
|
23
|
+
* Build every root-level agent directory into the content folder. Return the
|
|
24
|
+
* agents and their bindings separately so Flow artifact generation cannot
|
|
25
|
+
* overwrite the agent resources before the host merges them.
|
|
25
26
|
*/
|
|
26
|
-
export declare const processAgents: (fileSystem: IFileSystem, logger: IToolLogger, projectPath: string, contentFolder: string
|
|
27
|
+
export declare const processAgents: (fileSystem: IFileSystem, logger: IToolLogger, projectPath: string, contentFolder: string, context?: {
|
|
28
|
+
sharesSolutionDirectory?: boolean;
|
|
29
|
+
}) => Promise<{
|
|
30
|
+
agents: Map<string, Record<string, unknown>>;
|
|
31
|
+
bindings: BindingsResource[];
|
|
32
|
+
}>;
|
package/dist/bindings.d.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
+
import { type BindingResource } from "@uipath/flow-schema";
|
|
1
2
|
import type { IFileSystem } from "@uipath/solutionpackager-tool-core";
|
|
2
3
|
import type { AgentBuildResult } from "@uipath/tool-agent/build";
|
|
3
|
-
export
|
|
4
|
-
resource: string;
|
|
5
|
-
key: string;
|
|
6
|
-
[other: string]: unknown;
|
|
7
|
-
}
|
|
4
|
+
export type BindingsResource = BindingResource;
|
|
8
5
|
export interface Bindings {
|
|
9
6
|
version: string;
|
|
10
7
|
resources: BindingsResource[];
|
|
@@ -12,6 +9,10 @@ export interface Bindings {
|
|
|
12
9
|
export declare const toBindingsResources: (result: AgentBuildResult) => BindingsResource[];
|
|
13
10
|
/**
|
|
14
11
|
* Merge agent binding resources into the flow's bindings_v2.json.
|
|
15
|
-
* Deduplicates by (resource, key) tuple, keeping the first occurrence.
|
|
12
|
+
* Deduplicates by (resource, key) tuple, keeping the first occurrence. The
|
|
13
|
+
* resource kind is compared case-insensitively, the same rule as
|
|
14
|
+
* `mergeBindingResources` in `@uipath/flow-schema`: a Flow writes
|
|
15
|
+
* `Connection` where an agent build writes `connection`, and both name the
|
|
16
|
+
* same binding.
|
|
16
17
|
*/
|
|
17
18
|
export declare const mergeAgentBindings: (fileSystem: IFileSystem, contentFolder: string, agentBindingResources: BindingsResource[]) => Promise<void>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
type TriggerNode = Record<string, unknown> & {
|
|
2
|
+
id: string;
|
|
3
|
+
};
|
|
4
|
+
/**
|
|
5
|
+
* The flow's entry-point triggers, in `nodes[]` order. `isStartEventNode` is
|
|
6
|
+
* the predicate packaging uses to find entry points, so it covers connector
|
|
7
|
+
* triggers, not just `core.trigger.*`. Pass top-level nodes only: a subflow's
|
|
8
|
+
* trigger is not an entry point of the flow.
|
|
9
|
+
*/
|
|
10
|
+
export declare function entryPointTriggers(nodes: readonly unknown[]): TriggerNode[];
|
|
11
|
+
/**
|
|
12
|
+
* The trigger a run starts from when none is chosen: the one marked
|
|
13
|
+
* `isDefaultEntryPoint`, else the first. Studio Web writes `operate.json`
|
|
14
|
+
* `main` by the same rule. Undefined only when the flow has no trigger.
|
|
15
|
+
*/
|
|
16
|
+
export declare function defaultEntryPointNodeId(nodes: readonly unknown[]): string | undefined;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// src/entry-point-triggers.ts
|
|
2
|
+
import { isStartEventNode } from "@uipath/flow-schema";
|
|
3
|
+
function isRecord(value) {
|
|
4
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5
|
+
}
|
|
6
|
+
function entryPointTriggers(nodes) {
|
|
7
|
+
return nodes.filter((node) => isRecord(node) && typeof node.id === "string" && typeof node.type === "string" && isStartEventNode({
|
|
8
|
+
id: node.id,
|
|
9
|
+
type: node.type,
|
|
10
|
+
typeVersion: typeof node.typeVersion === "string" ? node.typeVersion : "1.0"
|
|
11
|
+
}));
|
|
12
|
+
}
|
|
13
|
+
function isDefaultEntryPoint(node) {
|
|
14
|
+
return isRecord(node.inputs) && node.inputs.isDefaultEntryPoint === true || isRecord(node.model) && node.model.isDefaultEntryPoint === true;
|
|
15
|
+
}
|
|
16
|
+
function defaultEntryPointNodeId(nodes) {
|
|
17
|
+
const triggers = entryPointTriggers(nodes);
|
|
18
|
+
return (triggers.find(isDefaultEntryPoint) ?? triggers[0])?.id;
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
defaultEntryPointNodeId,
|
|
22
|
+
entryPointTriggers
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
//# debugId=BF641D6B3631253B64756E2164756E21
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { getBindingResources, type PackagingNode, type Workflow } from "@uipath/flow-schema";
|
|
2
|
+
import type { IToolLogger } from "@uipath/solutionpackager-tool-core";
|
|
3
|
+
/** The flat node shape `getEntryPoints` and `getBindingResources` read. */
|
|
4
|
+
export declare function toPackagingNodes(workflow: Workflow): PackagingNode[];
|
|
5
|
+
/**
|
|
6
|
+
* The binding resources a Flow's package carries in `content/bindings_v2.json`.
|
|
7
|
+
* It runs `ensureProcessBindings` on a copy first, as pack does on the `.flow`
|
|
8
|
+
* before it generates the file, and never touches the workflow it is given.
|
|
9
|
+
* Pack and the solution's resource sync both read this, so they agree.
|
|
10
|
+
*
|
|
11
|
+
* Inline-agent bindings are added by `FlowToolFactory.describeResourcesAsync`
|
|
12
|
+
* after each agent is built, using the same merge order as pack.
|
|
13
|
+
*
|
|
14
|
+
* `ensureProcessBindings` is the same safety net pack runs, with the same
|
|
15
|
+
* reach: it walks `workflow.nodes`, not `workflow.subflows[*].nodes`. A
|
|
16
|
+
* subflow node authored outside the CLI whose `<bindings.*>` placeholder was
|
|
17
|
+
* never resolved therefore gets no binding generated — here or in a package.
|
|
18
|
+
* Subflow bindings that already exist in `workflow.bindings` are read, which
|
|
19
|
+
* is what `subflows` below is for. Widening the generator would change what
|
|
20
|
+
* every package carries, so it is its own change, not this one.
|
|
21
|
+
*/
|
|
22
|
+
export declare function flowBindingResources(workflow: Workflow, logger: IToolLogger): ReturnType<typeof getBindingResources>;
|
package/dist/flow-io.d.ts
CHANGED
|
@@ -30,9 +30,12 @@ export declare function migrateRawWorkflow(raw: unknown, logger?: FlowIoLogger):
|
|
|
30
30
|
* Build the standard `$ref` resolver for `.flow` chunk files: resolves the
|
|
31
31
|
* ref path against the referencing file's directory and reads it as UTF-8
|
|
32
32
|
* JSON. A missing target logs a warning (fail-soft) and resolves to `null`;
|
|
33
|
-
* the resulting workflow may be partial.
|
|
33
|
+
* the resulting workflow may be partial. When staging project-owned content,
|
|
34
|
+
* pass `projectRoot` to reject references whose canonical targets escape it.
|
|
34
35
|
*/
|
|
35
|
-
export declare function createFlowRefResolver(fs: IFileSystem, logger?: FlowIoLogger): ResolveRefCallback;
|
|
36
|
+
export declare function createFlowRefResolver(fs: IFileSystem, logger?: FlowIoLogger, projectRoot?: string): ResolveRefCallback;
|
|
37
|
+
/** Check source files and reference chunks before reading project-owned content. */
|
|
38
|
+
export declare function resolveProjectOwnedFlowPath(fs: IFileSystem, projectRoot: string, filePath: string): Promise<string>;
|
|
36
39
|
/**
|
|
37
40
|
* Resolve all `$ref` chunk references in a parsed `.flow` document. Throws
|
|
38
41
|
* when resolution itself errors (cycles, resolver throws); a missing target
|
|
@@ -50,7 +53,7 @@ export declare function resolveWorkflowRefs(parsed: unknown, resolver: ResolveRe
|
|
|
50
53
|
* was, and so does text that is not JSON, for the validator to report.
|
|
51
54
|
* Throws as {@link resolveWorkflowRefs} does.
|
|
52
55
|
*/
|
|
53
|
-
export declare function inlineFlowRefs(fs: IFileSystem, content: string, filePath: string, logger?: FlowIoLogger): Promise<string>;
|
|
56
|
+
export declare function inlineFlowRefs(fs: IFileSystem, content: string, filePath: string, logger?: FlowIoLogger, projectRoot?: string): Promise<string>;
|
|
54
57
|
/**
|
|
55
58
|
* The full read pipeline for a parsed `.flow` document: resolve `$ref`
|
|
56
59
|
* chunks, project to the fleet write floor, convert to the in-memory
|
|
@@ -67,6 +70,8 @@ export interface ReadFlowWorkflowOptions {
|
|
|
67
70
|
fs?: IFileSystem;
|
|
68
71
|
/** Logger for non-fatal `$ref` resolution failures. */
|
|
69
72
|
logger?: FlowIoLogger;
|
|
73
|
+
/** Bound project-owned source and chunk reads; other callers keep their existing semantics. */
|
|
74
|
+
projectRoot?: string;
|
|
70
75
|
}
|
|
71
76
|
/**
|
|
72
77
|
* Read a `.flow` file, resolve any `$ref` chunk references, and convert
|
|
@@ -103,12 +108,13 @@ export declare function resolveProjectFlowFile(fs: IFileSystem, projectPath: str
|
|
|
103
108
|
export declare function tryResolveProjectFlowFile(fs: IFileSystem, projectPath: string): Promise<string | undefined>;
|
|
104
109
|
/**
|
|
105
110
|
* Locate a flow project's `.flow` source file. Prefers the `project.uiproj`
|
|
106
|
-
* `MainFile` when it names a `.flow` inside the project, then
|
|
107
|
-
*
|
|
111
|
+
* `MainFile` when it names a `.flow` inside the project, then a file matching
|
|
112
|
+
* `preferredBaseName` anywhere in the root, `content/`, or `flow_files/`,
|
|
113
|
+
* then the first `.flow` in that directory order.
|
|
108
114
|
*
|
|
109
115
|
* Studio Web-exported solutions ship the flow as `new.flow` (not
|
|
110
116
|
* `<ProjectName>.flow`) with `MainFile: null`, so callers must NOT assume the
|
|
111
|
-
* file is named after the project. When
|
|
117
|
+
* file is named after the project. When the project holds multiple `.flow`s,
|
|
112
118
|
* pass `preferredBaseName` (the project name) to disambiguate to
|
|
113
119
|
* `<preferredBaseName>.flow` deterministically. Throws when no `.flow` is found.
|
|
114
120
|
*/
|
|
@@ -117,6 +123,11 @@ export declare function findProjectFlowFile(fs: IFileSystem, projectPath: string
|
|
|
117
123
|
* {@link findProjectFlowFile}, except that a project with no `.flow` answers
|
|
118
124
|
* `undefined` rather than throwing.
|
|
119
125
|
*
|
|
126
|
+
* Select MainFile first, then the project-named file across root, content/
|
|
127
|
+
* and flow_files/, then the first fallback in that directory order. Pack,
|
|
128
|
+
* resource refresh, debug, validate and local eval preparation share this
|
|
129
|
+
* selection through the project resolvers.
|
|
130
|
+
*
|
|
120
131
|
* For a caller to whom "this project has none" is an ordinary outcome — a
|
|
121
132
|
* Lite or Maestro Automate project packs fine without one. Reading the
|
|
122
133
|
* directory can still throw (EACCES, EIO); that is not the same answer and
|
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
import { type IFileSystem, type IProjectToolFactory, type IToolLogger, type ProjectTool, type ProjectType } from "@uipath/solutionpackager-tool-core";
|
|
1
|
+
import { type IFileSystem, type IProjectToolFactory, type IToolLogger, type ProjectOperationContext, type ProjectResourceContribution, type ProjectTool, type ProjectType } from "@uipath/solutionpackager-tool-core";
|
|
2
2
|
/**
|
|
3
3
|
* Factory for creating Flow project tools
|
|
4
4
|
*/
|
|
5
5
|
export declare class FlowToolFactory implements IProjectToolFactory {
|
|
6
6
|
readonly supportedTypes: readonly ProjectType[];
|
|
7
|
-
createAsync(logger: IToolLogger, fileSystem: IFileSystem): Promise<ProjectTool>;
|
|
7
|
+
createAsync(logger: IToolLogger, fileSystem: IFileSystem, context?: ProjectOperationContext): Promise<ProjectTool>;
|
|
8
|
+
/**
|
|
9
|
+
* A Flow keeps its bindings in the `.flow`; node edits also maintain a
|
|
10
|
+
* derived `bindings_v2.json` beside it. Contribute the source bindings
|
|
11
|
+
* pack writes, ignoring that derived file even after a hand edit. A
|
|
12
|
+
* project with no `.flow` may use its sidecar as the authored source;
|
|
13
|
+
* pack preserves it, so the solution must read it too.
|
|
14
|
+
*/
|
|
15
|
+
describeResourcesAsync(projectDir: string, fs: IFileSystem, context?: {
|
|
16
|
+
sharesSolutionDirectory: boolean;
|
|
17
|
+
}): Promise<ProjectResourceContribution>;
|
|
8
18
|
}
|
package/dist/flow-tool.d.ts
CHANGED
|
@@ -4,8 +4,9 @@ import { type IFileSystem, type IToolLogger, ProjectTool, ToolResult } from "@ui
|
|
|
4
4
|
* Flow project tool implementation
|
|
5
5
|
*/
|
|
6
6
|
export declare class FlowTool extends ProjectTool {
|
|
7
|
+
private readonly solutionRoot?;
|
|
7
8
|
private readonly _temporaryStorage;
|
|
8
|
-
constructor(fileSystem: IFileSystem, logger: IToolLogger);
|
|
9
|
+
constructor(fileSystem: IFileSystem, logger: IToolLogger, solutionRoot?: string | undefined);
|
|
9
10
|
restoreAsync(_options: IProjectRestoreOptions, _cancellationToken?: AbortSignal): Promise<ToolResult>;
|
|
10
11
|
validateAsync(options: IProjectValidateOptions, _cancellationToken?: AbortSignal): Promise<ToolResult>;
|
|
11
12
|
/**
|
|
@@ -40,6 +41,8 @@ export declare class FlowTool extends ProjectTool {
|
|
|
40
41
|
buildAsync(options: IProjectBuildOptions, _cancellationToken?: AbortSignal): Promise<ToolResult>;
|
|
41
42
|
packAsync(options: IProjectPackOptions, cancellationToken?: AbortSignal): Promise<ToolResult>;
|
|
42
43
|
dispose(): Promise<void>;
|
|
44
|
+
/** Stage the selected source last, resolving chunks before its layout changes. */
|
|
45
|
+
private stageFlowSource;
|
|
43
46
|
/**
|
|
44
47
|
* Read the .flow file from the content folder, resolve any unresolved
|
|
45
48
|
* process bindings, and write the updated workflow back.
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
import { type ParsedWorkflow, type ValidationRule, type WorkflowValidationContext, type WorkflowVariables } from "@uipath/flow-schema";
|
|
19
19
|
import type { FlowValidationIssue } from "./flow-validation-hook.js";
|
|
20
20
|
import { type ReadAgentJson } from "./inline-agent-utils.js";
|
|
21
|
+
import { type InlineEntityCheck } from "./inline-entity-bindings.js";
|
|
21
22
|
/** Graph shape shared by root workflow and each subflow entry; avoids `as ParsedWorkflow` over `unknown[]`. */
|
|
22
23
|
export interface FlowGraph {
|
|
23
24
|
nodes: Array<{
|
|
@@ -130,6 +131,7 @@ export declare function runDesignerRules(graph: FlowGraph, options?: DesignerRul
|
|
|
130
131
|
* {@link parseFlowSource}, then {@link runDesignerRules} over the root graph
|
|
131
132
|
* and every subflow — with each inline agent first hydrated from its
|
|
132
133
|
* `agent.json` through `readAgentJson`, as the designer shows it. This is the
|
|
133
|
-
* pack verdict: any `error` fails the pack.
|
|
134
|
+
* pack verdict: any `error` fails the pack. With `inlineEntities`, it also runs
|
|
135
|
+
* the unbound-entity rule ({@link inlineEntityBindingIssues}).
|
|
134
136
|
*/
|
|
135
|
-
export declare function validateFlowSource(content: string, readAgentJson?: ReadAgentJson): Promise<FlowValidationIssue[]>;
|
|
137
|
+
export declare function validateFlowSource(content: string, readAgentJson?: ReadAgentJson, inlineEntities?: InlineEntityCheck): Promise<FlowValidationIssue[]>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { type AgentInputLeaf, canonicalAgentInputPath, collectAgentInputLeaves, leafToBinding, SCHEMA_CONTAINER_MARKER, } from "./agent-input-encoding-utils.js";
|
|
2
2
|
export { buildInlineAgentContract, type InlineAgentContract, } from "./agents.js";
|
|
3
3
|
export { createProcessBindings, ensureProcessBindings, extractProcessGuid, } from "./ensure-process-bindings.js";
|
|
4
|
+
export { defaultEntryPointNodeId, entryPointTriggers, } from "./entry-point-triggers.js";
|
|
4
5
|
export { replaceExporterVersion } from "./exporter-version.js";
|
|
5
6
|
export { createFlowRefResolver, type FlowIoLogger, findProjectFlowFile, inlineFlowRefs, migrateRawWorkflow, readFlowWorkflow, resolveAndMigrateWorkflow, resolveProjectFlowFile, resolveWorkflowRefs, tryFindProjectFlowFile, tryResolveProjectFlowFile, } from "./flow-io.js";
|
|
6
7
|
export { FlowTool } from "./flow-tool.js";
|
|
@@ -8,6 +9,8 @@ export { FlowToolFactory } from "./flow-tool-factory.js";
|
|
|
8
9
|
export { type DesignerRuleOptions, type FlowGraph, hydrateAgentNodeInputs, type ParsedFlowSource, parseFlowSource, runDesignerRules, validateFlowSource, } from "./flow-validation.js";
|
|
9
10
|
export type { FlowValidationIssue, FlowValidationSeverity, } from "./flow-validation-hook.js";
|
|
10
11
|
export { type AgentInputVariable, agentJsonReader, hydrateInlineAgentInputVariables, isInlineAgentNodeType, type ReadAgentJson, readInlineAgentSource, reconcileInlineAgentInputVariables, setPublishIntentOnInlineAgents, } from "./inline-agent-utils.js";
|
|
12
|
+
export { describeUnboundInlineEntity, type EntityConfig, entityScopeKey, findInlineEntity, findUnboundInlineEntityNodes, INLINE_ENTITY_UNBOUND, type InlineEntity, type InlineEntityCheck, inlineEntityBindingIssues, isEntityNodeType, type ReadInlineEntities, registeredInlineEntityReader, registerInlineEntityReader, type ScannedWorkflow, type UnboundInlineEntityNode, } from "./inline-entity-bindings.js";
|
|
11
13
|
export { applyRuntimeProfile, isMaestroAutomateSentinel, RuntimeProfile, resolveRuntimeProfile, resolveRuntimeProfileForFlowFile, withRuntimeProfile, } from "./maestro-automate.js";
|
|
12
14
|
export { operateRuntimeOptions } from "./operate-runtime-options.js";
|
|
15
|
+
export { allNodesOf, bindingNodesOf, type FlowWithSubflows, } from "./trigger-node-types.js";
|
|
13
16
|
export { assertVoiceAgentDefinitionsEmbedded, type VoiceAgentFlowNode, voiceConvertOptions, } from "./voice-agent-definitions.js";
|
package/dist/index.js
CHANGED
|
@@ -3,100 +3,11 @@ import { toolsFactoryRepository } from "@uipath/solutionpackager-tool-core";
|
|
|
3
3
|
|
|
4
4
|
// src/flow-tool-factory.ts
|
|
5
5
|
import {
|
|
6
|
-
|
|
7
|
-
} from "@uipath/solutionpackager-tool-core";
|
|
8
|
-
|
|
9
|
-
// src/flow-tool.ts
|
|
10
|
-
import { convertFlowToBpmn } from "@uipath/flow-converter";
|
|
11
|
-
import {
|
|
12
|
-
generateBindingsJson,
|
|
13
|
-
generateEntryPointsJson,
|
|
14
|
-
generateOperateJson,
|
|
15
|
-
getBindingResources,
|
|
16
|
-
getEntryPoints,
|
|
17
|
-
inMemoryWorkflowToFileFormat,
|
|
18
|
-
ProjectType
|
|
6
|
+
mergeBindingResources as mergeBindingResources2
|
|
19
7
|
} from "@uipath/flow-schema";
|
|
20
8
|
import {
|
|
21
|
-
|
|
22
|
-
NugetConstants,
|
|
23
|
-
NugetPackager,
|
|
24
|
-
Path as Path4,
|
|
25
|
-
ProjectTool,
|
|
26
|
-
ProjectTypes,
|
|
27
|
-
TemporaryStorageService,
|
|
28
|
-
ToolErrorCodes,
|
|
29
|
-
ToolResult,
|
|
30
|
-
writeContentOperateFile
|
|
9
|
+
ProjectTypes as ProjectTypes2
|
|
31
10
|
} from "@uipath/solutionpackager-tool-core";
|
|
32
|
-
// package.json
|
|
33
|
-
var package_default = {
|
|
34
|
-
name: "@uipath/packager-tool-flow",
|
|
35
|
-
version: "1.204.0-preview.255",
|
|
36
|
-
description: "UiPath Flow tool implementation",
|
|
37
|
-
type: "module",
|
|
38
|
-
exports: {
|
|
39
|
-
".": "./dist/index.js",
|
|
40
|
-
"./maestro-automate": "./dist/maestro-automate-entry.js"
|
|
41
|
-
},
|
|
42
|
-
repository: {
|
|
43
|
-
type: "git",
|
|
44
|
-
url: "https://github.com/UiPath/cli.git",
|
|
45
|
-
directory: "packages/packager/packager-tool-flow"
|
|
46
|
-
},
|
|
47
|
-
publishConfig: {
|
|
48
|
-
registry: "https://npm.pkg.github.com/"
|
|
49
|
-
},
|
|
50
|
-
types: "./dist/index.d.ts",
|
|
51
|
-
scripts: {
|
|
52
|
-
build: "bun build ./src/index.ts --outdir dist --format esm --target browser --external @uipath/filesystem --external @uipath/solutionpackager-tool-core --external @uipath/tool-agent --external @uipath/flow-core --external @uipath/flow-converter --external @uipath/flow-migrations --external @uipath/flow-schema --external i18next --sourcemap=linked && bun build ./src/maestro-automate-entry.ts --outdir dist --format esm --target browser --external @uipath/filesystem --external @uipath/solutionpackager-tool-core --sourcemap=linked && tsc -p tsconfig.build.json --emitDeclarationOnly --noCheck --outDir dist",
|
|
53
|
-
typecheck: "tsc --noEmit",
|
|
54
|
-
dev: "bun build ./src/index.ts --outdir dist --format esm --target browser --external @uipath/filesystem --external @uipath/solutionpackager-tool-core --external @uipath/tool-agent --external @uipath/flow-core --external @uipath/flow-converter --external @uipath/flow-migrations --external @uipath/flow-schema --external i18next --watch",
|
|
55
|
-
test: "vitest run",
|
|
56
|
-
"test:browser": "vitest run --config=vitest.browser.config.ts",
|
|
57
|
-
"test:coverage": "vitest run --coverage",
|
|
58
|
-
"test:browser:coverage": "vitest run --config=vitest.browser.config.ts --coverage",
|
|
59
|
-
"test:all": "bun run test && bun run test:browser",
|
|
60
|
-
"test:all:coverage": "bun run test:coverage && bun run test:browser:coverage",
|
|
61
|
-
prepack: "bun run build",
|
|
62
|
-
"publish:dry": "bun publish --dry-run",
|
|
63
|
-
"publish:gh": "bun publish",
|
|
64
|
-
"version:patch": "bun version patch --no-git-tag-version",
|
|
65
|
-
"version:minor": "bun version minor --no-git-tag-version",
|
|
66
|
-
"version:major": "bun version major --no-git-tag-version",
|
|
67
|
-
lint: "biome check ."
|
|
68
|
-
},
|
|
69
|
-
files: [
|
|
70
|
-
"dist"
|
|
71
|
-
],
|
|
72
|
-
author: "UiPath",
|
|
73
|
-
license: "SEE LICENSE IN LICENSE.txt",
|
|
74
|
-
peerDependencies: {
|
|
75
|
-
"@uipath/filesystem": "workspace:*",
|
|
76
|
-
"@uipath/flow-converter": "0.69.3",
|
|
77
|
-
"@uipath/flow-core": "0.115.4-develop",
|
|
78
|
-
"@uipath/flow-migrations": "0.56.2",
|
|
79
|
-
"@uipath/flow-schema": "0.68.0",
|
|
80
|
-
"@uipath/solutionpackager-tool-core": "workspace:*",
|
|
81
|
-
"@uipath/tool-agent": "^2.0.0",
|
|
82
|
-
i18next: "^23.16.8"
|
|
83
|
-
},
|
|
84
|
-
devDependencies: {
|
|
85
|
-
"@types/node": "^25.5.2",
|
|
86
|
-
"@uipath/filesystem": "workspace:*",
|
|
87
|
-
"@uipath/flow-converter": "0.69.3",
|
|
88
|
-
"@uipath/flow-core": "0.115.4-develop",
|
|
89
|
-
"@uipath/solutionpackager-tool-core": "workspace:*",
|
|
90
|
-
"@uipath/tool-agent": "^2.0.0",
|
|
91
|
-
"@vitest/browser": "^4.1.11",
|
|
92
|
-
"@vitest/browser-playwright": "^4.1.11",
|
|
93
|
-
"@vitest/coverage-v8": "^4.1.11",
|
|
94
|
-
i18next: "^23.16.8",
|
|
95
|
-
playwright: "^1.57.0",
|
|
96
|
-
typescript: "^7.0.2",
|
|
97
|
-
vitest: "^4.1.11"
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
11
|
|
|
101
12
|
// src/agents.ts
|
|
102
13
|
import {
|
|
@@ -107,6 +18,9 @@ import { Path as Path2 } from "@uipath/solutionpackager-tool-core";
|
|
|
107
18
|
import { buildAgent } from "@uipath/tool-agent/build";
|
|
108
19
|
|
|
109
20
|
// src/bindings.ts
|
|
21
|
+
import {
|
|
22
|
+
mergeBindingResources
|
|
23
|
+
} from "@uipath/flow-schema";
|
|
110
24
|
import { Path } from "@uipath/solutionpackager-tool-core";
|
|
111
25
|
var BINDINGS_V2_FILE_NAME = "bindings_v2.json";
|
|
112
26
|
var toBindingsResources = (result) => result.bindings.resources.map((r) => ({ ...r }));
|
|
@@ -125,15 +39,10 @@ var mergeAgentBindings = async (fileSystem, contentFolder, agentBindingResources
|
|
|
125
39
|
} catch {}
|
|
126
40
|
}
|
|
127
41
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if (!seen.has(key)) {
|
|
133
|
-
seen.add(key);
|
|
134
|
-
existing.resources.push(binding);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
42
|
+
existing.resources = mergeBindingResources([
|
|
43
|
+
...existing.resources,
|
|
44
|
+
...agentBindingResources
|
|
45
|
+
]);
|
|
137
46
|
await fileSystem.writeFile(bindingsPath, JSON.stringify(existing, null, 2));
|
|
138
47
|
};
|
|
139
48
|
|
|
@@ -157,7 +66,7 @@ function healAgentInputEncoding(agent) {
|
|
|
157
66
|
const resources = Array.isArray(rawResources) ? rawResources.map((resource) => resource && typeof resource === "object" && !Array.isArray(resource) ? healResourceInputEncoding(resource) : resource) : rawResources;
|
|
158
67
|
return { ...normalized, resources };
|
|
159
68
|
}
|
|
160
|
-
var processAgents = async (fileSystem, logger, projectPath, contentFolder) => {
|
|
69
|
+
var processAgents = async (fileSystem, logger, projectPath, contentFolder, context) => {
|
|
161
70
|
const agentResults = [];
|
|
162
71
|
const builtAgents = new Map;
|
|
163
72
|
const entries = await fileSystem.readdir(projectPath);
|
|
@@ -167,6 +76,9 @@ var processAgents = async (fileSystem, logger, projectPath, contentFolder) => {
|
|
|
167
76
|
if (!stat?.isDirectory()) {
|
|
168
77
|
continue;
|
|
169
78
|
}
|
|
79
|
+
if (context?.sharesSolutionDirectory && (await fileSystem.exists(Path2.join(sourceDir, "project.uiproj")) || await fileSystem.exists(Path2.join(sourceDir, "project.json")))) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
170
82
|
const agentJsonPath = Path2.join(sourceDir, "agent.json");
|
|
171
83
|
if (!await fileSystem.exists(agentJsonPath)) {
|
|
172
84
|
continue;
|
|
@@ -187,13 +99,17 @@ var processAgents = async (fileSystem, logger, projectPath, contentFolder) => {
|
|
|
187
99
|
agentResults.push(result);
|
|
188
100
|
builtAgents.set(entry, agentJson);
|
|
189
101
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}
|
|
194
|
-
return builtAgents;
|
|
102
|
+
return {
|
|
103
|
+
agents: builtAgents,
|
|
104
|
+
bindings: agentResults.flatMap(toBindingsResources)
|
|
105
|
+
};
|
|
195
106
|
};
|
|
196
107
|
|
|
108
|
+
// src/flow-binding-resources.ts
|
|
109
|
+
import {
|
|
110
|
+
getBindingResources
|
|
111
|
+
} from "@uipath/flow-schema";
|
|
112
|
+
|
|
197
113
|
// src/ensure-process-bindings.ts
|
|
198
114
|
import { addBinding, createBinding } from "@uipath/flow-core";
|
|
199
115
|
var PROCESS_NODE_PREFIXES = [
|
|
@@ -374,8 +290,43 @@ function ensureProcessBindings(workflow, logger) {
|
|
|
374
290
|
return bindingsCreated;
|
|
375
291
|
}
|
|
376
292
|
|
|
377
|
-
// src/
|
|
378
|
-
|
|
293
|
+
// src/trigger-node-types.ts
|
|
294
|
+
import { collectWorkflowNodesDeep } from "@uipath/flow-schema";
|
|
295
|
+
function isTriggerLikeNodeType(type) {
|
|
296
|
+
return typeof type === "string" && (type.startsWith("uipath.connector.trigger.") || type === "core.trigger.scheduled");
|
|
297
|
+
}
|
|
298
|
+
function bindingNodesOf(workflow) {
|
|
299
|
+
const root = new Set(workflow?.nodes ?? []);
|
|
300
|
+
return allNodesOf(workflow).filter((node) => root.has(node) || !isTriggerLikeNodeType(node.type));
|
|
301
|
+
}
|
|
302
|
+
function allNodesOf(workflow) {
|
|
303
|
+
const subflows = {};
|
|
304
|
+
for (const [id, subflow] of Object.entries(workflow?.subflows ?? {})) {
|
|
305
|
+
if (subflow)
|
|
306
|
+
subflows[id] = { nodes: [...subflow.nodes ?? []] };
|
|
307
|
+
}
|
|
308
|
+
return collectWorkflowNodesDeep({
|
|
309
|
+
nodes: [...workflow?.nodes ?? []],
|
|
310
|
+
subflows
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// src/flow-binding-resources.ts
|
|
315
|
+
function toPackagingNodes(workflow) {
|
|
316
|
+
return (workflow.nodes ?? []).map((node) => ({
|
|
317
|
+
id: node.id,
|
|
318
|
+
type: node.type,
|
|
319
|
+
typeVersion: node.typeVersion ?? "1.0",
|
|
320
|
+
display: node.display,
|
|
321
|
+
inputs: node.inputs,
|
|
322
|
+
outputs: node.outputs
|
|
323
|
+
}));
|
|
324
|
+
}
|
|
325
|
+
function flowBindingResources(workflow, logger) {
|
|
326
|
+
const copy = structuredClone(workflow);
|
|
327
|
+
ensureProcessBindings(copy, logger);
|
|
328
|
+
return getBindingResources(toPackagingNodes({ ...copy, nodes: bindingNodesOf(copy) }), copy.bindings ?? [], copy.definitions ?? [], copy.subflows);
|
|
329
|
+
}
|
|
379
330
|
|
|
380
331
|
// src/flow-io.ts
|
|
381
332
|
import { getFileSystem } from "@uipath/filesystem";
|
|
@@ -410,9 +361,12 @@ function migrateRawWorkflow(raw, logger) {
|
|
|
410
361
|
return raw;
|
|
411
362
|
}
|
|
412
363
|
}
|
|
413
|
-
function createFlowRefResolver(fs, logger) {
|
|
364
|
+
function createFlowRefResolver(fs, logger, projectRoot) {
|
|
414
365
|
return async (refPath, baseUri) => {
|
|
415
|
-
|
|
366
|
+
let resolvedPath = fs.path.resolve(fs.path.dirname(baseUri), refPath);
|
|
367
|
+
if (projectRoot !== undefined) {
|
|
368
|
+
resolvedPath = await resolveProjectOwnedFlowPath(fs, projectRoot, resolvedPath);
|
|
369
|
+
}
|
|
416
370
|
const refContent = await readUtf8OrNull(fs, resolvedPath);
|
|
417
371
|
if (refContent === null) {
|
|
418
372
|
logger?.warn(`Failed to resolve $ref "${refPath}": file not found at ${resolvedPath}`);
|
|
@@ -421,6 +375,17 @@ function createFlowRefResolver(fs, logger) {
|
|
|
421
375
|
return JSON.parse(refContent);
|
|
422
376
|
};
|
|
423
377
|
}
|
|
378
|
+
async function resolveProjectOwnedFlowPath(fs, projectRoot, filePath) {
|
|
379
|
+
const [root, target] = await Promise.all([
|
|
380
|
+
fs.realpath(fs.path.resolve(projectRoot)),
|
|
381
|
+
fs.realpath(fs.path.resolve(filePath))
|
|
382
|
+
]);
|
|
383
|
+
const relative = fs.path.relative(root, target);
|
|
384
|
+
if (relative === ".." || relative.startsWith("../") || relative.startsWith("..\\") || fs.path.isAbsolute(relative)) {
|
|
385
|
+
throw new Error(`File resolves outside the Flow project: ${target}`);
|
|
386
|
+
}
|
|
387
|
+
return target;
|
|
388
|
+
}
|
|
424
389
|
async function resolveWorkflowRefs(parsed, resolver, baseUri) {
|
|
425
390
|
const { resolved, refMap, errors } = await resolveRefs(parsed, resolver, {
|
|
426
391
|
baseUri
|
|
@@ -431,7 +396,7 @@ async function resolveWorkflowRefs(parsed, resolver, baseUri) {
|
|
|
431
396
|
}
|
|
432
397
|
return { resolved, refMap };
|
|
433
398
|
}
|
|
434
|
-
async function inlineFlowRefs(fs, content, filePath, logger) {
|
|
399
|
+
async function inlineFlowRefs(fs, content, filePath, logger, projectRoot) {
|
|
435
400
|
if (!content.includes('"$ref"'))
|
|
436
401
|
return content;
|
|
437
402
|
let parsed;
|
|
@@ -440,7 +405,7 @@ async function inlineFlowRefs(fs, content, filePath, logger) {
|
|
|
440
405
|
} catch {
|
|
441
406
|
return content;
|
|
442
407
|
}
|
|
443
|
-
const { resolved } = await resolveWorkflowRefs(parsed, createFlowRefResolver(fs, logger), filePath);
|
|
408
|
+
const { resolved } = await resolveWorkflowRefs(parsed, createFlowRefResolver(fs, logger, projectRoot), filePath);
|
|
444
409
|
return JSON.stringify(resolved);
|
|
445
410
|
}
|
|
446
411
|
async function resolveAndMigrateWorkflow(parsed, resolver, baseUri, logger) {
|
|
@@ -454,8 +419,9 @@ async function resolveAndMigrateWorkflow(parsed, resolver, baseUri, logger) {
|
|
|
454
419
|
async function readFlowWorkflow(filePath, options = {}) {
|
|
455
420
|
const fs = options.fs ?? getFileSystem();
|
|
456
421
|
const logger = options.logger;
|
|
457
|
-
const
|
|
458
|
-
const
|
|
422
|
+
const sourcePath = options.projectRoot === undefined ? filePath : await resolveProjectOwnedFlowPath(fs, options.projectRoot, filePath);
|
|
423
|
+
const parsed = JSON.parse(await readUtf8(fs, sourcePath));
|
|
424
|
+
const { workflow } = await resolveAndMigrateWorkflow(parsed, createFlowRefResolver(fs, logger, options.projectRoot), sourcePath, logger);
|
|
459
425
|
return workflow;
|
|
460
426
|
}
|
|
461
427
|
async function readUtf8(fs, filePath) {
|
|
@@ -509,6 +475,7 @@ async function tryFindProjectFlowFile(fs, projectPath, mainFile, preferredBaseNa
|
|
|
509
475
|
fs.path.join(projectPath, "content"),
|
|
510
476
|
fs.path.join(projectPath, "flow_files")
|
|
511
477
|
];
|
|
478
|
+
let fallback;
|
|
512
479
|
for (const dir of candidateDirs) {
|
|
513
480
|
if (!await fs.exists(dir)) {
|
|
514
481
|
continue;
|
|
@@ -521,16 +488,135 @@ async function tryFindProjectFlowFile(fs, projectPath, mainFile, preferredBaseNa
|
|
|
521
488
|
if (flowFiles.length === 0) {
|
|
522
489
|
continue;
|
|
523
490
|
}
|
|
524
|
-
const chosen =
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
491
|
+
const chosen = preferred && flowFiles.find((f) => f.toLowerCase() === preferred);
|
|
492
|
+
if (chosen)
|
|
493
|
+
return fs.path.join(dir, chosen);
|
|
494
|
+
fallback ??= fs.path.join(dir, flowFiles[0]);
|
|
495
|
+
if (!preferred)
|
|
496
|
+
return fallback;
|
|
497
|
+
}
|
|
498
|
+
return fallback;
|
|
528
499
|
}
|
|
529
500
|
function isInsideDirectory(fs, directory, candidate) {
|
|
530
501
|
const relative = fs.path.relative(directory, candidate);
|
|
531
502
|
return relative !== "" && !/^\.\.(?:[\\/]|$)/.test(relative) && !fs.path.isAbsolute(relative);
|
|
532
503
|
}
|
|
533
504
|
|
|
505
|
+
// src/flow-tool.ts
|
|
506
|
+
import { convertFlowToBpmn } from "@uipath/flow-converter";
|
|
507
|
+
import {
|
|
508
|
+
generateBindingsJson,
|
|
509
|
+
generateEntryPointsJson,
|
|
510
|
+
generateOperateJson,
|
|
511
|
+
getEntryPoints,
|
|
512
|
+
inMemoryWorkflowToFileFormat,
|
|
513
|
+
ProjectType
|
|
514
|
+
} from "@uipath/flow-schema";
|
|
515
|
+
import {
|
|
516
|
+
ensureProjectId,
|
|
517
|
+
NugetConstants,
|
|
518
|
+
NugetPackager,
|
|
519
|
+
Path as Path4,
|
|
520
|
+
ProjectTool,
|
|
521
|
+
ProjectTypes,
|
|
522
|
+
TemporaryStorageService,
|
|
523
|
+
ToolErrorCodes,
|
|
524
|
+
ToolResult,
|
|
525
|
+
writeContentOperateFile
|
|
526
|
+
} from "@uipath/solutionpackager-tool-core";
|
|
527
|
+
// package.json
|
|
528
|
+
var package_default = {
|
|
529
|
+
name: "@uipath/packager-tool-flow",
|
|
530
|
+
version: "1.205.0-preview.256",
|
|
531
|
+
description: "UiPath Flow tool implementation",
|
|
532
|
+
type: "module",
|
|
533
|
+
exports: {
|
|
534
|
+
".": "./dist/index.js",
|
|
535
|
+
"./maestro-automate": "./dist/maestro-automate-entry.js",
|
|
536
|
+
"./entry-point-triggers": "./dist/entry-point-triggers.js"
|
|
537
|
+
},
|
|
538
|
+
repository: {
|
|
539
|
+
type: "git",
|
|
540
|
+
url: "https://github.com/UiPath/cli.git",
|
|
541
|
+
directory: "packages/packager/packager-tool-flow"
|
|
542
|
+
},
|
|
543
|
+
publishConfig: {
|
|
544
|
+
registry: "https://npm.pkg.github.com/"
|
|
545
|
+
},
|
|
546
|
+
types: "./dist/index.d.ts",
|
|
547
|
+
scripts: {
|
|
548
|
+
build: "bun build ./src/index.ts --outdir dist --format esm --target browser --external @uipath/filesystem --external @uipath/solutionpackager-tool-core --external @uipath/tool-agent --external @uipath/flow-core --external @uipath/flow-converter --external @uipath/flow-migrations --external @uipath/flow-schema --external i18next --sourcemap=linked && bun build ./src/maestro-automate-entry.ts --outdir dist --format esm --target browser --external @uipath/filesystem --external @uipath/solutionpackager-tool-core --sourcemap=linked && bun build ./src/entry-point-triggers.ts --outdir dist --format esm --target browser --external @uipath/flow-schema --sourcemap=linked && tsc -p tsconfig.build.json --emitDeclarationOnly --noCheck --outDir dist",
|
|
549
|
+
typecheck: "tsc --noEmit",
|
|
550
|
+
dev: "bun build ./src/index.ts --outdir dist --format esm --target browser --external @uipath/filesystem --external @uipath/solutionpackager-tool-core --external @uipath/tool-agent --external @uipath/flow-core --external @uipath/flow-converter --external @uipath/flow-migrations --external @uipath/flow-schema --external i18next --watch",
|
|
551
|
+
test: "vitest run",
|
|
552
|
+
"test:browser": "vitest run --config=vitest.browser.config.ts",
|
|
553
|
+
"test:coverage": "vitest run --coverage",
|
|
554
|
+
"test:browser:coverage": "vitest run --config=vitest.browser.config.ts --coverage",
|
|
555
|
+
"test:all": "bun run test && bun run test:browser",
|
|
556
|
+
"test:all:coverage": "bun run test:coverage && bun run test:browser:coverage",
|
|
557
|
+
prepack: "bun run build",
|
|
558
|
+
"publish:dry": "bun publish --dry-run",
|
|
559
|
+
"publish:gh": "bun publish",
|
|
560
|
+
"version:patch": "bun version patch --no-git-tag-version",
|
|
561
|
+
"version:minor": "bun version minor --no-git-tag-version",
|
|
562
|
+
"version:major": "bun version major --no-git-tag-version",
|
|
563
|
+
lint: "biome check ."
|
|
564
|
+
},
|
|
565
|
+
files: [
|
|
566
|
+
"dist"
|
|
567
|
+
],
|
|
568
|
+
author: "UiPath",
|
|
569
|
+
license: "SEE LICENSE IN LICENSE.txt",
|
|
570
|
+
peerDependencies: {
|
|
571
|
+
"@uipath/filesystem": "workspace:*",
|
|
572
|
+
"@uipath/flow-converter": "0.69.3",
|
|
573
|
+
"@uipath/flow-core": "^0.129.1",
|
|
574
|
+
"@uipath/flow-migrations": "^0.71.1",
|
|
575
|
+
"@uipath/flow-schema": "0.68.0",
|
|
576
|
+
"@uipath/solutionpackager-tool-core": "workspace:*",
|
|
577
|
+
"@uipath/tool-agent": "^2.0.0",
|
|
578
|
+
i18next: "^23.16.8"
|
|
579
|
+
},
|
|
580
|
+
devDependencies: {
|
|
581
|
+
"@types/node": "^25.5.2",
|
|
582
|
+
"@uipath/filesystem": "workspace:*",
|
|
583
|
+
"@uipath/flow-converter": "0.69.3",
|
|
584
|
+
"@uipath/flow-core": "^0.129.1",
|
|
585
|
+
"@uipath/solutionpackager-tool-core": "workspace:*",
|
|
586
|
+
"@uipath/tool-agent": "^2.0.0",
|
|
587
|
+
"@vitest/browser": "^4.1.11",
|
|
588
|
+
"@vitest/browser-playwright": "^4.1.11",
|
|
589
|
+
"@vitest/coverage-v8": "^4.1.11",
|
|
590
|
+
i18next: "^23.16.8",
|
|
591
|
+
playwright: "^1.57.0",
|
|
592
|
+
typescript: "^7.0.2",
|
|
593
|
+
vitest: "^4.1.11"
|
|
594
|
+
}
|
|
595
|
+
};
|
|
596
|
+
|
|
597
|
+
// src/entry-point-triggers.ts
|
|
598
|
+
import { isStartEventNode } from "@uipath/flow-schema";
|
|
599
|
+
function isRecord(value) {
|
|
600
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
601
|
+
}
|
|
602
|
+
function entryPointTriggers(nodes) {
|
|
603
|
+
return nodes.filter((node) => isRecord(node) && typeof node.id === "string" && typeof node.type === "string" && isStartEventNode({
|
|
604
|
+
id: node.id,
|
|
605
|
+
type: node.type,
|
|
606
|
+
typeVersion: typeof node.typeVersion === "string" ? node.typeVersion : "1.0"
|
|
607
|
+
}));
|
|
608
|
+
}
|
|
609
|
+
function isDefaultEntryPoint(node) {
|
|
610
|
+
return isRecord(node.inputs) && node.inputs.isDefaultEntryPoint === true || isRecord(node.model) && node.model.isDefaultEntryPoint === true;
|
|
611
|
+
}
|
|
612
|
+
function defaultEntryPointNodeId(nodes) {
|
|
613
|
+
const triggers = entryPointTriggers(nodes);
|
|
614
|
+
return (triggers.find(isDefaultEntryPoint) ?? triggers[0])?.id;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// src/exporter-version.ts
|
|
618
|
+
var replaceExporterVersion = (bpmnXml, version) => bpmnXml.replace(/exporterVersion="development"/g, () => `exporterVersion="${version}"`);
|
|
619
|
+
|
|
534
620
|
// src/flow-validation.ts
|
|
535
621
|
import {
|
|
536
622
|
AGENT_NODE_TYPES,
|
|
@@ -550,21 +636,21 @@ import { isAgentNodeType, isVoiceAgentNodeType } from "@uipath/flow-schema";
|
|
|
550
636
|
|
|
551
637
|
// src/agent-input-encoding-utils.ts
|
|
552
638
|
var SCHEMA_CONTAINER_MARKER = "x-uipath-container";
|
|
553
|
-
var
|
|
639
|
+
var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
554
640
|
function containerChildren(prop) {
|
|
555
|
-
if (!
|
|
641
|
+
if (!isRecord2(prop))
|
|
556
642
|
return;
|
|
557
643
|
if (prop[SCHEMA_CONTAINER_MARKER] !== true)
|
|
558
644
|
return;
|
|
559
645
|
const children = prop.properties;
|
|
560
|
-
return
|
|
646
|
+
return isRecord2(children) ? children : undefined;
|
|
561
647
|
}
|
|
562
648
|
function canonicalAgentInputPath(name) {
|
|
563
649
|
return name.split("__").join(".");
|
|
564
650
|
}
|
|
565
651
|
function collectAgentInputLeaves(inputSchema) {
|
|
566
|
-
const properties =
|
|
567
|
-
if (!
|
|
652
|
+
const properties = isRecord2(inputSchema) ? inputSchema.properties : undefined;
|
|
653
|
+
if (!isRecord2(properties))
|
|
568
654
|
return [];
|
|
569
655
|
const leaves = [];
|
|
570
656
|
const walk = (prop, segments) => {
|
|
@@ -574,7 +660,7 @@ function collectAgentInputLeaves(inputSchema) {
|
|
|
574
660
|
leaves.push({
|
|
575
661
|
flatKey,
|
|
576
662
|
path: canonicalAgentInputPath(segments.join(".")),
|
|
577
|
-
type:
|
|
663
|
+
type: isRecord2(prop) && typeof prop.type === "string" ? prop.type : undefined
|
|
578
664
|
});
|
|
579
665
|
return;
|
|
580
666
|
}
|
|
@@ -688,6 +774,75 @@ function setPublishIntentOnInlineAgents(fileFormat) {
|
|
|
688
774
|
}
|
|
689
775
|
}
|
|
690
776
|
|
|
777
|
+
// src/inline-entity-bindings.ts
|
|
778
|
+
var READER_KEY = Symbol.for("@uipath/packager-tool-flow/readInlineEntities");
|
|
779
|
+
var readerSlot = globalThis;
|
|
780
|
+
function registerInlineEntityReader(reader) {
|
|
781
|
+
readerSlot[READER_KEY] = reader;
|
|
782
|
+
}
|
|
783
|
+
function registeredInlineEntityReader() {
|
|
784
|
+
return readerSlot[READER_KEY];
|
|
785
|
+
}
|
|
786
|
+
function findInlineEntity(entities, entityName) {
|
|
787
|
+
return entities.get(entityName.toLowerCase());
|
|
788
|
+
}
|
|
789
|
+
var ENTITY_NODE_PREFIX = "core.datafabric.";
|
|
790
|
+
function isEntityNodeType(nodeType) {
|
|
791
|
+
return nodeType?.startsWith(ENTITY_NODE_PREFIX) ?? false;
|
|
792
|
+
}
|
|
793
|
+
function entityScopeKey(config) {
|
|
794
|
+
return typeof config?._resourceKey === "string" && config._resourceKey || typeof config?._entityKey === "string" && config._entityKey || "";
|
|
795
|
+
}
|
|
796
|
+
function findUnboundInlineEntityNodes(workflow, inlineEntities) {
|
|
797
|
+
if (inlineEntities.size === 0) {
|
|
798
|
+
return [];
|
|
799
|
+
}
|
|
800
|
+
const bindings = workflow.bindings ?? [];
|
|
801
|
+
const scoped = [
|
|
802
|
+
...(workflow.nodes ?? []).map((node) => ({ node, scope: "" })),
|
|
803
|
+
...Object.entries(workflow.subflows ?? {}).flatMap(([subflowId, sub]) => (sub.nodes ?? []).map((node) => ({
|
|
804
|
+
node,
|
|
805
|
+
scope: `subflows[${subflowId}].`
|
|
806
|
+
})))
|
|
807
|
+
];
|
|
808
|
+
const found = [];
|
|
809
|
+
for (const { node, scope } of scoped) {
|
|
810
|
+
if (!isEntityNodeType(node.type)) {
|
|
811
|
+
continue;
|
|
812
|
+
}
|
|
813
|
+
const config = node.inputs?.entityConfig;
|
|
814
|
+
const entityName = config?.entityName;
|
|
815
|
+
if (typeof entityName !== "string" || entityName === "") {
|
|
816
|
+
continue;
|
|
817
|
+
}
|
|
818
|
+
if (findInlineEntity(inlineEntities, entityName) === undefined) {
|
|
819
|
+
continue;
|
|
820
|
+
}
|
|
821
|
+
const scopeKey = entityScopeKey(config);
|
|
822
|
+
const bound = scopeKey !== "" && bindings.some((binding) => binding.resource === "Entity" && binding.resourceKey === scopeKey && binding.propertyAttribute === "name");
|
|
823
|
+
if (!bound) {
|
|
824
|
+
found.push({ nodeId: node.id, entityName, scope });
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
return found;
|
|
828
|
+
}
|
|
829
|
+
var INLINE_ENTITY_UNBOUND = "INLINE_ENTITY_UNBOUND";
|
|
830
|
+
function describeUnboundInlineEntity(node, flowFilePath) {
|
|
831
|
+
const problem = `Node "${node.nodeId}" names "${node.entityName}", an entity this solution authors locally, but carries no Entity binding. `;
|
|
832
|
+
const consequence = `Otherwise the entity resolves at tenant scope and the run fails as "Entity ${node.entityName} does not exist".`;
|
|
833
|
+
if (node.scope !== "") {
|
|
834
|
+
return problem + `It sits inside ${node.scope.replace(/\.$/, "")}, which 'uip maestro flow nodes configure' cannot target yet — it only resolves top-level nodes. ` + "Either move the node to the top-level graph and configure it there, or open the flow in Studio Web and re-pick the entity so the picker writes the keys. " + consequence;
|
|
835
|
+
}
|
|
836
|
+
return problem + `Run: uip maestro flow nodes configure ${flowFilePath} ${node.nodeId} --detail '{"entityName":"${node.entityName}"}' — ` + consequence;
|
|
837
|
+
}
|
|
838
|
+
function inlineEntityBindingIssues(workflow, inlineEntities, flowFilePath) {
|
|
839
|
+
return findUnboundInlineEntityNodes(workflow, inlineEntities).map((node) => ({
|
|
840
|
+
path: `${node.scope}nodes[${node.nodeId}].inputs.entityConfig`,
|
|
841
|
+
message: `[${INLINE_ENTITY_UNBOUND}] ${describeUnboundInlineEntity(node, flowFilePath)}`,
|
|
842
|
+
severity: "error"
|
|
843
|
+
}));
|
|
844
|
+
}
|
|
845
|
+
|
|
691
846
|
// src/flow-validation.ts
|
|
692
847
|
var validationMessagesRegistered = false;
|
|
693
848
|
function ensureValidationMessages() {
|
|
@@ -711,8 +866,8 @@ function hydrateAgentNodeInputs(node, agent) {
|
|
|
711
866
|
const inputs = node.inputs;
|
|
712
867
|
const settings = agent.settings;
|
|
713
868
|
if (isVoiceAgentNodeType2(node.type)) {
|
|
714
|
-
const voiceSettings =
|
|
715
|
-
if (
|
|
869
|
+
const voiceSettings = isRecord3(settings) ? settings.voice : undefined;
|
|
870
|
+
if (isRecord3(voiceSettings) && inputs.voice === undefined) {
|
|
716
871
|
inputs.voice = voiceSettings;
|
|
717
872
|
}
|
|
718
873
|
}
|
|
@@ -756,7 +911,7 @@ async function hydrateInlineAgents(nodes, readAgentJson) {
|
|
|
756
911
|
hydrateAgentNodeInputs(node, agent);
|
|
757
912
|
}
|
|
758
913
|
}
|
|
759
|
-
function
|
|
914
|
+
function isRecord3(value) {
|
|
760
915
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
761
916
|
}
|
|
762
917
|
function parseFlowSource(content) {
|
|
@@ -803,7 +958,7 @@ function runDesignerRules(graph, options = {}) {
|
|
|
803
958
|
const ruleErrors = runRules([...rules, conditionExpressionRule, ...options.extraRules ?? []], ctx);
|
|
804
959
|
return ruleErrors.map(validationErrorToIssue);
|
|
805
960
|
}
|
|
806
|
-
async function validateFlowSource(content, readAgentJson) {
|
|
961
|
+
async function validateFlowSource(content, readAgentJson, inlineEntities) {
|
|
807
962
|
const parsed = parseFlowSource(content);
|
|
808
963
|
if (!parsed.ok) {
|
|
809
964
|
return parsed.issues;
|
|
@@ -830,6 +985,9 @@ async function validateFlowSource(content, readAgentJson) {
|
|
|
830
985
|
path: `${prefix}${issue.path}`
|
|
831
986
|
})));
|
|
832
987
|
}
|
|
988
|
+
if (inlineEntities) {
|
|
989
|
+
issues.push(...inlineEntityBindingIssues(workflow, await inlineEntities.read(), inlineEntities.flowFilePath));
|
|
990
|
+
}
|
|
833
991
|
return issues;
|
|
834
992
|
}
|
|
835
993
|
function extractSupportsErrorHandling(content) {
|
|
@@ -1073,9 +1231,11 @@ var FLOW_VALIDATION_SOURCE = "Validator";
|
|
|
1073
1231
|
var SUBFLOW_PATH_SEGMENT = "subflows[";
|
|
1074
1232
|
|
|
1075
1233
|
class FlowTool extends ProjectTool {
|
|
1234
|
+
solutionRoot;
|
|
1076
1235
|
_temporaryStorage;
|
|
1077
|
-
constructor(fileSystem, logger) {
|
|
1236
|
+
constructor(fileSystem, logger, solutionRoot) {
|
|
1078
1237
|
super(fileSystem, logger);
|
|
1238
|
+
this.solutionRoot = solutionRoot;
|
|
1079
1239
|
this._temporaryStorage = new TemporaryStorageService(fileSystem);
|
|
1080
1240
|
}
|
|
1081
1241
|
async restoreAsync(_options, _cancellationToken) {
|
|
@@ -1094,13 +1254,19 @@ class FlowTool extends ProjectTool {
|
|
|
1094
1254
|
this.logger.info("Flow project has no .flow file; skipping Flow validation");
|
|
1095
1255
|
return ToolResult.success();
|
|
1096
1256
|
}
|
|
1097
|
-
const
|
|
1257
|
+
const canonicalFlowFile = await resolveProjectOwnedFlowPath(this.fileSystem, projectPath, flowFile);
|
|
1258
|
+
const content = await this.fileSystem.readFile(canonicalFlowFile, "utf-8");
|
|
1098
1259
|
if (content === null) {
|
|
1099
|
-
throw new Error(`Could not read ${
|
|
1260
|
+
throw new Error(`Could not read ${canonicalFlowFile}`);
|
|
1100
1261
|
}
|
|
1101
1262
|
this.logger.progress("Validating Flow project...");
|
|
1102
|
-
const source = await inlineFlowRefs(this.fileSystem, content,
|
|
1103
|
-
|
|
1263
|
+
const source = await inlineFlowRefs(this.fileSystem, content, canonicalFlowFile, this.logger, projectPath);
|
|
1264
|
+
const readInlineEntities = registeredInlineEntityReader();
|
|
1265
|
+
const resolvedFlowFile = canonicalFlowFile;
|
|
1266
|
+
issues = await validateFlowSource(source, agentJsonReader(this.fileSystem, projectPath), readInlineEntities ? {
|
|
1267
|
+
flowFilePath: resolvedFlowFile,
|
|
1268
|
+
read: () => readInlineEntities(this.fileSystem, resolvedFlowFile)
|
|
1269
|
+
} : undefined);
|
|
1104
1270
|
} catch (error) {
|
|
1105
1271
|
const message = error instanceof Error ? error.message : String(error);
|
|
1106
1272
|
this.logger.warn(`Could not validate the Flow project, continuing without validation: ${message}`);
|
|
@@ -1139,16 +1305,26 @@ class FlowTool extends ProjectTool {
|
|
|
1139
1305
|
const localBuildFolder = Path4.join(tempFolder, NugetConstants.OutputFolderName);
|
|
1140
1306
|
const contentFolder = Path4.join(localBuildFolder, NugetConstants.ContentFolderName);
|
|
1141
1307
|
try {
|
|
1308
|
+
const sharesSolutionDirectory = this.solutionRoot !== undefined && this.fileSystem.path.resolve(options.projectPath) === this.fileSystem.path.resolve(this.solutionRoot);
|
|
1309
|
+
const sourceFlow = await tryResolveProjectFlowFile(this.fileSystem, options.projectPath);
|
|
1310
|
+
const canonicalSource = sourceFlow ? await resolveProjectOwnedFlowPath(this.fileSystem, options.projectPath, sourceFlow) : undefined;
|
|
1311
|
+
const flowPath = sourceFlow ? Path4.join(contentFolder, this.fileSystem.path.relative(options.projectPath, sourceFlow).replace(/^content[\\/]/, "")) : undefined;
|
|
1142
1312
|
this.logger.progress("Copying files...");
|
|
1143
|
-
await this.copyProjectFiles(options.projectPath, contentFolder);
|
|
1313
|
+
await this.copyProjectFiles(options.projectPath, contentFolder, sharesSolutionDirectory);
|
|
1314
|
+
if (canonicalSource && flowPath) {
|
|
1315
|
+
await this.stageFlowSource(canonicalSource, flowPath, options.projectPath);
|
|
1316
|
+
}
|
|
1144
1317
|
this.logger.progress("Processing agents...");
|
|
1145
|
-
const builtAgents = await processAgents(this.fileSystem, this.logger, options.projectPath, contentFolder);
|
|
1318
|
+
const { agents: builtAgents, bindings: agentBindings } = await processAgents(this.fileSystem, this.logger, options.projectPath, contentFolder, { sharesSolutionDirectory });
|
|
1146
1319
|
this.logger.progress("Resolving process bindings...");
|
|
1147
|
-
await this.resolveProcessBindings(
|
|
1320
|
+
await this.resolveProcessBindings(flowPath);
|
|
1148
1321
|
const projectId = options.projectStorageId ?? await ensureProjectId(options.projectPath, this.fileSystem);
|
|
1149
1322
|
const profile = await resolveRuntimeProfile(this.fileSystem, options.projectPath);
|
|
1150
1323
|
this.logger.progress("Generating packaging artifacts from .flow...");
|
|
1151
|
-
await this.generateFlowPackagingArtifacts(contentFolder, projectId, builtAgents);
|
|
1324
|
+
await this.generateFlowPackagingArtifacts(contentFolder, projectId, builtAgents, flowPath);
|
|
1325
|
+
if (agentBindings.length > 0) {
|
|
1326
|
+
await mergeAgentBindings(this.fileSystem, contentFolder, agentBindings);
|
|
1327
|
+
}
|
|
1152
1328
|
this.logger.progress("Creating operate.json file...");
|
|
1153
1329
|
await this.createOperateFile(contentFolder, projectId, profile);
|
|
1154
1330
|
this.logger.progress("Creating package-descriptor.json file...");
|
|
@@ -1190,12 +1366,17 @@ class FlowTool extends ProjectTool {
|
|
|
1190
1366
|
await this._temporaryStorage.cleanup();
|
|
1191
1367
|
} catch {}
|
|
1192
1368
|
}
|
|
1193
|
-
async
|
|
1194
|
-
const
|
|
1195
|
-
|
|
1196
|
-
|
|
1369
|
+
async stageFlowSource(sourcePath, targetPath, projectRoot) {
|
|
1370
|
+
const source = await this.fileSystem.readFile(sourcePath, "utf-8");
|
|
1371
|
+
if (source === null)
|
|
1372
|
+
throw new Error(`Could not read ${sourcePath}`);
|
|
1373
|
+
const inlined = await inlineFlowRefs(this.fileSystem, source, sourcePath, this.logger, projectRoot);
|
|
1374
|
+
await this.fileSystem.mkdir(this.fileSystem.path.dirname(targetPath));
|
|
1375
|
+
await this.fileSystem.writeFile(targetPath, inlined);
|
|
1376
|
+
}
|
|
1377
|
+
async resolveProcessBindings(flowPath) {
|
|
1378
|
+
if (!flowPath)
|
|
1197
1379
|
return;
|
|
1198
|
-
const flowPath = Path4.join(contentFolder, flowFile);
|
|
1199
1380
|
const flowBuffer = await this.fileSystem.readFile(flowPath);
|
|
1200
1381
|
if (!flowBuffer)
|
|
1201
1382
|
return;
|
|
@@ -1211,19 +1392,18 @@ class FlowTool extends ProjectTool {
|
|
|
1211
1392
|
await this.fileSystem.writeFile(flowPath, JSON.stringify(workflow, null, 4));
|
|
1212
1393
|
}
|
|
1213
1394
|
}
|
|
1214
|
-
async generateFlowPackagingArtifacts(contentFolder, projectId, builtAgents) {
|
|
1215
|
-
|
|
1216
|
-
const flowFile = entries.find((e) => e.endsWith(".flow"));
|
|
1217
|
-
if (!flowFile) {
|
|
1395
|
+
async generateFlowPackagingArtifacts(contentFolder, projectId, builtAgents, flowFilePath) {
|
|
1396
|
+
if (!flowFilePath) {
|
|
1218
1397
|
this.logger.warn("No .flow file found in content folder — skipping artifact generation");
|
|
1219
1398
|
return;
|
|
1220
1399
|
}
|
|
1221
|
-
const
|
|
1400
|
+
const flowFile = this.fileSystem.path.basename(flowFilePath);
|
|
1222
1401
|
let workflow;
|
|
1223
1402
|
try {
|
|
1224
1403
|
workflow = await readFlowWorkflow(flowFilePath, {
|
|
1225
1404
|
fs: this.fileSystem,
|
|
1226
|
-
logger: this.logger
|
|
1405
|
+
logger: this.logger,
|
|
1406
|
+
projectRoot: contentFolder
|
|
1227
1407
|
});
|
|
1228
1408
|
} catch (err) {
|
|
1229
1409
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -1246,16 +1426,8 @@ class FlowTool extends ProjectTool {
|
|
|
1246
1426
|
const bpmn = replaceExporterVersion(rawBpmn, package_default.version);
|
|
1247
1427
|
assertVoiceAgentDefinitionsEmbedded(bpmn, flowNodes);
|
|
1248
1428
|
await this.fileSystem.writeFile(bpmnPath, bpmn);
|
|
1249
|
-
const packagingNodes = (workflow
|
|
1250
|
-
id: node.id,
|
|
1251
|
-
type: node.type,
|
|
1252
|
-
typeVersion: node.typeVersion ?? "1.0",
|
|
1253
|
-
display: node.display,
|
|
1254
|
-
inputs: node.inputs,
|
|
1255
|
-
outputs: node.outputs
|
|
1256
|
-
}));
|
|
1429
|
+
const packagingNodes = toPackagingNodes(workflow);
|
|
1257
1430
|
const variables = workflow.variables ?? {};
|
|
1258
|
-
const bindings = workflow.bindings ?? [];
|
|
1259
1431
|
const definitions = workflow.definitions ?? [];
|
|
1260
1432
|
const entryPointsPath = Path4.join(contentFolder, FlowConstants.EntryPointsFileName);
|
|
1261
1433
|
const entryPoints = getEntryPoints(bpmnFileName, packagingNodes, variables, definitions, ProjectType.Flow);
|
|
@@ -1299,12 +1471,12 @@ class FlowTool extends ProjectTool {
|
|
|
1299
1471
|
await this.fileSystem.writeFile(entryPointsPath, `${JSON.stringify(generateEntryPointsJson(allEntryPoints), null, 2)}
|
|
1300
1472
|
`);
|
|
1301
1473
|
const bindingsPath = Path4.join(contentFolder, FlowConstants.BindingsV2FileName);
|
|
1302
|
-
const bindingResources =
|
|
1474
|
+
const bindingResources = flowBindingResources(workflow, this.logger);
|
|
1303
1475
|
await this.fileSystem.writeFile(bindingsPath, `${JSON.stringify(generateBindingsJson(bindingResources), null, 2)}
|
|
1304
1476
|
`);
|
|
1305
1477
|
const operatePath = Path4.join(contentFolder, NugetConstants.OperateFileName);
|
|
1306
1478
|
const startEventMatch = bpmn.match(/<bpmn:startEvent\s+id="([^"]+)"/);
|
|
1307
|
-
const startEventId = startEventMatch?.[1] ?? "start";
|
|
1479
|
+
const startEventId = defaultEntryPointNodeId(workflow.nodes ?? []) ?? startEventMatch?.[1] ?? "start";
|
|
1308
1480
|
const mainEntryPoint = `/${bpmnFileName}#${startEventId}`;
|
|
1309
1481
|
const operateJson = generateOperateJson(projectId || workflow.id || "", mainEntryPoint, operateRuntimeOptions(flowNodes));
|
|
1310
1482
|
await this.fileSystem.writeFile(operatePath, `${JSON.stringify(operateJson, null, 2)}
|
|
@@ -1346,7 +1518,7 @@ class FlowTool extends ProjectTool {
|
|
|
1346
1518
|
return;
|
|
1347
1519
|
}
|
|
1348
1520
|
}
|
|
1349
|
-
async copyProjectFiles(projectPath, contentFolder) {
|
|
1521
|
+
async copyProjectFiles(projectPath, contentFolder, sharesSolutionDirectory = false) {
|
|
1350
1522
|
await this.fileSystem.mkdir(contentFolder);
|
|
1351
1523
|
const entries = await this.fileSystem.readdir(projectPath);
|
|
1352
1524
|
for (const entry of entries) {
|
|
@@ -1357,7 +1529,7 @@ class FlowTool extends ProjectTool {
|
|
|
1357
1529
|
await this.copyDirectoryContents(sourceEntry, contentFolder);
|
|
1358
1530
|
}
|
|
1359
1531
|
} else if (stat?.isFile()) {
|
|
1360
|
-
if (entry === "project.uiproj" || isMaestroAutomateSentinel(entry)) {
|
|
1532
|
+
if (entry === "project.uiproj" || sharesSolutionDirectory && entry === "bindings_v2.json" || isMaestroAutomateSentinel(entry)) {
|
|
1361
1533
|
continue;
|
|
1362
1534
|
}
|
|
1363
1535
|
const content = await this.fileSystem.readFile(sourceEntry);
|
|
@@ -1443,10 +1615,114 @@ function toFlowFinding(issue, flowFilePath) {
|
|
|
1443
1615
|
}
|
|
1444
1616
|
|
|
1445
1617
|
// src/flow-tool-factory.ts
|
|
1618
|
+
var quietLogger = {
|
|
1619
|
+
debug: () => {},
|
|
1620
|
+
info: () => {},
|
|
1621
|
+
warn: () => {},
|
|
1622
|
+
error: () => {},
|
|
1623
|
+
progress: () => {},
|
|
1624
|
+
log: () => {},
|
|
1625
|
+
logMessage: () => {}
|
|
1626
|
+
};
|
|
1627
|
+
async function readAuthoredSidecarBindings(fs, sidecarPath) {
|
|
1628
|
+
const raw = await fs.readFile(sidecarPath, "utf-8");
|
|
1629
|
+
if (raw === null)
|
|
1630
|
+
throw new Error("Sidecar file is missing");
|
|
1631
|
+
const parsed = JSON.parse(typeof raw === "string" ? raw : new TextDecoder().decode(raw));
|
|
1632
|
+
if (typeof parsed !== "object" || parsed === null || !("resources" in parsed) || !Array.isArray(parsed.resources)) {
|
|
1633
|
+
throw new Error("Expected a resources array");
|
|
1634
|
+
}
|
|
1635
|
+
return parsed.resources;
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1446
1638
|
class FlowToolFactory {
|
|
1447
1639
|
supportedTypes = [ProjectTypes2.Flow];
|
|
1448
|
-
async createAsync(logger, fileSystem) {
|
|
1449
|
-
return new FlowTool(fileSystem, logger);
|
|
1640
|
+
async createAsync(logger, fileSystem, context) {
|
|
1641
|
+
return new FlowTool(fileSystem, logger, context?.solutionRoot);
|
|
1642
|
+
}
|
|
1643
|
+
async describeResourcesAsync(projectDir, fs, context) {
|
|
1644
|
+
let flowFile;
|
|
1645
|
+
let stage = "flow";
|
|
1646
|
+
try {
|
|
1647
|
+
flowFile = await tryResolveProjectFlowFile(fs, projectDir);
|
|
1648
|
+
const workflow = flowFile ? await readFlowWorkflow(flowFile, {
|
|
1649
|
+
fs,
|
|
1650
|
+
projectRoot: projectDir
|
|
1651
|
+
}) : undefined;
|
|
1652
|
+
stage = "agents";
|
|
1653
|
+
const contentFolder = await fs.getTempDir();
|
|
1654
|
+
try {
|
|
1655
|
+
const { bindings: agentBindings } = await processAgents(fs, quietLogger, projectDir, contentFolder, {
|
|
1656
|
+
sharesSolutionDirectory: context?.sharesSolutionDirectory
|
|
1657
|
+
});
|
|
1658
|
+
if (!workflow) {
|
|
1659
|
+
if (context?.sharesSolutionDirectory) {
|
|
1660
|
+
return { bindings: agentBindings };
|
|
1661
|
+
}
|
|
1662
|
+
const sidecarPath = fs.path.join(projectDir, "bindings_v2.json");
|
|
1663
|
+
const hasSidecar = await fs.exists(sidecarPath);
|
|
1664
|
+
if (agentBindings.length === 0) {
|
|
1665
|
+
return hasSidecar ? {} : { bindings: [] };
|
|
1666
|
+
}
|
|
1667
|
+
stage = "sidecar";
|
|
1668
|
+
const authoredBindings = hasSidecar ? await readAuthoredSidecarBindings(fs, sidecarPath) : [];
|
|
1669
|
+
return {
|
|
1670
|
+
bindings: mergeBindingResources2([
|
|
1671
|
+
...authoredBindings,
|
|
1672
|
+
...agentBindings
|
|
1673
|
+
])
|
|
1674
|
+
};
|
|
1675
|
+
}
|
|
1676
|
+
return {
|
|
1677
|
+
bindings: mergeBindingResources2([
|
|
1678
|
+
...flowBindingResources(workflow, quietLogger),
|
|
1679
|
+
...agentBindings
|
|
1680
|
+
])
|
|
1681
|
+
};
|
|
1682
|
+
} finally {
|
|
1683
|
+
try {
|
|
1684
|
+
await fs.rm(contentFolder);
|
|
1685
|
+
} catch {}
|
|
1686
|
+
}
|
|
1687
|
+
} catch (err) {
|
|
1688
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
1689
|
+
if (stage === "sidecar") {
|
|
1690
|
+
const sidecarPath = fs.path.join(projectDir, "bindings_v2.json");
|
|
1691
|
+
return {
|
|
1692
|
+
bindings: [],
|
|
1693
|
+
errors: [
|
|
1694
|
+
{
|
|
1695
|
+
code: "sidecar_unreadable",
|
|
1696
|
+
message: `${sidecarPath} could not be read: ${detail}.`,
|
|
1697
|
+
instructions: `Fix ${sidecarPath}, then re-run the command.`
|
|
1698
|
+
}
|
|
1699
|
+
]
|
|
1700
|
+
};
|
|
1701
|
+
}
|
|
1702
|
+
if (stage === "agents") {
|
|
1703
|
+
return {
|
|
1704
|
+
bindings: [],
|
|
1705
|
+
errors: [
|
|
1706
|
+
{
|
|
1707
|
+
code: "agent_build_failed",
|
|
1708
|
+
message: `Inline agents in ${projectDir} could not be built: ${detail}.`,
|
|
1709
|
+
instructions: `Fix the inline agent files in ${projectDir}, then re-run the command.`
|
|
1710
|
+
}
|
|
1711
|
+
]
|
|
1712
|
+
};
|
|
1713
|
+
}
|
|
1714
|
+
const source = flowFile ?? projectDir;
|
|
1715
|
+
return {
|
|
1716
|
+
bindings: [],
|
|
1717
|
+
errors: [
|
|
1718
|
+
{
|
|
1719
|
+
code: "flow_unreadable",
|
|
1720
|
+
message: `${source} could not be read as a workflow: ${detail}.`,
|
|
1721
|
+
instructions: `Fix ${source} (or open it in the designer), then re-run the command.`
|
|
1722
|
+
}
|
|
1723
|
+
]
|
|
1724
|
+
};
|
|
1725
|
+
}
|
|
1450
1726
|
}
|
|
1451
1727
|
}
|
|
1452
1728
|
|
|
@@ -1455,22 +1731,33 @@ toolsFactoryRepository.registerProjectToolFactory(new FlowToolFactory);
|
|
|
1455
1731
|
export {
|
|
1456
1732
|
FlowTool,
|
|
1457
1733
|
FlowToolFactory,
|
|
1734
|
+
INLINE_ENTITY_UNBOUND,
|
|
1458
1735
|
RuntimeProfile,
|
|
1459
1736
|
SCHEMA_CONTAINER_MARKER,
|
|
1460
1737
|
agentJsonReader,
|
|
1738
|
+
allNodesOf,
|
|
1461
1739
|
applyRuntimeProfile,
|
|
1462
1740
|
assertVoiceAgentDefinitionsEmbedded,
|
|
1741
|
+
bindingNodesOf,
|
|
1463
1742
|
buildInlineAgentContract,
|
|
1464
1743
|
canonicalAgentInputPath,
|
|
1465
1744
|
collectAgentInputLeaves,
|
|
1466
1745
|
createFlowRefResolver,
|
|
1467
1746
|
createProcessBindings,
|
|
1747
|
+
defaultEntryPointNodeId,
|
|
1748
|
+
describeUnboundInlineEntity,
|
|
1468
1749
|
ensureProcessBindings,
|
|
1750
|
+
entityScopeKey,
|
|
1751
|
+
entryPointTriggers,
|
|
1469
1752
|
extractProcessGuid,
|
|
1753
|
+
findInlineEntity,
|
|
1470
1754
|
findProjectFlowFile,
|
|
1755
|
+
findUnboundInlineEntityNodes,
|
|
1471
1756
|
hydrateAgentNodeInputs,
|
|
1472
1757
|
hydrateInlineAgentInputVariables,
|
|
1758
|
+
inlineEntityBindingIssues,
|
|
1473
1759
|
inlineFlowRefs,
|
|
1760
|
+
isEntityNodeType,
|
|
1474
1761
|
isInlineAgentNodeType,
|
|
1475
1762
|
isMaestroAutomateSentinel,
|
|
1476
1763
|
leafToBinding,
|
|
@@ -1480,6 +1767,8 @@ export {
|
|
|
1480
1767
|
readFlowWorkflow,
|
|
1481
1768
|
readInlineAgentSource,
|
|
1482
1769
|
reconcileInlineAgentInputVariables,
|
|
1770
|
+
registerInlineEntityReader,
|
|
1771
|
+
registeredInlineEntityReader,
|
|
1483
1772
|
replaceExporterVersion,
|
|
1484
1773
|
resolveAndMigrateWorkflow,
|
|
1485
1774
|
resolveProjectFlowFile,
|
|
@@ -1495,4 +1784,4 @@ export {
|
|
|
1495
1784
|
withRuntimeProfile
|
|
1496
1785
|
};
|
|
1497
1786
|
|
|
1498
|
-
//# debugId=
|
|
1787
|
+
//# debugId=2428956CE060A14A64756E2164756E21
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The unbound-entity rule: a Data Fabric node naming an entity this solution
|
|
3
|
+
* authors must carry its `bindings[]` rows, or it resolves at tenant scope and
|
|
4
|
+
* fails as `Entity <Name> does not exist`. Lives beside the designer's rules so
|
|
5
|
+
* `uip solution pack` enforces it too.
|
|
6
|
+
*
|
|
7
|
+
* The entity layout belongs to packager-tool-datafabric, which this package
|
|
8
|
+
* does not import, so flow-tool registers a reader at runtime (Hard Rule 19).
|
|
9
|
+
* No reader (Studio Web's publish) means the rule does not run.
|
|
10
|
+
*/
|
|
11
|
+
import type { IFileSystem, LocalEntityRef } from "@uipath/solutionpackager-tool-core";
|
|
12
|
+
import type { FlowValidationIssue } from "./flow-validation-hook.js";
|
|
13
|
+
/** An entity the enclosing solution authors locally. The same shape the Data
|
|
14
|
+
* Fabric packager reads them into — shared through the packager core, since
|
|
15
|
+
* this package does not import that one. */
|
|
16
|
+
export type InlineEntity = LocalEntityRef;
|
|
17
|
+
/**
|
|
18
|
+
* The solution's locally authored entities, keyed by lower-cased name (read
|
|
19
|
+
* through {@link findInlineEntity}). Referenced platform entities are absent.
|
|
20
|
+
*/
|
|
21
|
+
export type ReadInlineEntities = (fs: IFileSystem, flowFilePath: string) => Promise<Map<string, InlineEntity>>;
|
|
22
|
+
/** Register (or, with `undefined`, clear) the entity reader. */
|
|
23
|
+
export declare function registerInlineEntityReader(reader: ReadInlineEntities | undefined): void;
|
|
24
|
+
/** The registered entity reader, if any tool supplied one. */
|
|
25
|
+
export declare function registeredInlineEntityReader(): ReadInlineEntities | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Case-insensitive lookup — entity names are solution-wide unique that way, as
|
|
28
|
+
* `findProjectsOwningEntity` assumes.
|
|
29
|
+
*/
|
|
30
|
+
export declare function findInlineEntity(entities: Map<string, InlineEntity>, entityName: string): InlineEntity | undefined;
|
|
31
|
+
/** Whether a node type is a native Data Fabric node. The one copy of this test. */
|
|
32
|
+
export declare function isEntityNodeType(nodeType: string | undefined): boolean;
|
|
33
|
+
/** A node's `inputs.entityConfig` as read off a `.flow` — hence `unknown`. */
|
|
34
|
+
export interface EntityConfig {
|
|
35
|
+
entityName?: unknown;
|
|
36
|
+
_resourceKey?: unknown;
|
|
37
|
+
_entityKey?: unknown;
|
|
38
|
+
_folderKey?: unknown;
|
|
39
|
+
[extra: string]: unknown;
|
|
40
|
+
}
|
|
41
|
+
/** The key packaging matches on — `_resourceKey`, else `_entityKey` — or `""`. */
|
|
42
|
+
export declare function entityScopeKey(config: EntityConfig | null | undefined): string;
|
|
43
|
+
/** A Data Fabric node that names a locally authored entity but carries no row. */
|
|
44
|
+
export interface UnboundInlineEntityNode {
|
|
45
|
+
nodeId: string;
|
|
46
|
+
entityName: string;
|
|
47
|
+
/** `""` for the root graph, `subflows[<id>].` for a subflow node. */
|
|
48
|
+
scope: string;
|
|
49
|
+
}
|
|
50
|
+
interface ScannedNode {
|
|
51
|
+
id: string;
|
|
52
|
+
type?: string;
|
|
53
|
+
inputs?: Record<string, unknown>;
|
|
54
|
+
}
|
|
55
|
+
/** The slice of a workflow the rule reads. `bindings[]` is flow-wide. */
|
|
56
|
+
export interface ScannedWorkflow {
|
|
57
|
+
nodes?: ScannedNode[];
|
|
58
|
+
bindings?: Array<{
|
|
59
|
+
resource?: string;
|
|
60
|
+
resourceKey?: string;
|
|
61
|
+
propertyAttribute?: string;
|
|
62
|
+
}>;
|
|
63
|
+
subflows?: Record<string, {
|
|
64
|
+
nodes?: ScannedNode[];
|
|
65
|
+
}>;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Nodes naming a locally authored entity with no `Entity` name row. Whole
|
|
69
|
+
* workflow, not per graph: a subflow node's rows live in the root `bindings[]`.
|
|
70
|
+
* Silent on tenant/referenced entities and on nodes with no `entityName`.
|
|
71
|
+
*
|
|
72
|
+
* Not `entityNodeIsTenantScoped` (flow-schema): it reads `_folderKey`, which an
|
|
73
|
+
* unbound local node lacks too.
|
|
74
|
+
*/
|
|
75
|
+
export declare function findUnboundInlineEntityNodes(workflow: ScannedWorkflow, inlineEntities: Map<string, InlineEntity>): UnboundInlineEntityNode[];
|
|
76
|
+
/** The rule code `splitIssueMessage` lifts into a finding's `ErrorCode`. */
|
|
77
|
+
export declare const INLINE_ENTITY_UNBOUND = "INLINE_ENTITY_UNBOUND";
|
|
78
|
+
/** One line per unbound node, naming the fix that works for it. */
|
|
79
|
+
export declare function describeUnboundInlineEntity(node: UnboundInlineEntityNode, flowFilePath: string): string;
|
|
80
|
+
/** The rule's findings as `error` issues — an undeclared key fails at runtime. */
|
|
81
|
+
export declare function inlineEntityBindingIssues(workflow: ScannedWorkflow, inlineEntities: Map<string, InlineEntity>, flowFilePath: string): FlowValidationIssue[];
|
|
82
|
+
/** What `validateFlowSource` needs to run the rule, bound by its caller. */
|
|
83
|
+
export interface InlineEntityCheck {
|
|
84
|
+
flowFilePath: string;
|
|
85
|
+
read: () => Promise<Map<string, InlineEntity>>;
|
|
86
|
+
}
|
|
87
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** The only shape {@link bindingNodesOf} reads. Nullable throughout: it runs
|
|
2
|
+
* on a `.flow` as parsed, before anything has vouched for it. */
|
|
3
|
+
export interface FlowWithSubflows<N> {
|
|
4
|
+
nodes?: readonly N[] | null;
|
|
5
|
+
subflows?: Record<string, {
|
|
6
|
+
nodes?: readonly N[] | null;
|
|
7
|
+
} | undefined>;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The nodes `getBindingResources` needs: top-level plus every subflow's, minus
|
|
11
|
+
* subflow triggers (a subflow is invoked, not triggered). Both packaging paths
|
|
12
|
+
* call this, so they cannot disagree on the list.
|
|
13
|
+
*
|
|
14
|
+
* The walk is flow-schema's `collectWorkflowNodesDeep`, the one `flow-tool`
|
|
15
|
+
* uses too. It expects well-formed scopes, so a null scope a hand-edited
|
|
16
|
+
* `.flow` can carry is dropped first; root nodes are told apart by identity,
|
|
17
|
+
* because only a SUBFLOW's trigger is excluded.
|
|
18
|
+
*/
|
|
19
|
+
export declare function bindingNodesOf<N extends {
|
|
20
|
+
type?: unknown;
|
|
21
|
+
}>(workflow: FlowWithSubflows<N> | null | undefined): N[];
|
|
22
|
+
/**
|
|
23
|
+
* Every node in the flow, top-level then each subflow's, from a `.flow` as
|
|
24
|
+
* parsed. flow-schema's `collectWorkflowNodesDeep` does the walk but expects
|
|
25
|
+
* well-formed scopes; a hand-edited file can carry a null subflow entry or
|
|
26
|
+
* null `nodes`, and those are dropped here instead of crashing the caller.
|
|
27
|
+
* The one walk both packages use, so the guard cannot exist in one and not
|
|
28
|
+
* the other.
|
|
29
|
+
*/
|
|
30
|
+
export declare function allNodesOf<N>(workflow: FlowWithSubflows<N> | null | undefined): N[];
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uipath/packager-tool-flow",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.205.0-preview.256",
|
|
4
4
|
"description": "UiPath Flow tool implementation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": "./dist/index.js",
|
|
8
|
-
"./maestro-automate": "./dist/maestro-automate-entry.js"
|
|
8
|
+
"./maestro-automate": "./dist/maestro-automate-entry.js",
|
|
9
|
+
"./entry-point-triggers": "./dist/entry-point-triggers.js"
|
|
9
10
|
},
|
|
10
11
|
"repository": {
|
|
11
12
|
"type": "git",
|
|
@@ -22,14 +23,14 @@
|
|
|
22
23
|
"author": "UiPath",
|
|
23
24
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
24
25
|
"peerDependencies": {
|
|
25
|
-
"@uipath/filesystem": "1.
|
|
26
|
+
"@uipath/filesystem": "1.205.0",
|
|
26
27
|
"@uipath/flow-converter": "0.69.3",
|
|
27
|
-
"@uipath/flow-core": "0.
|
|
28
|
-
"@uipath/flow-migrations": "0.
|
|
28
|
+
"@uipath/flow-core": "^0.129.1",
|
|
29
|
+
"@uipath/flow-migrations": "^0.71.1",
|
|
29
30
|
"@uipath/flow-schema": "0.68.0",
|
|
30
|
-
"@uipath/solutionpackager-tool-core": "1.
|
|
31
|
+
"@uipath/solutionpackager-tool-core": "1.205.0",
|
|
31
32
|
"@uipath/tool-agent": "^2.0.0",
|
|
32
33
|
"i18next": "^23.16.8"
|
|
33
34
|
},
|
|
34
|
-
"gitHead": "
|
|
35
|
+
"gitHead": "63740c6cbb7ff282fa9118cc16a148eb030b245f"
|
|
35
36
|
}
|