@uipath/maestro-builder-sdk 6.31.0 → 6.31.2
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.
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { Expr } from '../../../core/expr.js';
|
|
10
10
|
import { jsonClone } from '../../../core/json-clone.js';
|
|
11
|
+
import { isRecord } from '../../../core/node-envelope.js';
|
|
11
12
|
import { wireExprBody } from '../../../core/wire-expr.js';
|
|
12
13
|
import { checkHttpRead, checkHttpStep, plainHttpOnErrorMessage } from './check.js';
|
|
13
14
|
const PLAIN = 'core.action.http';
|
|
@@ -264,7 +265,7 @@ function liftHttp(node, ctx, managed) {
|
|
|
264
265
|
return raw;
|
|
265
266
|
return text.startsWith('=js:') ? ctx.expr(text) : text;
|
|
266
267
|
};
|
|
267
|
-
const map = (m) => m &&
|
|
268
|
+
const map = (m) => isRecord(m) && Object.keys(m).length
|
|
268
269
|
? Object.fromEntries(Object.entries(m).map(([k, v]) => [k, value(v)]))
|
|
269
270
|
: undefined;
|
|
270
271
|
const text = (v) => (typeof v === 'string' ? v : undefined);
|
|
@@ -7,6 +7,19 @@ import type { FlowCheckContext } from '../../../flow-node-type.js';
|
|
|
7
7
|
import type { QueueItemInputs } from './spec.js';
|
|
8
8
|
/** Every code the family reports, with the severity it reports it at. */
|
|
9
9
|
export declare const QUEUE_DIAGNOSTICS: DiagnosticCatalog;
|
|
10
|
+
/**
|
|
11
|
+
* Whether a definition stores `inputs.itemData` as a JSON STRING — the 1.0 era.
|
|
12
|
+
* 1.1 and later declare an `object`. Read off the definition being emitted or
|
|
13
|
+
* lifted, not off a version number, so a carried definition of any era answers
|
|
14
|
+
* for itself.
|
|
15
|
+
*/
|
|
16
|
+
export declare function itemDataIsString(def: unknown): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Why `item.<field>` cannot be an expression on a definition that stores the item
|
|
19
|
+
* as one JSON string. Shared by `check` (QUEUE_ITEM_EXPR_UNSUPPORTED) and the
|
|
20
|
+
* serializer's refusal, so the two say the same thing.
|
|
21
|
+
*/
|
|
22
|
+
export declare function queueItemExprMessage(step: string, typeName: string, version: string, field: string): string;
|
|
10
23
|
/**
|
|
11
24
|
* Check a `queueItem(...)` call.
|
|
12
25
|
*
|
|
@@ -31,5 +44,7 @@ export declare const QUEUE_DIAGNOSTICS: DiagnosticCatalog;
|
|
|
31
44
|
* - `returns` on a step that does not wait (there is nothing per-tenant to
|
|
32
45
|
* declare), and a `wait: true` step whose result nothing can read.
|
|
33
46
|
* - a non-ISO `dueDate` / `deferDate`.
|
|
47
|
+
* - an expression in `item` when the definition stores the item as one JSON
|
|
48
|
+
* string (1.0): the serializer refuses it, so `check` reports it first.
|
|
34
49
|
*/
|
|
35
|
-
export declare function checkQueueItem(inputs: QueueItemInputs | undefined, ctx: FlowCheckContext): void;
|
|
50
|
+
export declare function checkQueueItem(inputs: QueueItemInputs | undefined, ctx: FlowCheckContext, typeName: string): void;
|
|
@@ -11,6 +11,7 @@ export const QUEUE_DIAGNOSTICS = {
|
|
|
11
11
|
QUEUE_NO_ITEM: { severity: 'warning', summary: 'the item carries no data' },
|
|
12
12
|
QUEUE_ITEM_NOT_OBJECT: { severity: 'error', summary: 'the item is not an object' },
|
|
13
13
|
QUEUE_ITEM_FIELD_NOT_PRIMITIVE: { severity: 'error', summary: 'an item field is not a primitive' },
|
|
14
|
+
QUEUE_ITEM_EXPR_UNSUPPORTED: { severity: 'error', summary: 'an expression in an item stored as one JSON string' },
|
|
14
15
|
QUEUE_BAD_PRIORITY: { severity: 'error', summary: 'a priority the node type does not offer' },
|
|
15
16
|
QUEUE_BAD_DATE: { severity: 'error', summary: 'a date Orchestrator cannot read' },
|
|
16
17
|
QUEUE_RETURNS_WITHOUT_WAIT: { severity: 'warning', summary: 'returns without wait: true' },
|
|
@@ -18,6 +19,27 @@ export const QUEUE_DIAGNOSTICS = {
|
|
|
18
19
|
QUEUE_READ_WITHOUT_RETURNS: { severity: 'error', summary: 'a field read off a wait result with no returns' },
|
|
19
20
|
QUEUE_READ_UNKNOWN_FIELD: { severity: 'error', summary: 'a read of a field the step does not publish' },
|
|
20
21
|
};
|
|
22
|
+
/**
|
|
23
|
+
* Whether a definition stores `inputs.itemData` as a JSON STRING — the 1.0 era.
|
|
24
|
+
* 1.1 and later declare an `object`. Read off the definition being emitted or
|
|
25
|
+
* lifted, not off a version number, so a carried definition of any era answers
|
|
26
|
+
* for itself.
|
|
27
|
+
*/
|
|
28
|
+
export function itemDataIsString(def) {
|
|
29
|
+
const props = def
|
|
30
|
+
?.inputDefinition?.properties;
|
|
31
|
+
return props?.itemData?.type === 'string';
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Why `item.<field>` cannot be an expression on a definition that stores the item
|
|
35
|
+
* as one JSON string. Shared by `check` (QUEUE_ITEM_EXPR_UNSUPPORTED) and the
|
|
36
|
+
* serializer's refusal, so the two say the same thing.
|
|
37
|
+
*/
|
|
38
|
+
export function queueItemExprMessage(step, typeName, version, field) {
|
|
39
|
+
return `Queue step "${step}": ${typeName}@${version} stores the item as one JSON string, so \`item.${field}\` `
|
|
40
|
+
+ `cannot be an expression there. Omit the { version } to emit the SDK's default version, which `
|
|
41
|
+
+ `stores the item as an object of values and expressions.`;
|
|
42
|
+
}
|
|
21
43
|
/**
|
|
22
44
|
* Check a `queueItem(...)` call.
|
|
23
45
|
*
|
|
@@ -42,8 +64,10 @@ export const QUEUE_DIAGNOSTICS = {
|
|
|
42
64
|
* - `returns` on a step that does not wait (there is nothing per-tenant to
|
|
43
65
|
* declare), and a `wait: true` step whose result nothing can read.
|
|
44
66
|
* - a non-ISO `dueDate` / `deferDate`.
|
|
67
|
+
* - an expression in `item` when the definition stores the item as one JSON
|
|
68
|
+
* string (1.0): the serializer refuses it, so `check` reports it first.
|
|
45
69
|
*/
|
|
46
|
-
export function checkQueueItem(inputs, ctx) {
|
|
70
|
+
export function checkQueueItem(inputs, ctx, typeName) {
|
|
47
71
|
const step = ctx.step;
|
|
48
72
|
// Severity is the catalog's (QUEUE_DIAGNOSTICS): `at` and `warn` name the intent.
|
|
49
73
|
const at = (code, message, suggestion) => ctx.report(code, message, suggestion);
|
|
@@ -83,7 +107,12 @@ export function checkQueueItem(inputs, ctx) {
|
|
|
83
107
|
+ `item's \`SpecificContent\`.`, `item: { InvoiceId: 'INV-1', Amount: 120 }`);
|
|
84
108
|
}
|
|
85
109
|
else {
|
|
110
|
+
const itemIsString = itemDataIsString(ctx.definition());
|
|
86
111
|
for (const [k, v] of Object.entries(item)) {
|
|
112
|
+
if (v instanceof Expr && itemIsString) {
|
|
113
|
+
at('QUEUE_ITEM_EXPR_UNSUPPORTED', queueItemExprMessage(step, typeName, ctx.version, k));
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
87
116
|
// An Expr is a reference the runtime resolves — its VALUE may be anything,
|
|
88
117
|
// and nothing local can know, so it is not flagged here.
|
|
89
118
|
if (v instanceof Expr)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Expr } from '../../../core/expr.js';
|
|
2
2
|
import { jsonClone } from '../../../core/json-clone.js';
|
|
3
|
-
import {
|
|
3
|
+
import { isRecord } from '../../../core/node-envelope.js';
|
|
4
|
+
import { checkQueueItem, itemDataIsString, queueItemExprMessage } from './check.js';
|
|
4
5
|
import { QUEUE_ITEM_RECORD_SCHEMA } from './record.js';
|
|
5
6
|
const CREATE = 'core.action.queue.create';
|
|
6
7
|
const CREATE_AND_WAIT = 'core.action.queue.create-and-wait';
|
|
@@ -159,6 +160,87 @@ function liftReturns(node) {
|
|
|
159
160
|
.map(([k, v]) => [k, v.type]);
|
|
160
161
|
return entries.length ? Object.fromEntries(entries) : undefined;
|
|
161
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* The surface's `item` as a 1.0 node stores it: one JSON string, `''` for no
|
|
165
|
+
* data (the 1.0 definition's own default). A JSON string holds DATA, so an
|
|
166
|
+
* expression in a field has no spelling there; it is refused rather than
|
|
167
|
+
* written as text the runtime would never evaluate.
|
|
168
|
+
*/
|
|
169
|
+
function itemDataString(item, step, typeName, version) {
|
|
170
|
+
const rows = Object.entries(item);
|
|
171
|
+
if (rows.length === 0)
|
|
172
|
+
return '';
|
|
173
|
+
for (const [k, v] of rows) {
|
|
174
|
+
if (v instanceof Expr)
|
|
175
|
+
throw new Error(queueItemExprMessage(step, typeName, version, k));
|
|
176
|
+
}
|
|
177
|
+
return JSON.stringify(item);
|
|
178
|
+
}
|
|
179
|
+
/** Whether `v` is, or holds at any depth, an integer JSON.parse could not represent exactly. */
|
|
180
|
+
function hasUnsafeInteger(v) {
|
|
181
|
+
if (typeof v === 'number')
|
|
182
|
+
return Number.isInteger(v) && !Number.isSafeInteger(v);
|
|
183
|
+
if (Array.isArray(v))
|
|
184
|
+
return v.some(hasUnsafeInteger);
|
|
185
|
+
return isRecord(v) && Object.values(v).some(hasUnsafeInteger);
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* `inputs.itemData` back as the surface's `item`, in either wire shape:
|
|
189
|
+
*
|
|
190
|
+
* - 1.1 and later: an object of field → value, each value as the author wrote it
|
|
191
|
+
* (`=js:` text back to an Expr);
|
|
192
|
+
* - 1.0: ONE JSON STRING (`"{\"invoiceId\":\"INV-1001\"}"`), which is parsed back
|
|
193
|
+
* to the object it encodes; `''` is the 1.0 default, no data.
|
|
194
|
+
*
|
|
195
|
+
* `undefined`, with a warning, for a value `item` cannot hold without changing
|
|
196
|
+
* what the node does — a whole-item expression, a string that is not a JSON
|
|
197
|
+
* object, an integer beyond 2^53 (parsing rounds it), or a JSON field whose
|
|
198
|
+
* text starts with `=` (literal data at 1.0; it would become an expression once
|
|
199
|
+
* written as an object). The lift then
|
|
200
|
+
* declines the node and decompile keeps it as a `rawNode`, verbatim.
|
|
201
|
+
*
|
|
202
|
+
* Reading the shape off the value, never assuming it, is the point: treating
|
|
203
|
+
* the 1.0 string as an object spread it into one field per character
|
|
204
|
+
* (flow-builder-sdk#1164).
|
|
205
|
+
*/
|
|
206
|
+
function liftItem(raw, ctx, value) {
|
|
207
|
+
const decline = (why) => {
|
|
208
|
+
ctx.warn(`node ${JSON.stringify(ctx.nodeId)}: its queue item data (inputs.itemData) is ${why}, which \`queueItem({ item })\` `
|
|
209
|
+
+ `cannot hold without changing it, so the source keeps the node as a rawNode, verbatim.`);
|
|
210
|
+
return undefined;
|
|
211
|
+
};
|
|
212
|
+
if (raw === undefined || raw === null)
|
|
213
|
+
return {};
|
|
214
|
+
if (typeof raw === 'string') {
|
|
215
|
+
if (raw === '')
|
|
216
|
+
return {};
|
|
217
|
+
if (raw.startsWith('='))
|
|
218
|
+
return decline('an expression for the whole item');
|
|
219
|
+
let parsed;
|
|
220
|
+
try {
|
|
221
|
+
parsed = JSON.parse(raw);
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
return decline('a string that is not JSON');
|
|
225
|
+
}
|
|
226
|
+
if (!isRecord(parsed))
|
|
227
|
+
return decline('a JSON string that does not encode an object');
|
|
228
|
+
const expressionLike = Object.keys(parsed).find((k) => typeof parsed[k] === 'string' && parsed[k].startsWith('='));
|
|
229
|
+
if (expressionLike !== undefined)
|
|
230
|
+
return decline(`a JSON string whose field "${expressionLike}" starts with "="`);
|
|
231
|
+
// JSON.parse rounds an integer beyond 2^53 (`12345678901234567890` reads back
|
|
232
|
+
// as `12345678901234567000`), and the compile would write the rounded value.
|
|
233
|
+
const rounded = Object.keys(parsed).find((k) => hasUnsafeInteger(parsed[k]));
|
|
234
|
+
if (rounded !== undefined)
|
|
235
|
+
return decline(`a JSON string whose field "${rounded}" holds an integer too large to read back exactly`);
|
|
236
|
+
return parsed;
|
|
237
|
+
}
|
|
238
|
+
if (ctx.sourceText(raw) !== undefined)
|
|
239
|
+
return decline('an expression for the whole item');
|
|
240
|
+
if (!isRecord(raw))
|
|
241
|
+
return decline(Array.isArray(raw) ? 'an array' : `a ${typeof raw}`);
|
|
242
|
+
return Object.fromEntries(Object.entries(raw).map(([k, v]) => [k, value(v)]));
|
|
243
|
+
}
|
|
162
244
|
function queueAt(typeName, wait) {
|
|
163
245
|
return {
|
|
164
246
|
kind: 'queueItem', typeName, version: '1.2', factory: 'queueItem', definition: 'per-tenant', errorPort: true,
|
|
@@ -169,7 +251,8 @@ function queueAt(typeName, wait) {
|
|
|
169
251
|
const { ids, entries } = queueItemBindings(s, ctx.bindings);
|
|
170
252
|
for (const b of entries)
|
|
171
253
|
ctx.bind(b);
|
|
172
|
-
const
|
|
254
|
+
const base = ctx.definition(typeName, ctx.version);
|
|
255
|
+
const manifest = queueItemDef(s, typeName, ctx.step, ids, base);
|
|
173
256
|
return {
|
|
174
257
|
definition: { source: 'snapshot', nodeType: typeName, version: ctx.version, manifest },
|
|
175
258
|
// The result is read as `$vars.<step>.output`, like every other family: the
|
|
@@ -180,8 +263,11 @@ function queueAt(typeName, wait) {
|
|
|
180
263
|
inputs: {
|
|
181
264
|
queue: { name: s.queue, folderPath: s.folderPath, key: s.key },
|
|
182
265
|
// `itemData`, not `item`: the surface's name is friendlier, the node's is
|
|
183
|
-
// the platform's. Rendered one level deep, as the item is FLAT
|
|
184
|
-
|
|
266
|
+
// the platform's. Rendered one level deep, as the item is FLAT — or, for a
|
|
267
|
+
// definition of the 1.0 era, encoded as the one JSON string it declares.
|
|
268
|
+
itemData: itemDataIsString(base)
|
|
269
|
+
? itemDataString(s.item ?? {}, ctx.step, typeName, ctx.version)
|
|
270
|
+
: Object.fromEntries(Object.entries(s.item ?? {}).map(([k, v]) => [k, ctx.render(v)])),
|
|
185
271
|
priority: s.priority ?? 'Normal',
|
|
186
272
|
reference: s.reference === undefined ? '' : ctx.render(s.reference),
|
|
187
273
|
deferDate: s.deferDate === undefined ? '' : ctx.render(s.deferDate),
|
|
@@ -209,12 +295,14 @@ function queueAt(typeName, wait) {
|
|
|
209
295
|
// A wait's `returns` is the schema serialize wrote for THIS step (the
|
|
210
296
|
// template ships none), as the node's own `outputs` carries it.
|
|
211
297
|
const returns = wait ? liftReturns(node) : undefined;
|
|
298
|
+
const item = liftItem(inputs.itemData, ctx, value);
|
|
299
|
+
if (item === undefined)
|
|
300
|
+
return undefined;
|
|
212
301
|
return {
|
|
213
302
|
kind: 'queueItem',
|
|
214
303
|
inputs: {
|
|
215
304
|
queue: q.name, folderPath: q.folderPath, key: q.key,
|
|
216
|
-
item
|
|
217
|
-
.map(([k, v]) => [k, value(v)])),
|
|
305
|
+
item,
|
|
218
306
|
...(typeof priority === 'string' ? { priority: priority } : {}),
|
|
219
307
|
...(optional(inputs.reference) !== undefined ? { reference: optional(inputs.reference) } : {}),
|
|
220
308
|
...(optional(inputs.deferDate) !== undefined ? { deferDate: optional(inputs.deferDate) } : {}),
|
|
@@ -249,7 +337,7 @@ function queueAt(typeName, wait) {
|
|
|
249
337
|
],
|
|
250
338
|
};
|
|
251
339
|
},
|
|
252
|
-
check: ({ inputs }, ctx) => checkQueueItem(inputs, ctx),
|
|
340
|
+
check: ({ inputs }, ctx) => checkQueueItem(inputs, ctx, typeName),
|
|
253
341
|
// check collected no expressions for a queue step before the port; unchanged by it.
|
|
254
342
|
expressions: () => [],
|
|
255
343
|
output: ({ inputs }) => queueOutput(inputs, wait),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uipath/maestro-builder-sdk",
|
|
3
|
-
"version": "6.31.
|
|
3
|
+
"version": "6.31.2",
|
|
4
4
|
"description": "Build UiPath Flow, Case, and BPMN artifacts by writing TypeScript.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://docs.uipath.com/maestro",
|
|
@@ -62,6 +62,7 @@
|
|
|
62
62
|
],
|
|
63
63
|
"files": [
|
|
64
64
|
"dist",
|
|
65
|
+
"!dist/api.model.json",
|
|
65
66
|
"lib/library-json.samples",
|
|
66
67
|
"README.md"
|
|
67
68
|
],
|
|
@@ -92,5 +93,5 @@
|
|
|
92
93
|
"@types/node": "^22.7.0",
|
|
93
94
|
"esbuild": "^0.28.1"
|
|
94
95
|
},
|
|
95
|
-
"gitref": "
|
|
96
|
+
"gitref": "37b4b349e7ce452d74154e65bdae4dff9a1aeb93"
|
|
96
97
|
}
|