@uipath/maestro-builder-sdk 6.11.3 → 6.11.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/api-index.md +132 -132
- package/dist/api-members.md +333 -333
- package/dist/check.js +192 -61
- package/dist/core/actions.d.ts +18 -0
- package/dist/core/queue-record.d.ts +106 -0
- package/dist/core/queue-record.js +48 -0
- package/dist/flow-sdk.d.ts +1 -1
- package/dist/flow-sdk.js +1 -1
- package/dist/registry/cache.d.ts +9 -0
- package/dist/registry/cache.js +9 -0
- package/dist/registry/path-cli.js +2 -2
- package/dist/registry/search-cli.js +6 -2
- package/dist/serialize.js +1 -47
- package/package.json +2 -2
package/dist/check.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { Expr, SCHEDULE_PRESETS, DELAY_PRESETS, VARIANT_OPERATION, parseIxpProjectType, flatNameOf, flatNameSegmentsOf, FLAT_SEP } from './flow-sdk.js';
|
|
9
9
|
import { FlowNode } from './core/node-classes.js';
|
|
10
10
|
import { isLookupToken, resolvedValue, unresolvedLookupMessage, } from './core/lookups.js';
|
|
11
|
+
import { QUEUE_ITEM_RECORD_SCHEMA } from './core/queue-record.js';
|
|
11
12
|
import { EVENT_FILTER_OPERATORS, readEventFilter, eventFilterProblem } from './event-filters.js';
|
|
12
13
|
import { extractRefs } from './core/expr-check.js';
|
|
13
14
|
import { bindingSelfNameMessage, bindingUndeclaredMessage, undeclaredBinding } from './core/binding-messages.js';
|
|
@@ -145,20 +146,12 @@ function checkFlow(built, ancestors, opts = {}) {
|
|
|
145
146
|
// form's ANSWER fields (plus `Action`), so a read of it is checked against the
|
|
146
147
|
// form the author wrote rather than waved through (see HITL_READ_* below).
|
|
147
148
|
const hitlForms = new Map();
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
// Agentic-process step name → its call. Same reason as api-workflow's map: the
|
|
151
|
-
// step publishes the job's output arguments and the only offline statement of
|
|
152
|
-
// what those are is the step's own `returns`.
|
|
149
|
+
// Agentic-process step name → its call, for the form-field rules below. Its
|
|
150
|
+
// output READS go through OUTPUT_READ_RULES like every `returns` family.
|
|
153
151
|
const agenticProcesses = new Map();
|
|
154
|
-
//
|
|
155
|
-
//
|
|
156
|
-
|
|
157
|
-
const agents = new Map();
|
|
158
|
-
// Inline-agent step name → its call. NOT the same reason: an inline agent's
|
|
159
|
-
// contract is AUTHORED rather than looked up on a tenant, so a read outside the
|
|
160
|
-
// declared `returns` is a mistake the compiler can be certain about.
|
|
161
|
-
const inlineAgents = new Map();
|
|
152
|
+
// Step name → the read rule for its output, bound to its inputs. Filled from
|
|
153
|
+
// OUTPUT_READ_RULES for every kind whose inputs take a `returns`.
|
|
154
|
+
const outputReaders = new Map();
|
|
162
155
|
const connectorSteps = new Map();
|
|
163
156
|
// Subflow step name → the child flow it runs. A subflow's output is the
|
|
164
157
|
// OBJECT of the child's declared outputs, so a read of it is checked against
|
|
@@ -434,11 +427,9 @@ function checkFlow(built, ancestors, opts = {}) {
|
|
|
434
427
|
checkRpaWorkflow(s.name, s.spec.inputs, diags);
|
|
435
428
|
if (s.spec.kind === 'apiWorkflow') {
|
|
436
429
|
checkApiWorkflow(s.name, s.spec.inputs, diags);
|
|
437
|
-
apiWorkflows.set(s.name, s.spec.inputs);
|
|
438
430
|
}
|
|
439
431
|
if (s.spec.kind === 'publishedFunction') {
|
|
440
432
|
checkPublishedFunction(s.name, s.spec.inputs, diags);
|
|
441
|
-
publishedFunctions.set(s.name, s.spec.inputs);
|
|
442
433
|
}
|
|
443
434
|
if (s.spec.kind === 'sendMessage' || s.spec.kind === 'waitForMessage'
|
|
444
435
|
|| s.spec.kind === 'conversationContext') {
|
|
@@ -456,14 +447,20 @@ function checkFlow(built, ancestors, opts = {}) {
|
|
|
456
447
|
}
|
|
457
448
|
if (s.spec.kind === 'agent') {
|
|
458
449
|
checkAgent(s.name, s.spec.inputs, diags);
|
|
459
|
-
agents.set(s.name, s.spec.inputs);
|
|
460
450
|
}
|
|
461
451
|
if (s.spec.kind === 'inlineAgent') {
|
|
462
452
|
checkInlineAgent(s.name, s.spec.inputs, diags);
|
|
463
|
-
inlineAgents.set(s.name, s.spec.inputs);
|
|
464
453
|
}
|
|
465
454
|
if (s.spec.kind === 'queueItem')
|
|
466
455
|
checkQueueItem(s.name, s.spec.inputs, diags);
|
|
456
|
+
{
|
|
457
|
+
const rule = OUTPUT_READ_RULES[s.spec.kind];
|
|
458
|
+
if (typeof rule === 'function') {
|
|
459
|
+
const stepName = s.name;
|
|
460
|
+
const inputs = s.spec.inputs;
|
|
461
|
+
outputReaders.set(stepName, (field, rest, at, d) => rule(stepName, field, rest, inputs, at, d));
|
|
462
|
+
}
|
|
463
|
+
}
|
|
467
464
|
if (s.spec.kind === 'documentClassify' || s.spec.kind === 'dynamicExtract') {
|
|
468
465
|
const fr = s.spec.inputs.fileRef;
|
|
469
466
|
const empty = fr === undefined || fr === null || (typeof fr === 'string' && fr.trim() === '');
|
|
@@ -1142,7 +1139,8 @@ function checkFlow(built, ancestors, opts = {}) {
|
|
|
1142
1139
|
code: 'MOCK_HAS_NO_OUTPUT',
|
|
1143
1140
|
message: `Placeholder "${name}" publishes nothing, but "$vars.${name}${field ? '.' + field : ''}" reads it in "${step}". `
|
|
1144
1141
|
+ 'A mock() is a marker for a node that does not exist yet — its output is null at run time, always. '
|
|
1145
|
-
+ '
|
|
1142
|
+
+ 'Keep the placeholder while the real node does not exist, and have the reader use a value you supply instead (a flow input, as example/ClaimScaffold.flow.ts does). '
|
|
1143
|
+
+ 'Replace the placeholder only with the real node, once `registry search` finds it; a script returning fixed values is not the real node.',
|
|
1146
1144
|
step,
|
|
1147
1145
|
});
|
|
1148
1146
|
continue;
|
|
@@ -1167,49 +1165,13 @@ function checkFlow(built, ancestors, opts = {}) {
|
|
|
1167
1165
|
checkHitlRead(name, field, rest, form, step, diags);
|
|
1168
1166
|
continue;
|
|
1169
1167
|
}
|
|
1170
|
-
//
|
|
1171
|
-
//
|
|
1172
|
-
//
|
|
1173
|
-
//
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
checkApiWorkflowRead(name, field, rest, apiwf, step, diags);
|
|
1178
|
-
continue;
|
|
1179
|
-
}
|
|
1180
|
-
// A published function publishes its result the same way, and the same
|
|
1181
|
-
// three read mistakes are decidable from the same place — so the reader is
|
|
1182
|
-
// shared, with the family named in the codes.
|
|
1183
|
-
const fn = publishedFunctions.get(name);
|
|
1184
|
-
if (fn) {
|
|
1185
|
-
checkPublishedFunctionRead(name, field, rest, fn, step, diags);
|
|
1186
|
-
continue;
|
|
1187
|
-
}
|
|
1188
|
-
// An agentic process publishes its job's output arguments the same way, so
|
|
1189
|
-
// the same three read mistakes are decidable from the same place.
|
|
1190
|
-
const agentic = agenticProcesses.get(name);
|
|
1191
|
-
if (agentic) {
|
|
1192
|
-
checkAgenticProcessRead(name, field, rest, agentic, step, diags);
|
|
1193
|
-
continue;
|
|
1194
|
-
}
|
|
1195
|
-
// A published agent publishes its job's output arguments the same way its
|
|
1196
|
-
// three siblings do, so the same three read mistakes are decidable — with one
|
|
1197
|
-
// extra that only this family has: a read whose CASE differs from the declared
|
|
1198
|
-
// field. That used to be a live-only defect (the poll verb PascalCased the
|
|
1199
|
-
// answer, flow-builder-sdk #122), so the wrong case was right live and wrong
|
|
1200
|
-
// offline for a while. Now it is simply wrong, and worth naming as itself
|
|
1201
|
-
// rather than as an unknown field.
|
|
1202
|
-
const published = agents.get(name);
|
|
1203
|
-
if (published) {
|
|
1204
|
-
checkAgentRead(name, field, rest, published, step, diags);
|
|
1205
|
-
continue;
|
|
1206
|
-
}
|
|
1207
|
-
// An inline agent's readable fields are exactly its declared `returns` — the
|
|
1208
|
-
// node's `agentOutputVariables`, which is also what the engine's live path
|
|
1209
|
-
// coerces the model's completion to. Nothing on a tenant to consult.
|
|
1210
|
-
const inline = inlineAgents.get(name);
|
|
1211
|
-
if (inline) {
|
|
1212
|
-
checkInlineAgentRead(name, field, rest, inline, step, diags);
|
|
1168
|
+
// Every family that declares its output's fields — the author's `returns`, or
|
|
1169
|
+
// a shape the SDK fixes — has its read rule in OUTPUT_READ_RULES, keyed by
|
|
1170
|
+
// kind. A read outside the declared set is undefined on every rung and on
|
|
1171
|
+
// the platform, so it is refused here rather than at `flow debug`.
|
|
1172
|
+
const readOutput = outputReaders.get(name);
|
|
1173
|
+
if (readOutput) {
|
|
1174
|
+
readOutput(field, rest, step, diags);
|
|
1213
1175
|
continue;
|
|
1214
1176
|
}
|
|
1215
1177
|
// A loop step exposes a fixed set of fields, and only those resolve at run
|
|
@@ -2814,6 +2776,175 @@ function checkPublishedFunctionRead(name, field, rest, spec, step, diags) {
|
|
|
2814
2776
|
suggestion: `returns: { ${wanted}: 'string' }`,
|
|
2815
2777
|
});
|
|
2816
2778
|
}
|
|
2779
|
+
/**
|
|
2780
|
+
* The fields every HTTP response carries at the top of `output`, whatever the
|
|
2781
|
+
* API answered. `core.action.http`'s definition declares all three; the author's
|
|
2782
|
+
* `returns` describes what is INSIDE `body`, never beside it.
|
|
2783
|
+
*/
|
|
2784
|
+
const HTTP_ENVELOPE_FIELDS = ['body', 'statusCode', 'headers'];
|
|
2785
|
+
/**
|
|
2786
|
+
* A read of an `http()` step's result.
|
|
2787
|
+
*
|
|
2788
|
+
* The response is an envelope — `{ body, statusCode, headers }` — and `returns`
|
|
2789
|
+
* declares the parsed JSON body's top-level fields, so a declared field is read
|
|
2790
|
+
* at `output.body.<field>` (`out('<step>', 'body.<field>')`). That nesting is the
|
|
2791
|
+
* one thing this family does not share with the process families, and it is
|
|
2792
|
+
* exactly where flow-builder-sdk#850's run went wrong: a branch kept reading
|
|
2793
|
+
* `output.currentDayForecast…` (the Azure Maps connector's path) after the step
|
|
2794
|
+
* became an Open-Meteo `http()`, passed `check` and `validate`, and faulted at
|
|
2795
|
+
* `flow debug` as `[400302]`.
|
|
2796
|
+
*/
|
|
2797
|
+
function checkHttpRead(name, field, rest, spec, step, diags) {
|
|
2798
|
+
if (field === undefined)
|
|
2799
|
+
return; // `out('fetch')` — the whole response.
|
|
2800
|
+
if (field === 'error')
|
|
2801
|
+
return; // the failure envelope (managed http's error port).
|
|
2802
|
+
if (field !== 'output') {
|
|
2803
|
+
diags.push({
|
|
2804
|
+
level: 'error', code: 'HTTP_READ_NOT_OUTPUT', step,
|
|
2805
|
+
message: `HTTP step "${name}" publishes its response under "output", but "$vars.${name}.${field}" `
|
|
2806
|
+
+ `(read in "${step}") asks for "${field}", which is undefined at run time.`,
|
|
2807
|
+
suggestion: `out('${name}', 'body.<field>')`,
|
|
2808
|
+
});
|
|
2809
|
+
return;
|
|
2810
|
+
}
|
|
2811
|
+
const [top, inner] = (rest ?? '').replace(/^\./, '').split('.');
|
|
2812
|
+
if (!top)
|
|
2813
|
+
return; // `$vars.<name>.output` — the whole envelope.
|
|
2814
|
+
const declared = Object.keys(spec?.returns ?? {});
|
|
2815
|
+
if (!HTTP_ENVELOPE_FIELDS.includes(top)) {
|
|
2816
|
+
// The commonest form: a declared body field read one level too high.
|
|
2817
|
+
const hoisted = declared.includes(top) ? top : undefined;
|
|
2818
|
+
const nearest = hoisted ?? nearestName(top, declared);
|
|
2819
|
+
diags.push({
|
|
2820
|
+
level: 'error', code: 'HTTP_READ_UNKNOWN_FIELD', step,
|
|
2821
|
+
message: `"$vars.${name}.output.${top}" (read in "${step}") is not a field of HTTP step "${name}"'s `
|
|
2822
|
+
+ `response. An HTTP response publishes ${HTTP_ENVELOPE_FIELDS.map((f) => `"${f}"`).join(', ')}; `
|
|
2823
|
+
+ `the fields \`returns\` declares live under "body"`
|
|
2824
|
+
+ (hoisted ? `, so "${top}" is read as "$vars.${name}.output.body.${top}".` : '.')
|
|
2825
|
+
+ ` A read outside that shape resolves to undefined and faults a gateway at run time.`,
|
|
2826
|
+
...(nearest !== undefined ? { suggestion: `out('${name}', 'body.${nearest}')` } : {}),
|
|
2827
|
+
});
|
|
2828
|
+
return;
|
|
2829
|
+
}
|
|
2830
|
+
if (top !== 'body' || !inner)
|
|
2831
|
+
return; // `statusCode`, `headers`, or the whole body.
|
|
2832
|
+
if (declared.length === 0) {
|
|
2833
|
+
diags.push({
|
|
2834
|
+
level: 'error', code: 'HTTP_READ_WITHOUT_RETURNS', step,
|
|
2835
|
+
message: `"$vars.${name}.output.body.${inner}" (read in "${step}") reads a field of HTTP step "${name}"'s `
|
|
2836
|
+
+ `response body, but the step declares no \`returns\` — so the node carries no body schema and nothing `
|
|
2837
|
+
+ `can tell a real field from a typo. Only the API being called knows its body; declare the fields you read.`,
|
|
2838
|
+
suggestion: `returns: { ${inner}: 'string' }`,
|
|
2839
|
+
});
|
|
2840
|
+
return;
|
|
2841
|
+
}
|
|
2842
|
+
if (declared.includes(inner))
|
|
2843
|
+
return;
|
|
2844
|
+
const nearest = nearestName(inner, declared);
|
|
2845
|
+
diags.push({
|
|
2846
|
+
level: 'error', code: 'HTTP_READ_UNKNOWN_FIELD', step,
|
|
2847
|
+
message: `HTTP step "${name}" declares no body field "${inner}" (read as "$vars.${name}.output.body.${inner}" `
|
|
2848
|
+
+ `in "${step}"). Its \`returns\` names: ${declared.join(', ')}. A read outside that set resolves to undefined.`,
|
|
2849
|
+
...(nearest !== undefined ? { suggestion: `out('${name}', 'body.${nearest}')` } : {}),
|
|
2850
|
+
});
|
|
2851
|
+
}
|
|
2852
|
+
/**
|
|
2853
|
+
* The read rule the process-shaped families share: the result is published
|
|
2854
|
+
* under `output`, keyed by a known field list — the author's `returns`, or a
|
|
2855
|
+
* shape the SDK itself fixes. `declared: undefined` means "the author declared
|
|
2856
|
+
* nothing", which is its own mistake (`<PREFIX>_READ_WITHOUT_RETURNS`).
|
|
2857
|
+
*/
|
|
2858
|
+
function checkDeclaredOutputRead(o) {
|
|
2859
|
+
const { prefix, what, name, field, rest, step, diags } = o;
|
|
2860
|
+
if (field === undefined || field === 'error')
|
|
2861
|
+
return;
|
|
2862
|
+
if (field !== 'output') {
|
|
2863
|
+
diags.push({
|
|
2864
|
+
level: 'error', code: `${prefix}_READ_NOT_OUTPUT`, step,
|
|
2865
|
+
message: `${what} "${name}" publishes its result under "output", but "$vars.${name}.${field}" `
|
|
2866
|
+
+ `(read in "${step}") asks for "${field}", which is undefined at run time.`,
|
|
2867
|
+
suggestion: `out('${name}', '<field>')`,
|
|
2868
|
+
});
|
|
2869
|
+
return;
|
|
2870
|
+
}
|
|
2871
|
+
const wanted = (rest ?? '').replace(/^\./, '').split('.')[0];
|
|
2872
|
+
if (!wanted)
|
|
2873
|
+
return;
|
|
2874
|
+
if (o.declared === undefined) {
|
|
2875
|
+
diags.push({
|
|
2876
|
+
level: 'error', code: `${prefix}_READ_WITHOUT_RETURNS`, step,
|
|
2877
|
+
message: `"$vars.${name}.output.${wanted}" (read in "${step}") reads a field of ${what} "${name}"'s result, `
|
|
2878
|
+
+ `but the step declares no \`returns\` — so the node carries no output schema and nothing can tell a `
|
|
2879
|
+
+ `real field from a typo. ${o.withoutReturns}`,
|
|
2880
|
+
suggestion: `returns: { ${wanted}: 'string' }`,
|
|
2881
|
+
});
|
|
2882
|
+
return;
|
|
2883
|
+
}
|
|
2884
|
+
if (o.declared.includes(wanted))
|
|
2885
|
+
return;
|
|
2886
|
+
const nearest = nearestName(wanted, o.declared);
|
|
2887
|
+
diags.push({
|
|
2888
|
+
level: 'error', code: `${prefix}_READ_UNKNOWN_FIELD`, step,
|
|
2889
|
+
message: `${what} "${name}" declares no output "${wanted}" (read as "$vars.${name}.output.${wanted}" in `
|
|
2890
|
+
+ `"${step}"). It publishes: ${o.declared.join(', ')}. A read outside that set resolves to undefined.`,
|
|
2891
|
+
...(nearest !== undefined ? { suggestion: `out('${name}', '${nearest}')` } : {}),
|
|
2892
|
+
});
|
|
2893
|
+
}
|
|
2894
|
+
function checkRpaWorkflowRead(name, field, rest, spec, step, diags) {
|
|
2895
|
+
const declared = Object.keys(spec?.returns ?? {});
|
|
2896
|
+
checkDeclaredOutputRead({
|
|
2897
|
+
prefix: 'RPA', what: 'RPA process', name, field, rest, step, diags,
|
|
2898
|
+
declared: declared.length ? declared : undefined,
|
|
2899
|
+
withoutReturns: `The process's output arguments live on the tenant; declare the ones you read. `
|
|
2900
|
+
+ `\`uip maestro flow registry get uipath.core.rpa-workflow.${spec?.key}\` shows what the platform `
|
|
2901
|
+
+ `synthesizes for it.`,
|
|
2902
|
+
});
|
|
2903
|
+
}
|
|
2904
|
+
/**
|
|
2905
|
+
* A queue step publishes one of two shapes: a plain enqueue publishes the queue
|
|
2906
|
+
* ITEM's Orchestrator record (fixed, declared by the serializer from
|
|
2907
|
+
* `QUEUE_ITEM_RECORD_SCHEMA`), a `wait: true` publishes the processed result,
|
|
2908
|
+
* whose fields only the author's `returns` states.
|
|
2909
|
+
*/
|
|
2910
|
+
function checkQueueItemRead(name, field, rest, spec, step, diags) {
|
|
2911
|
+
const waitReturns = Object.keys(spec?.returns ?? {});
|
|
2912
|
+
checkDeclaredOutputRead({
|
|
2913
|
+
prefix: 'QUEUE', what: spec?.wait ? 'Queue wait' : 'Queue item', name, field, rest, step, diags,
|
|
2914
|
+
declared: !spec?.wait
|
|
2915
|
+
? Object.keys(QUEUE_ITEM_RECORD_SCHEMA.properties)
|
|
2916
|
+
: waitReturns.length ? waitReturns : undefined,
|
|
2917
|
+
withoutReturns: `What the consumer writes into the processed item's result is that automation's business; `
|
|
2918
|
+
+ `declare the fields you read.`,
|
|
2919
|
+
});
|
|
2920
|
+
}
|
|
2921
|
+
/**
|
|
2922
|
+
* THE GATE (flow-builder-sdk#850). Each `returns`-bearing kind maps to the rule
|
|
2923
|
+
* that checks a read of its output, or to a stated reason it has none.
|
|
2924
|
+
*
|
|
2925
|
+
* Before this table each family's rule was wired by hand — a map filled in the
|
|
2926
|
+
* walk plus a branch in the `$vars` dispatch — and nothing tied "this family
|
|
2927
|
+
* takes `returns`" to "this family has a read rule". `http`, `rpaWorkflow` and
|
|
2928
|
+
* `queueItem` shipped without one, so a read of an undeclared field passed
|
|
2929
|
+
* `check` and `validate` and only faulted live. The type below is exhaustive
|
|
2930
|
+
* over the derived kinds: give a new family a `returns` and `tsc` refuses to
|
|
2931
|
+
* build until it lands here.
|
|
2932
|
+
*/
|
|
2933
|
+
const OUTPUT_READ_RULES = {
|
|
2934
|
+
http: checkHttpRead,
|
|
2935
|
+
rpaWorkflow: checkRpaWorkflowRead,
|
|
2936
|
+
apiWorkflow: checkApiWorkflowRead,
|
|
2937
|
+
publishedFunction: checkPublishedFunctionRead,
|
|
2938
|
+
agenticProcess: checkAgenticProcessRead,
|
|
2939
|
+
agent: checkAgentRead,
|
|
2940
|
+
inlineAgent: checkInlineAgentRead,
|
|
2941
|
+
queueItem: checkQueueItemRead,
|
|
2942
|
+
script: {
|
|
2943
|
+
exempt: 'Not yet: only the field-map form of a script\'s `returns` gives a list to check against (the '
|
|
2944
|
+
+ 'type form and the inferred form do not), and script is the most-used step, so its rule lands with '
|
|
2945
|
+
+ 'its own false-positive sweep — flow-builder-sdk#855.',
|
|
2946
|
+
},
|
|
2947
|
+
};
|
|
2817
2948
|
function checkApiWorkflowRead(name, field, rest, spec, step, diags) {
|
|
2818
2949
|
if (field === undefined)
|
|
2819
2950
|
return; // `out('call')` — the whole output object.
|
package/dist/core/actions.d.ts
CHANGED
|
@@ -82,6 +82,16 @@ interface HttpInputsBase {
|
|
|
82
82
|
* fields, and nothing downstream can tell a real field from a typo. Same rule,
|
|
83
83
|
* and the same word, as
|
|
84
84
|
* `rpaWorkflow`'s `returns`.
|
|
85
|
+
*
|
|
86
|
+
* **Where a declared field is read:** under `body`, never beside it. The
|
|
87
|
+
* response is an envelope — `{ body, statusCode, headers }` — and these are the
|
|
88
|
+
* body's fields, so `returns: { items: 'array' }` is read as
|
|
89
|
+
* `out('fetch', 'body.items')`, which is `$vars.fetch.output.body.items`.
|
|
90
|
+
* `$vars.fetch.output.items` is undefined at run time.
|
|
91
|
+
*
|
|
92
|
+
* @enforcedBy HTTP_READ_UNKNOWN_FIELD A read must be `output.body.<declared field>`,
|
|
93
|
+
* `output.statusCode` or `output.headers`.
|
|
94
|
+
* @enforcedBy HTTP_READ_WITHOUT_RETURNS Reading a body field requires declaring it here.
|
|
85
95
|
*/
|
|
86
96
|
returns?: Record<string, ReturnFieldType>;
|
|
87
97
|
/**
|
|
@@ -991,6 +1001,9 @@ export interface RpaWorkflowInputs {
|
|
|
991
1001
|
* the fields here is the same thing the platform's own definition does when it
|
|
992
1002
|
* can reach the process, and it is what lets a misspelled read be caught at
|
|
993
1003
|
* `uip maestro flow check` instead of at run time.
|
|
1004
|
+
*
|
|
1005
|
+
* @enforcedBy RPA_READ_UNKNOWN_FIELD A read of the output must name a field declared here.
|
|
1006
|
+
* @enforcedBy RPA_READ_WITHOUT_RETURNS Reading a field off the result requires declaring it here.
|
|
994
1007
|
*/
|
|
995
1008
|
returns?: Record<string, ReturnFieldType>;
|
|
996
1009
|
}
|
|
@@ -2035,6 +2048,11 @@ export interface QueueItemInputs {
|
|
|
2035
2048
|
* `wait: false` needs none: what it publishes is the queue ITEM's own
|
|
2036
2049
|
* Orchestrator record (`Key`, `Status`, `Reference`, `SpecificContent`, …),
|
|
2037
2050
|
* which is the same for every queue, so the serializer declares it for you.
|
|
2051
|
+
*
|
|
2052
|
+
* @enforcedBy QUEUE_READ_UNKNOWN_FIELD A read must name a field of the record
|
|
2053
|
+
* (`wait: false`) or of this `returns` (`wait: true`).
|
|
2054
|
+
* @enforcedBy QUEUE_READ_WITHOUT_RETURNS Reading a field off a `wait: true` result
|
|
2055
|
+
* requires declaring it here.
|
|
2038
2056
|
*/
|
|
2039
2057
|
returns?: Record<string, ReturnFieldType>;
|
|
2040
2058
|
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The queue item's own Orchestrator record — the fields `core.action.queue.create`
|
|
3
|
+
* publishes, declared so a downstream read is checkable. Shared by the serializer
|
|
4
|
+
* (which declares it on the node) and `check` (which refuses a read outside it).
|
|
5
|
+
*
|
|
6
|
+
* Unlike an rpa process's output arguments, this shape is NOT per-tenant: it is
|
|
7
|
+
* Orchestrator's queue-item record, the same for every queue, so the author has
|
|
8
|
+
* nothing to declare and `returns` is not needed for a fire-and-forget enqueue.
|
|
9
|
+
* The dispatcher returns `env.Data` from `uip or queue-items add` verbatim, and
|
|
10
|
+
* these are the fields a real add answered with (pinned 2026-07-28 against
|
|
11
|
+
* `Shared/SupplierInvoices` on codereval; `gen-tests`' fixture for the node is the
|
|
12
|
+
* same list). Declaring the EVIDENCED fields and no more is PR 10's payload-schema
|
|
13
|
+
* pattern — an invented field would be #73's `firedAt` again.
|
|
14
|
+
*/
|
|
15
|
+
export declare const QUEUE_ITEM_RECORD_SCHEMA: {
|
|
16
|
+
readonly type: "object";
|
|
17
|
+
readonly properties: {
|
|
18
|
+
readonly Id: {
|
|
19
|
+
readonly type: "number";
|
|
20
|
+
};
|
|
21
|
+
readonly Key: {
|
|
22
|
+
readonly type: "string";
|
|
23
|
+
};
|
|
24
|
+
readonly UniqueKey: {
|
|
25
|
+
readonly type: "string";
|
|
26
|
+
};
|
|
27
|
+
readonly Reference: {
|
|
28
|
+
readonly type: "string";
|
|
29
|
+
};
|
|
30
|
+
readonly Status: {
|
|
31
|
+
readonly type: "string";
|
|
32
|
+
};
|
|
33
|
+
readonly Priority: {
|
|
34
|
+
readonly type: "string";
|
|
35
|
+
};
|
|
36
|
+
readonly QueueDefinitionName: {
|
|
37
|
+
readonly type: "string";
|
|
38
|
+
};
|
|
39
|
+
readonly QueueDefinitionKey: {
|
|
40
|
+
readonly type: "string";
|
|
41
|
+
};
|
|
42
|
+
readonly CreationTime: {
|
|
43
|
+
readonly type: "string";
|
|
44
|
+
};
|
|
45
|
+
readonly StartProcessing: {
|
|
46
|
+
readonly type: "string";
|
|
47
|
+
};
|
|
48
|
+
readonly EndProcessing: {
|
|
49
|
+
readonly type: "string";
|
|
50
|
+
};
|
|
51
|
+
readonly Progress: {
|
|
52
|
+
readonly type: "string";
|
|
53
|
+
};
|
|
54
|
+
readonly ReviewStatus: {
|
|
55
|
+
readonly type: "string";
|
|
56
|
+
};
|
|
57
|
+
readonly DueDate: {
|
|
58
|
+
readonly type: "string";
|
|
59
|
+
};
|
|
60
|
+
readonly RiskSlaDate: {
|
|
61
|
+
readonly type: "string";
|
|
62
|
+
};
|
|
63
|
+
readonly DeferDate: {
|
|
64
|
+
readonly type: "string";
|
|
65
|
+
};
|
|
66
|
+
readonly Encrypted: {
|
|
67
|
+
readonly type: "boolean";
|
|
68
|
+
};
|
|
69
|
+
readonly SpecificContent: {
|
|
70
|
+
readonly type: "object";
|
|
71
|
+
};
|
|
72
|
+
readonly Output: {
|
|
73
|
+
readonly type: "object";
|
|
74
|
+
};
|
|
75
|
+
readonly OutputData: {
|
|
76
|
+
readonly type: "string";
|
|
77
|
+
};
|
|
78
|
+
readonly Analytics: {
|
|
79
|
+
readonly type: "object";
|
|
80
|
+
};
|
|
81
|
+
readonly AnalyticsData: {
|
|
82
|
+
readonly type: "string";
|
|
83
|
+
};
|
|
84
|
+
readonly ProcessingExceptionType: {
|
|
85
|
+
readonly type: "string";
|
|
86
|
+
};
|
|
87
|
+
readonly ProcessingExceptionReason: {
|
|
88
|
+
readonly type: "string";
|
|
89
|
+
};
|
|
90
|
+
readonly SecondsInPreviousAttempts: {
|
|
91
|
+
readonly type: "number";
|
|
92
|
+
};
|
|
93
|
+
readonly RetryNumber: {
|
|
94
|
+
readonly type: "number";
|
|
95
|
+
};
|
|
96
|
+
readonly CreatorJobKey: {
|
|
97
|
+
readonly type: "string";
|
|
98
|
+
};
|
|
99
|
+
readonly ExecutorJobKey: {
|
|
100
|
+
readonly type: "string";
|
|
101
|
+
};
|
|
102
|
+
readonly RobotKey: {
|
|
103
|
+
readonly type: "string";
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The queue item's own Orchestrator record — the fields `core.action.queue.create`
|
|
3
|
+
* publishes, declared so a downstream read is checkable. Shared by the serializer
|
|
4
|
+
* (which declares it on the node) and `check` (which refuses a read outside it).
|
|
5
|
+
*
|
|
6
|
+
* Unlike an rpa process's output arguments, this shape is NOT per-tenant: it is
|
|
7
|
+
* Orchestrator's queue-item record, the same for every queue, so the author has
|
|
8
|
+
* nothing to declare and `returns` is not needed for a fire-and-forget enqueue.
|
|
9
|
+
* The dispatcher returns `env.Data` from `uip or queue-items add` verbatim, and
|
|
10
|
+
* these are the fields a real add answered with (pinned 2026-07-28 against
|
|
11
|
+
* `Shared/SupplierInvoices` on codereval; `gen-tests`' fixture for the node is the
|
|
12
|
+
* same list). Declaring the EVIDENCED fields and no more is PR 10's payload-schema
|
|
13
|
+
* pattern — an invented field would be #73's `firedAt` again.
|
|
14
|
+
*/
|
|
15
|
+
export const QUEUE_ITEM_RECORD_SCHEMA = {
|
|
16
|
+
type: 'object',
|
|
17
|
+
properties: {
|
|
18
|
+
Id: { type: 'number' },
|
|
19
|
+
Key: { type: 'string' },
|
|
20
|
+
UniqueKey: { type: 'string' },
|
|
21
|
+
Reference: { type: 'string' },
|
|
22
|
+
Status: { type: 'string' },
|
|
23
|
+
Priority: { type: 'string' },
|
|
24
|
+
QueueDefinitionName: { type: 'string' },
|
|
25
|
+
QueueDefinitionKey: { type: 'string' },
|
|
26
|
+
CreationTime: { type: 'string' },
|
|
27
|
+
StartProcessing: { type: 'string' },
|
|
28
|
+
EndProcessing: { type: 'string' },
|
|
29
|
+
Progress: { type: 'string' },
|
|
30
|
+
ReviewStatus: { type: 'string' },
|
|
31
|
+
DueDate: { type: 'string' },
|
|
32
|
+
RiskSlaDate: { type: 'string' },
|
|
33
|
+
DeferDate: { type: 'string' },
|
|
34
|
+
Encrypted: { type: 'boolean' },
|
|
35
|
+
SpecificContent: { type: 'object' },
|
|
36
|
+
Output: { type: 'object' },
|
|
37
|
+
OutputData: { type: 'string' },
|
|
38
|
+
Analytics: { type: 'object' },
|
|
39
|
+
AnalyticsData: { type: 'string' },
|
|
40
|
+
ProcessingExceptionType: { type: 'string' },
|
|
41
|
+
ProcessingExceptionReason: { type: 'string' },
|
|
42
|
+
SecondsInPreviousAttempts: { type: 'number' },
|
|
43
|
+
RetryNumber: { type: 'number' },
|
|
44
|
+
CreatorJobKey: { type: 'string' },
|
|
45
|
+
ExecutorJobKey: { type: 'string' },
|
|
46
|
+
RobotKey: { type: 'string' },
|
|
47
|
+
},
|
|
48
|
+
};
|
package/dist/flow-sdk.d.ts
CHANGED
|
@@ -974,7 +974,7 @@ declare class StepList {
|
|
|
974
974
|
* **Paginate until the API says stop**
|
|
975
975
|
* ```ts
|
|
976
976
|
* .var('page', types.number, 1)
|
|
977
|
-
* .doWhile('paginate', js`$vars.fetch.output.hasNextPage === true`, (b) => b
|
|
977
|
+
* .doWhile('paginate', js`$vars.fetch.output.body.hasNextPage === true`, (b) => b
|
|
978
978
|
* .step('fetch', http({ url: tmpl`https://api.example.test/items?page=${v('page')}`, method: 'GET', managed: false, returns: { hasNextPage: 'boolean' } }), {
|
|
979
979
|
* updates: { page: js`$vars.page + 1` },
|
|
980
980
|
* }), { limit: 50 })
|
package/dist/flow-sdk.js
CHANGED
|
@@ -709,7 +709,7 @@ class StepList {
|
|
|
709
709
|
* **Paginate until the API says stop**
|
|
710
710
|
* ```ts
|
|
711
711
|
* .var('page', types.number, 1)
|
|
712
|
-
* .doWhile('paginate', js`$vars.fetch.output.hasNextPage === true`, (b) => b
|
|
712
|
+
* .doWhile('paginate', js`$vars.fetch.output.body.hasNextPage === true`, (b) => b
|
|
713
713
|
* .step('fetch', http({ url: tmpl`https://api.example.test/items?page=${v('page')}`, method: 'GET', managed: false, returns: { hasNextPage: 'boolean' } }), {
|
|
714
714
|
* updates: { page: js`$vars.page + 1` },
|
|
715
715
|
* }), { limit: 50 })
|
package/dist/registry/cache.d.ts
CHANGED
|
@@ -21,6 +21,15 @@
|
|
|
21
21
|
export declare const LIBRARY_JSON_DIR = "library-json";
|
|
22
22
|
export declare const LIBRARY_MARKDOWN_DIR = "library-md";
|
|
23
23
|
export declare const CURRENT_LINK = "current";
|
|
24
|
+
/**
|
|
25
|
+
* The command a message tells a person or agent to run when the cache is
|
|
26
|
+
* empty. It is `uip`, not `npx flow-sdk registry pull`: `uip maestro registry
|
|
27
|
+
* pull` runs this package's pull and fills the same cache, and it is the one
|
|
28
|
+
* command the authoring skill teaches. Each message used to spell the command
|
|
29
|
+
* out by hand, so they kept naming the SDK's own entry point after the skill
|
|
30
|
+
* moved to `uip`. Name it here once.
|
|
31
|
+
*/
|
|
32
|
+
export declare const PULL_COMMAND = "uip maestro registry pull";
|
|
24
33
|
/**
|
|
25
34
|
* Root of the library cache. `UIP_FLOW_SDK_LIBRARY_CACHE` overrides it.
|
|
26
35
|
*
|
package/dist/registry/cache.js
CHANGED
|
@@ -24,6 +24,15 @@ import { join } from "node:path";
|
|
|
24
24
|
export const LIBRARY_JSON_DIR = "library-json";
|
|
25
25
|
export const LIBRARY_MARKDOWN_DIR = "library-md";
|
|
26
26
|
export const CURRENT_LINK = "current";
|
|
27
|
+
/**
|
|
28
|
+
* The command a message tells a person or agent to run when the cache is
|
|
29
|
+
* empty. It is `uip`, not `npx flow-sdk registry pull`: `uip maestro registry
|
|
30
|
+
* pull` runs this package's pull and fills the same cache, and it is the one
|
|
31
|
+
* command the authoring skill teaches. Each message used to spell the command
|
|
32
|
+
* out by hand, so they kept naming the SDK's own entry point after the skill
|
|
33
|
+
* moved to `uip`. Name it here once.
|
|
34
|
+
*/
|
|
35
|
+
export const PULL_COMMAND = "uip maestro registry pull";
|
|
27
36
|
/**
|
|
28
37
|
* Root of the library cache. `UIP_FLOW_SDK_LIBRARY_CACHE` overrides it.
|
|
29
38
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { reportResult } from '../cli-result.js';
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import { CURRENT_LINK, currentEntrySha, libraryCacheRoot, resolveCachedLibrary, resolveCachedMarkdown, } from "./cache.js";
|
|
3
|
+
import { CURRENT_LINK, PULL_COMMAND, currentEntrySha, libraryCacheRoot, resolveCachedLibrary, resolveCachedMarkdown, } from "./cache.js";
|
|
4
4
|
/**
|
|
5
5
|
* Say where the connector library is.
|
|
6
6
|
*
|
|
@@ -34,7 +34,7 @@ export async function run(argv) {
|
|
|
34
34
|
const single = (field, value) => {
|
|
35
35
|
reportResult({ [field]: value ?? null });
|
|
36
36
|
if (!value) {
|
|
37
|
-
console.error(
|
|
37
|
+
console.error(`No connector library in the cache yet. Run \`${PULL_COMMAND}\`.`);
|
|
38
38
|
return 1;
|
|
39
39
|
}
|
|
40
40
|
console.log(value);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { reportResult } from '../cli-result.js';
|
|
2
2
|
import { readFile, stat } from "node:fs/promises";
|
|
3
|
-
import { resolveLibraryDir } from "./cache.js";
|
|
3
|
+
import { PULL_COMMAND, resolveLibraryDir } from "./cache.js";
|
|
4
4
|
import { dirname, join } from "node:path";
|
|
5
5
|
export const DEFAULT_SEARCH_LIMIT = 20;
|
|
6
6
|
const USAGE = "Usage: flow-sdk registry search [query] [--library <dir>] [--library-md <dir>] [--connector <key>] [--limit <n>]";
|
|
@@ -52,7 +52,7 @@ export async function searchRegistryOperations(options) {
|
|
|
52
52
|
content = await readFile(indexPath, "utf-8");
|
|
53
53
|
}
|
|
54
54
|
catch {
|
|
55
|
-
throw new Error(`Could not read ${indexPath}. Run
|
|
55
|
+
throw new Error(`Could not read ${indexPath}. Run \`${PULL_COMMAND}\`, or point` +
|
|
56
56
|
" --library at an extracted connector library.");
|
|
57
57
|
}
|
|
58
58
|
let parsed;
|
|
@@ -120,6 +120,10 @@ export async function run(argv) {
|
|
|
120
120
|
// verbs defaulted it was the inconsistency an author hit first.
|
|
121
121
|
const libraryPath = resolveLibraryDir(value(argv, "--library"));
|
|
122
122
|
if (!libraryPath) {
|
|
123
|
+
// Say why. A bare usage line here read as "no match" to an agent deciding
|
|
124
|
+
// between a connector and http(): it took the failed search for a miss.
|
|
125
|
+
console.error(`No connector library is cached. Run \`${PULL_COMMAND}\`, or pass` +
|
|
126
|
+
" --library <dir>.");
|
|
123
127
|
console.error(USAGE);
|
|
124
128
|
return 2;
|
|
125
129
|
}
|