@uipath/maestro-builder-sdk 6.53.0 → 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.
@@ -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.
@@ -1754,7 +1755,7 @@ const ERROR_OUTPUT_SCHEMA = {
1754
1755
  };
1755
1756
  function connectorOutputs(rc, elementId, resolver) {
1756
1757
  const responseSchema = rc.entry.outputSchema
1757
- ? schemaFromFields(rc.entry.outputSchema.fields ?? [])
1758
+ ? responseJsonSchema(rc.entry.outputSchema.fields ?? [])
1758
1759
  : { type: 'object', properties: {} };
1759
1760
  const responseVar = connectorOutputVar(resolver, 'response');
1760
1761
  const errorVar = connectorOutputVar(resolver, 'Error');
@@ -1771,29 +1772,6 @@ function connectorOutputs(rc, elementId, resolver) {
1771
1772
  },
1772
1773
  ];
1773
1774
  }
1774
- /** A minimal JSON-schema `{type:object, properties}` from library output fields. */
1775
- function schemaFromFields(fields) {
1776
- const properties = {};
1777
- for (const f of fields) {
1778
- const name = f?.name;
1779
- if (!name)
1780
- continue;
1781
- properties[name] = { title: f.displayName ?? name, type: jsonType(f.type) };
1782
- }
1783
- return { type: 'object', properties };
1784
- }
1785
- function jsonType(t) {
1786
- switch (String(t ?? '').toLowerCase()) {
1787
- case 'number':
1788
- case 'integer':
1789
- case 'float': return 'number';
1790
- case 'boolean':
1791
- case 'bool': return 'boolean';
1792
- case 'object': return 'object';
1793
- case 'array': return 'array';
1794
- default: return 'string';
1795
- }
1796
- }
1797
1775
  /** snake_case → camelCase (the caseplan camelCases declared param names). */
1798
1776
  function toCamel(s) {
1799
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.53.0",
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": "b271a259a3f380839348c118f296f9ec060f1598"
99
+ "gitref": "19cae12b584be7d3ae29f393942b36c474217a81"
100
100
  }