@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 @@
1
+ export declare function bindingSelfNameMessage(where: string, name: string, attribute: 'connection' | 'folder'): string;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The refusal for a bindings.json entry that answers with its own name — shared by
3
+ * `serialize` (which throws it) and `check` (BINDING_SELF_NAME), so the author reads
4
+ * the same sentence from the inner loop as from compile. Before this, `check`
5
+ * printed `0 error(s)` for a source `compile` then refused (teams-decision,
6
+ * 2026-09-01, turn 22 → 23).
7
+ */
8
+ import { prepareCommand } from './cli-spelling.js';
9
+ export function bindingSelfNameMessage(where, name, attribute) {
10
+ return `${where}: binding "${name}" resolves to its own name, so the ${attribute} would compile to the `
11
+ + `literal string "${name}" and the run would fault with "'Connection' has an invalid GUID value: `
12
+ + `'${name}'". Set its "resourceKey" to the real id: \`${prepareCommand('<connector-key>', '<action>')}\` `
13
+ + `discovers the connection and writes both the connection and the folder entry into bindings.json; by hand, `
14
+ + `read Id and FolderKey from \`uip is connections list --all-folders --output json\` (the default listing `
15
+ + `shows only your own folder, so a connection shared from another folder is invisible without --all-folders).`;
16
+ }
@@ -0,0 +1,12 @@
1
+ export declare class Bindings {
2
+ private list;
3
+ constructor(file?: string);
4
+ /** Resolve by binding `name` or `id`; returns its resourceKey (or default). */
5
+ resolve(name?: string): string | undefined;
6
+ /** Every symbolic name the file declares — what an author CAN write in `connection:` / `folder:`. */
7
+ declared(): string[];
8
+ /** The full binding entry by `name` or `id` — for consumers that emit a binding
9
+ * registry + `=bindings.<id>` refs (the Case caseplan) rather than inlining the
10
+ * resourceKey (the Flow node). */
11
+ entry(name?: string): Record<string, unknown> | undefined;
12
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * bindings — resolve symbolic connection/folder names to their resource keys
3
+ * from a bindings.json (same format the Flow Code arm uses).
4
+ */
5
+ import { readFileSync, existsSync } from 'node:fs';
6
+ export class Bindings {
7
+ list = [];
8
+ constructor(file) {
9
+ if (file && existsSync(file)) {
10
+ this.list = normalizeBindings(JSON.parse(readFileSync(file, 'utf8')));
11
+ }
12
+ }
13
+ /** Resolve by binding `name` or `id`; returns its resourceKey (or default). */
14
+ resolve(name) {
15
+ if (!name)
16
+ return undefined;
17
+ const b = this.list.find((x) => x.name === name || x.id === name);
18
+ if (!b)
19
+ return undefined;
20
+ return (b.resourceKey ?? b.default);
21
+ }
22
+ /** Every symbolic name the file declares — what an author CAN write in `connection:` / `folder:`. */
23
+ declared() {
24
+ const names = [];
25
+ for (const b of this.list) {
26
+ const n = (b?.name ?? b?.id);
27
+ if (typeof n === 'string' && !names.includes(n))
28
+ names.push(n);
29
+ }
30
+ return names;
31
+ }
32
+ /** The full binding entry by `name` or `id` — for consumers that emit a binding
33
+ * registry + `=bindings.<id>` refs (the Case caseplan) rather than inlining the
34
+ * resourceKey (the Flow node). */
35
+ entry(name) {
36
+ if (!name)
37
+ return undefined;
38
+ return this.list.find((x) => x.name === name || x.id === name);
39
+ }
40
+ }
41
+ /**
42
+ * Accept the shapes a real `bindings.json` turns up in, rather than assuming the array.
43
+ *
44
+ * The declared format is `{ bindings: [ { id, name, resourceKey, default, … } ] }`. But this
45
+ * file name is shared: the local BPMN engine's `--bindings` reads a NAME→VALUE MAP, either
46
+ * flat or under a `bindings` key, and anyone running a process locally writes one of those.
47
+ * The old code did `parsed.bindings ?? []` and then `.find(…)` on it, so a map crashed
48
+ * `compile` with `this.list.find is not a function` — no file named, no format explained. It
49
+ * cost real debugging time when a bindings.json written for a local run happened to sit in the
50
+ * compile directory, and an author told to write one for a live run can easily produce the map
51
+ * form.
52
+ *
53
+ * A map entry becomes `{ id, name, resourceKey, default }` with the value in all three
54
+ * key-ish slots, which is what `resolve`/`entry` read, so both formats behave the same.
55
+ */
56
+ function normalizeBindings(parsed) {
57
+ if (parsed === null || typeof parsed !== 'object')
58
+ return [];
59
+ const inner = 'bindings' in parsed ? parsed.bindings : parsed;
60
+ if (Array.isArray(inner))
61
+ return inner;
62
+ if (inner === null || typeof inner !== 'object')
63
+ return [];
64
+ return Object.entries(inner)
65
+ .filter(([, value]) => typeof value === 'string')
66
+ .map(([id, value]) => ({ id, name: id, resourceKey: value, default: value }));
67
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * core/ceql — parse a CEQL filter expression into the canonical filter tree.
3
+ *
4
+ * ## Why a filter needs two representations
5
+ *
6
+ * An Integration Service list operation takes a server-side filter through a
7
+ * "FilterBuilder" parameter — usually named `where`, sometimes `q`. Two
8
+ * consumers read it, and they want different things:
9
+ *
10
+ * - the RUNTIME dials IS with a CEQL string, `inputs.detail.queryParameters.where`;
11
+ * - the Studio Web CANVAS renders the filter widget from a structured tree, at
12
+ * `essentialConfiguration.savedFilterTrees.where` inside the node's
13
+ * `=jsonString:`-encoded `inputs.detail.configuration`.
14
+ *
15
+ * A string cannot be reverse-engineered into the widget's model reliably, so the
16
+ * artifact carries both. Author only the string and the flow RUNS correctly while
17
+ * the FilterBuilder shows nothing when the activity is reopened — which is why
18
+ * product validation rejects a `queryParameters.<name>` with no matching
19
+ * `savedFilterTrees.<name>` (MST-9265), even though a debug run would pass.
20
+ *
21
+ * The v1 CLI solved this by making the TREE the input (`node configure
22
+ * --detail.filter`) and compiling the string from it. The builder SDK has no
23
+ * such command, so this goes the other way: authors write the CEQL they would
24
+ * write anyway, and the tree is DERIVED. One source of truth either way.
25
+ *
26
+ * ## Scope
27
+ *
28
+ * Deliberately a literal-only parser. A filter whose operand is a runtime
29
+ * expression compiles to a `{var_…}` placeholder plus `inputs.detail.filterVariables`
30
+ * on the v1 path; nothing here can produce that from a `=js:` string, and
31
+ * guessing would emit a tree that disagrees with the query. Such a filter keeps
32
+ * its runtime half and gets no tree — the same state as before this existed,
33
+ * rather than a wrong one.
34
+ */
35
+ /** A leaf's comparison operator, in the canonical PascalCase the canvas stores. */
36
+ export type CeqlOperator = 'Equals' | 'NotEquals' | 'LessThan' | 'LessThanOrEqual' | 'GreaterThan' | 'GreaterThanOrEqual' | 'Contains' | 'NotContains' | 'StartsWith' | 'NotStartsWith' | 'EndsWith' | 'NotEndsWith' | 'Like' | 'NotLike' | 'IsNull' | 'IsNotNull';
37
+ /** One comparison — `<field> <operator> <value>`. */
38
+ export interface CeqlFilter {
39
+ id: string;
40
+ operator: CeqlOperator;
41
+ value?: {
42
+ value: unknown;
43
+ rawString: string;
44
+ isLiteral: true;
45
+ };
46
+ uiId?: string;
47
+ }
48
+ /** A group of comparisons joined by one logical operator. Groups nest. */
49
+ export interface CeqlTree {
50
+ /** 0 = And, 1 = Or — how this level's siblings combine. */
51
+ groupOperator: 0 | 1;
52
+ index: number;
53
+ filters: CeqlFilter[];
54
+ groups: CeqlTree[];
55
+ uuId?: string;
56
+ }
57
+ /** Raised when an expression is not CEQL this parser can represent. */
58
+ export declare class CeqlParseError extends Error {
59
+ readonly expression: string;
60
+ constructor(message: string, expression: string);
61
+ }
62
+ /**
63
+ * Parse a CEQL filter expression into the canvas's filter tree.
64
+ *
65
+ * `seed` makes the tree's ids deterministic — recompiling an unchanged flow must
66
+ * be byte-identical, so the node id and parameter name are folded in rather than
67
+ * minting random uuids the way the designer does.
68
+ *
69
+ * Throws {@link CeqlParseError} with the reason when the expression is not CEQL
70
+ * this can represent. That is the point: the alternative is a tenant-side
71
+ * `[102003] Integration Services bad request` with nothing naming the step.
72
+ */
73
+ export declare function parseCeql(expression: string, seed: string): CeqlTree;
@@ -0,0 +1,272 @@
1
+ /**
2
+ * core/ceql — parse a CEQL filter expression into the canonical filter tree.
3
+ *
4
+ * ## Why a filter needs two representations
5
+ *
6
+ * An Integration Service list operation takes a server-side filter through a
7
+ * "FilterBuilder" parameter — usually named `where`, sometimes `q`. Two
8
+ * consumers read it, and they want different things:
9
+ *
10
+ * - the RUNTIME dials IS with a CEQL string, `inputs.detail.queryParameters.where`;
11
+ * - the Studio Web CANVAS renders the filter widget from a structured tree, at
12
+ * `essentialConfiguration.savedFilterTrees.where` inside the node's
13
+ * `=jsonString:`-encoded `inputs.detail.configuration`.
14
+ *
15
+ * A string cannot be reverse-engineered into the widget's model reliably, so the
16
+ * artifact carries both. Author only the string and the flow RUNS correctly while
17
+ * the FilterBuilder shows nothing when the activity is reopened — which is why
18
+ * product validation rejects a `queryParameters.<name>` with no matching
19
+ * `savedFilterTrees.<name>` (MST-9265), even though a debug run would pass.
20
+ *
21
+ * The v1 CLI solved this by making the TREE the input (`node configure
22
+ * --detail.filter`) and compiling the string from it. The builder SDK has no
23
+ * such command, so this goes the other way: authors write the CEQL they would
24
+ * write anyway, and the tree is DERIVED. One source of truth either way.
25
+ *
26
+ * ## Scope
27
+ *
28
+ * Deliberately a literal-only parser. A filter whose operand is a runtime
29
+ * expression compiles to a `{var_…}` placeholder plus `inputs.detail.filterVariables`
30
+ * on the v1 path; nothing here can produce that from a `=js:` string, and
31
+ * guessing would emit a tree that disagrees with the query. Such a filter keeps
32
+ * its runtime half and gets no tree — the same state as before this existed,
33
+ * rather than a wrong one.
34
+ */
35
+ import { stableId } from './stable-id.js';
36
+ /** Raised when an expression is not CEQL this parser can represent. */
37
+ export class CeqlParseError extends Error {
38
+ expression;
39
+ constructor(message, expression) {
40
+ super(message);
41
+ this.expression = expression;
42
+ this.name = 'CeqlParseError';
43
+ }
44
+ }
45
+ /**
46
+ * Word operators, longest first so `Not Contains` wins over `Contains` and
47
+ * `Is Not Null` over `Is Null`. Matched case-insensitively with flexible inner
48
+ * spacing, because the platform's own rendering is `Starts With` but authors
49
+ * write `startswith` as often as not.
50
+ */
51
+ const WORD_OPERATORS = [
52
+ [/^is\s+not\s+null\b/i, 'IsNotNull'],
53
+ [/^is\s+null\b/i, 'IsNull'],
54
+ [/^not\s+starts\s*with\b/i, 'NotStartsWith'],
55
+ [/^not\s+ends\s*with\b/i, 'NotEndsWith'],
56
+ [/^not\s+contains\b/i, 'NotContains'],
57
+ [/^not\s+like\b/i, 'NotLike'],
58
+ [/^starts\s*with\b/i, 'StartsWith'],
59
+ [/^ends\s*with\b/i, 'EndsWith'],
60
+ [/^contains\b/i, 'Contains'],
61
+ [/^like\b/i, 'Like'],
62
+ ];
63
+ /** Symbol operators, longest first so `<=` wins over `<` and `!=` over `=`. */
64
+ const SYMBOL_OPERATORS = [
65
+ ['>=', 'GreaterThanOrEqual'],
66
+ ['<=', 'LessThanOrEqual'],
67
+ ['!=', 'NotEquals'],
68
+ ['>', 'GreaterThan'],
69
+ ['<', 'LessThan'],
70
+ ['=', 'Equals'],
71
+ ];
72
+ /**
73
+ * The OData spellings CEQL rejects. Named explicitly because the failure is
74
+ * otherwise a `[102003] Integration Services bad request` from the tenant, with
75
+ * nothing pointing at the operator.
76
+ */
77
+ const ODATA_ALIASES = {
78
+ eq: '=', ne: '!=', gt: '>', ge: '>=', lt: '<', le: '<=',
79
+ };
80
+ class Scanner {
81
+ src;
82
+ pos = 0;
83
+ constructor(src) {
84
+ this.src = src;
85
+ }
86
+ get rest() { return this.src.slice(this.pos); }
87
+ skipSpace() {
88
+ while (this.pos < this.src.length && /\s/.test(this.src[this.pos]))
89
+ this.pos++;
90
+ }
91
+ /** Consume `text` (case-insensitive) when it is next; report whether it was. */
92
+ eat(text) {
93
+ this.skipSpace();
94
+ if (this.src.slice(this.pos, this.pos + text.length).toLowerCase() !== text.toLowerCase())
95
+ return false;
96
+ // A word must not be consumed out of the middle of an identifier.
97
+ if (/\w$/.test(text)) {
98
+ const after = this.src[this.pos + text.length];
99
+ if (after !== undefined && /[\w.]/.test(after))
100
+ return false;
101
+ }
102
+ this.pos += text.length;
103
+ return true;
104
+ }
105
+ atEnd() { this.skipSpace(); return this.pos >= this.src.length; }
106
+ }
107
+ /** `displayName`, `user.department` — bare, never quoted (a quoted token is a value). */
108
+ function readField(s) {
109
+ s.skipSpace();
110
+ const m = /^[A-Za-z_][\w]*(?:\.[A-Za-z_][\w]*)*/.exec(s.rest);
111
+ if (!m) {
112
+ if (/^['"]/.test(s.rest)) {
113
+ throw new CeqlParseError(`quoted field name at "${s.rest.slice(0, 24)}" — CEQL reads a quoted token as a value, `
114
+ + 'so write the field bare: `displayName = \'active\'`, never `\'displayName\' = \'active\'`.', s.src);
115
+ }
116
+ throw new CeqlParseError(`expected a field name at "${s.rest.slice(0, 24) || '<end>'}"`, s.src);
117
+ }
118
+ s.pos += m[0].length;
119
+ return m[0];
120
+ }
121
+ function readOperator(s) {
122
+ s.skipSpace();
123
+ for (const [pattern, op] of WORD_OPERATORS) {
124
+ const m = pattern.exec(s.rest);
125
+ if (m) {
126
+ s.pos += m[0].length;
127
+ return op;
128
+ }
129
+ }
130
+ const alias = /^([A-Za-z]+)\b/.exec(s.rest);
131
+ if (alias && ODATA_ALIASES[alias[1].toLowerCase()]) {
132
+ const wrong = alias[1];
133
+ throw new CeqlParseError(`\`${wrong}\` is an OData operator; CEQL uses \`${ODATA_ALIASES[wrong.toLowerCase()]}\`.`, s.src);
134
+ }
135
+ for (const [text, op] of SYMBOL_OPERATORS) {
136
+ if (s.src.startsWith(text, s.pos)) {
137
+ s.pos += text.length;
138
+ return op;
139
+ }
140
+ }
141
+ throw new CeqlParseError(`expected an operator at "${s.rest.slice(0, 24) || '<end>'}"`, s.src);
142
+ }
143
+ /** A single-quoted string, a number, or a boolean. Doubled `''` escapes a quote. */
144
+ function readValue(s) {
145
+ s.skipSpace();
146
+ if (s.rest.startsWith("'")) {
147
+ let i = 1;
148
+ let text = '';
149
+ for (;;) {
150
+ if (i >= s.rest.length)
151
+ throw new CeqlParseError('unterminated string value', s.src);
152
+ const ch = s.rest[i];
153
+ if (ch === "'") {
154
+ if (s.rest[i + 1] === "'") {
155
+ text += "'";
156
+ i += 2;
157
+ continue;
158
+ }
159
+ i++;
160
+ break;
161
+ }
162
+ text += ch;
163
+ i++;
164
+ }
165
+ s.pos += i;
166
+ return { value: text, rawString: JSON.stringify(text) };
167
+ }
168
+ if (s.rest.startsWith('"')) {
169
+ throw new CeqlParseError('double-quoted value — CEQL reads a double-quoted token as a COLUMN reference, not a string. '
170
+ + "Single-quote it: `accountNumber = 'ACC123'`.", s.src);
171
+ }
172
+ const bool = /^(true|false)\b/i.exec(s.rest);
173
+ if (bool) {
174
+ s.pos += bool[0].length;
175
+ const value = bool[0].toLowerCase() === 'true';
176
+ return { value, rawString: String(value) };
177
+ }
178
+ const num = /^-?\d+(?:\.\d+)?/.exec(s.rest);
179
+ if (num) {
180
+ s.pos += num[0].length;
181
+ return { value: Number(num[0]), rawString: num[0] };
182
+ }
183
+ throw new CeqlParseError(`expected a quoted string, number, or boolean at "${s.rest.slice(0, 24) || '<end>'}"`, s.src);
184
+ }
185
+ function readComparison(s, seed, ordinal) {
186
+ const id = readField(s);
187
+ const operator = readOperator(s);
188
+ const uiId = stableId(`${seed}:${id}:${ordinal}`);
189
+ if (operator === 'IsNull' || operator === 'IsNotNull')
190
+ return { id, operator, uiId };
191
+ const { value, rawString } = readValue(s);
192
+ return { id, operator, value: { value, rawString, isLiteral: true }, uiId };
193
+ }
194
+ /**
195
+ * One level: comparisons and parenthesised sub-groups joined by a SINGLE logical
196
+ * operator.
197
+ *
198
+ * Mixing `AND` and `OR` at one level is refused rather than guessed. The tree has
199
+ * exactly one `groupOperator` per level, so `a = 1 AND b = 2 OR c = 3` has no
200
+ * faithful representation — and picking a precedence would silently emit a tree
201
+ * that filters differently from the string beside it, which is the one outcome
202
+ * worse than not supporting it. Parenthesise to say which was meant.
203
+ */
204
+ function readGroup(s, seed, index, depth) {
205
+ if (depth > 32)
206
+ throw new CeqlParseError('filter nests too deeply', s.src);
207
+ const filters = [];
208
+ const groups = [];
209
+ let groupOperator;
210
+ let ordinal = 0;
211
+ for (;;) {
212
+ s.skipSpace();
213
+ if (s.rest.startsWith('(')) {
214
+ s.pos++;
215
+ groups.push(readGroup(s, `${seed}:g${groups.length}`, groups.length, depth + 1));
216
+ s.skipSpace();
217
+ if (!s.eat(')'))
218
+ throw new CeqlParseError('unbalanced parenthesis', s.src);
219
+ }
220
+ else {
221
+ filters.push(readComparison(s, seed, ordinal++));
222
+ }
223
+ const before = s.pos;
224
+ if (s.eat('AND')) {
225
+ if (groupOperator === 1) {
226
+ s.pos = before;
227
+ throw new CeqlParseError('AND and OR are mixed at one level. A filter tree carries one operator per level, so '
228
+ + 'parenthesise the intent: `(a AND b) OR c`.', s.src);
229
+ }
230
+ groupOperator = 0;
231
+ continue;
232
+ }
233
+ if (s.eat('OR')) {
234
+ if (groupOperator === 0) {
235
+ s.pos = before;
236
+ throw new CeqlParseError('AND and OR are mixed at one level. A filter tree carries one operator per level, so '
237
+ + 'parenthesise the intent: `(a OR b) AND c`.', s.src);
238
+ }
239
+ groupOperator = 1;
240
+ continue;
241
+ }
242
+ break;
243
+ }
244
+ return { groupOperator: groupOperator ?? 0, index, filters, groups, uuId: stableId(`${seed}:group`) };
245
+ }
246
+ /**
247
+ * Parse a CEQL filter expression into the canvas's filter tree.
248
+ *
249
+ * `seed` makes the tree's ids deterministic — recompiling an unchanged flow must
250
+ * be byte-identical, so the node id and parameter name are folded in rather than
251
+ * minting random uuids the way the designer does.
252
+ *
253
+ * Throws {@link CeqlParseError} with the reason when the expression is not CEQL
254
+ * this can represent. That is the point: the alternative is a tenant-side
255
+ * `[102003] Integration Services bad request` with nothing naming the step.
256
+ */
257
+ export function parseCeql(expression, seed) {
258
+ const trimmed = expression.trim();
259
+ if (trimmed === '')
260
+ throw new CeqlParseError('empty filter expression', expression);
261
+ const s = new Scanner(trimmed);
262
+ const tree = readGroup(s, seed, 0, 0);
263
+ if (!s.atEnd()) {
264
+ throw new CeqlParseError(`unexpected "${s.rest.slice(0, 24)}" after the filter`, expression);
265
+ }
266
+ // A lone parenthesised expression parses as a group holding one group. Lift it,
267
+ // so `(a = 1)` and `a = 1` produce the same tree.
268
+ if (tree.filters.length === 0 && tree.groups.length === 1) {
269
+ return { ...tree.groups[0], index: tree.index, uuId: tree.uuId };
270
+ }
271
+ return tree;
272
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * core/cli-spelling — naming the CLI the user is actually holding.
3
+ *
4
+ * Every remedy `check` prints is a command meant to be pasted. Which binary
5
+ * spells it depends on how the SDK was reached, and the SDK cannot see that:
6
+ * `@uipath/cli` resolves the workspace SDK and spawns `dist/cli/index.js`, so
7
+ * by the time this code runs, `process.argv[1]` is the SDK's own bin either
8
+ * way. The caller knows, and passes it down in `FLOW_SDK_INVOKED_AS`.
9
+ *
10
+ * The default stays `npx flow-sdk`, which is what a workspace with no `uip`
11
+ * needs and what the original hard-coding was protecting.
12
+ */
13
+ /** The spelling used when nothing says otherwise. */
14
+ export declare const DEFAULT_CLI_SPELLING = "npx flow-sdk";
15
+ /** Just the variable this module reads — see {@link cliSpelling} for why. */
16
+ export interface CliSpellingEnv {
17
+ FLOW_SDK_INVOKED_AS?: string | undefined;
18
+ }
19
+ /**
20
+ * How to spell the CLI in a printed remedy.
21
+ *
22
+ * @param env - Environment to read; defaults to the ambient `process.env`.
23
+ * @returns `uip maestro` when the caller said so, else `npx flow-sdk`.
24
+ */
25
+ export declare function cliSpelling(env?: CliSpellingEnv): string;
26
+ /**
27
+ * A `registry prepare` command line, spelled for whoever is driving.
28
+ *
29
+ * @param args - Everything after `registry prepare`, e.g. the connector key and action.
30
+ * @returns The full command, no trailing newline.
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * prepareCommand('uipath-salesforce-slack', 'send-message-to-user');
35
+ * // -> "npx flow-sdk registry prepare uipath-salesforce-slack send-message-to-user"
36
+ * // -> "uip maestro registry prepare …" when FLOW_SDK_INVOKED_AS="uip maestro"
37
+ * ```
38
+ */
39
+ export declare function prepareCommand(...args: string[]): string;
@@ -0,0 +1,62 @@
1
+ /**
2
+ * core/cli-spelling — naming the CLI the user is actually holding.
3
+ *
4
+ * Every remedy `check` prints is a command meant to be pasted. Which binary
5
+ * spells it depends on how the SDK was reached, and the SDK cannot see that:
6
+ * `@uipath/cli` resolves the workspace SDK and spawns `dist/cli/index.js`, so
7
+ * by the time this code runs, `process.argv[1]` is the SDK's own bin either
8
+ * way. The caller knows, and passes it down in `FLOW_SDK_INVOKED_AS`.
9
+ *
10
+ * The default stays `npx flow-sdk`, which is what a workspace with no `uip`
11
+ * needs and what the original hard-coding was protecting.
12
+ */
13
+ /** The spelling used when nothing says otherwise. */
14
+ export const DEFAULT_CLI_SPELLING = 'npx flow-sdk';
15
+ /**
16
+ * Lowercase words, single-spaced, at most three.
17
+ *
18
+ * The value is interpolated into a command a human is invited to paste into a
19
+ * shell, so it is validated rather than trusted: an unset-but-inherited or
20
+ * malformed value must degrade to the default, not travel into someone's
21
+ * terminal. `npx flow-sdk` and `uip maestro` both satisfy it.
22
+ */
23
+ const SPELLING = /^[a-z][a-z0-9-]*(?: [a-z][a-z0-9-]*){0,2}$/;
24
+ /**
25
+ * `process.env`, read through `globalThis` so this module needs no Node types.
26
+ *
27
+ * `core/lookups.ts` imports this one, and the generated connector modules are
28
+ * type-checked against the SDK SOURCE under `strict` with no `@types/node`
29
+ * (see `tests/connectors.test.ts`). Naming `NodeJS.ProcessEnv` or a bare
30
+ * `process` here fails that check, which is a real constraint and not a
31
+ * formality: it is the same graph an author's `tsc` walks.
32
+ */
33
+ function ambientEnv() {
34
+ const global = globalThis;
35
+ return global.process?.env ?? {};
36
+ }
37
+ /**
38
+ * How to spell the CLI in a printed remedy.
39
+ *
40
+ * @param env - Environment to read; defaults to the ambient `process.env`.
41
+ * @returns `uip maestro` when the caller said so, else `npx flow-sdk`.
42
+ */
43
+ export function cliSpelling(env = ambientEnv()) {
44
+ const hint = (env.FLOW_SDK_INVOKED_AS ?? '').trim();
45
+ return SPELLING.test(hint) ? hint : DEFAULT_CLI_SPELLING;
46
+ }
47
+ /**
48
+ * A `registry prepare` command line, spelled for whoever is driving.
49
+ *
50
+ * @param args - Everything after `registry prepare`, e.g. the connector key and action.
51
+ * @returns The full command, no trailing newline.
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * prepareCommand('uipath-salesforce-slack', 'send-message-to-user');
56
+ * // -> "npx flow-sdk registry prepare uipath-salesforce-slack send-message-to-user"
57
+ * // -> "uip maestro registry prepare …" when FLOW_SDK_INVOKED_AS="uip maestro"
58
+ * ```
59
+ */
60
+ export function prepareCommand(...args) {
61
+ return [cliSpelling(), 'registry', 'prepare', ...args.filter(Boolean)].join(' ');
62
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Why a `rawNode` may not carry a connector node type, or `undefined` when the
3
+ * type is not a connector's.
4
+ *
5
+ * Every entry of the connector library is `uipath.connector.<key>.<action>`
6
+ * (7,455 of 7,455 measured), and every one of them needs what only
7
+ * {@link connector} produces: `inputs.detail` routed by field location plus the
8
+ * flow-level connection/folder bindings. A raw node renders the author's inputs
9
+ * as they are, so the artifact compiles, `validate` merely warns that the
10
+ * connector "is not configured", and the run has no connection to call. Measured
11
+ * on the eval archive: 4 of 4 Data Fabric flows authored this way failed their
12
+ * checker, each after `compile` had refused an input the static library does not
13
+ * carry — the raw node was the escape hatch around that refusal.
14
+ *
15
+ * Event and trigger types (`uipath.connector.event.*`, `uipath.connector.trigger.*`)
16
+ * are named separately: they belong to {@link onEvent}, not to a step.
17
+ *
18
+ * @param nodeType - The definition's `nodeType`, as passed to {@link rawNode}.
19
+ * @returns The refusal to report, or `undefined` for a non-connector type.
20
+ */
21
+ export declare function connectorRawNodeRefusal(nodeType: string): string | undefined;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Internal: the one rule that keeps `rawNode` from standing in for `connector()`.
3
+ * Not re-exported from the package entry point.
4
+ */
5
+ import { prepareCommand } from './cli-spelling.js';
6
+ /**
7
+ * Why a `rawNode` may not carry a connector node type, or `undefined` when the
8
+ * type is not a connector's.
9
+ *
10
+ * Every entry of the connector library is `uipath.connector.<key>.<action>`
11
+ * (7,455 of 7,455 measured), and every one of them needs what only
12
+ * {@link connector} produces: `inputs.detail` routed by field location plus the
13
+ * flow-level connection/folder bindings. A raw node renders the author's inputs
14
+ * as they are, so the artifact compiles, `validate` merely warns that the
15
+ * connector "is not configured", and the run has no connection to call. Measured
16
+ * on the eval archive: 4 of 4 Data Fabric flows authored this way failed their
17
+ * checker, each after `compile` had refused an input the static library does not
18
+ * carry — the raw node was the escape hatch around that refusal.
19
+ *
20
+ * Event and trigger types (`uipath.connector.event.*`, `uipath.connector.trigger.*`)
21
+ * are named separately: they belong to {@link onEvent}, not to a step.
22
+ *
23
+ * @param nodeType - The definition's `nodeType`, as passed to {@link rawNode}.
24
+ * @returns The refusal to report, or `undefined` for a non-connector type.
25
+ */
26
+ export function connectorRawNodeRefusal(nodeType) {
27
+ if (typeof nodeType !== 'string' || !nodeType.startsWith('uipath.connector.'))
28
+ return undefined;
29
+ const rest = nodeType.slice('uipath.connector.'.length);
30
+ const isTrigger = rest.startsWith('event.') || rest.startsWith('trigger.');
31
+ if (isTrigger) {
32
+ return (`rawNode("${nodeType}") names a connector event, which cannot be placed as a step and cannot be `
33
+ + `authored raw: use onEvent(...) as the flow's trigger (or waitForEvent(...) mid-flow) so the `
34
+ + `subscription and its connection binding are emitted.`);
35
+ }
36
+ const dot = rest.lastIndexOf('.');
37
+ const key = dot > 0 ? rest.slice(0, dot) : rest;
38
+ const action = dot > 0 ? rest.slice(dot + 1) : '<action>';
39
+ return (`rawNode("${nodeType}") names a connector operation. A raw node keeps its inputs verbatim, so the `
40
+ + `emitted node would have no inputs.detail and no connection binding: \`validate\` only warns `
41
+ + `("Connector is not configured") and the run can never reach Integration Service. `
42
+ + `Author it as connector('${key}', '${action}', { ...inputs }, { connection: '<binding>', folder: '<binding>' }). `
43
+ + `If compile then refuses an input the static library does not carry, run `
44
+ + `\`${prepareCommand(key, action)}\` — it discovers the connection, writes bindings.json `
45
+ + `and loads the connection-resolved fields into ./connectors-local/ (add \`-f <parent>=<value>\`, e.g. `
46
+ + `\`-f entityName=<Entity>\`, when the operation's fields depend on a parent input).`);
47
+ }