@uipath/maestro-builder-sdk 6.11.6 → 6.12.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.
@@ -19,12 +19,16 @@ export function registryTypeNames() {
19
19
  * `FLOW_SDK_BPMN_REGISTRY_FALLBACK=0` to keep resolution snapshot-only.
20
20
  *
21
21
  * @param type - The extension type, e.g. `'Intsvc.UnifiedHttpRequest'`.
22
+ * @param inline - A spec supplied by the author, which is used as is.
22
23
  * @returns Its emission spec.
23
24
  * @throws If the type is in neither the snapshot nor the registry — which means a
24
25
  * typo, or no `uip` to ask.
25
26
  */
26
- export function registryType(type) {
27
- const spec = REGISTRY.types[type] ?? resolveFromRegistry(type);
27
+ export function registryType(type, inline) {
28
+ // An inline spec wins over both the snapshot and the tenant — it is the author
29
+ // saying "emit THIS", for a type the snapshot lacks and no `uip` can describe, or
30
+ // for one the snapshot describes wrongly. See `ActivityNodeOpts.spec`.
31
+ const spec = inline ?? REGISTRY.types[type] ?? resolveFromRegistry(type);
28
32
  if (!spec) {
29
33
  throw new Error(`unknown extension type "${type}". The committed registry snapshot has ${REGISTRY.provenance.typeCount} types `
30
34
  + `(uip ${REGISTRY.provenance.uipVersion}) and the registry could not be asked for this one either — `
@@ -82,7 +86,22 @@ export const REGISTRY_GAPS = {
82
86
  // which `uip maestro bpmn validate` has always accepted. So the guard was right
83
87
  // that they are undeclared and wrong that they are invalid — recorded here rather
84
88
  // than by loosening the guard, which is what catches an author's typo.
85
- 'Intsvc.ActivityExecution': { extraContext: ['activity', 'resourceKey'] },
89
+ // `requiredContext` — context fields the PLATFORM requires and the registry
90
+ // snapshot does not mark required (or, here, does not declare at all).
91
+ //
92
+ // `Intsvc.ActivityExecution` must carry `activity`; without it `uip maestro bpmn
93
+ // validate` reports
94
+ //
95
+ // [canvas] [ERROR] EMPTY_REQUIRED_FIELD: The field 'activity' in node 'op' is
96
+ // required but has no value.
97
+ //
98
+ // and `check` could not know, because it derives required fields from the snapshot.
99
+ // The connector emitter has always written `activity`, so this only bites a
100
+ // hand-rolled `.activity()` — but it bit it at the LAST rung. The divergence is
101
+ // measured rather than assumed: `bpmn-registry-required-drift.test.ts` diffs the
102
+ // required-field set the canvas validator carries against the snapshot's, over every
103
+ // type both know, and asserts the only difference is what this table records.
104
+ 'Intsvc.ActivityExecution': { extraContext: ['activity', 'resourceKey'], requiredContext: ['activity'] },
86
105
  // `outputRowsFixed` — the type permits EXACTLY the output row its spec declares.
87
106
  // A mapped second row is refused:
88
107
  //
@@ -115,8 +134,8 @@ function identifierize(name) {
115
134
  .join('');
116
135
  }
117
136
  /** The variable a typed node's output row writes, or `undefined` when it has none. */
118
- export function typedNodeOutputVar(id, type, outputVar) {
119
- const spec = registryType(type);
137
+ export function typedNodeOutputVar(id, type, outputVar, inline) {
138
+ const spec = registryType(type, inline);
120
139
  if (!spec.output)
121
140
  return undefined;
122
141
  return outputVar ?? `${id}_${identifierize(spec.output.name)}`;
@@ -182,7 +201,13 @@ function contextRows(m, type, spec, supplied, verbatim = false) {
182
201
  // it and the author never learns why their setting did nothing — so it is
183
202
  // refused. The exception is a type with a recorded `extraContext` gap, where the
184
203
  // platform is known to accept fields the registry omits.
185
- const known = new Set([...spec.context.map((f) => f.name), ...(REGISTRY_GAPS[type]?.extraContext ?? [])]);
204
+ const known = new Set([
205
+ ...spec.context.map((f) => f.name),
206
+ ...(REGISTRY_GAPS[type]?.extraContext ?? []),
207
+ // A field the platform REQUIRES is necessarily one it permits, so recording it as
208
+ // required is enough — an `extraContext` twin is not also needed.
209
+ ...(REGISTRY_GAPS[type]?.requiredContext ?? []),
210
+ ]);
186
211
  const unknown = Object.keys(supplied).filter((k) => !known.has(k));
187
212
  if (unknown.length) {
188
213
  throw new Error(`context field(s) ${unknown.map((u) => `"${u}"`).join(', ')} are not declared by this extension type. ` +
@@ -234,10 +259,16 @@ function inputRows(m, spec, inputs) {
234
259
  // platform does not read, and one no validator complains about.
235
260
  //
236
261
  // So: the declared field decides when there is one, the key when there is not.
262
+ //
263
+ // The same split decides the TYPE of an undeclared field. Every undeclared value
264
+ // used to be written as a `json` body, so a scalar came out JSON-quoted —
265
+ // `recordId` as `"1111-…"`, quotes included, where every real export writes
266
+ // `type="string" value="1111-…"`. A structured value is still a json body; a
267
+ // scalar is written as the `value` attribute, the way a declared scalar is.
237
268
  const declared = new Map(spec.inputs.map((f) => [f.name, f]));
238
269
  return keys.map((k) => {
239
270
  const field = declared.get(k);
240
- return payloadInput(m, k, field?.target ?? k, inputs[k], field?.type ?? 'json');
271
+ return payloadInput(m, k, field?.target ?? k, inputs[k], field?.type ?? inferredInputType(inputs[k]));
241
272
  });
242
273
  }
243
274
  if (!spec.inputName)
@@ -277,6 +308,23 @@ function payloadInput(m, name, target, value, type) {
277
308
  props.target = target;
278
309
  return m.create('uipath:Input', props);
279
310
  }
311
+ /** `json` for an object or array, `string` for anything else — see `inputRows`. */
312
+ function inferredInputType(value) {
313
+ return value !== null && typeof value === 'object' ? 'json' : 'string';
314
+ }
315
+ /** `uipath:input` payload rows exactly as the caller spelled them, deriving nothing. */
316
+ export function verbatimInputRows(m, rows) {
317
+ return rows.map((row) => {
318
+ const props = { name: row.name, type: row.type ?? 'string' };
319
+ if (row.target !== undefined)
320
+ props.target = row.target;
321
+ if (row.value !== undefined)
322
+ props.value = row.value;
323
+ if (row.body !== undefined)
324
+ props.body = jsonBody(row.body);
325
+ return m.create('uipath:Input', props);
326
+ });
327
+ }
280
328
  /** The `uipath:output` row, when the type declares one. */
281
329
  function outputRow(m, spec, varName) {
282
330
  if (!spec.output)
@@ -308,7 +356,7 @@ export function createTypedNode(m, id, type, input,
308
356
  * Optional so a caller with no variable context still gets today's behaviour.
309
357
  */
310
358
  varType) {
311
- const spec = registryType(type);
359
+ const spec = registryType(type, input.spec);
312
360
  if (!spec.element || !spec.tag) {
313
361
  throw new Error(`extension type "${type}" has no element/tag in the registry snapshot; it cannot be authored.`);
314
362
  }
@@ -352,7 +400,10 @@ varType) {
352
400
  }
353
401
  payload.context = m.create('uipath:Context', context);
354
402
  }
355
- const ins = inputRows(m, spec, input.inputs ?? {});
403
+ // Spelled out by the caller: emit exactly these rows, deriving nothing — see
404
+ // TypedNodeInput.inputRows. This is what lets a connector's per-parameter rows
405
+ // (`name="start" type="string" value="0" target="query"`) survive a round trip.
406
+ const ins = input.inputRows ? verbatimInputRows(m, input.inputRows) : inputRows(m, spec, input.inputs ?? {});
356
407
  if (ins.length)
357
408
  payload.input = ins;
358
409
  const rows = [];
@@ -365,7 +416,7 @@ varType) {
365
416
  payload.output = rows;
366
417
  return finish(m, spec, id, input.name, payload);
367
418
  }
368
- const outVar = typedNodeOutputVar(id, type, input.outputVar);
419
+ const outVar = typedNodeOutputVar(id, type, input.outputVar, spec);
369
420
  const out = outVar ? outputRow(m, spec, outVar) : undefined;
370
421
  if (out)
371
422
  rows.push(out);
@@ -476,8 +527,8 @@ function moddleElementOf(element) {
476
527
  * @param type - The extension type.
477
528
  * @returns Its fields that must be bound, with the target each binding needs.
478
529
  */
479
- export function bindingRequiredFields(type) {
480
- return registryType(type).context.filter((f) => f.bindingInfo !== null && f.required);
530
+ export function bindingRequiredFields(type, inline) {
531
+ return registryType(type, inline).context.filter((f) => f.bindingInfo !== null && f.required);
481
532
  }
482
533
  /**
483
534
  * Required context fields the author left unset and the registry cannot default.
@@ -490,10 +541,21 @@ export function bindingRequiredFields(type) {
490
541
  * @param context - The context values the author supplied.
491
542
  * @returns The names of required fields with no value and no default.
492
543
  */
493
- export function missingRequiredContext(type, context = {}) {
494
- return registryType(type)
495
- .context.filter((f) => f.required && context[f.name] === undefined && (f.default ?? '') === '')
544
+ export function missingRequiredContext(type, context = {}, inline) {
545
+ // The platform's test is `isNilOrEmpty(field.value)`, so a field present and BLANK is
546
+ // as missing as one absent — and blank is the likelier authoring slip of the two, a
547
+ // value that came from an expression or a variable that had nothing in it. Checking
548
+ // only for `undefined` let every one of those through to the last rung.
549
+ const unset = (name) => {
550
+ const v = context[name];
551
+ return v === undefined || v === null || (typeof v === 'string' && v.trim() === '');
552
+ };
553
+ const declared = registryType(type, inline)
554
+ .context.filter((f) => f.required && unset(f.name) && (f.default ?? '') === '')
496
555
  .map((f) => f.name);
556
+ // Fields the platform requires that the snapshot does not — see `REGISTRY_GAPS`.
557
+ const gaps = (REGISTRY_GAPS[type]?.requiredContext ?? []).filter((name) => !declared.includes(name) && unset(name));
558
+ return [...declared, ...gaps];
497
559
  }
498
560
  /**
499
561
  * Required PAYLOAD fields the author left unset.
@@ -519,9 +581,9 @@ export function missingRequiredInputs(type, inputs = {},
519
581
  * genuinely does not spell (it writes `connection`). Reading both makes this
520
582
  * agree with the CLI instead of guessing on either side of it.
521
583
  */
522
- context = {}) {
584
+ context = {}, inline) {
523
585
  const notEnforced = new Set(REGISTRY_GAPS[type]?.notEnforcedInputs ?? []);
524
- return registryType(type)
586
+ return registryType(type, inline)
525
587
  .inputs.filter((f) => f.required &&
526
588
  !notEnforced.has(f.name) &&
527
589
  inputs[f.name] === undefined &&
@@ -560,8 +622,8 @@ context = {}) {
560
622
  * @param type - The extension type.
561
623
  * @returns The required payload field names that cannot be expressed, or `[]`.
562
624
  */
563
- export function unsatisfiableRequiredInputs(type) {
564
- const spec = registryType(type);
625
+ export function unsatisfiableRequiredInputs(type, inline) {
626
+ const spec = registryType(type, inline);
565
627
  if (spec.inputPattern !== 'mergedBody' && spec.inputPattern !== 'splitInputsItemData')
566
628
  return [];
567
629
  return spec.inputs.filter((f) => f.required).map((f) => f.name);
@@ -18,6 +18,7 @@ export function registerBpmnCommands(program) {
18
18
  .description('Check authored TypeScript. Check a .bpmn with `uip maestro bpmn validate`.')
19
19
  .argument('<input>', 'a .bpmn.ts path or bare name')
20
20
  .option('--source', 'check authored TypeScript')
21
+ .option('--graph', 'also print the resolved wiring: every element with the flows leaving it, implied edges marked ~>')
21
22
  .addOption(retiredCompiledOption())
22
23
  .action(async (input, options) => {
23
24
  let mode;
@@ -32,7 +33,10 @@ export function registerBpmnCommands(program) {
32
33
  refuse('flow-sdk bpmn check --compiled: use `uip maestro bpmn validate <file.bpmn>`');
33
34
  return;
34
35
  }
35
- await invoke('bpmn check', () => loadTool(import.meta.url, '../../bpmn/check-cli.js'), [input]);
36
+ const argv = [input];
37
+ if (options.graph)
38
+ argv.push('--graph');
39
+ await invoke('bpmn check', () => loadTool(import.meta.url, '../../bpmn/check-cli.js'), argv);
36
40
  });
37
41
  family.command('tidy')
38
42
  .description('Add diagram layout to a compiled .bpmn artifact.')
@@ -49,10 +53,12 @@ export function registerBpmnCommands(program) {
49
53
  .argument('<input>', 'input .bpmn path')
50
54
  .option('-o, --output <file>', 'output .bpmn.ts path')
51
55
  .option('--import <specifier>', 'SDK import specifier in generated source')
56
+ .option('--style <style>', 'explicit (default) writes one call per element and flow; nested lifts boundary events, gateways and event sub-processes into the nesting constructs where the graph is provably the same')
52
57
  .action(async (input, options) => {
53
58
  const argv = [input];
54
59
  addValue(argv, '-o', options.output);
55
60
  addValue(argv, '--import', options.import);
61
+ addValue(argv, '--style', options.style);
56
62
  await invoke('bpmn decompile', () => loadTool(import.meta.url, '../../bpmn/decompile-cli.js'), argv);
57
63
  });
58
64
  family
package/dist/index.d.ts CHANGED
@@ -24,9 +24,12 @@ export type { CaseRule, CaseRuleInput, CaseRuleGrid, WhenExpression, CaseJsonPre
24
24
  export { serialize as serializeCase } from './case/serialize.js';
25
25
  export { decompile as decompileCase, decompileWithDiagnostics as decompileCaseWithDiagnostics } from './case/decompile.js';
26
26
  export { bpmn } from './bpmn/bpmn-sdk.js';
27
- export type { BuiltBpmn, BpmnNode, BpmnFlow, BpmnVarDecl, EventDef, GatewayKind, EventKind, LoopSpec, RetrySpec, ActivityOpts, HttpOpts, } from './bpmn/bpmn-sdk.js';
27
+ export type { BuiltBpmn, BpmnNode, BpmnFlow, BpmnVarDecl, EventDef, GatewayKind, EventKind, LoopSpec, RetrySpec, ActivityOpts, HttpOpts, ActivityBodyFn, ArmBodyFn, HandlerOpts, ErrorHandlerOpts, TimerHandlerOpts, MessageHandlerOpts, ChooseArm, ChooseOpts, SplitOpts, JoinOpts, EventSubProcessOpts, FlowMode, } from './bpmn/bpmn-sdk.js';
28
+ export { PathBuilder, ActivityBuilder } from './bpmn/bpmn-sdk.js';
29
+ export { renderGraph as renderBpmnGraph, graphModel as bpmnGraphModel } from './bpmn/graph.js';
30
+ export type { GraphScope as BpmnGraphScope, GraphNode as BpmnGraphNode, GraphEdge as BpmnGraphEdge } from './bpmn/graph.js';
28
31
  export { registryTypeNames, registryType, isSnapshotType } from './bpmn/typed-node.js';
29
- export type { RegistryTypeSpec, RegistryContextField, RegistryOutput } from './bpmn/typed-node.js';
32
+ export type { RegistryTypeSpec, RegistryContextField, RegistryInputField, RegistryOutput, TypedContextRow, TypedInputRow, TypedOutputRow } from './bpmn/typed-node.js';
30
33
  export { serialize as serializeBpmn } from './bpmn/serialize.js';
31
34
  export { check as checkBpmn } from './bpmn/check.js';
32
35
  export type { Diagnostic as BpmnDiagnostic } from './bpmn/check.js';
package/dist/index.js CHANGED
@@ -27,6 +27,9 @@ export { serialize as serializeCase } from './case/serialize.js';
27
27
  export { decompile as decompileCase, decompileWithDiagnostics as decompileCaseWithDiagnostics } from './case/decompile.js';
28
28
  // BPMN authoring API. `bpmn()` exposes only BPMN methods.
29
29
  export { bpmn } from './bpmn/bpmn-sdk.js';
30
+ export { PathBuilder, ActivityBuilder } from './bpmn/bpmn-sdk.js';
31
+ // The resolved wiring `bpmn check --graph` prints, for a tool that wants it as data.
32
+ export { renderGraph as renderBpmnGraph, graphModel as bpmnGraphModel } from './bpmn/graph.js';
30
33
  // The registry snapshot the typed nodes emit from — exposed so the coverage
31
34
  // ledger and its audit read the same source the emitter does. `isSnapshotType`
32
35
  // separates the two answers `registryType` now gives: a type the snapshot carries
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uipath/maestro-builder-sdk",
3
- "version": "6.11.6",
3
+ "version": "6.12.0",
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",
@@ -92,5 +92,5 @@
92
92
  "@types/node": "^22.7.0",
93
93
  "esbuild": "^0.28.1"
94
94
  },
95
- "gitref": "db117054e312c3c2aa7b7b208d3a92fc68de7fb9"
95
+ "gitref": "82b2ac95dd3b9af08b6a40f3421af49a5c95d7c8"
96
96
  }