@uipath/packager-tool-flow 0.0.17 → 0.0.18

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.
@@ -11,6 +11,15 @@ export declare class FlowTool extends ProjectTool {
11
11
  buildAsync(options: IProjectBuildOptions, _cancellationToken?: AbortSignal): Promise<ToolResult>;
12
12
  packAsync(options: IProjectPackOptions, cancellationToken?: AbortSignal): Promise<ToolResult>;
13
13
  dispose(): Promise<void>;
14
+ /**
15
+ * Read the .flow file from the content folder, convert to BPMN, and
16
+ * generate entry-points.json, bindings_v2.json, and the BPMN file.
17
+ *
18
+ * Artifacts are always regenerated from the .flow source to ensure
19
+ * the package reflects the current state of the workflow, regardless
20
+ * of any stale artifacts that may exist on disk.
21
+ */
22
+ private generateFlowPackagingArtifacts;
14
23
  /**
15
24
  * Copy project files into the correct nupkg structure.
16
25
  *
package/dist/index.js CHANGED
@@ -7,6 +7,15 @@ import {
7
7
  } from "@uipath/solutionpackager-tool-core";
8
8
 
9
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
+ ProjectType
18
+ } from "@uipath/flow-schema";
10
19
  import {
11
20
  NugetConstants,
12
21
  NugetPackager,
@@ -112,6 +121,8 @@ class FlowTool extends ProjectTool {
112
121
  await this.copyProjectFiles(options.projectPath, contentFolder);
113
122
  this.logger.progress("Processing agents...");
114
123
  await processAgents(this.fileSystem, this.logger, options.projectPath, contentFolder);
124
+ this.logger.progress("Generating packaging artifacts from .flow...");
125
+ await this.generateFlowPackagingArtifacts(contentFolder, options.projectStorageId ?? "");
115
126
  this.logger.progress("Creating operate.json file...");
116
127
  await this.createOperateFile(options, contentFolder);
117
128
  this.logger.progress("Creating package-descriptor.json file...");
@@ -153,6 +164,59 @@ class FlowTool extends ProjectTool {
153
164
  await this._temporaryStorage.cleanup();
154
165
  } catch {}
155
166
  }
167
+ async generateFlowPackagingArtifacts(contentFolder, projectId) {
168
+ const entries = await this.fileSystem.readdir(contentFolder);
169
+ const flowFile = entries.find((e) => e.endsWith(".flow"));
170
+ if (!flowFile) {
171
+ this.logger.warn("No .flow file found in content folder — skipping artifact generation");
172
+ return;
173
+ }
174
+ const flowJsonBuffer = await this.fileSystem.readFile(Path3.join(contentFolder, flowFile));
175
+ if (!flowJsonBuffer) {
176
+ this.logger.warn(`Could not read ${flowFile} — skipping artifact generation`);
177
+ return;
178
+ }
179
+ const flowJson = typeof flowJsonBuffer === "string" ? flowJsonBuffer : new TextDecoder().decode(flowJsonBuffer);
180
+ let flowData;
181
+ try {
182
+ flowData = JSON.parse(flowJson);
183
+ } catch {
184
+ this.logger.warn(`Could not parse ${flowFile} as JSON — skipping artifact generation`);
185
+ return;
186
+ }
187
+ const bpmnFileName = flowFile.replace(/\.flow$/, ".bpmn");
188
+ const bpmnPath = Path3.join(contentFolder, bpmnFileName);
189
+ const { bpmn } = await convertFlowToBpmn(flowJson);
190
+ await this.fileSystem.writeFile(bpmnPath, bpmn);
191
+ const packagingNodes = (flowData.nodes ?? []).map((node) => ({
192
+ id: node.id,
193
+ type: node.type,
194
+ data: {
195
+ type: node.type,
196
+ typeVersion: node.typeVersion ?? "1.0.0",
197
+ display: node.display,
198
+ inputs: node.inputs,
199
+ outputs: node.outputs,
200
+ model: node.model
201
+ }
202
+ }));
203
+ const variables = flowData.variables ?? {};
204
+ const bindings = flowData.bindings ?? [];
205
+ const entryPointsPath = Path3.join(contentFolder, FlowConstants.EntryPointsFileName);
206
+ const entryPoints = getEntryPoints(bpmnFileName, packagingNodes, variables, ProjectType.Flow);
207
+ await this.fileSystem.writeFile(entryPointsPath, `${JSON.stringify(generateEntryPointsJson(entryPoints), null, 2)}
208
+ `);
209
+ const bindingsPath = Path3.join(contentFolder, FlowConstants.BindingsV2FileName);
210
+ const bindingResources = getBindingResources(packagingNodes, bindings);
211
+ await this.fileSystem.writeFile(bindingsPath, `${JSON.stringify(generateBindingsJson(bindingResources), null, 2)}
212
+ `);
213
+ const operatePath = Path3.join(contentFolder, NugetConstants.OperateFileName);
214
+ const startEventMatch = bpmn.match(/<bpmn:startEvent\s+id="([^"]+)"/);
215
+ const startEventId = startEventMatch?.[1] ?? "start";
216
+ const mainEntryPoint = `/${bpmnFileName}#${startEventId}`;
217
+ await this.fileSystem.writeFile(operatePath, `${JSON.stringify(generateOperateJson(projectId || flowData.id || "", mainEntryPoint), null, 2)}
218
+ `);
219
+ }
156
220
  async copyProjectFiles(projectPath, contentFolder) {
157
221
  await this.fileSystem.mkdir(contentFolder);
158
222
  const entries = await this.fileSystem.readdir(projectPath);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uipath/packager-tool-flow",
3
- "version": "0.0.17",
3
+ "version": "0.0.18",
4
4
  "description": "UiPath Flow tool implementation",
5
5
  "type": "module",
6
6
  "exports": {
@@ -19,8 +19,8 @@
19
19
  },
20
20
  "types": "./dist/index.d.ts",
21
21
  "scripts": {
22
- "build": "bun build ./src/index.ts --outdir dist --format esm --target browser --external @uipath/solutionpackager-tool-core --external @uipath/tool-agent && tsc --emitDeclarationOnly --outDir dist",
23
- "dev": "bun build ./src/index.ts --outdir dist --format esm --target browser --external @uipath/solutionpackager-tool-core --external @uipath/tool-agent --watch",
22
+ "build": "bun build ./src/index.ts --outdir dist --format esm --target browser --external @uipath/solutionpackager-tool-core --external @uipath/tool-agent --external @uipath/flow-converter --external @uipath/flow-schema && tsc --emitDeclarationOnly --outDir dist",
23
+ "dev": "bun build ./src/index.ts --outdir dist --format esm --target browser --external @uipath/solutionpackager-tool-core --external @uipath/tool-agent --external @uipath/flow-converter --external @uipath/flow-schema --watch",
24
24
  "test": "vitest run",
25
25
  "test:browser": "vitest run --config=vitest.browser.config.ts",
26
26
  "test:coverage": "vitest run --coverage",
@@ -43,12 +43,14 @@
43
43
  "author": "",
44
44
  "license": "ISC",
45
45
  "peerDependencies": {
46
- "@uipath/solutionpackager-tool-core": "0.0.31",
46
+ "@uipath/flow-converter": "^0.1.6",
47
+ "@uipath/flow-schema": "^0.2.141",
48
+ "@uipath/solutionpackager-tool-core": "0.0.33",
47
49
  "@uipath/tool-agent": "^1.0.1"
48
50
  },
49
51
  "devDependencies": {
50
52
  "@types/node": "^25.5.0",
51
- "@uipath/solutionpackager-tool-core": "0.0.31",
53
+ "@uipath/solutionpackager-tool-core": "0.0.33",
52
54
  "@uipath/tool-agent": "^1.0.1",
53
55
  "@vitest/browser": "^4.0.14",
54
56
  "@vitest/browser-playwright": "^4.0.14",
@@ -56,5 +58,6 @@
56
58
  "playwright": "^1.57.0",
57
59
  "typescript": "^5.9.3",
58
60
  "vitest": "^4.0.14"
59
- }
61
+ },
62
+ "gitHead": "3f1b4d8e9f910be81e4cab956537f21dbd5d63ac"
60
63
  }
package/src/flow-tool.ts CHANGED
@@ -1,3 +1,15 @@
1
+ import { convertFlowToBpmn } from "@uipath/flow-converter";
2
+ import {
3
+ generateBindingsJson,
4
+ generateEntryPointsJson,
5
+ generateOperateJson,
6
+ getBindingResources,
7
+ getEntryPoints,
8
+ type PackagingBinding,
9
+ type PackagingNode,
10
+ type PackagingWorkflowVariables,
11
+ ProjectType,
12
+ } from "@uipath/flow-schema";
1
13
  import type {
2
14
  EntryPointsFileModel,
3
15
  IProjectBuildOptions,
@@ -79,6 +91,14 @@ export class FlowTool extends ProjectTool {
79
91
  contentFolder,
80
92
  );
81
93
 
94
+ this.logger.progress(
95
+ "Generating packaging artifacts from .flow...",
96
+ );
97
+ await this.generateFlowPackagingArtifacts(
98
+ contentFolder,
99
+ options.projectStorageId ?? "",
100
+ );
101
+
82
102
  this.logger.progress("Creating operate.json file...");
83
103
  await this.createOperateFile(options, contentFolder);
84
104
 
@@ -149,6 +169,134 @@ export class FlowTool extends ProjectTool {
149
169
  }
150
170
  }
151
171
 
172
+ /**
173
+ * Read the .flow file from the content folder, convert to BPMN, and
174
+ * generate entry-points.json, bindings_v2.json, and the BPMN file.
175
+ *
176
+ * Artifacts are always regenerated from the .flow source to ensure
177
+ * the package reflects the current state of the workflow, regardless
178
+ * of any stale artifacts that may exist on disk.
179
+ */
180
+ private async generateFlowPackagingArtifacts(
181
+ contentFolder: string,
182
+ projectId: string,
183
+ ): Promise<void> {
184
+ // Find the .flow file in content folder
185
+ const entries = await this.fileSystem.readdir(contentFolder);
186
+ const flowFile = entries.find((e: string) => e.endsWith(".flow"));
187
+ if (!flowFile) {
188
+ this.logger.warn(
189
+ "No .flow file found in content folder — skipping artifact generation",
190
+ );
191
+ return;
192
+ }
193
+
194
+ // Read the .flow JSON
195
+ const flowJsonBuffer = await this.fileSystem.readFile(
196
+ Path.join(contentFolder, flowFile),
197
+ );
198
+ if (!flowJsonBuffer) {
199
+ this.logger.warn(
200
+ `Could not read ${flowFile} — skipping artifact generation`,
201
+ );
202
+ return;
203
+ }
204
+ const flowJson =
205
+ typeof flowJsonBuffer === "string"
206
+ ? flowJsonBuffer
207
+ : new TextDecoder().decode(flowJsonBuffer);
208
+
209
+ let flowData: {
210
+ id?: string;
211
+ nodes?: Array<{
212
+ id: string;
213
+ type: string;
214
+ typeVersion?: string;
215
+ display?: Record<string, unknown>;
216
+ inputs?: Record<string, unknown>;
217
+ outputs?: Record<string, unknown>;
218
+ model?: Record<string, unknown>;
219
+ }>;
220
+ bindings?: PackagingBinding[];
221
+ variables?: PackagingWorkflowVariables;
222
+ };
223
+
224
+ try {
225
+ flowData = JSON.parse(flowJson);
226
+ } catch {
227
+ this.logger.warn(
228
+ `Could not parse ${flowFile} as JSON — skipping artifact generation`,
229
+ );
230
+ return;
231
+ }
232
+
233
+ // Convert .flow to BPMN (always regenerate from .flow source)
234
+ const bpmnFileName = flowFile.replace(/\.flow$/, ".bpmn");
235
+ const bpmnPath = Path.join(contentFolder, bpmnFileName);
236
+ const { bpmn } = await convertFlowToBpmn(flowJson);
237
+ await this.fileSystem.writeFile(bpmnPath, bpmn);
238
+
239
+ // Build PackagingNode[] from the .flow nodes
240
+ const packagingNodes: PackagingNode[] = (flowData.nodes ?? []).map(
241
+ (node) => ({
242
+ id: node.id,
243
+ type: node.type,
244
+ data: {
245
+ type: node.type,
246
+ typeVersion: node.typeVersion ?? "1.0.0",
247
+ display: node.display,
248
+ inputs: node.inputs,
249
+ outputs: node.outputs,
250
+ model: node.model,
251
+ },
252
+ }),
253
+ );
254
+
255
+ const variables =
256
+ (flowData.variables as PackagingWorkflowVariables) ?? {};
257
+ const bindings = (flowData.bindings ?? []) as PackagingBinding[];
258
+
259
+ // Generate entry-points.json (always regenerate from .flow source)
260
+ const entryPointsPath = Path.join(
261
+ contentFolder,
262
+ FlowConstants.EntryPointsFileName,
263
+ );
264
+ const entryPoints = getEntryPoints(
265
+ bpmnFileName,
266
+ packagingNodes,
267
+ variables,
268
+ ProjectType.Flow,
269
+ );
270
+ await this.fileSystem.writeFile(
271
+ entryPointsPath,
272
+ `${JSON.stringify(generateEntryPointsJson(entryPoints), null, 2)}\n`,
273
+ );
274
+
275
+ // Generate bindings_v2.json (always regenerate from .flow source)
276
+ const bindingsPath = Path.join(
277
+ contentFolder,
278
+ FlowConstants.BindingsV2FileName,
279
+ );
280
+ const bindingResources = getBindingResources(packagingNodes, bindings);
281
+ await this.fileSystem.writeFile(
282
+ bindingsPath,
283
+ `${JSON.stringify(generateBindingsJson(bindingResources), null, 2)}\n`,
284
+ );
285
+
286
+ // Generate operate.json (always regenerate from .flow source)
287
+ const operatePath = Path.join(
288
+ contentFolder,
289
+ NugetConstants.OperateFileName,
290
+ );
291
+ const startEventMatch = bpmn.match(/<bpmn:startEvent\s+id="([^"]+)"/);
292
+ const startEventId = startEventMatch?.[1] ?? "start";
293
+ const mainEntryPoint = `/${bpmnFileName}#${startEventId}`;
294
+ await this.fileSystem.writeFile(
295
+ operatePath,
296
+ `${JSON.stringify(generateOperateJson(projectId || flowData.id || "", mainEntryPoint), null, 2)}\n`,
297
+ );
298
+ }
299
+
152
300
  /**
153
301
  * Copy project files into the correct nupkg structure.
154
302
  *