@uipath/maestro-builder-sdk 6.70.8 → 6.71.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.
@@ -0,0 +1,33 @@
1
+ /**
2
+ * A mid-flow wait for an Integration Service event — `waitForEvent(subscription)`,
3
+ * a node type per event: `uipath.connector.event.<connectorKey>.<event>`. The
4
+ * type owns every name under `uipath.connector.event.` that names an event,
5
+ * nested inside the connector operations' `uipath.connector.` prefix, whose
6
+ * narrowing leaves it alone. Per-tenant: the definition is the library's event
7
+ * entry, and so is its version (`versionedByDefinition`).
8
+ *
9
+ * The same node type opens a flow as its start trigger (`onEvent`). That place
10
+ * stays the pipeline's until the triggers port: serialize places the trigger, and
11
+ * decompile reads a root `uipath.connector.event.*` node as one. This type is the
12
+ * node as a step, with an incoming edge.
13
+ *
14
+ * The subscription's emission — `inputs.detail`, the library's resolution, the
15
+ * refusals compile makes with and without a library — is shared with the trigger,
16
+ * so it stays in `core/event-subscription.ts` and is called here through
17
+ * `ctx.events`; the subscription's check rules stay in `core/event-checks.ts` and
18
+ * run through `ctx.eventSubscription`, with their codes.
19
+ *
20
+ * Moved from serialize.ts / check.ts / decompile.ts in Phase 4 of
21
+ * docs/NODE_TYPE_ARCHITECTURE_DESIGN.md.
22
+ */
23
+ import type { ActionSpec } from '../../../core/actions.js';
24
+ import type { FlowVersionedNodeType } from '../../../flow-node-type.js';
25
+ export type EventWaitSpec = Extract<ActionSpec, {
26
+ kind: 'waitEvent';
27
+ }>;
28
+ /** `<connector>.<event>` after the prefix, split on the last dot; undefined for a name with no event. */
29
+ export declare function splitEvent(typeName: string): {
30
+ connector: string;
31
+ event: string;
32
+ } | undefined;
33
+ export declare const eventWaitNodeType: FlowVersionedNodeType<EventWaitSpec>;
@@ -0,0 +1,162 @@
1
+ import { missingBindingLabels } from '../../../core/binding-messages.js';
2
+ import { prepareCommand } from '../../../core/cli-spelling.js';
3
+ import { commentText } from '../../../core/comment-text.js';
4
+ import { eventFilterFromTreeLeaf } from '../../../core/event-filters.js';
5
+ import { eventDetail, eventTarget, libraryRequiredForEvent, refuseUnverifiedByoa, resolveEvent } from '../../../core/event-subscription.js';
6
+ import { Expr } from '../../../core/expr.js';
7
+ import { tsLiteral, tsObject, tsOptions } from '../../../core/ts-literal.js';
8
+ const EVENT_PREFIX = 'uipath.connector.event.';
9
+ /** `<connector>.<event>` after the prefix, split on the last dot; undefined for a name with no event. */
10
+ export function splitEvent(typeName) {
11
+ if (!typeName.startsWith(EVENT_PREFIX))
12
+ return undefined;
13
+ const rest = typeName.slice(EVENT_PREFIX.length);
14
+ const dot = rest.lastIndexOf('.');
15
+ if (dot <= 0)
16
+ return undefined;
17
+ return { connector: rest.slice(0, dot), event: rest.slice(dot + 1) };
18
+ }
19
+ function serializeEventWait(spec, ctx) {
20
+ const sub = spec.subscription;
21
+ const site = `waitForEvent "${ctx.step}"`;
22
+ if (!ctx.library)
23
+ throw libraryRequiredForEvent(ctx.events, sub, ctx.nodeId, site, site);
24
+ const rc = resolveEvent(ctx.library, 'event', sub, site);
25
+ refuseUnverifiedByoa(ctx.events, site, sub);
26
+ const detail = eventDetail(rc, sub, ctx.nodeId, ctx.events, site);
27
+ // The platform reaches the connection through the flow's `bindings[]`, as for
28
+ // a connector operation (board G-19). `eventDetail` refused a node without
29
+ // both labels, so both resolve here.
30
+ const target = eventTarget(sub);
31
+ const connectionId = ctx.resolveBinding(sub.connection, 'connection', site, target);
32
+ const folderKey = ctx.resolveBinding(sub.folder, 'folder', site, target);
33
+ ctx.bindConnection({
34
+ model: rc.v1def?.model,
35
+ connectorKey: rc.connectorKey, connectionId: connectionId,
36
+ ...(folderKey !== undefined ? { folderKey } : {}),
37
+ });
38
+ // The node is the event the author named (`rc.nodeType`); a definition naming
39
+ // another is written under that name, so the node and its definitions[] entry agree.
40
+ const v1def = rc.v1def;
41
+ const def = v1def.nodeType === rc.nodeType ? v1def : { ...v1def, nodeType: rc.nodeType };
42
+ return {
43
+ definition: { source: 'snapshot', nodeType: def.nodeType, version: def.version, manifest: def },
44
+ inputs: { detail },
45
+ // A wait continues on `output`, as every connector node does.
46
+ port: 'output',
47
+ };
48
+ }
49
+ /** A `where` value as decompile reads it: an expression back to an `Expr`, wire text as text, any other JSON as is. */
50
+ function liftValue(v, ctx) {
51
+ const raw = Array.isArray(v) ? undefined : ctx.sourceText(v);
52
+ if (raw === undefined)
53
+ return v;
54
+ return raw.startsWith('=js:') ? new Expr(raw.slice(4)) : raw;
55
+ }
56
+ /**
57
+ * The subscription back from the node: the `where` scope from
58
+ * `detail.eventParameters`, which carries it verbatim, and the filters from the
59
+ * filter tree inside `detail.configuration`. Both are also encoded into the
60
+ * generated `filterExpression`, but reading the structured copies avoids parsing
61
+ * a string compile generated.
62
+ */
63
+ function liftEventWait(node, ctx) {
64
+ const n = node;
65
+ const split = splitEvent(n.type);
66
+ if (!split)
67
+ return undefined;
68
+ const detail = (n.inputs?.detail ?? undefined);
69
+ const where = Object.entries((detail?.eventParameters ?? {}))
70
+ .filter(([, v]) => v !== undefined && v !== null && String(v) !== '')
71
+ .map(([k, v]) => [k, liftValue(v, ctx)]);
72
+ // The filter tree lives inside the `=jsonString:` configuration blob, and so
73
+ // does the one fact that says whether `detail.objectName` was the AUTHOR's
74
+ // choice: a GENERIC event (`activityType: GenericTrigger`) carries the object
75
+ // the author named, a curated one carries its built-in object.
76
+ let filters = [];
77
+ let generic = false;
78
+ const config = detail?.configuration;
79
+ if (typeof config === 'string' && config.startsWith('=jsonString:')) {
80
+ try {
81
+ const parsed = JSON.parse(config.slice('=jsonString:'.length));
82
+ generic = parsed?.essentialConfiguration?.instanceParameters?.activityType === 'GenericTrigger';
83
+ const rows = (parsed?.essentialConfiguration?.filter?.filters ?? []);
84
+ filters = rows
85
+ .map((f) => eventFilterFromTreeLeaf(f))
86
+ .filter((f) => f !== undefined);
87
+ }
88
+ catch {
89
+ // A hand-edited blob is not ours to guess at — the scope and identity
90
+ // still recover, and the filters simply do not come back.
91
+ filters = [];
92
+ }
93
+ }
94
+ const object = generic && typeof detail?.objectName === 'string' && detail.objectName !== ''
95
+ ? detail.objectName
96
+ : undefined;
97
+ const connection = typeof detail?.connectionId === 'string' ? detail.connectionId : undefined;
98
+ const folder = typeof detail?.connectionFolderKey === 'string' ? detail.connectionFolderKey : undefined;
99
+ // A connection the file never picked (`connectionId: null`): the source cannot
100
+ // invent labels for it, and compile and check refuse a node without both
101
+ // (BINDING_MISSING, flow-builder-sdk#890), so the source says so at the node
102
+ // and the run warns once.
103
+ const missing = missingBindingLabels({ connection, folder });
104
+ if (missing.length > 0) {
105
+ ctx.warn(`node ${tsLiteral(n.id)} (${n.type}) has no ${missing.join(' or ')} in the .flow (an unbound draft). `
106
+ + `The source leaves ${missing.length > 1 ? 'them' : 'it'} out, and compile and check refuse it (BINDING_MISSING) `
107
+ + `until it names both labels: run \`${prepareCommand(split.connector, split.event)}\`, then pass `
108
+ + `\`connection\` and \`folder\`.`);
109
+ }
110
+ return { kind: 'waitEvent', ...split, where, object, filters, connection, folder, missing };
111
+ }
112
+ /**
113
+ * `waitForEvent({ … })`, the stringly form: the subscription as one object. The
114
+ * unbound marker sits inside the call, after the object, where the lift has
115
+ * always put it.
116
+ */
117
+ function printEventWait(l, ctx) {
118
+ const value = (v) => (v instanceof Expr ? ctx.value(v) : ctx.json(v));
119
+ const filters = l.filters.map((f) => tsOptions([
120
+ ['field', tsLiteral(f.field)],
121
+ [f.operator, typeof f.value === 'string' ? tsLiteral(f.value) : JSON.stringify(f.value)],
122
+ ]));
123
+ const subscription = tsOptions([
124
+ ['connector', tsLiteral(l.connector)],
125
+ ['event', tsLiteral(l.event)],
126
+ ['where', l.where.length ? tsObject(l.where.map(([k, v]) => [k, value(v)])) : undefined],
127
+ ['object', l.object !== undefined ? tsLiteral(l.object) : undefined],
128
+ ['filters', filters.length ? `[${filters.join(', ')}]` : undefined],
129
+ ['connection', l.connection !== undefined ? tsLiteral(l.connection) : undefined],
130
+ ['folder', l.folder !== undefined ? tsLiteral(l.folder) : undefined],
131
+ ]);
132
+ const marker = l.missing.length > 0
133
+ ? ` /* TODO: bind ${commentText(l.missing.join(' and '))}; check refuses this node until it has both labels (BINDING_MISSING) */`
134
+ : '';
135
+ return { factory: 'waitForEvent', positional: [subscription + marker] };
136
+ }
137
+ const eventWait10 = {
138
+ kind: 'waitEvent', typeName: `${EVENT_PREFIX}*`, version: '1.0.0', factory: 'waitForEvent',
139
+ definition: 'per-tenant',
140
+ // An event wait resumes or it does not: it has no error port to route.
141
+ errorPort: false,
142
+ serialize: (spec, ctx) => serializeEventWait(spec, ctx),
143
+ deserialize: (node, ctx) => liftEventWait(node, ctx),
144
+ print: (spec, ctx) => printEventWait(spec, ctx),
145
+ check: (spec, ctx) => ctx.eventSubscription(spec.subscription, `waitForEvent "${ctx.step}"`),
146
+ namedNode: (spec) => {
147
+ const sub = spec.subscription;
148
+ return {
149
+ typeName: `${EVENT_PREFIX}${sub?.connector}.${sub?.event}`,
150
+ ...(typeof sub?.version === 'string' ? { version: sub.version } : {}),
151
+ };
152
+ },
153
+ expressions: () => [],
154
+ output: () => ({ kind: 'opaque' }),
155
+ };
156
+ export const eventWaitNodeType = {
157
+ kind: 'waitEvent', typeName: `${EVENT_PREFIX}*`, typeNamePrefix: EVENT_PREFIX, factory: 'waitForEvent',
158
+ typeNameMatches: (typeName) => splitEvent(typeName) !== undefined,
159
+ versionedByDefinition: true,
160
+ defaultVersion: eventWait10.version,
161
+ versions: { [eventWait10.version]: eventWait10 },
162
+ };
@@ -1,3 +1,3 @@
1
- /** The connector node family, as flow-node-registry.ts lists it: an Integration Service connector operation. */
1
+ /** The connector node family, as flow-node-registry.ts lists it: an Integration Service connector operation, and a mid-flow event wait. */
2
2
  import type { FlowNodeFamily } from '../../../flow-node-type.js';
3
3
  export declare const connectorFlowFamily: FlowNodeFamily;
@@ -1,8 +1,9 @@
1
+ import { eventWaitNodeType } from './event-wait.js';
1
2
  import { connectorNodeType } from './node-type.js';
2
3
  export const connectorFlowFamily = {
3
4
  id: 'connector',
4
5
  title: 'Integration Service connector',
5
- types: [connectorNodeType],
6
- // Its rules' codes are the pipeline's, shared with an event subscription (ctx.connector).
6
+ types: [connectorNodeType, eventWaitNodeType],
7
+ // Its rules' codes are the pipeline's, shared with the triggers (ctx.connector, ctx.eventSubscription).
7
8
  diagnostics: {},
8
9
  };