@uipath/maestro-builder-sdk 6.52.2 → 6.53.1

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.
@@ -381,8 +381,13 @@ export interface BuiltCaseExitCondition {
381
381
  rules: CaseRule[][];
382
382
  }
383
383
  export type TaskKind = 'process' | 'agent' | 'rpa' | 'api-workflow' | 'case-management' | 'flow-process' | 'function' | 'business-rule' | 'external-agent' | 'external-workflow' | 'action' | 'connector' | 'wait-for-timer' | 'wait-for-connector';
384
- /** Published-resource task kinds that the Case schema permits as unresolved skeletons. */
385
- export type UnresolvedReferenceTaskKind = 'process' | 'agent' | 'rpa' | 'api-workflow' | 'case-management' | 'function';
384
+ /**
385
+ * Task kinds that the Case schema permits as unresolved skeletons: the
386
+ * published-resource kinds, and `action` (a human task whose Action App or form
387
+ * is not known yet). Each compiles to a task whose `data` is `{}`, which
388
+ * `uip maestro case validate` reports as a `TASK_NOT_CONFIGURED` warning.
389
+ */
390
+ export type UnresolvedReferenceTaskKind = 'process' | 'agent' | 'rpa' | 'api-workflow' | 'case-management' | 'function' | 'action';
386
391
  /**
387
392
  * A `wait-for-connector` subscription: suspend on an Integration Service event.
388
393
  * Omit `connectorKey`/`operation` for a bare **placeholder** (for a connector not
@@ -853,15 +858,18 @@ declare class TaskBuilder {
853
858
  folder?: string;
854
859
  }): this;
855
860
  /**
856
- * Preserve an explicitly unresolved published-resource task as a typed
857
- * skeleton whose serialized `data` is `{}`.
861
+ * Preserve an explicitly unresolved task as a typed skeleton whose serialized
862
+ * `data` is `{}`.
858
863
  *
859
864
  * @remarks
860
865
  * Use this only when the requested resource identity cannot be resolved.
861
866
  * Do not invent a name or folder. An unresolved task cannot declare input or
862
867
  * output bindings because there is no referenced contract to bind against.
868
+ * `unresolved('action')` is the human-task skeleton: no Action App, title,
869
+ * recipient or form fields, for an app that is not published yet. Use
870
+ * `.action({ ... })` instead once the form is known.
863
871
  *
864
- * @param kind - The published-resource family to preserve.
872
+ * @param kind - The task kind to preserve: a published-resource family, or `'action'` for a human task.
865
873
  * @returns This builder, so calls chain.
866
874
  */
867
875
  unresolved(kind: UnresolvedReferenceTaskKind): this;
@@ -197,15 +197,18 @@ class TaskBuilder {
197
197
  return this.reference('process', name, opts);
198
198
  }
199
199
  /**
200
- * Preserve an explicitly unresolved published-resource task as a typed
201
- * skeleton whose serialized `data` is `{}`.
200
+ * Preserve an explicitly unresolved task as a typed skeleton whose serialized
201
+ * `data` is `{}`.
202
202
  *
203
203
  * @remarks
204
204
  * Use this only when the requested resource identity cannot be resolved.
205
205
  * Do not invent a name or folder. An unresolved task cannot declare input or
206
206
  * output bindings because there is no referenced contract to bind against.
207
+ * `unresolved('action')` is the human-task skeleton: no Action App, title,
208
+ * recipient or form fields, for an app that is not published yet. Use
209
+ * `.action({ ... })` instead once the form is known.
207
210
  *
208
- * @param kind - The published-resource family to preserve.
211
+ * @param kind - The task kind to preserve: a published-resource family, or `'action'` for a human task.
209
212
  * @returns This builder, so calls chain.
210
213
  */
211
214
  unresolved(kind) {
@@ -708,6 +708,11 @@ function emitTaskKind(task, refs, library) {
708
708
  if (isAuthorableBusinessRule(task))
709
709
  return businessRuleCall(task, refs);
710
710
  if (kind === 'action') {
711
+ // The skeleton human task (v1's placeholder, validate's TASK_NOT_CONFIGURED):
712
+ // nothing configured, so `.action({})` would recompile with a default
713
+ // `priority` the source never had.
714
+ if (Object.keys(data).length === 0)
715
+ return `.unresolved(${tsLiteral('action')})`;
711
716
  let recipient;
712
717
  if (data.recipient) {
713
718
  const type = Number(data.recipient.Type);
@@ -27,6 +27,7 @@ import { resolveSchemaVersion } from '../schema-version.js';
27
27
  import { caseJsonPreservation, caseJsonPreservationErrors, } from './preserve.js';
28
28
  import { businessEventProblems } from './business-event-shape.js';
29
29
  import { readEventFilter, eventFilterProblem, eventFilterTreeLeaf } from '../core/event-filters.js';
30
+ import { responseJsonSchema } from '../core/connector-response-schema.js';
30
31
  import { ruleShapeProblems } from './rule-options.js';
31
32
  /**
32
33
  * Condition `displayName` allocator.
@@ -962,6 +963,11 @@ function taskData(task, resolver, taskId, stageId, ids) {
962
963
  case 'business-rule':
963
964
  return businessRuleTaskData(task, resolver, `${stageId}-${taskId}`, ids);
964
965
  case 'action': {
966
+ // `.unresolved('action')`: the skeleton human task, `data: {}` like an
967
+ // unresolved resource task (validate warns TASK_NOT_CONFIGURED). `.action()`
968
+ // always sets `task.action`, so only the skeleton reaches here without one.
969
+ if (!task.action && !task.ref)
970
+ return {};
965
971
  const a = task.action ?? {};
966
972
  const data = {};
967
973
  if (a.title)
@@ -1749,7 +1755,7 @@ const ERROR_OUTPUT_SCHEMA = {
1749
1755
  };
1750
1756
  function connectorOutputs(rc, elementId, resolver) {
1751
1757
  const responseSchema = rc.entry.outputSchema
1752
- ? schemaFromFields(rc.entry.outputSchema.fields ?? [])
1758
+ ? responseJsonSchema(rc.entry.outputSchema.fields ?? [])
1753
1759
  : { type: 'object', properties: {} };
1754
1760
  const responseVar = connectorOutputVar(resolver, 'response');
1755
1761
  const errorVar = connectorOutputVar(resolver, 'Error');
@@ -1766,29 +1772,6 @@ function connectorOutputs(rc, elementId, resolver) {
1766
1772
  },
1767
1773
  ];
1768
1774
  }
1769
- /** A minimal JSON-schema `{type:object, properties}` from library output fields. */
1770
- function schemaFromFields(fields) {
1771
- const properties = {};
1772
- for (const f of fields) {
1773
- const name = f?.name;
1774
- if (!name)
1775
- continue;
1776
- properties[name] = { title: f.displayName ?? name, type: jsonType(f.type) };
1777
- }
1778
- return { type: 'object', properties };
1779
- }
1780
- function jsonType(t) {
1781
- switch (String(t ?? '').toLowerCase()) {
1782
- case 'number':
1783
- case 'integer':
1784
- case 'float': return 'number';
1785
- case 'boolean':
1786
- case 'bool': return 'boolean';
1787
- case 'object': return 'object';
1788
- case 'array': return 'array';
1789
- default: return 'string';
1790
- }
1791
- }
1792
1775
  /** snake_case → camelCase (the caseplan camelCases declared param names). */
1793
1776
  function toCamel(s) {
1794
1777
  return s.replace(/_([a-z0-9])/gi, (_m, c) => String(c).toUpperCase());
@@ -0,0 +1,54 @@
1
+ /**
2
+ * The JSON Schema of a connector activity's `response`, built from the
3
+ * library's flat output fields.
4
+ *
5
+ * The connector library lists an operation's output as flat leaf fields with
6
+ * dotted paths (`message.bot_profile.icons.image_36`, `blocks[*].text.type`);
7
+ * it carries no nested schema. Studio Web writes the response as a NESTED JSON
8
+ * Schema, with one `definitions` entry per object on a path and `$ref`s to them
9
+ * (`fieldsContainer.outputJsonSchema`, written into `output.body` by
10
+ * `getIntsvcOutputJsonSchema`), and `uip maestro case spec` returns the same
11
+ * shape. Writing each leaf as a top-level key instead gave Slack
12
+ * `send-message-to-channel` 102 dotted keys where the contract has 13 top-level
13
+ * properties (builder-sdk#1423).
14
+ *
15
+ * This is a port of the CLI's `buildResponseJsonSchema`
16
+ * (`UiPath/cli` `packages/maestro-sdk/src/connector-spec/connector-task-spec.ts`),
17
+ * which mirrors the Studio Web front end:
18
+ *
19
+ * - a one-segment field (`ts`) is a top-level property;
20
+ * - a one-segment array (`reply_users[*]`) is a top-level array of primitives;
21
+ * - a dotted path walks through definitions: `message.bot_profile.icons.x`
22
+ * makes property `message` → `$ref` `message`, whose property `bot_profile`
23
+ * → `$ref` `messageBot_profile`, whose property `icons` → `$ref`
24
+ * `messageBot_profileIcons`, which holds the leaf `x`;
25
+ * - an array segment (`attendees[*].…`) is an array whose `items` `$ref` the
26
+ * definition.
27
+ *
28
+ * A definition name is the first segment, then each deeper segment with its
29
+ * first letter upper-cased, concatenated (`[*]` and `_` kept). Leaf types are
30
+ * the library's own (`integer` stays `integer`), as the CLI and Studio Web
31
+ * write them.
32
+ */
33
+ /** One library output field: a dotted path, its type and its display name. */
34
+ export interface ResponseField {
35
+ name?: unknown;
36
+ type?: unknown;
37
+ displayName?: unknown;
38
+ }
39
+ /** The nested response schema: `type`, `properties` and `definitions` (no `$schema`; the caller adds it). */
40
+ export interface ResponseJsonSchema {
41
+ type: 'object';
42
+ properties: Record<string, unknown>;
43
+ definitions: Record<string, {
44
+ type: 'object';
45
+ properties: Record<string, unknown>;
46
+ }>;
47
+ }
48
+ /**
49
+ * Build the nested response schema from the library's flat output fields.
50
+ *
51
+ * @param fields - The operation's `outputSchema.fields`, in library order.
52
+ * @returns `{ type: 'object', properties, definitions }`.
53
+ */
54
+ export declare function responseJsonSchema(fields: readonly ResponseField[]): ResponseJsonSchema;
@@ -0,0 +1,107 @@
1
+ /**
2
+ * The JSON Schema of a connector activity's `response`, built from the
3
+ * library's flat output fields.
4
+ *
5
+ * The connector library lists an operation's output as flat leaf fields with
6
+ * dotted paths (`message.bot_profile.icons.image_36`, `blocks[*].text.type`);
7
+ * it carries no nested schema. Studio Web writes the response as a NESTED JSON
8
+ * Schema, with one `definitions` entry per object on a path and `$ref`s to them
9
+ * (`fieldsContainer.outputJsonSchema`, written into `output.body` by
10
+ * `getIntsvcOutputJsonSchema`), and `uip maestro case spec` returns the same
11
+ * shape. Writing each leaf as a top-level key instead gave Slack
12
+ * `send-message-to-channel` 102 dotted keys where the contract has 13 top-level
13
+ * properties (builder-sdk#1423).
14
+ *
15
+ * This is a port of the CLI's `buildResponseJsonSchema`
16
+ * (`UiPath/cli` `packages/maestro-sdk/src/connector-spec/connector-task-spec.ts`),
17
+ * which mirrors the Studio Web front end:
18
+ *
19
+ * - a one-segment field (`ts`) is a top-level property;
20
+ * - a one-segment array (`reply_users[*]`) is a top-level array of primitives;
21
+ * - a dotted path walks through definitions: `message.bot_profile.icons.x`
22
+ * makes property `message` → `$ref` `message`, whose property `bot_profile`
23
+ * → `$ref` `messageBot_profile`, whose property `icons` → `$ref`
24
+ * `messageBot_profileIcons`, which holds the leaf `x`;
25
+ * - an array segment (`attendees[*].…`) is an array whose `items` `$ref` the
26
+ * definition.
27
+ *
28
+ * A definition name is the first segment, then each deeper segment with its
29
+ * first letter upper-cased, concatenated (`[*]` and `_` kept). Leaf types are
30
+ * the library's own (`integer` stays `integer`), as the CLI and Studio Web
31
+ * write them.
32
+ */
33
+ /**
34
+ * Build the nested response schema from the library's flat output fields.
35
+ *
36
+ * @param fields - The operation's `outputSchema.fields`, in library order.
37
+ * @returns `{ type: 'object', properties, definitions }`.
38
+ */
39
+ export function responseJsonSchema(fields) {
40
+ const properties = {};
41
+ const definitions = {};
42
+ for (const field of fields) {
43
+ if (typeof field?.name !== 'string' || !field.name)
44
+ continue;
45
+ insertField(field.name, field, properties, definitions);
46
+ }
47
+ return { type: 'object', properties, definitions };
48
+ }
49
+ function insertField(path, field, properties, definitions) {
50
+ const segments = path.split('.');
51
+ let current = properties;
52
+ let defName = '';
53
+ for (let i = 0; i < segments.length - 1; i++) {
54
+ const segment = segments[i];
55
+ defName = i === 0 ? segment : defName + capitalize(segment);
56
+ // Own-key test: a definition named like an Object.prototype member
57
+ // (`constructor`) must not read the prototype's.
58
+ if (!Object.prototype.hasOwnProperty.call(definitions, defName)) {
59
+ definitions[defName] = { type: 'object', properties: {} };
60
+ current[segment] = refTo(segment, defName);
61
+ }
62
+ current = definitions[defName].properties;
63
+ }
64
+ const leaf = segments[segments.length - 1];
65
+ current[leaf] = leafSchema(leaf, field);
66
+ }
67
+ function leafSchema(segment, field) {
68
+ const title = typeof field.displayName === 'string' ? field.displayName : humanize(segment);
69
+ const type = schemaType(field.type);
70
+ // An array of primitives: `reply_users[*]` at the leaf.
71
+ if (segment.endsWith('[*]'))
72
+ return { title, type: 'array', items: { type } };
73
+ return { title, type };
74
+ }
75
+ /**
76
+ * A library field type as a JSON Schema type. The library's types are JSON
77
+ * Schema's own (`string`, `integer`, `object`, …) except `octet-stream`, which
78
+ * 77 file-download fields carry (ServiceNow `download-attachment`
79
+ * `fileDownload`). That is not a schema type, so it is written `string`, as the
80
+ * old flat builder wrote it. The CLI never meets it: it gives a file response
81
+ * its own file schema before this builder runs.
82
+ */
83
+ function schemaType(type) {
84
+ return type === 'octet-stream' ? 'string' : type;
85
+ }
86
+ function refTo(segment, defName) {
87
+ // An array of objects: `attendees[*].…` is an array whose items `$ref` the definition.
88
+ if (segment.endsWith('[*]'))
89
+ return { title: humanize(segment), type: 'array', items: { $ref: `#/definitions/${defName}` } };
90
+ return { title: humanize(segment), $ref: `#/definitions/${defName}` };
91
+ }
92
+ /** Upper-case the first letter, for definition-name compounding (`[*]` kept). */
93
+ function capitalize(segment) {
94
+ return segment ? segment.charAt(0).toUpperCase() + segment.slice(1) : segment;
95
+ }
96
+ /**
97
+ * The front end's title for an intermediate segment: `[*]` dropped, camelCase
98
+ * split into words, sentence case (`emailAddress` → `Email address`,
99
+ * `bot_profile` → `Bot_profile`).
100
+ */
101
+ function humanize(segment) {
102
+ const clean = segment.replace(/\[\*\]/g, '');
103
+ if (!clean)
104
+ return '';
105
+ const spaced = clean.replace(/([A-Z])/g, ' $1').toLowerCase().trim();
106
+ return spaced.charAt(0).toUpperCase() + spaced.slice(1);
107
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uipath/maestro-builder-sdk",
3
- "version": "6.52.2",
3
+ "version": "6.53.1",
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",
@@ -96,5 +96,5 @@
96
96
  "@types/node": "^22.7.0",
97
97
  "esbuild": "^0.28.1"
98
98
  },
99
- "gitref": "410164517bc2552666c867e9107b2cbb57acd083"
99
+ "gitref": "19cae12b584be7d3ae29f393942b36c474217a81"
100
100
  }