@uipath/maestro-builder-sdk 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +322 -0
  3. package/dist/bindings-v2.d.ts +37 -0
  4. package/dist/bindings-v2.js +155 -0
  5. package/dist/bindings.d.ts +6 -0
  6. package/dist/bindings.js +6 -0
  7. package/dist/bpmn/bpmn-expr-check.d.ts +41 -0
  8. package/dist/bpmn/bpmn-expr-check.js +218 -0
  9. package/dist/bpmn/bpmn-sdk.d.ts +2257 -0
  10. package/dist/bpmn/bpmn-sdk.js +1476 -0
  11. package/dist/bpmn/check-cli.d.ts +3 -0
  12. package/dist/bpmn/check-cli.js +32 -0
  13. package/dist/bpmn/check.d.ts +25 -0
  14. package/dist/bpmn/check.js +430 -0
  15. package/dist/bpmn/compile-cli.d.ts +3 -0
  16. package/dist/bpmn/compile-cli.js +60 -0
  17. package/dist/bpmn/connector.d.ts +56 -0
  18. package/dist/bpmn/connector.js +199 -0
  19. package/dist/bpmn/decompile-cli.d.ts +8 -0
  20. package/dist/bpmn/decompile-cli.js +54 -0
  21. package/dist/bpmn/decompile.d.ts +6 -0
  22. package/dist/bpmn/decompile.js +1108 -0
  23. package/dist/bpmn/format-profile.d.ts +27 -0
  24. package/dist/bpmn/format-profile.js +11 -0
  25. package/dist/bpmn/intsvc.d.ts +77 -0
  26. package/dist/bpmn/intsvc.js +155 -0
  27. package/dist/bpmn/load.d.ts +4 -0
  28. package/dist/bpmn/load.js +22 -0
  29. package/dist/bpmn/merge-cli.d.ts +3 -0
  30. package/dist/bpmn/merge-cli.js +45 -0
  31. package/dist/bpmn/merge.d.ts +19 -0
  32. package/dist/bpmn/merge.js +293 -0
  33. package/dist/bpmn/registry-types.json +1869 -0
  34. package/dist/bpmn/serialize.d.ts +28 -0
  35. package/dist/bpmn/serialize.js +757 -0
  36. package/dist/bpmn/tidy-cli.d.ts +2 -0
  37. package/dist/bpmn/tidy-cli.js +39 -0
  38. package/dist/bpmn/typed-node.d.ts +382 -0
  39. package/dist/bpmn/typed-node.js +551 -0
  40. package/dist/bpmn/uipath-moddle.v1.json +823 -0
  41. package/dist/bpmn/xml-ranges.d.ts +45 -0
  42. package/dist/bpmn/xml-ranges.js +151 -0
  43. package/dist/case/case-expr-check.d.ts +35 -0
  44. package/dist/case/case-expr-check.js +85 -0
  45. package/dist/case/case-sdk.d.ts +1282 -0
  46. package/dist/case/case-sdk.js +923 -0
  47. package/dist/case/check-cli.d.ts +3 -0
  48. package/dist/case/check-cli.js +31 -0
  49. package/dist/case/check.d.ts +18 -0
  50. package/dist/case/check.js +456 -0
  51. package/dist/case/compile-cli.d.ts +3 -0
  52. package/dist/case/compile-cli.js +291 -0
  53. package/dist/case/decompile-cli.d.ts +9 -0
  54. package/dist/case/decompile-cli.js +117 -0
  55. package/dist/case/decompile.d.ts +187 -0
  56. package/dist/case/decompile.js +1170 -0
  57. package/dist/case/entry-points.d.ts +79 -0
  58. package/dist/case/entry-points.js +118 -0
  59. package/dist/case/format-profile.d.ts +60 -0
  60. package/dist/case/format-profile.js +79 -0
  61. package/dist/case/ids.d.ts +24 -0
  62. package/dist/case/ids.js +76 -0
  63. package/dist/case/load.d.ts +12 -0
  64. package/dist/case/load.js +32 -0
  65. package/dist/case/preserve.d.ts +133 -0
  66. package/dist/case/preserve.js +105 -0
  67. package/dist/case/serialize.d.ts +10 -0
  68. package/dist/case/serialize.js +1414 -0
  69. package/dist/check-cli.d.ts +3 -0
  70. package/dist/check-cli.js +118 -0
  71. package/dist/check.d.ts +146 -0
  72. package/dist/check.js +4898 -0
  73. package/dist/cli/commands/bpmn.d.ts +2 -0
  74. package/dist/cli/commands/bpmn.js +73 -0
  75. package/dist/cli/commands/case.d.ts +2 -0
  76. package/dist/cli/commands/case.js +60 -0
  77. package/dist/cli/commands/flow.d.ts +2 -0
  78. package/dist/cli/commands/flow.js +99 -0
  79. package/dist/cli/commands/registry.d.ts +10 -0
  80. package/dist/cli/commands/registry.js +170 -0
  81. package/dist/cli/common.d.ts +30 -0
  82. package/dist/cli/common.js +92 -0
  83. package/dist/cli/index.d.ts +2 -0
  84. package/dist/cli/index.js +18 -0
  85. package/dist/cli-run.d.ts +2 -0
  86. package/dist/cli-run.js +42 -0
  87. package/dist/compile-cli.d.ts +3 -0
  88. package/dist/compile-cli.js +160 -0
  89. package/dist/config.d.ts +47 -0
  90. package/dist/config.js +201 -0
  91. package/dist/core/actions.d.ts +3244 -0
  92. package/dist/core/actions.js +1062 -0
  93. package/dist/core/binding-messages.d.ts +1 -0
  94. package/dist/core/binding-messages.js +16 -0
  95. package/dist/core/bindings.d.ts +12 -0
  96. package/dist/core/bindings.js +67 -0
  97. package/dist/core/ceql.d.ts +73 -0
  98. package/dist/core/ceql.js +272 -0
  99. package/dist/core/cli-spelling.d.ts +39 -0
  100. package/dist/core/cli-spelling.js +62 -0
  101. package/dist/core/connector-raw-node.d.ts +21 -0
  102. package/dist/core/connector-raw-node.js +47 -0
  103. package/dist/core/connectors.d.ts +184 -0
  104. package/dist/core/connectors.js +128 -0
  105. package/dist/core/expr-check.d.ts +93 -0
  106. package/dist/core/expr-check.js +186 -0
  107. package/dist/core/expr.d.ts +323 -0
  108. package/dist/core/expr.js +400 -0
  109. package/dist/core/index.d.ts +10 -0
  110. package/dist/core/index.js +10 -0
  111. package/dist/core/library.d.ts +440 -0
  112. package/dist/core/library.js +1183 -0
  113. package/dist/core/list-envelope.d.ts +45 -0
  114. package/dist/core/list-envelope.js +97 -0
  115. package/dist/core/lookup-store.d.ts +22 -0
  116. package/dist/core/lookup-store.js +85 -0
  117. package/dist/core/lookups.d.ts +227 -0
  118. package/dist/core/lookups.js +231 -0
  119. package/dist/core/node-classes.d.ts +234 -0
  120. package/dist/core/node-classes.js +158 -0
  121. package/dist/core/script-return.d.ts +68 -0
  122. package/dist/core/script-return.js +197 -0
  123. package/dist/core/stable-id.d.ts +28 -0
  124. package/dist/core/stable-id.js +37 -0
  125. package/dist/core-definitions.json +16249 -0
  126. package/dist/decompile-cli.d.ts +3 -0
  127. package/dist/decompile-cli.js +131 -0
  128. package/dist/decompile.d.ts +138 -0
  129. package/dist/decompile.js +2482 -0
  130. package/dist/emit.d.ts +10 -0
  131. package/dist/emit.js +60 -0
  132. package/dist/event-filters.d.ts +130 -0
  133. package/dist/event-filters.js +137 -0
  134. package/dist/flow-expr-check.d.ts +17 -0
  135. package/dist/flow-expr-check.js +193 -0
  136. package/dist/flow-sdk.d.ts +1341 -0
  137. package/dist/flow-sdk.js +1164 -0
  138. package/dist/flow-variables.d.ts +13 -0
  139. package/dist/flow-variables.js +42 -0
  140. package/dist/format-profile.d.ts +72 -0
  141. package/dist/format-profile.js +97 -0
  142. package/dist/generators/_connections.py +287 -0
  143. package/dist/generators/_events.py +355 -0
  144. package/dist/generators/_lookups.py +114 -0
  145. package/dist/generators/_naming.py +185 -0
  146. package/dist/generators/_objects.py +299 -0
  147. package/dist/generators/_resolve.py +273 -0
  148. package/dist/generators/convert_library_to_md.py +1441 -0
  149. package/dist/generators/extract_library.py +125 -0
  150. package/dist/generators/generate_connectors_ts.py +936 -0
  151. package/dist/generators/generate_library_json.py +2527 -0
  152. package/dist/generators/generate_triggers_ts.py +110 -0
  153. package/dist/generators/materialize_registry.py +155 -0
  154. package/dist/generators/prepare_connector.py +1688 -0
  155. package/dist/index.d.ts +35 -0
  156. package/dist/index.js +35 -0
  157. package/dist/ixp-definition.json +1982 -0
  158. package/dist/library.d.ts +6 -0
  159. package/dist/library.js +6 -0
  160. package/dist/load.d.ts +16 -0
  161. package/dist/load.js +95 -0
  162. package/dist/merge-cli.d.ts +3 -0
  163. package/dist/merge-cli.js +47 -0
  164. package/dist/merge.d.ts +125 -0
  165. package/dist/merge.js +0 -0
  166. package/dist/migrate.d.ts +15 -0
  167. package/dist/migrate.js +245 -0
  168. package/dist/node-runtime.d.ts +3 -0
  169. package/dist/node-runtime.js +22 -0
  170. package/dist/package-name.d.ts +17 -0
  171. package/dist/package-name.js +17 -0
  172. package/dist/ref-resolve.d.ts +77 -0
  173. package/dist/ref-resolve.js +170 -0
  174. package/dist/registry/cache.d.ts +55 -0
  175. package/dist/registry/cache.js +134 -0
  176. package/dist/registry/curated-overlay.d.ts +16 -0
  177. package/dist/registry/curated-overlay.js +62 -0
  178. package/dist/registry/extractor.d.ts +22 -0
  179. package/dist/registry/extractor.js +18 -0
  180. package/dist/registry/materialize-bin.d.ts +2 -0
  181. package/dist/registry/materialize-bin.js +7 -0
  182. package/dist/registry/materialize-cli.d.ts +1 -0
  183. package/dist/registry/materialize-cli.js +46 -0
  184. package/dist/registry/materializer.d.ts +23 -0
  185. package/dist/registry/materializer.js +34 -0
  186. package/dist/registry/path-cli.d.ts +1 -0
  187. package/dist/registry/path-cli.js +56 -0
  188. package/dist/registry/prepare-cli.d.ts +62 -0
  189. package/dist/registry/prepare-cli.js +185 -0
  190. package/dist/registry/pull-cli.d.ts +1 -0
  191. package/dist/registry/pull-cli.js +274 -0
  192. package/dist/registry/python.d.ts +26 -0
  193. package/dist/registry/python.js +46 -0
  194. package/dist/registry/search-cli.d.ts +52 -0
  195. package/dist/registry/search-cli.js +159 -0
  196. package/dist/schema-version.d.ts +165 -0
  197. package/dist/schema-version.js +148 -0
  198. package/dist/serialize.d.ts +64 -0
  199. package/dist/serialize.js +6398 -0
  200. package/lib/README.md +112 -0
  201. package/lib/library-json.samples/index.json +158 -0
  202. package/lib/library-json.samples/invariant-collections.json +83 -0
  203. package/lib/library-json.samples/list-envelopes.json +123 -0
  204. package/lib/library-json.samples/uipath-atlassian-jira/create-issue@1.0.0.json +131 -0
  205. package/lib/library-json.samples/uipath-atlassian-jira/create-issue@1.0.0.v1def.json +306 -0
  206. package/lib/library-json.samples/uipath-atlassian-jira/generic/create_issue/create@1.0.0.json +86 -0
  207. package/lib/library-json.samples/uipath-atlassian-jira/generic/create_issue/create@1.0.0.v1def.json +208 -0
  208. package/lib/library-json.samples/uipath-atlassian-jira/get-issue@1.0.0.json +2040 -0
  209. package/lib/library-json.samples/uipath-atlassian-jira/get-issue@1.0.0.v1def.json +195 -0
  210. package/lib/library-json.samples/uipath-google-vertex/execute-google-vertex-agent@1.0.0.json +169 -0
  211. package/lib/library-json.samples/uipath-google-vertex/execute-google-vertex-agent@1.0.0.v1def.json +209 -0
  212. package/lib/library-json.samples/uipath-http-webhook/event-http-webhook@1.0.0.json +63 -0
  213. package/lib/library-json.samples/uipath-http-webhook/event-http-webhook@1.0.0.v1def.json +262 -0
  214. package/lib/library-json.samples/uipath-http-webhook/trigger-http-webhook@1.0.0.json +63 -0
  215. package/lib/library-json.samples/uipath-http-webhook/trigger-http-webhook@1.0.0.v1def.json +213 -0
  216. package/lib/library-json.samples/uipath-microsoft-azureactivedirectory/list-groups@1.0.0.json +227 -0
  217. package/lib/library-json.samples/uipath-microsoft-azureactivedirectory/list-groups@1.0.0.v1def.json +373 -0
  218. package/lib/library-json.samples/uipath-microsoft-onedrive/event-file-created@1.0.0.json +116 -0
  219. package/lib/library-json.samples/uipath-microsoft-onedrive/event-file-created@1.0.0.v1def.json +369 -0
  220. package/lib/library-json.samples/uipath-microsoft-onedrive/event-list-item-added@1.0.0.json +56 -0
  221. package/lib/library-json.samples/uipath-microsoft-onedrive/event-list-item-added@1.0.0.v1def.json +256 -0
  222. package/lib/library-json.samples/uipath-microsoft-onedrive/trigger-file-created@1.0.0.json +116 -0
  223. package/lib/library-json.samples/uipath-microsoft-onedrive/trigger-file-created@1.0.0.v1def.json +320 -0
  224. package/lib/library-json.samples/uipath-microsoft-onedrive/trigger-list-item-added@1.0.0.json +56 -0
  225. package/lib/library-json.samples/uipath-microsoft-onedrive/trigger-list-item-added@1.0.0.v1def.json +207 -0
  226. package/lib/library-json.samples/uipath-microsoft-outlook365/event-email-received@1.0.0.json +107 -0
  227. package/lib/library-json.samples/uipath-microsoft-outlook365/event-email-received@1.0.0.v1def.json +264 -0
  228. package/lib/library-json.samples/uipath-microsoft-outlook365/send-email@1.0.0.json +142 -0
  229. package/lib/library-json.samples/uipath-microsoft-outlook365/send-email@1.0.0.v1def.json +306 -0
  230. package/lib/library-json.samples/uipath-microsoft-outlook365/trigger-email-received@1.0.0.json +107 -0
  231. package/lib/library-json.samples/uipath-microsoft-outlook365/trigger-email-received@1.0.0.v1def.json +217 -0
  232. package/lib/library-json.samples/uipath-microsoft-powerautomate/invoke-a-microsoft-power-automate-flow@1.0.0.json +85 -0
  233. package/lib/library-json.samples/uipath-microsoft-powerautomate/invoke-a-microsoft-power-automate-flow@1.0.0.v1def.json +209 -0
  234. package/lib/library-json.samples/uipath-salesforce-slack/send-message-to-user@1.0.0.json +755 -0
  235. package/lib/library-json.samples/uipath-salesforce-slack/send-message-to-user@1.0.0.v1def.json +513 -0
  236. package/lib/library-json.samples/uipath-uipath-dataservice/query-entity-records@1.0.0.json +122 -0
  237. package/lib/library-json.samples/uipath-uipath-dataservice/query-entity-records@1.0.0.v1def.json +227 -0
  238. package/package.json +85 -0
@@ -0,0 +1,6 @@
1
+ /**
2
+ * library — compatibility re-export. The connector library resolver now lives
3
+ * in `core/` (shared across flow/case/bpmn); this shim preserves the historical
4
+ * `./library.js` import path.
5
+ */
6
+ export * from './core/library.js';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * library — compatibility re-export. The connector library resolver now lives
3
+ * in `core/` (shared across flow/case/bpmn); this shim preserves the historical
4
+ * `./library.js` import path.
5
+ */
6
+ export * from './core/library.js';
package/dist/load.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ import type { BuiltFlow } from './flow-sdk.js';
2
+ /** Resolve a user argument (a `.ts` path or a BaseName) to a flow source file. */
3
+ export declare function resolveFlowFile(arg: string): string;
4
+ export declare function loadBuiltFlow(file: string): Promise<BuiltFlow>;
5
+ /**
6
+ * Turn a failed connector import into an error naming the file that exists.
7
+ *
8
+ * Exported for tests. It cannot be exercised through a real `import()` under
9
+ * vitest: vite resolves `./x.js` to `x.ts` itself, so the import succeeds and
10
+ * there is no resolution error to diagnose. Node's own loader — what runs in
11
+ * production — does not, which is the case this handles. So the tests hand it
12
+ * the error object Node produces instead of trying to provoke one.
13
+ *
14
+ * @internal
15
+ */
16
+ export declare function connectorImportDiagnostic(error: unknown): Error | undefined;
package/dist/load.js ADDED
@@ -0,0 +1,95 @@
1
+ /** Shared: dynamic-import an authored flow module and return its BuiltFlow. */
2
+ import { fileURLToPath, pathToFileURL } from 'node:url';
3
+ import { basename, dirname, join, resolve } from 'node:path';
4
+ import { statSync } from 'node:fs';
5
+ /** Resolve a user argument (a `.ts` path or a BaseName) to a flow source file. */
6
+ export function resolveFlowFile(arg) {
7
+ const candidates = [arg, `${arg}.flow.ts`, `${arg}.ts`];
8
+ const resolvedArg = resolve(arg);
9
+ const argStat = statSync(resolvedArg, { throwIfNoEntry: false });
10
+ for (const candidate of candidates) {
11
+ const resolvedCandidate = resolve(candidate);
12
+ if (!statSync(resolvedCandidate, { throwIfNoEntry: false })?.isFile())
13
+ continue;
14
+ if (candidate !== arg && argStat?.isDirectory()) {
15
+ console.error(`flow source: "${resolvedArg}" is a directory; using "${resolvedCandidate}"`);
16
+ }
17
+ return resolvedCandidate;
18
+ }
19
+ throw new Error(`flow source not found: tried ${candidates.join(', ')}`);
20
+ }
21
+ export async function loadBuiltFlow(file) {
22
+ let mod;
23
+ try {
24
+ mod = await import(pathToFileURL(file).href);
25
+ }
26
+ catch (error) {
27
+ throw connectorImportDiagnostic(error) ?? error;
28
+ }
29
+ const exp = mod.default ?? mod.flow ?? mod.workflow;
30
+ if (!exp)
31
+ throw new Error(`${file} has no default export. Add: export default flow('id')...build();`);
32
+ const built = typeof exp.build === 'function' ? exp.build() : exp;
33
+ if (!built || !Array.isArray(built.steps))
34
+ throw new Error(`${file} default export is not a built flow. Did you call .build()?`);
35
+ return built;
36
+ }
37
+ /**
38
+ * Turn a failed connector import into an error naming the file that exists.
39
+ *
40
+ * Exported for tests. It cannot be exercised through a real `import()` under
41
+ * vitest: vite resolves `./x.js` to `x.ts` itself, so the import succeeds and
42
+ * there is no resolution error to diagnose. Node's own loader — what runs in
43
+ * production — does not, which is the case this handles. So the tests hand it
44
+ * the error object Node produces instead of trying to provoke one.
45
+ *
46
+ * @internal
47
+ */
48
+ export function connectorImportDiagnostic(error) {
49
+ const resolutionError = error;
50
+ if (!error ||
51
+ typeof resolutionError.url !== 'string' ||
52
+ !['ERR_MODULE_NOT_FOUND', 'ERR_UNSUPPORTED_DIR_IMPORT'].includes(String(resolutionError.code))) {
53
+ return undefined;
54
+ }
55
+ let unresolved;
56
+ try {
57
+ unresolved = fileURLToPath(resolutionError.url);
58
+ }
59
+ catch {
60
+ return undefined;
61
+ }
62
+ // Both trees emit plain `.ts`, so the conventional `./x.js` specifier resolves
63
+ // to nothing. `connectors-local/` is written by `registry prepare` and keeps
64
+ // its descriptor data in a sibling directory; `connectors/` is written by
65
+ // `registry pull` and is modules only. Covering both matters because the pull
66
+ // is the FIRST thing an author does — without it that path fails with a bare
67
+ // "Cannot find module" and no clue that the extension is the problem.
68
+ const parent = basename(dirname(unresolved));
69
+ if (parent !== 'connectors-local' && parent !== 'connectors')
70
+ return undefined;
71
+ // The specifier an author actually writes is `./connectors/<key>.js` — the ESM
72
+ // convention of naming the compiled output. So the candidate is that path with
73
+ // `.js` SWAPPED for `.ts`, not `.ts` appended: appending produced
74
+ // `<key>.js.ts`, which never exists, so this diagnostic only fired for an
75
+ // extensionless import and was therefore unreachable in practice.
76
+ const stem = unresolved.endsWith('.js')
77
+ ? unresolved.slice(0, -'.js'.length)
78
+ : unresolved;
79
+ const moduleFile = `${stem}.ts`;
80
+ if (!statSync(moduleFile, { throwIfNoEntry: false })?.isFile()) {
81
+ return undefined;
82
+ }
83
+ if (parent === 'connectors') {
84
+ return new Error(`connector import "${unresolved}" does not name a file. The generated ` +
85
+ `descriptors are TypeScript, so the specifier keeps its real extension; ` +
86
+ `import "${moduleFile}"`);
87
+ }
88
+ const descriptorData = join(dirname(unresolved), 'descriptors', basename(stem));
89
+ if (!statSync(descriptorData, { throwIfNoEntry: false })?.isDirectory()) {
90
+ return undefined;
91
+ }
92
+ return new Error(`connector import "${unresolved}" does not name a file; module candidate ` +
93
+ `"${moduleFile}" and descriptor data "${descriptorData}" are separate; ` +
94
+ `import "${moduleFile}"`);
95
+ }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { type CliExitCode } from './cli-run.js';
3
+ export declare function run(argv: string[]): CliExitCode;
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * merge-cli — merge an edited flow back into the original `.flow` (bin `flow-merge`)
4
+ *
5
+ * Usage:
6
+ * flow-merge <original.flow> <edited.flow> [-o merged.flow] [--baseline <baseline.flow>]
7
+ *
8
+ * `edited.flow` is compile(decompile(original) after your edits). `--baseline`
9
+ * is compile(decompile(original)) BEFORE any edit — supplying it enables the
10
+ * delta merge (untouched nodes keep their original content, placeholder-safe);
11
+ * omit it for a two-way merge (take the edited graph, re-attach original layout).
12
+ * See merge.ts.
13
+ */
14
+ import { readFileSync, writeFileSync } from 'node:fs';
15
+ import { basename } from 'node:path';
16
+ import { mergeFlow } from './merge.js';
17
+ import { runWhenInvokedDirectly } from './cli-run.js';
18
+ function opt(argv, name) {
19
+ const i = argv.indexOf(name);
20
+ return i >= 0 ? argv[i + 1] : undefined;
21
+ }
22
+ export function run(argv) {
23
+ if (argv.length === 0 || argv[0] === '-h' || argv[0] === '--help') {
24
+ console.error('usage: flow-merge <original.flow> <edited.flow> [-o merged.flow] [--baseline <baseline.flow>]');
25
+ return 2;
26
+ }
27
+ const flags = new Set(['-o', '--baseline']);
28
+ const positionals = argv.filter((a, i) => !flags.has(a) && !flags.has(argv[i - 1]) && !a.startsWith('-'));
29
+ const [originalPath, editedPath] = positionals;
30
+ if (!originalPath || !editedPath) {
31
+ console.error('flow-merge: need <original.flow> and <edited.flow>');
32
+ return 2;
33
+ }
34
+ const original = JSON.parse(readFileSync(originalPath, 'utf8'));
35
+ const edited = JSON.parse(readFileSync(editedPath, 'utf8'));
36
+ const baselinePath = opt(argv, '--baseline');
37
+ const baseline = baselinePath ? JSON.parse(readFileSync(baselinePath, 'utf8')) : undefined;
38
+ const merged = mergeFlow(original, edited, {
39
+ baseline,
40
+ warn: (m) => console.error(`flow-merge: warning: ${m}`),
41
+ });
42
+ const out = opt(argv, '-o') ?? 'merged.flow';
43
+ writeFileSync(out, JSON.stringify(merged, null, 2) + '\n');
44
+ console.log(`flow-merge: wrote ${basename(out)} (${(merged.nodes ?? []).length} nodes, ${(merged.edges ?? []).length} edges)`);
45
+ return 0;
46
+ }
47
+ runWhenInvokedDirectly(import.meta.url, 'flow-merge', run);
@@ -0,0 +1,125 @@
1
+ /**
2
+ * merge — write a decompiled-then-edited flow back into the ORIGINAL `.flow`
3
+ * JSON, splicing in only what changed and preserving everything cosmetic or
4
+ * mechanically-reconstructable.
5
+ *
6
+ * The brownfield pipeline is:
7
+ *
8
+ * original.flow --decompile--> Flow.flow.ts --(edit)--> --compile--> edited.flow
9
+ * mergeFlow(original, edited[, baseline]) --> merged.flow
10
+ *
11
+ * Why not just take `edited` wholesale? Because decompile is **semantically**
12
+ * lossless, not byte-for-byte: it discards layout, and it lowers node types it
13
+ * cannot yet fully invert (some agents / IxP / …) to `mock()` placeholders. A
14
+ * blind overwrite would flatten an untouched connector's layout and turn an
15
+ * untouched agent into a mock. So the merge is a **delta**:
16
+ *
17
+ * - `baseline` (optional) = compile(decompile(original)) BEFORE any edit — i.e.
18
+ * what a faithful round-trip of the original produces. When a node in
19
+ * `edited` is byte-equal to its `baseline` counterpart, the user did NOT
20
+ * touch it, so the merge keeps the ORIGINAL node verbatim (its real type,
21
+ * inputs, layout — even for a placeholder). Only nodes the user actually
22
+ * changed (or added) are taken from `edited`.
23
+ * - Without a `baseline`, the merge is two-way: it takes `edited`'s graph and
24
+ * re-attaches the original layout by node-id match. This is correct as long
25
+ * as decompile was faithful for every node (the common case).
26
+ *
27
+ * Layout, `metadata`, `solutionId`, `projectId`, `runtime` and `layout` are
28
+ * preserved from the original; `definitions` and `bindings` are unioned
29
+ * (original wins on conflict, since the original's are the tenant-resolved
30
+ * authority). Node ids are stable by construction (decompile names every step by
31
+ * its node id), which is what lets every re-attach key on id.
32
+ *
33
+ * ## Definitions are keyed by `nodeType@version`, not by `nodeType`
34
+ *
35
+ * The node array a merge produces is deliberately MIXED: an untouched node is
36
+ * emitted from the original (so it keeps the original's `typeVersion`), while an
37
+ * edited or added one comes from `edited` (so it carries whatever version the
38
+ * SDK resolved). Both are correct. What was not correct was keying
39
+ * `definitions[]` by `nodeType` alone — one slot per type, original winning —
40
+ * because that dropped the edited file's definition for a type whose version
41
+ * differed, and left the added node pointing at a version the emitted
42
+ * `definitions[]` no longer contained:
43
+ *
44
+ * nodes: convertToCelsius core.action.script@1.0.0
45
+ * definitions: core.action.script@1.0 <- original won, 1.0.0 discarded
46
+ * → validate: Node type "core.action.script:1.0.0" has no matching definition
47
+ *
48
+ * That is flow-builder-sdk#673's second-order failure: it fires on any
49
+ * STRUCTURAL edit (add / move / remove / regroup a node) and never on an
50
+ * in-place field edit, because `nodeUnchanged` keys on type+inputs only. Every
51
+ * agent that hit it abandoned the merge and copied `edited.flow` over the
52
+ * target, which is how a brownfield edit silently rewrote every untouched
53
+ * node's version.
54
+ *
55
+ * So the union is keyed by the `(nodeType, version)` PAIR and selected by the
56
+ * pairs the final node array actually uses. Pair-keying also makes the emitted
57
+ * `definitions[]` able to hold two versions of one family at once — which the
58
+ * format always allowed, which the bundle already ships (`core.logic.loop@1.0.0`
59
+ * + `@2.4`), and which a flow legitimately needs when the author pins one node
60
+ * to an older version and takes the default on another.
61
+ *
62
+ * A node whose pair is in NEITHER file cannot be given a definition here, and a
63
+ * merge that stayed silent about it wrote a file it already knew would fail
64
+ * `validate`. Those are reported through {@link MergeOptions.warn}.
65
+ */
66
+ interface AnyNode {
67
+ id: string;
68
+ type: string;
69
+ typeVersion?: string;
70
+ parentId?: string;
71
+ ui?: unknown;
72
+ display?: unknown;
73
+ inputs?: Record<string, unknown>;
74
+ outputs?: Record<string, unknown>;
75
+ [k: string]: unknown;
76
+ }
77
+ interface AnyEdge {
78
+ id?: string;
79
+ sourceNodeId: string;
80
+ sourcePort: string;
81
+ targetNodeId: string;
82
+ targetPort: string;
83
+ [k: string]: unknown;
84
+ }
85
+ interface AnyFlow {
86
+ id?: string;
87
+ name?: string;
88
+ version?: string;
89
+ nodes?: AnyNode[];
90
+ edges?: AnyEdge[];
91
+ definitions?: Array<{
92
+ nodeType?: string;
93
+ [k: string]: unknown;
94
+ }>;
95
+ variables?: unknown;
96
+ subflows?: Record<string, unknown>;
97
+ bindings?: Array<{
98
+ id?: string;
99
+ [k: string]: unknown;
100
+ }>;
101
+ metadata?: unknown;
102
+ solutionId?: unknown;
103
+ projectId?: unknown;
104
+ layout?: unknown;
105
+ runtime?: unknown;
106
+ [k: string]: unknown;
107
+ }
108
+ export interface MergeOptions {
109
+ /**
110
+ * compile(decompile(original)) captured BEFORE the user's edits. Enables the
111
+ * delta merge: a node byte-equal to its baseline is treated as untouched and
112
+ * kept from the original. Omit for a two-way merge (take `edited`, re-attach
113
+ * original layout by id).
114
+ */
115
+ baseline?: AnyFlow;
116
+ /**
117
+ * Called once per finding, mirroring `DecompileOptions.warn`. Today the only
118
+ * finding is a node whose `(type, typeVersion)` pair has no definition in
119
+ * either input — the one case where the merge cannot produce a self-consistent
120
+ * file and `validate` will refuse the result.
121
+ */
122
+ warn?: (message: string) => void;
123
+ }
124
+ export declare function mergeFlow(original: AnyFlow, edited: AnyFlow, options?: MergeOptions): AnyFlow;
125
+ export {};
package/dist/merge.js ADDED
Binary file
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Bring a freshly-built FlowFile up to `target`, the file-format version the
3
+ * document will declare.
4
+ *
5
+ * @param flow - The serializer's in-progress FlowFile, mutated in place.
6
+ * @param target - The declared target version. Defaults to the profile pin, so
7
+ * every existing caller keeps its behaviour exactly.
8
+ */
9
+ export declare function migrateToSchemaVersion(flow: any, target?: string): void;
10
+ /**
11
+ * @deprecated Use {@link migrateToSchemaVersion}. Kept because the name says
12
+ * "1.6" while the function has emitted the profile's version for several floors
13
+ * now — the rename is the point, and callers that pass no target are unchanged.
14
+ */
15
+ export declare function migrateTo16(flow: any): void;
@@ -0,0 +1,245 @@
1
+ /**
2
+ * Node inputs the wrap must LEAVE ALONE, keyed by node-type prefix.
3
+ *
4
+ * The envelope is the current file format's general spelling for a dynamic
5
+ * value, and wrapping by a blanket `startsWith('=')` rule is right almost
6
+ * everywhere. It is not right everywhere, and the platform's own migration says
7
+ * so out loud: `migrateV1_2_to_v1_3` skips `node.inputs` entirely for the agent
8
+ * families (`isAgentNodeType` / `isAgentResourceNodeType`, flow-v1
9
+ * `packages/migrations/src/migrations/v1.2-to-v1.3.ts:187`) because "their
10
+ * prompt/template inputs flow through agent.json + the PromptEditor, neither of
11
+ * which is EV-aware". This SDK mirrored the wrap without mirroring the
12
+ * exemption mechanism, and one field paid for it.
13
+ *
14
+ * **`uipath.ixp.*` → `fileRef`** (card ga7, measured 2026-08-01):
15
+ *
16
+ * - `uip maestro flow validate` REFUSES the envelope outright. The product's
17
+ * `ixp-node` validator tests `typeof fileRef !== 'string'` and errors with
18
+ * *"inputs.fileRef must be a `=js:$vars.…` expression"*
19
+ * (uipath-cli `packages/flow-tool/src/services/node-validators/ixp-node-validator.ts:78`).
20
+ * That is criterion 1 of GA row 7, weight 3.0 — so every SDK-authored IxP
21
+ * flow was failing 30% of that row's bar.
22
+ * - The node's OWN registry manifest agrees: `inputDefinition.properties.fileRef`
23
+ * is `{ type: 'string', minLength: 1 }` (`ixp-definition.json`, pulled
24
+ * 2026-07-31), and an object satisfies neither half.
25
+ * - So does the deployed corpus: of the **150** v1-authored `uipath.ixp.*`
26
+ * nodes in `~/root/workspaces/runs` that carry a `fileRef`, **150 carry a
27
+ * STRING** (148 the `=js:$vars.…` expression form, 2 a literal) and **ZERO
28
+ * carry an envelope**. The only 18 envelopes anywhere are this SDK's own
29
+ * output. Spread across file versions 1.6, 1.8 AND 1.9, so this is NOT an
30
+ * era difference — 1.9 is the newest era present and spells it the same way.
31
+ * (Reproduce: `runs/flow-sdk-ga7-2026-08-01/ixp-fileref-scan.py`.)
32
+ *
33
+ * Why the bug survived a platform run: the RUNTIME accepts both. G-19/G-20's
34
+ * `flow debug` runs Completed with the envelope and really extracted six fields
35
+ * from the real PDF, so nothing before this card had reason to look. `flow
36
+ * validate` is the only reader that refuses it, and it was never run on an
37
+ * SDK-authored IxP flow until now (lesson 45, one family over).
38
+ */
39
+ import { FLOW_FORMAT_PROFILE } from './format-profile.js';
40
+ import { schemaVersionAtLeast } from './schema-version.js';
41
+ import { readFlowGlobals } from './flow-variables.js';
42
+ const UNWRAPPED_INPUTS = [
43
+ { typePrefix: 'uipath.ixp.', keys: new Set(['fileRef']) },
44
+ ];
45
+ /** True if `key` on a node of type `nodeType` must stay a plain string. */
46
+ function isUnwrappedInput(nodeType, key) {
47
+ if (typeof nodeType !== 'string')
48
+ return false;
49
+ return UNWRAPPED_INPUTS.some((r) => nodeType.startsWith(r.typePrefix) && r.keys.has(key));
50
+ }
51
+ /**
52
+ * The only `fieldType` values `@uipath/flow-schema`'s `expressionValueSchema`
53
+ * accepts (it is `.strict()`, so anything else fails the file's schema and with
54
+ * it every migration hop and `uip maestro flow validate`).
55
+ */
56
+ const FIELD_TYPES = new Set(['string', 'number', 'boolean', 'object', 'array', 'null']);
57
+ /**
58
+ * The emission steps that are CONDITIONAL on the target file-format version,
59
+ * newest gate last.
60
+ *
61
+ * The ladder exists because a declared version is a claim about the whole
62
+ * document (`schema-version.ts`), so "which target am I writing?" has to be
63
+ * able to change what gets written — the alternative is stamping a version and
64
+ * hoping the bytes match it. Today one step is version-gated and it is the
65
+ * expression envelope: the `{ type, expression, fieldType }` spelling is the
66
+ * 1.6-and-later form, so the gate is `>= 1.6` rather than unconditional.
67
+ *
68
+ * Nothing in this table distinguishes 1.9 from 1.10, and that is a READ result
69
+ * rather than an omission: `workflowSchemaV1_10` is `workflowSchemaV1_9.extend`
70
+ * with a new `version` literal, and the 1.9 -> 1.10 hop is a binding-name data
71
+ * repair for a defect this SDK cannot emit (see `FLOW_SCHEMA_VERSIONS`). The
72
+ * first genuine divergence gets a row here, and gets it in one place.
73
+ */
74
+ const VERSION_CONDITIONAL = [
75
+ {
76
+ from: '1.6',
77
+ what: 'wrap dynamic values into the { type, expression, fieldType } envelope',
78
+ apply: wrapDynamicValues,
79
+ },
80
+ ];
81
+ /**
82
+ * Bring a freshly-built FlowFile up to `target`, the file-format version the
83
+ * document will declare.
84
+ *
85
+ * @param flow - The serializer's in-progress FlowFile, mutated in place.
86
+ * @param target - The declared target version. Defaults to the profile pin, so
87
+ * every existing caller keeps its behaviour exactly.
88
+ */
89
+ export function migrateToSchemaVersion(flow, target = FLOW_FORMAT_PROFILE.version) {
90
+ flow.version = target;
91
+ delete flow.metadata;
92
+ for (const step of VERSION_CONDITIONAL)
93
+ if (schemaVersionAtLeast(target, step.from))
94
+ step.apply(flow);
95
+ }
96
+ /**
97
+ * @deprecated Use {@link migrateToSchemaVersion}. Kept because the name says
98
+ * "1.6" while the function has emitted the profile's version for several floors
99
+ * now — the rename is the point, and callers that pass no target are unchanged.
100
+ */
101
+ export function migrateTo16(flow) {
102
+ migrateToSchemaVersion(flow);
103
+ }
104
+ function wrapDynamicValues(flow) {
105
+ const schemaByType = new Map();
106
+ for (const d of flow.definitions ?? []) {
107
+ schemaByType.set(d.nodeType, {
108
+ inputs: d.inputDefinition?.properties,
109
+ outputs: d.outputDefinition?.properties,
110
+ });
111
+ }
112
+ const globalTypeByName = new Map();
113
+ for (const g of readFlowGlobals(flow.variables))
114
+ if (g.id && g.type)
115
+ globalTypeByName.set(g.id, g.type);
116
+ const subflows = (flow.subflows ?? {});
117
+ wrapNodes(flow.nodes ?? [], schemaByType, globalTypeByName, subflows);
118
+ wrapVariableUpdates(flow.variables, globalTypeByName);
119
+ for (const sub of Object.values(subflows)) {
120
+ // Each subflow body has its OWN globals — an End node inside it maps the
121
+ // subflow's outputs, not the parent flow's, so the fieldType lookup has to
122
+ // follow the scope. (Before subflows existed this always fell back to
123
+ // "string", which is right only by accident for a string-typed output.)
124
+ const scopeTypes = new Map();
125
+ for (const g of readFlowGlobals(sub?.variables))
126
+ if (g.id && g.type)
127
+ scopeTypes.set(g.id, g.type);
128
+ wrapNodes(sub?.nodes ?? [], schemaByType, scopeTypes, subflows);
129
+ wrapVariableUpdates(sub?.variables, scopeTypes);
130
+ }
131
+ }
132
+ function wrapNodes(nodes, schemaByType, globalTypeByName, subflows = {}) {
133
+ for (const n of nodes) {
134
+ const schema = schemaByType.get(n.type);
135
+ // A subflow node's inputs are declared by its BODY, not by its type
136
+ // (`core.subflow` has no inputDefinition), so its fieldTypes come from the
137
+ // subflow's `in` variables — keyed, as everywhere, by the node's own id.
138
+ const childInputType = new Map();
139
+ if (n.type === 'core.subflow') {
140
+ for (const g of readFlowGlobals(subflows[n.id]?.variables))
141
+ if (g?.direction === 'in' && g.id && g.type)
142
+ childInputType.set(g.id, g.type);
143
+ }
144
+ if (n.inputs) {
145
+ for (const [k, v] of Object.entries(n.inputs)) {
146
+ if (typeof v !== 'string')
147
+ continue;
148
+ if (isWrappedSource(v))
149
+ continue;
150
+ // The platform reads a few inputs as plain `=js:` strings and refuses
151
+ // the envelope on them — see UNWRAPPED_INPUTS for each one's evidence.
152
+ if (isUnwrappedInput(n.type, k))
153
+ continue;
154
+ const declared = fieldTypeOf(childInputType.get(k) ?? schema?.inputs?.[k]?.type);
155
+ if (v.startsWith('=') || declared !== 'string')
156
+ n.inputs[k] = wrap(v, declared);
157
+ }
158
+ }
159
+ if (n.outputs) {
160
+ for (const [k, vobj] of Object.entries(n.outputs)) {
161
+ if (!vobj || typeof vobj !== 'object')
162
+ continue;
163
+ const src = vobj.source;
164
+ if (typeof src !== 'string' || isWrappedSource(src))
165
+ continue;
166
+ const declared = fieldTypeOf(n.type === 'core.control.end' || n.type === 'core.logic.terminate'
167
+ ? globalTypeByName.get(k)
168
+ : schema?.outputs?.[k]?.type);
169
+ vobj.source = wrap(src, declared);
170
+ }
171
+ }
172
+ }
173
+ }
174
+ /**
175
+ * `variables.variableUpdates[*][*].expression` — an ExpressionValue object, not
176
+ * a string, from file version **1.3** on: the 1.2→1.3 migration is what
177
+ * converted the legacy strings ("Migration v1.2 → v1.3 converts legacy
178
+ * strings", `v1_3VariableUpdateSchema` in `@uipath/flow-schema`), and every
179
+ * later version inherits that shape.
180
+ *
181
+ * Leaving them as raw strings while declaring 1.8 makes the file
182
+ * self-inconsistent, and the product rejects it at the first migration hop it
183
+ * tries — `uip maestro flow validate` reports
184
+ * `[MIGRATION] Workflow migration failed at 1.8→1.9 … Offending field(s):
185
+ * variables.variableUpdates.end.0.expression`, because each migration validates
186
+ * its input against that version's schema. (Only flows that write a variable —
187
+ * i.e. every flow with a `.return(…)` — carry the field at all, which is why
188
+ * connector-only fixtures passed while any flow with an End-node update failed.)
189
+ */
190
+ function wrapVariableUpdates(variables, typeByName) {
191
+ const byNode = variables?.variableUpdates;
192
+ if (!byNode || typeof byNode !== 'object')
193
+ return;
194
+ for (const updates of Object.values(byNode)) {
195
+ for (const u of updates ?? []) {
196
+ if (!u || typeof u.expression !== 'string')
197
+ continue;
198
+ u.expression = wrap(u.expression, fieldTypeOf(typeByName.get(u.variableId)));
199
+ }
200
+ }
201
+ }
202
+ function isWrappedSource(v) {
203
+ return typeof v === 'object' && v !== null && 'type' in v && 'expression' in v && 'fieldType' in v;
204
+ }
205
+ /**
206
+ * Normalize a declared type to a `fieldType` the platform's schema accepts,
207
+ * mirroring flow-schema's own `jsonSchemaTypeToFieldType` +
208
+ * `expectedTypeToFieldType`: `integer`→`number`, `text`→`string`, a JSON-Schema
209
+ * type UNION (`["object","null"]`, which `core.action.http`'s
210
+ * `swaggerDefinition` declares) → its first mappable member, and anything else
211
+ * — including the SDK's own `types.file` / `types.any` — → `string`, the
212
+ * platform's own default.
213
+ *
214
+ * Without this a single `.output({ blob: types.any })` (or any node input typed
215
+ * `integer`, of which the connector library has 593) emitted `fieldType: "any"`
216
+ * and made the whole file unparseable: `expressionValueSchema` is `.strict()`
217
+ * over a six-value enum.
218
+ */
219
+ function fieldTypeOf(declared) {
220
+ if (Array.isArray(declared)) {
221
+ for (const t of declared) {
222
+ const mapped = mapScalarType(t);
223
+ if (mapped)
224
+ return mapped;
225
+ }
226
+ return 'string';
227
+ }
228
+ return mapScalarType(declared) ?? 'string';
229
+ }
230
+ function mapScalarType(t) {
231
+ if (typeof t !== 'string')
232
+ return undefined;
233
+ if (FIELD_TYPES.has(t))
234
+ return t;
235
+ if (t === 'integer')
236
+ return 'number';
237
+ if (t === 'text')
238
+ return 'string';
239
+ return undefined;
240
+ }
241
+ function wrap(value, fieldType) {
242
+ if (value.startsWith('=js:'))
243
+ return { type: 'jsExpression', expression: value.slice(4), fieldType };
244
+ return { type: 'literal', expression: value, fieldType };
245
+ }
@@ -0,0 +1,3 @@
1
+ export type TypeStripDecision = 'native' | 'flag' | 'unsupported';
2
+ export declare function typeStripDecision(version: string, execArgv?: readonly string[]): TypeStripDecision;
3
+ export declare function ensureTypeScriptRuntime(): void;
@@ -0,0 +1,22 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ export function typeStripDecision(version, execArgv = []) {
3
+ const [major = 0, minor = 0] = version.split('.').map(Number);
4
+ if (major >= 23 || (major === 22 && minor >= 18))
5
+ return 'native';
6
+ if (major === 22 && minor >= 6) {
7
+ return execArgv.includes('--experimental-strip-types') ? 'native' : 'flag';
8
+ }
9
+ return 'unsupported';
10
+ }
11
+ export function ensureTypeScriptRuntime() {
12
+ const decision = typeStripDecision(process.versions.node, process.execArgv);
13
+ if (decision === 'native')
14
+ return;
15
+ if (decision === 'unsupported') {
16
+ throw new Error(`authoring TypeScript requires Node >= 22.6 (found ${process.versions.node}); install Node 22 LTS or newer`);
17
+ }
18
+ const child = spawnSync(process.execPath, ['--experimental-strip-types', ...process.execArgv, ...process.argv.slice(1)], { stdio: 'inherit', env: process.env });
19
+ if (child.error)
20
+ throw child.error;
21
+ process.exit(child.status ?? 1);
22
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * The published package name, in one place.
3
+ *
4
+ * Four CLIs and the registry materializer bake this into the `import { … } from
5
+ * '…'` line of the source they emit, so that decompiled and generated files
6
+ * resolve for a package consumer rather than only inside this checkout. Before
7
+ * the rename to `@uipath/maestro-builder-sdk` those were five independent string
8
+ * literals; a sixth emitter would have been a sixth. Import the constant.
9
+ *
10
+ * These are the *defaults* — every emitter still takes `--import` to override
11
+ * the specifier, which is what an in-tree or vendored consumer uses.
12
+ */
13
+ export declare const PACKAGE_NAME = "@uipath/maestro-builder-sdk";
14
+ /** The `./case` subpath export. */
15
+ export declare const CASE_IMPORT = "@uipath/maestro-builder-sdk/case";
16
+ /** The `./bpmn` subpath export. */
17
+ export declare const BPMN_IMPORT = "@uipath/maestro-builder-sdk/bpmn";
@@ -0,0 +1,17 @@
1
+ /**
2
+ * The published package name, in one place.
3
+ *
4
+ * Four CLIs and the registry materializer bake this into the `import { … } from
5
+ * '…'` line of the source they emit, so that decompiled and generated files
6
+ * resolve for a package consumer rather than only inside this checkout. Before
7
+ * the rename to `@uipath/maestro-builder-sdk` those were five independent string
8
+ * literals; a sixth emitter would have been a sixth. Import the constant.
9
+ *
10
+ * These are the *defaults* — every emitter still takes `--import` to override
11
+ * the specifier, which is what an in-tree or vendored consumer uses.
12
+ */
13
+ export const PACKAGE_NAME = '@uipath/maestro-builder-sdk';
14
+ /** The `./case` subpath export. */
15
+ export const CASE_IMPORT = `${PACKAGE_NAME}/case`;
16
+ /** The `./bpmn` subpath export. */
17
+ export const BPMN_IMPORT = `${PACKAGE_NAME}/bpmn`;