@uipath/maestro-builder-sdk 6.56.0 → 6.58.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 (75) hide show
  1. package/dist/api-index.md +6 -2
  2. package/dist/api-members.md +1 -1
  3. package/dist/case/subscription.d.ts +4 -2
  4. package/dist/case/subscription.js +5 -2
  5. package/dist/cli/commands/flow.js +2 -0
  6. package/dist/core/actions.js +2 -2
  7. package/dist/core/binding-messages.d.ts +2 -1
  8. package/dist/core/binding-messages.js +3 -4
  9. package/dist/core/byoa.d.ts +3 -2
  10. package/dist/core/byoa.js +3 -3
  11. package/dist/core/carried-definitions.d.ts +0 -18
  12. package/dist/core/carried-definitions.js +3 -2
  13. package/dist/core/ceql.d.ts +2 -1
  14. package/dist/core/ceql.js +3 -2
  15. package/dist/core/compile-refusal.d.ts +21 -0
  16. package/dist/core/compile-refusal.js +26 -0
  17. package/dist/core/connector-inputs.js +2 -1
  18. package/dist/core/connector-resolve-error.d.ts +2 -1
  19. package/dist/core/connector-resolve-error.js +3 -4
  20. package/dist/core/connectors.js +2 -1
  21. package/dist/core/event-filters.js +2 -1
  22. package/dist/core/hitl-routing.d.ts +7 -82
  23. package/dist/core/hitl-routing.js +95 -6
  24. package/dist/core/library.js +4 -3
  25. package/dist/core/lookups.js +6 -5
  26. package/dist/core/nodes/registry.js +3 -2
  27. package/dist/core/nodes/versioned.js +3 -2
  28. package/dist/core/process-resource-sort-order.js +1 -1
  29. package/dist/core/read-text.d.ts +0 -28
  30. package/dist/core/read-text.js +3 -2
  31. package/dist/core/refusals.d.ts +465 -0
  32. package/dist/core/refusals.js +504 -0
  33. package/dist/core/script-function.d.ts +126 -0
  34. package/dist/core/script-function.js +511 -0
  35. package/dist/core/typescript-module.js +2 -1
  36. package/dist/decompile-cli.js +11 -3
  37. package/dist/decompile.d.ts +9 -0
  38. package/dist/decompile.js +76 -3
  39. package/dist/flow-expr-check.d.ts +2 -1
  40. package/dist/flow-expr-check.js +4 -2
  41. package/dist/flow-node-type.d.ts +21 -0
  42. package/dist/flow-sdk.js +17 -16
  43. package/dist/flow-step-tree.js +1 -1
  44. package/dist/flow-variables.js +3 -2
  45. package/dist/load.js +19 -5
  46. package/dist/nodes/agent/flow/inline-agent.js +7 -6
  47. package/dist/nodes/connector/flow/node-type.js +2 -1
  48. package/dist/nodes/data-fabric/flow/factories.js +2 -1
  49. package/dist/nodes/data-fabric/flow/verbs.js +2 -1
  50. package/dist/nodes/delay/flow/factories.js +2 -1
  51. package/dist/nodes/document/flow/ixp.js +5 -1
  52. package/dist/nodes/hitl/flow/check.js +4 -2
  53. package/dist/nodes/hitl/flow/node-type.js +6 -5
  54. package/dist/nodes/http/flow/factories.js +2 -1
  55. package/dist/nodes/http/flow/node-type.js +6 -5
  56. package/dist/nodes/process/flow/factories.js +2 -1
  57. package/dist/nodes/queue/flow/node-type.js +3 -2
  58. package/dist/nodes/script/flow/factories.d.ts +42 -1
  59. package/dist/nodes/script/flow/factories.js +8 -9
  60. package/dist/nodes/script/flow/node-type.js +71 -0
  61. package/dist/nodes/script/flow/runtime.d.ts +20 -0
  62. package/dist/nodes/script/flow/runtime.js +29 -0
  63. package/dist/nodes/script/flow/spec.d.ts +32 -1
  64. package/dist/nodes/transform/flow/node-type.js +2 -1
  65. package/dist/raw-node.js +3 -2
  66. package/dist/ref-resolve.d.ts +0 -36
  67. package/dist/ref-resolve.js +9 -8
  68. package/dist/schema-version.d.ts +0 -38
  69. package/dist/schema-version.js +3 -2
  70. package/dist/script-function-scope.d.ts +57 -0
  71. package/dist/script-function-scope.js +203 -0
  72. package/dist/sdk-resolve.js +2 -1
  73. package/dist/serialize.d.ts +5 -2
  74. package/dist/serialize.js +115 -83
  75. package/package.json +2 -2
@@ -0,0 +1,57 @@
1
+ /** One name a script function reads from outside itself. */
2
+ export interface ScriptFunctionCapture {
3
+ /** How the call is named in messages: `script(renderSafe)`. */
4
+ call: string;
5
+ /** The name read. */
6
+ name: string;
7
+ /** Where the binding it resolves to is declared, `file:line`. */
8
+ declaredAt: string;
9
+ /** Where the read is, `file:line`. */
10
+ readAt: string;
11
+ }
12
+ /** What the pass found in a source: the captures, and what it could not check. */
13
+ export interface ScriptFunctionScope {
14
+ captures: ScriptFunctionCapture[];
15
+ /** `script(<arg>)` calls whose function-typed argument it could not follow, `file:line` each. */
16
+ unfollowed: string[];
17
+ /**
18
+ * `script(<arg>)` calls whose argument it could not follow and whose type is
19
+ * `any` or `unknown` (`fns.check` on an `any` object, a function from a `.js`
20
+ * file): a function or a string script's options, the pass cannot tell which.
21
+ */
22
+ untyped: string[];
23
+ /** How many distinct script functions it followed to a declaration. */
24
+ followed: number;
25
+ /**
26
+ * Each followed function's text as Node's type stripping leaves it, whitespace
27
+ * removed: what `Function.prototype.toString()` returns for it under that
28
+ * loader, so a lowered function can be matched to its declaration. Empty when
29
+ * this Node has no `module.stripTypeScriptTypes`.
30
+ */
31
+ followedTexts: Set<string>;
32
+ }
33
+ /**
34
+ * Every name a `script(fn)` function in `file` (or a file it imports) reads from
35
+ * outside itself, and every call whose function it could not follow.
36
+ *
37
+ * It follows a bare identifier (through `const`, a function declaration and
38
+ * imports between the author's files) and an inline function. Any other
39
+ * function-typed argument (`script(h.check)`, `script(fns.check)`, a wrapper's
40
+ * parameter) is `unfollowed`, and the caller refuses it rather than let a capture
41
+ * through unchecked. An argument that is not a function (`script({ code })`, or
42
+ * options passed by name) is the string form and is not a script function.
43
+ */
44
+ export declare function scriptFunctionScope(file: string): ScriptFunctionScope;
45
+ /** A whitespace-free key for comparing function texts. */
46
+ export declare function functionTextKey(text: string): string;
47
+ /**
48
+ * Why a loaded flow cannot be trusted with its script functions, or undefined.
49
+ *
50
+ * Fails closed: a function the pass could not follow, or fewer functions found in
51
+ * the source than `script(fn)` lowered (a call made through `const sc = script`,
52
+ * a re-exporting module, or a function from a file outside the program), is
53
+ * refused like a capture, because what it reads was not checked.
54
+ */
55
+ export declare function scriptFunctionScopeProblem(file: string, lowered: readonly string[]): string | undefined;
56
+ /** The message a load refuses with, one line per capture. */
57
+ export declare function scriptFunctionCaptureMessage(captures: readonly ScriptFunctionCapture[]): string;
@@ -0,0 +1,203 @@
1
+ import { relative } from 'node:path';
2
+ import { typescript } from './core/typescript-module.js';
3
+ import { isReference } from './core/script-function.js';
4
+ /**
5
+ * Every name a `script(fn)` function in `file` (or a file it imports) reads from
6
+ * outside itself, and every call whose function it could not follow.
7
+ *
8
+ * It follows a bare identifier (through `const`, a function declaration and
9
+ * imports between the author's files) and an inline function. Any other
10
+ * function-typed argument (`script(h.check)`, `script(fns.check)`, a wrapper's
11
+ * parameter) is `unfollowed`, and the caller refuses it rather than let a capture
12
+ * through unchecked. An argument that is not a function (`script({ code })`, or
13
+ * options passed by name) is the string form and is not a script function.
14
+ */
15
+ export function scriptFunctionScope(file) {
16
+ const ts = typescript();
17
+ const options = {
18
+ noLib: true, types: [], noEmit: true, skipLibCheck: true, allowImportingTsExtensions: true,
19
+ target: ts.ScriptTarget.ES2022, module: ts.ModuleKind.NodeNext, moduleResolution: ts.ModuleResolutionKind.NodeNext,
20
+ };
21
+ const program = ts.createProgram([file], options);
22
+ const checker = program.getTypeChecker();
23
+ const cwd = process.cwd();
24
+ const where = (n) => {
25
+ const sf = n.getSourceFile();
26
+ return `${relative(cwd, sf.fileName) || sf.fileName}:${sf.getLineAndCharacterOfPosition(n.getStart()).line + 1}`;
27
+ };
28
+ const out = [];
29
+ const unfollowed = [];
30
+ const untyped = [];
31
+ const seen = new Set();
32
+ const followedTexts = new Set();
33
+ const strip = stripTypes();
34
+ for (const sf of program.getSourceFiles()) {
35
+ if (sf.isDeclarationFile || sf.fileName.includes('/node_modules/'))
36
+ continue;
37
+ const visit = (n) => {
38
+ if (ts.isCallExpression(n) && isScriptCall(ts, checker, n) && n.arguments.length > 0) {
39
+ const arg = n.arguments[0];
40
+ const fn = functionOf(ts, checker, arg);
41
+ if (!fn) {
42
+ const type = checker.getTypeAtLocation(arg);
43
+ if (type.getCallSignatures().length > 0)
44
+ unfollowed.push(where(arg));
45
+ else if (type.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown))
46
+ untyped.push(where(arg));
47
+ }
48
+ if (fn && !seen.has(fn)) {
49
+ seen.add(fn);
50
+ const text = strip?.(fnText(ts, fn));
51
+ if (text !== undefined)
52
+ followedTexts.add(text);
53
+ const call = `script(${ts.isIdentifier(n.arguments[0]) ? n.arguments[0].text : 'function'})`;
54
+ for (const c of capturesIn(ts, checker, fn))
55
+ out.push({ call, name: c.id.text, declaredAt: where(c.decl), readAt: where(c.id) });
56
+ }
57
+ }
58
+ ts.forEachChild(n, visit);
59
+ };
60
+ visit(sf);
61
+ }
62
+ return { captures: out, unfollowed, untyped, followed: seen.size, followedTexts };
63
+ }
64
+ /** A whitespace-free key for comparing function texts. */
65
+ export function functionTextKey(text) {
66
+ return text.replace(/\s+/g, '');
67
+ }
68
+ /**
69
+ * Node's own type stripping (`module.stripTypeScriptTypes`, Node 22.13+), as a
70
+ * function from a function's source text to its key; undefined when this Node
71
+ * does not have it, or the text does not strip on its own.
72
+ */
73
+ function stripTypes() {
74
+ const getBuiltinModule = process.getBuiltinModule;
75
+ const mod = getBuiltinModule?.('node:module');
76
+ const stripTs = mod?.stripTypeScriptTypes;
77
+ if (!stripTs)
78
+ return undefined;
79
+ return (text) => {
80
+ try {
81
+ // Parenthesised, so an anonymous function expression is a valid statement.
82
+ const stripped = stripTs(`(${text})`, { mode: 'strip' });
83
+ return functionTextKey(stripped.slice(1, -1));
84
+ }
85
+ catch {
86
+ return undefined;
87
+ }
88
+ };
89
+ }
90
+ /** A function's source as `toString()` would start it: without `export` / `default`. */
91
+ function fnText(ts, fn) {
92
+ const sf = fn.getSourceFile();
93
+ const mods = ts.canHaveModifiers(fn) ? ts.getModifiers(fn) ?? [] : [];
94
+ const lead = mods.filter((m) => m.kind === ts.SyntaxKind.ExportKeyword || m.kind === ts.SyntaxKind.DefaultKeyword);
95
+ const start = lead.length > 0 ? lead[lead.length - 1].end : fn.getStart();
96
+ return sf.text.slice(start, fn.end).trim();
97
+ }
98
+ /**
99
+ * Why a loaded flow cannot be trusted with its script functions, or undefined.
100
+ *
101
+ * Fails closed: a function the pass could not follow, or fewer functions found in
102
+ * the source than `script(fn)` lowered (a call made through `const sc = script`,
103
+ * a re-exporting module, or a function from a file outside the program), is
104
+ * refused like a capture, because what it reads was not checked.
105
+ */
106
+ export function scriptFunctionScopeProblem(file, lowered) {
107
+ const scope = scriptFunctionScope(file);
108
+ const parts = [];
109
+ if (scope.captures.length > 0)
110
+ parts.push(scriptFunctionCaptureMessage(scope.captures));
111
+ // Which lowered functions the pass accounts for. Matched by text when it can
112
+ // be: under Node's type stripping a lowered function's text IS its
113
+ // declaration's, minus types, so each one must match a followed declaration,
114
+ // and a `script()` call that never ran accounts for nothing. When nothing
115
+ // matches at all, either the loader reprints (tsx) or nothing lowered was
116
+ // followed; then an argument it could not type keeps it closed, and the
117
+ // count is the backstop.
118
+ const keys = [...new Set(lowered.map(functionTextKey))];
119
+ const matched = keys.filter((k) => scope.followedTexts.has(k)).length;
120
+ const unaccounted = matched > 0
121
+ ? keys.length - matched
122
+ : (scope.untyped.length > 0 ? Math.max(scope.untyped.length, 1) : Math.max(0, keys.length - scope.followed));
123
+ const where = [...scope.unfollowed, ...(matched > 0 ? [] : scope.untyped)];
124
+ if (scope.unfollowed.length > 0 || unaccounted > 0) {
125
+ const at = where.length > 0 ? ` (${where.join(', ')})` : '';
126
+ parts.push(`${Math.max(scope.unfollowed.length + unaccounted, 1)} script function(s) could not be checked for names taken from the module${at}: `
127
+ + 'pass each function to `script()` by name, or inline (`script(fn)`, `script((vars) => …)`), from a `.ts` file, with `script` imported by that name.');
128
+ }
129
+ return parts.length > 0 ? parts.join('\n') : undefined;
130
+ }
131
+ /** The message a load refuses with, one line per capture. */
132
+ export function scriptFunctionCaptureMessage(captures) {
133
+ const lines = captures.map((c) => ` ${c.call} reads ${c.name} (${c.readAt}), which resolves to ${c.declaredAt} in the author's code, `
134
+ + `but the lowered script runs alone, so ${c.name} would be the runtime's own global of that name, or nothing.`);
135
+ return `${captures.length} script function read(s) a name from outside the function:\n${lines.join('\n')}\n`
136
+ + 'Move the helper\'s code inside the function, or give it a name the runtime does not have.';
137
+ }
138
+ /**
139
+ * Whether a call is `script(…)` from an import: the callee is an identifier
140
+ * imported under the name `script`, or `<namespace import>.script`.
141
+ */
142
+ function isScriptCall(ts, checker, call) {
143
+ const callee = call.expression;
144
+ if (ts.isIdentifier(callee)) {
145
+ const decl = checker.getSymbolAtLocation(callee)?.declarations?.[0];
146
+ return decl !== undefined && ts.isImportSpecifier(decl) && (decl.propertyName ?? decl.name).text === 'script';
147
+ }
148
+ if (ts.isPropertyAccessExpression(callee) && callee.name.text === 'script' && ts.isIdentifier(callee.expression)) {
149
+ const decl = checker.getSymbolAtLocation(callee.expression)?.declarations?.[0];
150
+ return decl !== undefined && ts.isNamespaceImport(decl);
151
+ }
152
+ return false;
153
+ }
154
+ /** The function an argument is, or names: inline, a declaration, or a `const` bound to one, through imports. */
155
+ function functionOf(ts, checker, arg) {
156
+ const fnLike = (n) => {
157
+ while (n && (ts.isParenthesizedExpression(n) || ts.isAsExpression(n) || ts.isSatisfiesExpression(n)))
158
+ n = n.expression;
159
+ return n && (ts.isArrowFunction(n) || ts.isFunctionExpression(n) || ts.isFunctionDeclaration(n)) ? n : undefined;
160
+ };
161
+ const inline = fnLike(arg);
162
+ if (inline)
163
+ return inline;
164
+ if (!ts.isIdentifier(arg))
165
+ return undefined;
166
+ let symbol = checker.getSymbolAtLocation(arg);
167
+ if (symbol && symbol.flags & ts.SymbolFlags.Alias)
168
+ symbol = checker.getAliasedSymbol(symbol);
169
+ for (const d of symbol?.declarations ?? []) {
170
+ const f = ts.isVariableDeclaration(d) ? fnLike(d.initializer) : fnLike(d);
171
+ if (f)
172
+ return f;
173
+ }
174
+ return undefined;
175
+ }
176
+ /** Each read in `fn` of a binding declared outside it, with that declaration. */
177
+ function capturesIn(ts, checker, fn) {
178
+ const found = [];
179
+ const names = new Set();
180
+ const inside = (d) => d.getSourceFile() === fn.getSourceFile() && d.pos >= fn.pos && d.end <= fn.end;
181
+ const visit = (n) => {
182
+ if (ts.isIdentifier(n) && isReference(ts, n) && !names.has(n.text)) {
183
+ const p = n.parent;
184
+ const symbol = ts.isShorthandPropertyAssignment(p) && p.name === n
185
+ ? checker.getShorthandAssignmentValueSymbol(p)
186
+ : checker.getSymbolAtLocation(n);
187
+ // An import, or any binding the author's own files declare outside the
188
+ // function. A name that resolves to nothing, or only to a declaration file
189
+ // (`console` once `@types/node` is in the program), is a global, and the
190
+ // lowering has judged it already. An import still lands on its specifier
191
+ // in the author's file.
192
+ const decl = symbol?.declarations?.find((d) => !inside(d) && !d.getSourceFile().isDeclarationFile);
193
+ if (decl && !symbol.declarations.some(inside)) {
194
+ names.add(n.text);
195
+ found.push({ id: n, decl });
196
+ }
197
+ }
198
+ ts.forEachChild(n, visit);
199
+ };
200
+ if (fn.body)
201
+ visit(fn.body);
202
+ return found;
203
+ }
@@ -3,6 +3,7 @@ import { existsSync } from 'node:fs';
3
3
  import { register } from 'node:module';
4
4
  import { fileURLToPath } from 'node:url';
5
5
  import { PACKAGE_NAME } from './package-name.js';
6
+ import { CompileRefusal } from './core/compile-refusal.js';
6
7
  let registered = false;
7
8
  /**
8
9
  * Make `import … from '@uipath/maestro-builder-sdk'` in authored source resolve
@@ -25,7 +26,7 @@ export function useThisSdkForAuthoredSource() {
25
26
  registered = true;
26
27
  return;
27
28
  }
28
- throw new Error(`cannot point authored source at this copy of ${PACKAGE_NAME}: ${fileURLToPath(hook)} is missing, as in a bundle, `
29
+ throw new CompileRefusal('SDK_RESOLVE_HOOK_MISSING', `cannot point authored source at this copy of ${PACKAGE_NAME}: ${fileURLToPath(hook)} is missing, as in a bundle, `
29
30
  + 'so its imports would load a second copy and serialize wrong. Run the installed package, or load authored source yourself.');
30
31
  }
31
32
  register(hook);
@@ -188,9 +188,12 @@ export declare function assertFileWideIdsUnique(flow: any): void;
188
188
  * It holds for real definitions: of the 5,102 in the local registry index
189
189
  * (2026-09-30), 4,999 reference a `<bindings.…>` name and every one of them
190
190
  * declares that name in `model.bindings.values`, which is what the emitters
191
- * close. Agent resource definitions are the one exemption (see below).
191
+ * close. Agent resource definitions are one exemption (see below); `unbound`,
192
+ * the nodes a draft compile reported as `BINDING_MISSING`, is the other: such a
193
+ * node names no connection, so it writes no binding rows, and the draft finding
194
+ * already says so.
192
195
  *
193
196
  * @throws BindingRefusal `BINDING_PLACEHOLDER_UNRESOLVED`, naming each dangling
194
197
  * placeholder and the step that carries it.
195
198
  */
196
- export declare function assertBindingPlaceholdersResolve(flow: any): void;
199
+ export declare function assertBindingPlaceholdersResolve(flow: any, unbound?: ReadonlySet<string>): void;