@uipath/maestro-builder-sdk 6.18.1 → 6.18.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.
@@ -9,7 +9,7 @@
9
9
  */
10
10
  import type { BuiltCase } from './case-sdk.js';
11
11
  import { type ConnectorCheckOpts } from '../core/connector-checks.js';
12
- import type { EventCheckOpts } from '../core/event-checks.js';
12
+ import type { EventSubscription } from '../core/actions.js';
13
13
  export interface Diagnostic {
14
14
  level: 'error' | 'warning';
15
15
  code: string;
@@ -31,7 +31,18 @@ export interface Diagnostic {
31
31
  * Every hook fails open: without a library, `check` stays a pure function of the
32
32
  * built model.
33
33
  */
34
- export type CaseCheckOpts = Pick<ConnectorCheckOpts, 'connectorResolveError' | 'schemaReadiness'> & Pick<EventCheckOpts, 'eventResolveError'>;
34
+ export type CaseCheckOpts = Pick<ConnectorCheckOpts, 'connectorResolveError' | 'schemaReadiness'> & {
35
+ /**
36
+ * What Case `compile` would refuse an event subscription with, or `undefined`
37
+ * when it resolves: `EVENT_UNKNOWN` (the event is not in the library, or
38
+ * refuses the `object`) or `EVENT_GENERIC_NO_OBJECT` (a GENERIC event with no
39
+ * `object`). Built on `resolveCaseSubscription`, the call compile makes.
40
+ */
41
+ subscriptionError?: (kind: 'trigger' | 'event', subscription: EventSubscription) => {
42
+ code: string;
43
+ message: string;
44
+ } | undefined;
45
+ };
35
46
  /**
36
47
  * Validate a built case.
37
48
  *
@@ -271,7 +271,8 @@ export function check(built, opts = {}) {
271
271
  * their operation (`library.resolve`): CONNECTOR_NOT_IN_LIBRARY,
272
272
  * CONNECTOR_OBJECT_REQUIRED, CONNECTOR_OBJECT_NOT_GENERIC;
273
273
  * - an event trigger, a wait-for-connector task and a wait-for-connector rule
274
- * resolve their subscription (`library.resolveEvent`): EVENT_UNKNOWN.
274
+ * resolve their subscription (`resolveCaseSubscription`): EVENT_UNKNOWN,
275
+ * EVENT_GENERIC_NO_OBJECT.
275
276
  *
276
277
  * A connector task also gets the schema-readiness warnings, because the
277
278
  * `connectors-local` overlay `registry prepare` writes is what Case compile
@@ -282,16 +283,11 @@ function checkLibraryConnectors(built, opts, diags) {
282
283
  diags.push({ level: d.level, code: d.code, message: d.message, where: at, ...(d.suggestion ? { suggestion: d.suggestion } : {}) });
283
284
  };
284
285
  const subscription = (kind, sub, where, at) => {
285
- // Exactly the arguments `resolvedSubscriptionBag` passes to `resolveEvent`.
286
- // It passes no `object` (a Case compile gap, tracked separately), so neither
287
- // does this: check must refuse what compile refuses, no more.
288
- const unresolved = opts.eventResolveError?.(kind, {
289
- connector: sub.connector,
290
- event: sub.event,
291
- ...(sub.version !== undefined ? { version: sub.version } : {}),
292
- });
293
- if (unresolved !== undefined)
294
- diags.push({ level: 'error', code: 'EVENT_UNKNOWN', message: `${where}: ${unresolved}`, where: at });
286
+ // The call `resolvedSubscriptionBag` makes (`resolveCaseSubscription`), so
287
+ // check refuses exactly what compile refuses, with the same text.
288
+ const refused = opts.subscriptionError?.(kind, sub);
289
+ if (refused !== undefined)
290
+ diags.push({ level: 'error', code: refused.code, message: `${where}: ${refused.message}`, where: at });
295
291
  };
296
292
  const rules = (conditions, where) => {
297
293
  for (const c of conditions)
@@ -4,7 +4,8 @@ import type { CaseCheckOpts } from './check.js';
4
4
  * Case's check options from a library the CLI already opened, or `{}` without one.
5
5
  *
6
6
  * Only the hooks for refusals Case `compile` makes (see {@link CaseCheckOpts}):
7
- * the operation and event resolution, and the schema-readiness warnings. The
7
+ * the operation and event resolution (the event through `resolveCaseSubscription`,
8
+ * compile's own call), and the schema-readiness warnings. The
8
9
  * field-contract, binding-label and BYOA hooks of the shared bag are left out,
9
10
  * because Case `serialize` does not enforce them.
10
11
  *
@@ -8,11 +8,13 @@
8
8
  * both `case check` and `case compile`'s check pass call.
9
9
  */
10
10
  import { connectorCheckOpts } from '../core/cli-library.js';
11
+ import { EVENT_GENERIC_NO_OBJECT, GenericEventNoObjectError, resolveCaseSubscription } from './subscription.js';
11
12
  /**
12
13
  * Case's check options from a library the CLI already opened, or `{}` without one.
13
14
  *
14
15
  * Only the hooks for refusals Case `compile` makes (see {@link CaseCheckOpts}):
15
- * the operation and event resolution, and the schema-readiness warnings. The
16
+ * the operation and event resolution (the event through `resolveCaseSubscription`,
17
+ * compile's own call), and the schema-readiness warnings. The
16
18
  * field-contract, binding-label and BYOA hooks of the shared bag are left out,
17
19
  * because Case `serialize` does not enforce them.
18
20
  *
@@ -26,6 +28,17 @@ export function caseCheckOpts(library) {
26
28
  return {
27
29
  connectorResolveError: shared.connectorResolveError,
28
30
  schemaReadiness: shared.schemaReadiness,
29
- eventResolveError: shared.eventResolveError,
31
+ subscriptionError: (kind, sub) => {
32
+ try {
33
+ resolveCaseSubscription(library, kind, sub);
34
+ return undefined;
35
+ }
36
+ catch (error) {
37
+ return {
38
+ code: error instanceof GenericEventNoObjectError ? EVENT_GENERIC_NO_OBJECT : 'EVENT_UNKNOWN',
39
+ message: error instanceof Error ? error.message : String(error),
40
+ };
41
+ }
42
+ },
30
43
  };
31
44
  }
@@ -190,6 +190,8 @@ function resolvedSubscriptionSource(bag, owner, kind, refs) {
190
190
  return opts([
191
191
  ['connector', tsLiteral(identity.key)],
192
192
  ['event', tsLiteral(identity.event)],
193
+ // A GENERIC event's object is the author's choice, so it comes back as `object`.
194
+ ['object', identity.object !== undefined ? tsLiteral(identity.object) : undefined],
193
195
  ['where', where !== undefined ? tsLiteral(where) : undefined],
194
196
  ['filters', filters !== undefined ? tsLiteral(filters) : undefined],
195
197
  ['connection', connection !== undefined ? tsLiteral(connection) : undefined],
@@ -11,6 +11,7 @@
11
11
  import { IdGen } from './ids.js';
12
12
  import { transportHttpMethod } from '../core/connector-inputs.js';
13
13
  import { refuseLookupToken } from '../core/lookups.js';
14
+ import { resolveCaseSubscription } from './subscription.js';
14
15
  import { CASE_FORMAT_PROFILE, CASE_SCHEMA_VERSIONS } from './format-profile.js';
15
16
  import { resolveSchemaVersion } from '../schema-version.js';
16
17
  import { caseJsonPreservation, caseJsonPreservationErrors, } from './preserve.js';
@@ -885,7 +886,7 @@ function resolvedSubscriptionBag(kind, spec, resolver, elementId) {
885
886
  if (!resolver.library)
886
887
  throw new Error(`${kind === 'trigger' ? 'event trigger' : 'wait-for-connector'} needs the connector library — `
887
888
  + `pass { library } to serialize or use uip maestro case compile --library.`);
888
- const rc = resolver.library.resolveEvent(kind, spec.connector, spec.event, spec.version);
889
+ const rc = resolveCaseSubscription(resolver.library, kind, spec);
889
890
  const op = rc.entry.operation ?? {};
890
891
  const context = [io('connectorKey', 'string', { value: rc.connectorKey })];
891
892
  const connection = bindingRef(resolver, spec.connection, 'Connection', 'ConnectionId', `${rc.connectorKey} connection`);
@@ -0,0 +1,30 @@
1
+ /**
2
+ * case/subscription — how Case resolves a connector event subscription against
3
+ * the library, shared by `serialize` (which throws) and `check` (which reports).
4
+ *
5
+ * One function, so the two cannot drift: the event trigger, the
6
+ * wait-for-connector task and the wait-for-connector rule all resolve here, with
7
+ * the author's `object` (#1033), and a GENERIC event that names no object is
8
+ * refused here with the text Flow's compile uses too
9
+ * (`genericEventObjectRefusal`).
10
+ */
11
+ import type { EventSubscription } from '../core/actions.js';
12
+ import type { Library, ResolvedConnector } from '../core/library.js';
13
+ /** Check's code for {@link GenericEventNoObjectError}; Flow and BPMN `check` use the same one. */
14
+ export declare const EVENT_GENERIC_NO_OBJECT = "EVENT_GENERIC_NO_OBJECT";
15
+ /** A GENERIC event subscription that names no object. */
16
+ export declare class GenericEventNoObjectError extends Error {
17
+ readonly code = "EVENT_GENERIC_NO_OBJECT";
18
+ }
19
+ /**
20
+ * Resolve a Case event subscription: `library.resolveEvent` with the
21
+ * subscription's own `version` and `object`, then refuse a GENERIC event the
22
+ * author named no object for.
23
+ *
24
+ * @param library - The connector library.
25
+ * @param kind - `trigger` for an event trigger, `event` for a wait-for-connector task or rule.
26
+ * @param sub - The authored subscription.
27
+ * @returns The resolved event.
28
+ * @throws What `resolveEvent` throws, or {@link GenericEventNoObjectError}.
29
+ */
30
+ export declare function resolveCaseSubscription(library: Library, kind: 'trigger' | 'event', sub: EventSubscription): ResolvedConnector;
@@ -0,0 +1,29 @@
1
+ import { genericEventObjectRefusal } from '../core/event-checks.js';
2
+ /** Check's code for {@link GenericEventNoObjectError}; Flow and BPMN `check` use the same one. */
3
+ export const EVENT_GENERIC_NO_OBJECT = 'EVENT_GENERIC_NO_OBJECT';
4
+ /** A GENERIC event subscription that names no object. */
5
+ export class GenericEventNoObjectError extends Error {
6
+ code = EVENT_GENERIC_NO_OBJECT;
7
+ }
8
+ /** How a Case subscription spells the `object` of a GENERIC event, for the refusal text. */
9
+ function caseObjectOption(object) {
10
+ return `{ connector, event, object: '${object}', … } in the subscription`;
11
+ }
12
+ /**
13
+ * Resolve a Case event subscription: `library.resolveEvent` with the
14
+ * subscription's own `version` and `object`, then refuse a GENERIC event the
15
+ * author named no object for.
16
+ *
17
+ * @param library - The connector library.
18
+ * @param kind - `trigger` for an event trigger, `event` for a wait-for-connector task or rule.
19
+ * @param sub - The authored subscription.
20
+ * @returns The resolved event.
21
+ * @throws What `resolveEvent` throws, or {@link GenericEventNoObjectError}.
22
+ */
23
+ export function resolveCaseSubscription(library, kind, sub) {
24
+ const rc = library.resolveEvent(kind, sub.connector, sub.event, sub.version, sub.object);
25
+ const noObject = genericEventObjectRefusal(rc, sub, caseObjectOption);
26
+ if (noObject)
27
+ throw new GenericEventNoObjectError(noObject);
28
+ return rc;
29
+ }
@@ -136,4 +136,35 @@ export declare function eventParamsFor(subscription: unknown, opts: EventCheckOp
136
136
  * under the event-form node type — the form `prepare` stores.
137
137
  */
138
138
  export declare function checkEventResolution(subscription: unknown, where: string, kind: 'trigger' | 'event', opts: EventCheckOpts, error: (code: string, message: string, suggestion?: string) => void, warn: (code: string, message: string, suggestion?: string) => void, eventParams?: EventParamFields): void;
139
+ /**
140
+ * The compile-time refusal of a GENERIC event subscription that names no object,
141
+ * or `undefined` when the resolved event is fine.
142
+ *
143
+ * A GENERIC event (`activityType: GenericTrigger` — Data Fabric, Salesforce,
144
+ * ServiceNow, Jira, … `record-created`/`record-updated`) fires for ONE object of
145
+ * the connection, and its library entry names none: the author's `object` is the
146
+ * only source. `Library.resolveEvent` stamps that object into the resolved
147
+ * operation's `objectName`; without it the operation's `objectName` stays `''`,
148
+ * and a node built from it validates and is refused by the platform's dispatcher
149
+ * ("missing objectName"), or watches nothing.
150
+ *
151
+ * Every family's serializer that emits a connector event calls this on the
152
+ * connector `resolveEvent` returned, so the refusal has one text. Case `check`
153
+ * calls it on the same resolution, so it reports exactly what Case `compile`
154
+ * throws.
155
+ *
156
+ * @param rc - What `library.resolveEvent(kind, connector, event, version, object)` returned.
157
+ * @param sub - The authored subscription (only `where` is read, for the hint).
158
+ * @param objectOption - How this family spells the `object` option, given the object.
159
+ * @returns The refusal message (no site prefix), or `undefined`.
160
+ */
161
+ export declare function genericEventObjectRefusal(rc: {
162
+ nodeType: string;
163
+ connectorKey: string;
164
+ entry?: {
165
+ operation?: Record<string, unknown>;
166
+ };
167
+ }, sub: {
168
+ where?: unknown;
169
+ }, objectOption: (object: string) => string): string | undefined;
139
170
  export declare function checkEventSubscription(subscription: unknown, where: string, at: (code: string, message: string, suggestion?: string) => void, warn?: (code: string, message: string, suggestion?: string) => void, eventParams?: EventParamFields): void;
@@ -204,6 +204,44 @@ export function checkEventResolution(subscription, where, kind, opts, error, war
204
204
  });
205
205
  }
206
206
  }
207
+ /**
208
+ * The compile-time refusal of a GENERIC event subscription that names no object,
209
+ * or `undefined` when the resolved event is fine.
210
+ *
211
+ * A GENERIC event (`activityType: GenericTrigger` — Data Fabric, Salesforce,
212
+ * ServiceNow, Jira, … `record-created`/`record-updated`) fires for ONE object of
213
+ * the connection, and its library entry names none: the author's `object` is the
214
+ * only source. `Library.resolveEvent` stamps that object into the resolved
215
+ * operation's `objectName`; without it the operation's `objectName` stays `''`,
216
+ * and a node built from it validates and is refused by the platform's dispatcher
217
+ * ("missing objectName"), or watches nothing.
218
+ *
219
+ * Every family's serializer that emits a connector event calls this on the
220
+ * connector `resolveEvent` returned, so the refusal has one text. Case `check`
221
+ * calls it on the same resolution, so it reports exactly what Case `compile`
222
+ * throws.
223
+ *
224
+ * @param rc - What `library.resolveEvent(kind, connector, event, version, object)` returned.
225
+ * @param sub - The authored subscription (only `where` is read, for the hint).
226
+ * @param objectOption - How this family spells the `object` option, given the object.
227
+ * @returns The refusal message (no site prefix), or `undefined`.
228
+ */
229
+ export function genericEventObjectRefusal(rc, sub, objectOption) {
230
+ const op = (rc.entry?.operation ?? {});
231
+ if (op.activityType !== 'GenericTrigger' || String(op.objectName ?? '') !== '')
232
+ return undefined;
233
+ const scopeObject = sub.where && typeof sub.where === 'object'
234
+ ? Object.entries(sub.where)
235
+ .find(([k]) => /^(objectName|entityName|object)$/i.test(k))?.[1]
236
+ : undefined;
237
+ return `${rc.nodeType} is a GENERIC event — it watches ONE object of the connection `
238
+ + `(an entity, a table, a custom object) and its library entry carries no default. Name it with the `
239
+ + `\`object\` option: ${objectOption(scopeObject !== undefined ? String(scopeObject) : '<Object>')}. `
240
+ + (scopeObject !== undefined
241
+ ? `\`where: { objectName }\` is not it — \`where\` holds event PARAMETERS, and this operation has none. `
242
+ : '')
243
+ + `\`uip is triggers objects ${rc.connectorKey} ${String(op.eventOperation ?? '<EVENT>')} --connection-id <id>\` lists the objects.`;
244
+ }
207
245
  export function checkEventSubscription(subscription, where, at, warn, eventParams) {
208
246
  const sub = subscription;
209
247
  if (!sub || typeof sub !== 'object') {
package/dist/serialize.js CHANGED
@@ -20,6 +20,7 @@ import { isAnswerField } from './core/hitl-answers.js';
20
20
  import { connectionConnectors } from './bindings-v2.js';
21
21
  import { BindingRefusal, GUID_RE, bindingMissingMessage, bindingSelfNameMessage, bindingUndeclaredMessage, missingBindingLabels, undeclaredBinding } from './core/binding-messages.js';
22
22
  import { ByoaRefusal, byoaUnverified } from './core/byoa.js';
23
+ import { genericEventObjectRefusal } from './core/event-checks.js';
23
24
  import { OUTCOME_HANDLE_NODE_TYPES, assertHitlExitInvariant, hitlExitModel, hitlExitViolation, outcomeSlug } from './core/hitl-routing.js';
24
25
  import { declaredExits, hasExits } from './core/step-ports.js';
25
26
  import { stopsAtEnd } from './flow-step-tree.js';
@@ -4115,25 +4116,13 @@ function eventDetail(rc, sub, nodeId, opts, site) {
4115
4116
  const folder = resolveBinding(opts, sub.folder, 'folder', `event node "${nodeId}"`, eventTarget(sub));
4116
4117
  const op = (rc.entry?.operation ?? {});
4117
4118
  const filters = sub.filters ?? [];
4118
- // A GENERIC event (`activityType: GenericTrigger` — Data Fabric, Salesforce,
4119
- // ServiceNow, Jira, … `record-created`/`record-updated`) fires for ONE object of
4120
- // the connection, and the library entry names none: the author's `object` is
4121
- // the only source. Without it the node would carry `objectName: ""` — it
4122
- // validates, and the platform's dispatcher refuses it ("missing objectName") or
4123
- // the designer shows a trigger bound to nothing. Refused here, at the layer
4124
- // that would otherwise emit it.
4119
+ // A GENERIC event with no `object` would carry `objectName: ""`: it validates
4120
+ // and the platform's dispatcher refuses it. Refused here, at the layer that
4121
+ // would otherwise emit it, with the text every family's compile shares.
4125
4122
  const objectName = String(op.objectName ?? '');
4126
- if (op.activityType === 'GenericTrigger' && objectName === '') {
4127
- const scopeObject = Object.entries(sub.where ?? {})
4128
- .find(([k]) => /^(objectName|entityName|object)$/i.test(k))?.[1];
4129
- throw new Error(`event node "${nodeId}": ${rc.nodeType} is a GENERIC event — it watches ONE object of the connection `
4130
- + `(an entity, a table, a custom object) and its library entry carries no default. Name it with the `
4131
- + `\`object\` option: onEvent(…, { object: '${scopeObject ?? '<Object>'}' }). `
4132
- + (scopeObject !== undefined
4133
- ? `\`where: { objectName }\` is not it — \`where\` holds event PARAMETERS, and this operation has none. `
4134
- : '')
4135
- + `\`uip is triggers objects ${rc.connectorKey} ${String(op.eventOperation ?? '<EVENT>')} --connection-id <id>\` lists the objects.`);
4136
- }
4123
+ const noObject = genericEventObjectRefusal(rc, sub, (o) => `onEvent(…, { object: '${o}' })`);
4124
+ if (noObject)
4125
+ throw new Error(`event node "${nodeId}": ${noObject}`);
4137
4126
  // An unresolved `where` lookup is swapped for its recorded id — the id
4138
4127
  // `prepare --resolve` stored under the EVENT-form node type — or refused.
4139
4128
  // Same rule as connector inputs: emitting a placeholder for a value nobody
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uipath/maestro-builder-sdk",
3
- "version": "6.18.1",
3
+ "version": "6.18.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",
@@ -92,5 +92,5 @@
92
92
  "@types/node": "^22.7.0",
93
93
  "esbuild": "^0.28.1"
94
94
  },
95
- "gitref": "6598e64a2bc931298fcb9938dc4868d5760243e6"
95
+ "gitref": "a1a9df938c60a4e31cc9025ec9664d34f41aa799"
96
96
  }