@uipath/packager-tool-flow 1.200.0-preview.109 → 1.201.0-preview.115

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/flow-io.d.ts CHANGED
@@ -1,23 +1,58 @@
1
1
  import { type IFileSystem } from "@uipath/filesystem";
2
- import { type Workflow } from "@uipath/flow-schema";
2
+ import { type RefMap, type ResolveRefCallback, type Workflow } from "@uipath/flow-schema";
3
3
  export type FlowIoLogger = {
4
4
  warn: (message: string) => void;
5
5
  debug?: (message: string) => void;
6
6
  };
7
7
  /**
8
- * Migrate a freshly-parsed raw workflow document to the current schema
9
- * version, in memory. `inMemoryWorkflowToFileFormat` refuses to serialize a
10
- * workflow whose `version` predates the current one (the flow-schema
11
- * migration contract), so every read that can reach a serialize path —
12
- * debug, format, pack, node/edge edits — must migrate first, the same way
13
- * the canvas migrates on open. The source file is never touched; the
14
- * migrated version is persisted only when a caller explicitly writes back.
8
+ * Migrate a freshly-parsed raw workflow document to the fleet write floor
9
+ * (`MINIMUM_SUPPORTED_SCHEMA_VERSION`), in memory. `inMemoryWorkflowToFileFormat`
10
+ * refuses to serialize a workflow whose `version` differs from the floor (the
11
+ * flow-schema write-floor contract), so every read that can reach a serialize
12
+ * path — debug, format, pack, node/edge edits — must project to the floor
13
+ * first, the same way the canvas does on open. Older documents migrate up to
14
+ * the floor; newer reversible documents (up to `runtimeVersion`) project back
15
+ * down to it. The source file is never touched; the migrated version is
16
+ * persisted only when a caller explicitly writes back.
15
17
  *
16
- * Fail-soft: a missing/current `version`, an unknown version with no
17
- * migration chain, or a failing chain step all return the document
18
- * unchanged the serializer guard remains the backstop, exactly as before.
18
+ * The document must have its `$ref` chunks resolved BEFORE this runs — the
19
+ * floor projection validates the full document shape (e.g. `layout.nodes`),
20
+ * which an unresolved `$ref` placeholder would fail. Use
21
+ * {@link resolveAndMigrateWorkflow} (or `resolveWorkflowRefs` + this) rather
22
+ * than calling this on raw file content.
23
+ *
24
+ * Fail-soft: a missing `version`, an unknown version with no migration chain,
25
+ * or a failing chain step all return the document unchanged — the serializer
26
+ * guard remains the backstop.
19
27
  */
20
28
  export declare function migrateRawWorkflow(raw: unknown, logger?: FlowIoLogger): unknown;
29
+ /**
30
+ * Build the standard `$ref` resolver for `.flow` chunk files: resolves the
31
+ * ref path against the referencing file's directory and reads it as UTF-8
32
+ * JSON. A missing target logs a warning (fail-soft) and resolves to `null`;
33
+ * the resulting workflow may be partial.
34
+ */
35
+ export declare function createFlowRefResolver(fs: IFileSystem, logger?: FlowIoLogger): ResolveRefCallback;
36
+ /**
37
+ * Resolve all `$ref` chunk references in a parsed `.flow` document. Throws
38
+ * when resolution itself errors (cycles, resolver throws); a missing target
39
+ * is handled fail-soft by the resolver, not here.
40
+ */
41
+ export declare function resolveWorkflowRefs(parsed: unknown, resolver: ResolveRefCallback, baseUri: string): Promise<{
42
+ resolved: unknown;
43
+ refMap: RefMap;
44
+ }>;
45
+ /**
46
+ * The full read pipeline for a parsed `.flow` document: resolve `$ref`
47
+ * chunks, project to the fleet write floor, convert to the in-memory
48
+ * Workflow. Refs are resolved BEFORE migrating because the floor projection
49
+ * validates the full document shape (e.g. `layout.nodes`), which an
50
+ * unresolved `$ref` placeholder would fail.
51
+ */
52
+ export declare function resolveAndMigrateWorkflow(parsed: unknown, resolver: ResolveRefCallback, baseUri: string, logger?: FlowIoLogger): Promise<{
53
+ workflow: Workflow;
54
+ refMap: RefMap;
55
+ }>;
21
56
  export interface ReadFlowWorkflowOptions {
22
57
  /** Filesystem to read from. Defaults to `getFileSystem()`. */
23
58
  fs?: IFileSystem;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { buildInlineAgentContract, type InlineAgentContract, } from "./agents.js";
2
2
  export { replaceExporterVersion } from "./exporter-version.js";
3
- export { type FlowIoLogger, migrateRawWorkflow, readFlowWorkflow, } from "./flow-io.js";
3
+ export { createFlowRefResolver, type FlowIoLogger, migrateRawWorkflow, readFlowWorkflow, resolveAndMigrateWorkflow, resolveWorkflowRefs, } from "./flow-io.js";
4
4
  export { FlowTool } from "./flow-tool.js";
5
5
  export { FlowToolFactory } from "./flow-tool-factory.js";
6
6
  export { setPublishIntentOnInlineAgents } from "./inline-agent-utils.js";
package/dist/index.js CHANGED
@@ -32,7 +32,7 @@ import {
32
32
  // package.json
33
33
  var package_default = {
34
34
  name: "@uipath/packager-tool-flow",
35
- version: "1.200.0-preview.109",
35
+ version: "1.201.0-preview.115",
36
36
  description: "UiPath Flow tool implementation",
37
37
  type: "module",
38
38
  exports: {
@@ -75,17 +75,17 @@ var package_default = {
75
75
  license: "ISC",
76
76
  peerDependencies: {
77
77
  "@uipath/filesystem": "workspace:*",
78
- "@uipath/flow-converter": "0.25.0",
79
- "@uipath/flow-core": "^0.34.1",
80
- "@uipath/flow-migrations": "^0.15.1",
81
- "@uipath/flow-schema": "^0.22.1",
78
+ "@uipath/flow-converter": "^0.25.4",
79
+ "@uipath/flow-core": "^0.34.3",
80
+ "@uipath/flow-migrations": "^0.15.4",
81
+ "@uipath/flow-schema": "^0.22.4",
82
82
  "@uipath/solutionpackager-tool-core": "workspace:*",
83
83
  "@uipath/tool-agent": "^2.0.0"
84
84
  },
85
85
  devDependencies: {
86
86
  "@types/node": "^25.5.2",
87
87
  "@uipath/filesystem": "workspace:*",
88
- "@uipath/flow-core": "^0.34.1",
88
+ "@uipath/flow-core": "^0.34.3",
89
89
  "@uipath/solutionpackager-tool-core": "workspace:*",
90
90
  "@uipath/tool-agent": "^2.0.0",
91
91
  "@vitest/browser": "^4.1.6",
@@ -350,21 +350,27 @@ var replaceExporterVersion = (bpmnXml, version) => bpmnXml.replace(/exporterVers
350
350
  // src/flow-io.ts
351
351
  import { getFileSystem } from "@uipath/filesystem";
352
352
  import {
353
- currentVersion,
354
- migrateWorkflow,
355
- migrations
353
+ migrateWorkflowToFloor,
354
+ minimumSupportedVersion,
355
+ runtimeMigrations,
356
+ runtimeVersion
356
357
  } from "@uipath/flow-migrations";
357
- import { resolveAndConvertWorkflow } from "@uipath/flow-schema";
358
+ import {
359
+ fileFormatToInMemoryWorkflow,
360
+ resolveRefs
361
+ } from "@uipath/flow-schema";
358
362
  function migrateRawWorkflow(raw, logger) {
359
363
  const doc = raw;
360
- if (!doc?.version || doc.version === currentVersion) {
364
+ if (!doc?.version) {
361
365
  return raw;
362
366
  }
363
367
  try {
364
- const result = migrateWorkflow(migrations, doc, currentVersion);
368
+ const result = migrateWorkflowToFloor(runtimeMigrations, doc, runtimeVersion, minimumSupportedVersion);
369
+ if (result.error) {
370
+ logger?.warn(`migrateRawWorkflow: migration ${result.fromVersion} -> ${result.toVersion} did not apply: [${result.error.step}] ${result.error.message}`);
371
+ return raw;
372
+ }
365
373
  if (!result.migrated) {
366
- const detail = result.error ? `: [${result.error.step}] ${result.error.message}` : "";
367
- logger?.warn(`migrateRawWorkflow: migration ${result.fromVersion} -> ${result.toVersion} did not apply${detail}`);
368
374
  return raw;
369
375
  }
370
376
  logger?.debug?.(`migrateRawWorkflow: migrated workflow ${result.fromVersion} -> ${result.toVersion}`);
@@ -374,11 +380,8 @@ function migrateRawWorkflow(raw, logger) {
374
380
  return raw;
375
381
  }
376
382
  }
377
- async function readFlowWorkflow(filePath, options = {}) {
378
- const fs = options.fs ?? getFileSystem();
379
- const logger = options.logger;
380
- const raw = migrateRawWorkflow(JSON.parse(await readUtf8(fs, filePath)), logger);
381
- const resolver = async (refPath, baseUri) => {
383
+ function createFlowRefResolver(fs, logger) {
384
+ return async (refPath, baseUri) => {
382
385
  const resolvedPath = fs.path.resolve(fs.path.dirname(baseUri), refPath);
383
386
  const refContent = await readUtf8OrNull(fs, resolvedPath);
384
387
  if (refContent === null) {
@@ -387,9 +390,30 @@ async function readFlowWorkflow(filePath, options = {}) {
387
390
  }
388
391
  return JSON.parse(refContent);
389
392
  };
390
- const { workflow } = await resolveAndConvertWorkflow(raw, resolver, {
391
- baseUri: filePath
393
+ }
394
+ async function resolveWorkflowRefs(parsed, resolver, baseUri) {
395
+ const { resolved, refMap, errors } = await resolveRefs(parsed, resolver, {
396
+ baseUri
392
397
  });
398
+ if (errors.length > 0) {
399
+ const messages = errors.map((e) => `${e.pointer}: ${e.message}`).join("; ");
400
+ throw new Error(`Failed to resolve $ref(s): ${messages}`);
401
+ }
402
+ return { resolved, refMap };
403
+ }
404
+ async function resolveAndMigrateWorkflow(parsed, resolver, baseUri, logger) {
405
+ const { resolved, refMap } = await resolveWorkflowRefs(parsed, resolver, baseUri);
406
+ const migrated = migrateRawWorkflow(resolved, logger);
407
+ return {
408
+ workflow: fileFormatToInMemoryWorkflow(migrated),
409
+ refMap
410
+ };
411
+ }
412
+ async function readFlowWorkflow(filePath, options = {}) {
413
+ const fs = options.fs ?? getFileSystem();
414
+ const logger = options.logger;
415
+ const parsed = JSON.parse(await readUtf8(fs, filePath));
416
+ const { workflow } = await resolveAndMigrateWorkflow(parsed, createFlowRefResolver(fs, logger), filePath, logger);
393
417
  return workflow;
394
418
  }
395
419
  async function readUtf8(fs, filePath) {
@@ -712,12 +736,15 @@ class FlowToolFactory {
712
736
  toolsFactoryRepository.registerProjectToolFactory(new FlowToolFactory);
713
737
  export {
714
738
  setPublishIntentOnInlineAgents,
739
+ resolveWorkflowRefs,
740
+ resolveAndMigrateWorkflow,
715
741
  replaceExporterVersion,
716
742
  readFlowWorkflow,
717
743
  migrateRawWorkflow,
744
+ createFlowRefResolver,
718
745
  buildInlineAgentContract,
719
746
  FlowToolFactory,
720
747
  FlowTool
721
748
  };
722
749
 
723
- //# debugId=C70BAE8CC057EB2764756E2164756E21
750
+ //# debugId=A24A63C9F661398464756E2164756E21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uipath/packager-tool-flow",
3
- "version": "1.200.0-preview.109",
3
+ "version": "1.201.0-preview.115",
4
4
  "description": "UiPath Flow tool implementation",
5
5
  "type": "module",
6
6
  "exports": {
@@ -25,13 +25,13 @@
25
25
  "author": "",
26
26
  "license": "ISC",
27
27
  "peerDependencies": {
28
- "@uipath/filesystem": "1.200.0",
29
- "@uipath/flow-converter": "0.25.0",
30
- "@uipath/flow-core": "^0.34.1",
31
- "@uipath/flow-migrations": "^0.15.1",
32
- "@uipath/flow-schema": "^0.22.1",
33
- "@uipath/solutionpackager-tool-core": "1.200.0",
28
+ "@uipath/filesystem": "1.201.0",
29
+ "@uipath/flow-converter": "^0.25.4",
30
+ "@uipath/flow-core": "^0.34.3",
31
+ "@uipath/flow-migrations": "^0.15.4",
32
+ "@uipath/flow-schema": "^0.22.4",
33
+ "@uipath/solutionpackager-tool-core": "1.201.0",
34
34
  "@uipath/tool-agent": "^2.0.0"
35
35
  },
36
- "gitHead": "fcc01cdae81bbd0c25d3d4fc287537a9d19d99f4"
36
+ "gitHead": "f1086b73654d7728cb71f280588b3e0c77d535fc"
37
37
  }
package/src/flow-io.ts CHANGED
@@ -1,11 +1,19 @@
1
1
  import { getFileSystem, type IFileSystem } from "@uipath/filesystem";
2
2
  import {
3
- currentVersion,
4
3
  type MigrationWorkflow,
5
- migrateWorkflow,
6
- migrations,
4
+ migrateWorkflowToFloor,
5
+ minimumSupportedVersion,
6
+ runtimeMigrations,
7
+ runtimeVersion,
7
8
  } from "@uipath/flow-migrations";
8
- import { resolveAndConvertWorkflow, type Workflow } from "@uipath/flow-schema";
9
+ import {
10
+ fileFormatToInMemoryWorkflow,
11
+ type RefMap,
12
+ type ResolveRefCallback,
13
+ resolveRefs,
14
+ type Workflow,
15
+ type WorkflowFile,
16
+ } from "@uipath/flow-schema";
9
17
 
10
18
  export type FlowIoLogger = {
11
19
  warn: (message: string) => void;
@@ -13,37 +21,51 @@ export type FlowIoLogger = {
13
21
  };
14
22
 
15
23
  /**
16
- * Migrate a freshly-parsed raw workflow document to the current schema
17
- * version, in memory. `inMemoryWorkflowToFileFormat` refuses to serialize a
18
- * workflow whose `version` predates the current one (the flow-schema
19
- * migration contract), so every read that can reach a serialize path —
20
- * debug, format, pack, node/edge edits — must migrate first, the same way
21
- * the canvas migrates on open. The source file is never touched; the
22
- * migrated version is persisted only when a caller explicitly writes back.
24
+ * Migrate a freshly-parsed raw workflow document to the fleet write floor
25
+ * (`MINIMUM_SUPPORTED_SCHEMA_VERSION`), in memory. `inMemoryWorkflowToFileFormat`
26
+ * refuses to serialize a workflow whose `version` differs from the floor (the
27
+ * flow-schema write-floor contract), so every read that can reach a serialize
28
+ * path — debug, format, pack, node/edge edits — must project to the floor
29
+ * first, the same way the canvas does on open. Older documents migrate up to
30
+ * the floor; newer reversible documents (up to `runtimeVersion`) project back
31
+ * down to it. The source file is never touched; the migrated version is
32
+ * persisted only when a caller explicitly writes back.
33
+ *
34
+ * The document must have its `$ref` chunks resolved BEFORE this runs — the
35
+ * floor projection validates the full document shape (e.g. `layout.nodes`),
36
+ * which an unresolved `$ref` placeholder would fail. Use
37
+ * {@link resolveAndMigrateWorkflow} (or `resolveWorkflowRefs` + this) rather
38
+ * than calling this on raw file content.
23
39
  *
24
- * Fail-soft: a missing/current `version`, an unknown version with no
25
- * migration chain, or a failing chain step all return the document
26
- * unchanged — the serializer guard remains the backstop, exactly as before.
40
+ * Fail-soft: a missing `version`, an unknown version with no migration chain,
41
+ * or a failing chain step all return the document unchanged — the serializer
42
+ * guard remains the backstop.
27
43
  */
28
44
  export function migrateRawWorkflow(
29
45
  raw: unknown,
30
46
  logger?: FlowIoLogger,
31
47
  ): unknown {
32
48
  const doc = raw as MigrationWorkflow | null;
33
- if (!doc?.version || doc.version === currentVersion) {
49
+ if (!doc?.version) {
34
50
  return raw;
35
51
  }
36
52
  try {
37
- const result = migrateWorkflow(migrations, doc, currentVersion);
38
- if (!result.migrated) {
39
- const detail = result.error
40
- ? `: [${result.error.step}] ${result.error.message}`
41
- : "";
53
+ const result = migrateWorkflowToFloor(
54
+ runtimeMigrations,
55
+ doc,
56
+ runtimeVersion,
57
+ minimumSupportedVersion,
58
+ );
59
+ if (result.error) {
42
60
  logger?.warn(
43
- `migrateRawWorkflow: migration ${result.fromVersion} -> ${result.toVersion} did not apply${detail}`,
61
+ `migrateRawWorkflow: migration ${result.fromVersion} -> ${result.toVersion} did not apply: [${result.error.step}] ${result.error.message}`,
44
62
  );
45
63
  return raw;
46
64
  }
65
+ if (!result.migrated) {
66
+ // Already at the floor with no repair to retain — nothing to change.
67
+ return raw;
68
+ }
47
69
  logger?.debug?.(
48
70
  `migrateRawWorkflow: migrated workflow ${result.fromVersion} -> ${result.toVersion}`,
49
71
  );
@@ -58,6 +80,76 @@ export function migrateRawWorkflow(
58
80
  }
59
81
  }
60
82
 
83
+ /**
84
+ * Build the standard `$ref` resolver for `.flow` chunk files: resolves the
85
+ * ref path against the referencing file's directory and reads it as UTF-8
86
+ * JSON. A missing target logs a warning (fail-soft) and resolves to `null`;
87
+ * the resulting workflow may be partial.
88
+ */
89
+ export function createFlowRefResolver(
90
+ fs: IFileSystem,
91
+ logger?: FlowIoLogger,
92
+ ): ResolveRefCallback {
93
+ return async (refPath: string, baseUri: string) => {
94
+ const resolvedPath = fs.path.resolve(fs.path.dirname(baseUri), refPath);
95
+ const refContent = await readUtf8OrNull(fs, resolvedPath);
96
+ if (refContent === null) {
97
+ logger?.warn(
98
+ `Failed to resolve $ref "${refPath}": file not found at ${resolvedPath}`,
99
+ );
100
+ return null;
101
+ }
102
+ return JSON.parse(refContent);
103
+ };
104
+ }
105
+
106
+ /**
107
+ * Resolve all `$ref` chunk references in a parsed `.flow` document. Throws
108
+ * when resolution itself errors (cycles, resolver throws); a missing target
109
+ * is handled fail-soft by the resolver, not here.
110
+ */
111
+ export async function resolveWorkflowRefs(
112
+ parsed: unknown,
113
+ resolver: ResolveRefCallback,
114
+ baseUri: string,
115
+ ): Promise<{ resolved: unknown; refMap: RefMap }> {
116
+ const { resolved, refMap, errors } = await resolveRefs(parsed, resolver, {
117
+ baseUri,
118
+ });
119
+ if (errors.length > 0) {
120
+ const messages = errors
121
+ .map((e) => `${e.pointer}: ${e.message}`)
122
+ .join("; ");
123
+ throw new Error(`Failed to resolve $ref(s): ${messages}`);
124
+ }
125
+ return { resolved, refMap };
126
+ }
127
+
128
+ /**
129
+ * The full read pipeline for a parsed `.flow` document: resolve `$ref`
130
+ * chunks, project to the fleet write floor, convert to the in-memory
131
+ * Workflow. Refs are resolved BEFORE migrating because the floor projection
132
+ * validates the full document shape (e.g. `layout.nodes`), which an
133
+ * unresolved `$ref` placeholder would fail.
134
+ */
135
+ export async function resolveAndMigrateWorkflow(
136
+ parsed: unknown,
137
+ resolver: ResolveRefCallback,
138
+ baseUri: string,
139
+ logger?: FlowIoLogger,
140
+ ): Promise<{ workflow: Workflow; refMap: RefMap }> {
141
+ const { resolved, refMap } = await resolveWorkflowRefs(
142
+ parsed,
143
+ resolver,
144
+ baseUri,
145
+ );
146
+ const migrated = migrateRawWorkflow(resolved, logger);
147
+ return {
148
+ workflow: fileFormatToInMemoryWorkflow(migrated as WorkflowFile),
149
+ refMap,
150
+ };
151
+ }
152
+
61
153
  export interface ReadFlowWorkflowOptions {
62
154
  /** Filesystem to read from. Defaults to `getFileSystem()`. */
63
155
  fs?: IFileSystem;
@@ -86,26 +178,13 @@ export async function readFlowWorkflow(
86
178
  ): Promise<Workflow> {
87
179
  const fs = options.fs ?? getFileSystem();
88
180
  const logger = options.logger;
89
- const raw = migrateRawWorkflow(
90
- JSON.parse(await readUtf8(fs, filePath)),
181
+ const parsed: unknown = JSON.parse(await readUtf8(fs, filePath));
182
+ const { workflow } = await resolveAndMigrateWorkflow(
183
+ parsed,
184
+ createFlowRefResolver(fs, logger),
185
+ filePath,
91
186
  logger,
92
187
  );
93
-
94
- const resolver = async (refPath: string, baseUri: string) => {
95
- const resolvedPath = fs.path.resolve(fs.path.dirname(baseUri), refPath);
96
- const refContent = await readUtf8OrNull(fs, resolvedPath);
97
- if (refContent === null) {
98
- logger?.warn(
99
- `Failed to resolve $ref "${refPath}": file not found at ${resolvedPath}`,
100
- );
101
- return null;
102
- }
103
- return JSON.parse(refContent);
104
- };
105
-
106
- const { workflow } = await resolveAndConvertWorkflow(raw, resolver, {
107
- baseUri: filePath,
108
- });
109
188
  return workflow;
110
189
  }
111
190
 
package/src/index.ts CHANGED
@@ -14,9 +14,12 @@ export {
14
14
  } from "./agents.js";
15
15
  export { replaceExporterVersion } from "./exporter-version.js";
16
16
  export {
17
+ createFlowRefResolver,
17
18
  type FlowIoLogger,
18
19
  migrateRawWorkflow,
19
20
  readFlowWorkflow,
21
+ resolveAndMigrateWorkflow,
22
+ resolveWorkflowRefs,
20
23
  } from "./flow-io.js";
21
24
  export { FlowTool } from "./flow-tool.js";
22
25
  export { FlowToolFactory } from "./flow-tool-factory.js";