@uipath/maestro-builder-sdk 6.18.9 → 6.19.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.
- package/dist/api-index.md +185 -184
- package/dist/api-members.md +504 -473
- package/dist/bpmn/uipath-moddle.v1.json +5 -0
- package/dist/case/decompile-cli.js +2 -8
- package/dist/check.js +177 -650
- package/dist/core/actions.d.ts +119 -760
- package/dist/core/actions.js +0 -306
- package/dist/core/error-port.d.ts +6 -0
- package/dist/core/error-port.js +9 -0
- package/dist/core/node-classes.d.ts +4 -63
- package/dist/core/node-classes.js +0 -112
- package/dist/core/nodes/family.d.ts +36 -0
- package/dist/core/nodes/family.js +1 -0
- package/dist/core/nodes/node-type.d.ts +136 -0
- package/dist/core/nodes/node-type.js +1 -0
- package/dist/core/nodes/registry.d.ts +57 -0
- package/dist/core/nodes/registry.js +122 -0
- package/dist/core/nodes/versioned.d.ts +50 -0
- package/dist/core/nodes/versioned.js +46 -0
- package/dist/core/typed-raw-node.d.ts +13 -62
- package/dist/core/typed-raw-node.js +40 -154
- package/dist/decompile-cli.js +2 -9
- package/dist/decompile.js +92 -271
- package/dist/flow-definitions.d.ts +10 -0
- package/dist/flow-definitions.js +35 -0
- package/dist/flow-node-registry.d.ts +13 -0
- package/dist/flow-node-registry.js +19 -0
- package/dist/flow-node-type.d.ts +192 -0
- package/dist/flow-node-type.js +1 -0
- package/dist/flow-sdk.d.ts +7 -0
- package/dist/flow-sdk.js +8 -0
- package/dist/nodes/data-fabric/flow/check.d.ts +13 -0
- package/dist/nodes/data-fabric/flow/check.js +164 -0
- package/dist/nodes/data-fabric/flow/factories.d.ts +113 -0
- package/dist/nodes/data-fabric/flow/factories.js +134 -0
- package/dist/nodes/data-fabric/flow/family.d.ts +7 -0
- package/dist/nodes/data-fabric/flow/family.js +9 -0
- package/dist/nodes/data-fabric/flow/index.d.ts +8 -0
- package/dist/nodes/data-fabric/flow/index.js +8 -0
- package/dist/nodes/data-fabric/flow/raw.d.ts +32 -0
- package/dist/nodes/data-fabric/flow/raw.js +100 -0
- package/dist/nodes/data-fabric/flow/shared.d.ts +77 -0
- package/dist/nodes/data-fabric/flow/shared.js +174 -0
- package/dist/nodes/data-fabric/flow/spec.d.ts +238 -0
- package/dist/nodes/data-fabric/flow/spec.js +1 -0
- package/dist/nodes/data-fabric/flow/verbs.d.ts +29 -0
- package/dist/nodes/data-fabric/flow/verbs.js +239 -0
- package/dist/nodes/delay/flow/check.d.ts +16 -0
- package/dist/nodes/delay/flow/check.js +86 -0
- package/dist/nodes/delay/flow/factories.d.ts +28 -0
- package/dist/nodes/delay/flow/factories.js +38 -0
- package/dist/nodes/delay/flow/family.d.ts +3 -0
- package/dist/nodes/delay/flow/family.js +8 -0
- package/dist/nodes/delay/flow/index.d.ts +3 -0
- package/dist/nodes/delay/flow/index.js +3 -0
- package/dist/nodes/delay/flow/node-type.d.ts +13 -0
- package/dist/nodes/delay/flow/node-type.js +71 -0
- package/dist/nodes/delay/flow/spec.d.ts +43 -0
- package/dist/nodes/delay/flow/spec.js +16 -0
- package/dist/nodes/document/flow/factories.d.ts +27 -0
- package/dist/nodes/document/flow/factories.js +30 -0
- package/dist/nodes/document/flow/family.d.ts +3 -0
- package/dist/nodes/document/flow/family.js +7 -0
- package/dist/nodes/document/flow/index.d.ts +3 -0
- package/dist/nodes/document/flow/index.js +3 -0
- package/dist/nodes/document/flow/node-type.d.ts +14 -0
- package/dist/nodes/document/flow/node-type.js +150 -0
- package/dist/nodes/document/flow/spec.d.ts +65 -0
- package/dist/nodes/document/flow/spec.js +1 -0
- package/dist/nodes/mock/flow/factories.d.ts +51 -0
- package/dist/nodes/mock/flow/factories.js +47 -0
- package/dist/nodes/mock/flow/family.d.ts +3 -0
- package/dist/nodes/mock/flow/family.js +7 -0
- package/dist/nodes/mock/flow/index.d.ts +2 -0
- package/dist/nodes/mock/flow/index.js +2 -0
- package/dist/nodes/mock/flow/node-type.d.ts +11 -0
- package/dist/nodes/mock/flow/node-type.js +51 -0
- package/dist/nodes/script/flow/check.d.ts +19 -0
- package/dist/nodes/script/flow/check.js +49 -0
- package/dist/nodes/script/flow/factories.d.ts +14 -0
- package/dist/nodes/script/flow/factories.js +15 -0
- package/dist/nodes/script/flow/family.d.ts +3 -0
- package/dist/nodes/script/flow/family.js +8 -0
- package/dist/nodes/script/flow/index.d.ts +3 -0
- package/dist/nodes/script/flow/index.js +3 -0
- package/dist/nodes/script/flow/node-type.d.ts +7 -0
- package/dist/nodes/script/flow/node-type.js +125 -0
- package/dist/nodes/script/flow/spec.d.ts +52 -0
- package/dist/nodes/script/flow/spec.js +1 -0
- package/dist/nodes/transform/flow/check.d.ts +6 -0
- package/dist/nodes/transform/flow/check.js +229 -0
- package/dist/nodes/transform/flow/factories.d.ts +52 -0
- package/dist/nodes/transform/flow/factories.js +53 -0
- package/dist/nodes/transform/flow/family.d.ts +3 -0
- package/dist/nodes/transform/flow/family.js +8 -0
- package/dist/nodes/transform/flow/index.d.ts +3 -0
- package/dist/nodes/transform/flow/index.js +3 -0
- package/dist/nodes/transform/flow/node-type.d.ts +7 -0
- package/dist/nodes/transform/flow/node-type.js +244 -0
- package/dist/nodes/transform/flow/spec.d.ts +116 -0
- package/dist/nodes/transform/flow/spec.js +10 -0
- package/dist/raw-node-advice.d.ts +16 -0
- package/dist/raw-node-advice.js +36 -0
- package/dist/raw-node.d.ts +71 -0
- package/dist/raw-node.js +116 -0
- package/dist/registry/uip/launch.d.ts +11 -1
- package/dist/registry/uip/launch.js +50 -43
- package/dist/registry/uip/pipeline-front-door.d.ts +2 -0
- package/dist/registry/uip/pipeline-front-door.js +88 -0
- package/dist/serialize.js +138 -492
- package/package.json +2 -2
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Flow specialization of the node-type contract (`core/nodes/`), and the
|
|
3
|
+
* contexts Flow lends a node type for each job. docs/NODE_TYPE_ARCHITECTURE_DESIGN.md
|
|
4
|
+
* §4.1–§4.3.
|
|
5
|
+
*
|
|
6
|
+
* A Flow node type serializes to a {@link FlowNodeContribution} — the same contract
|
|
7
|
+
* a custom `FlowAction.contribute()` returns, plus the two things built-in node
|
|
8
|
+
* types need and custom ones never had (`model`, `port`). The serializer still
|
|
9
|
+
* owns the node's id, label, `typeVersion`, layout, edges and definition dedupe;
|
|
10
|
+
* each context below is the whole of what a node type can see.
|
|
11
|
+
*/
|
|
12
|
+
import type { ArtifactContexts, NodeType } from './core/nodes/node-type.js';
|
|
13
|
+
import type { VersionedNodeType } from './core/nodes/versioned.js';
|
|
14
|
+
import type { NodeFamily, Placement } from './core/nodes/family.js';
|
|
15
|
+
import type { DefinitionReference, NodeContribution } from './core/node-classes.js';
|
|
16
|
+
import type { CheckOpts } from './check.js';
|
|
17
|
+
/**
|
|
18
|
+
* What a Flow node type's `serialize` returns: the node's type-owned fields.
|
|
19
|
+
*
|
|
20
|
+
* The `inputs`, `outputs` and `bindings` are a {@link NodeContribution}'s; only
|
|
21
|
+
* `definition` differs (optional here), and `model` and `port` are Flow's own.
|
|
22
|
+
*
|
|
23
|
+
* A node type owns its bindings: together with what it hoists through
|
|
24
|
+
* `ctx.bind`, they must close every `<bindings.NAME>` its definition references.
|
|
25
|
+
* `serialize` enforces that (#942); `check` does not verify it, because the
|
|
26
|
+
* bindings exist only once the type serializes and no author input can open the
|
|
27
|
+
* gap, so the type's own tests are what pin it.
|
|
28
|
+
*/
|
|
29
|
+
export interface FlowNodeContribution extends Omit<NodeContribution, 'definition'> {
|
|
30
|
+
/**
|
|
31
|
+
* The definition to compile against. A `bundled` type must omit it: the
|
|
32
|
+
* serializer resolves `<typeName>@<version>` from the bundle, and refuses one
|
|
33
|
+
* returned. A `per-tenant` type must supply the definition it built (a
|
|
34
|
+
* `snapshot` reference).
|
|
35
|
+
*/
|
|
36
|
+
definition?: DefinitionReference;
|
|
37
|
+
/**
|
|
38
|
+
* Whether the node carries the definition's `model` (`'definition'`, the default)
|
|
39
|
+
* or none (`'omit'`) — Data Fabric nodes never carry one (see `makeNode`).
|
|
40
|
+
*/
|
|
41
|
+
model?: 'definition' | 'omit';
|
|
42
|
+
/** The forward port the next step's edge leaves from. Default: the definition's default source handle. */
|
|
43
|
+
port?: string;
|
|
44
|
+
}
|
|
45
|
+
/** What `serialize` may ask of the serializer, for one placement. */
|
|
46
|
+
export interface FlowSerializeContext {
|
|
47
|
+
/** The step name the author gave this node. */
|
|
48
|
+
readonly step: string;
|
|
49
|
+
/**
|
|
50
|
+
* The version being emitted, always set: the author's `{ version }` when the step
|
|
51
|
+
* names one, else what `select()` or the default chose. It does not say whether
|
|
52
|
+
* the author pinned it.
|
|
53
|
+
*/
|
|
54
|
+
readonly version: string;
|
|
55
|
+
/** Render one value (an `Expr`, or a literal) as the file stores it, with this scope's rename map. */
|
|
56
|
+
render(value: unknown): unknown;
|
|
57
|
+
/**
|
|
58
|
+
* Apply this scope's rename map to raw JavaScript that is not an `Expr` — a
|
|
59
|
+
* script body reads `$vars.<step>` like any expression, so a reused child's
|
|
60
|
+
* body must follow its copy's node ids too.
|
|
61
|
+
*/
|
|
62
|
+
renameRefs(js: string): string;
|
|
63
|
+
/** The node id another step of this scope was emitted under — rename-aware, for subflow copies. */
|
|
64
|
+
stepNodeId(step: string): string;
|
|
65
|
+
/** A deterministic id for `seed`, unique to this flow and node. */
|
|
66
|
+
mint(seed: string): string;
|
|
67
|
+
/**
|
|
68
|
+
* Hoist a binding entry into the flow's `bindings`, deduplicated by `id`. With
|
|
69
|
+
* the contribution's own `bindings`, these must close every `<bindings.NAME>`
|
|
70
|
+
* the node's definition references: serialize refuses a name left open
|
|
71
|
+
* (`CONTRIBUTION_BINDING_UNRESOLVED`), and `check` does not see bindings.
|
|
72
|
+
*/
|
|
73
|
+
bind(entry: {
|
|
74
|
+
readonly id: string;
|
|
75
|
+
} & Readonly<Record<string, unknown>>): void;
|
|
76
|
+
/** The bundled definition `<typeName>@<version>`, or undefined when the SDK does not ship it. */
|
|
77
|
+
definition(typeName: string, version: string): unknown;
|
|
78
|
+
}
|
|
79
|
+
/** What `deserialize` may ask of the decompiler, for one serialized node. */
|
|
80
|
+
export interface FlowDeserializeContext {
|
|
81
|
+
/** The serialized node's id. */
|
|
82
|
+
readonly nodeId: string;
|
|
83
|
+
/** A serialized value back as the spec holds it: `=js:` text becomes an `Expr`; a literal stays itself. */
|
|
84
|
+
expr(raw: unknown): unknown;
|
|
85
|
+
/**
|
|
86
|
+
* A serialized value's TEXT, unwrapped from an expression envelope: a string
|
|
87
|
+
* as is, a `{ type: 'jsExpression', expression }` envelope as `=js:<expression>`,
|
|
88
|
+
* any other envelope as its expression; undefined for anything else.
|
|
89
|
+
*/
|
|
90
|
+
sourceText(raw: unknown): string | undefined;
|
|
91
|
+
/** A plain value, unwrapped from a `{ type: 'literal', expression: '<json>' }` envelope when it is one. */
|
|
92
|
+
plainValue(raw: unknown): unknown;
|
|
93
|
+
/** The step name a node id was emitted for. */
|
|
94
|
+
stepName(nodeId: string): string;
|
|
95
|
+
/** The file's own `definitions[]` entry for this node, if it carries one. */
|
|
96
|
+
definition(): unknown;
|
|
97
|
+
/** Report something the lift could not keep. Decompile prints it once. */
|
|
98
|
+
warn(message: string): void;
|
|
99
|
+
}
|
|
100
|
+
/** What `print` may ask of the decompiler. Every method returns source text. */
|
|
101
|
+
export interface FlowPrintContext {
|
|
102
|
+
/**
|
|
103
|
+
* Any spec value as source: an `Expr` as the helper an author writes (`input('x')`, `js\`…\``), an array or
|
|
104
|
+
* plain object recursively (`[a, b]`, `{ k: v }`), anything else as a literal.
|
|
105
|
+
*/
|
|
106
|
+
value(value: unknown): string;
|
|
107
|
+
/** A string literal. */
|
|
108
|
+
string(text: string): string;
|
|
109
|
+
/** Any JSON value as a literal, verbatim (`{"a":1}`), where the source writes the value as data. */
|
|
110
|
+
json(value: unknown): string;
|
|
111
|
+
/** An object key: a bare identifier when legal, otherwise a quoted string. */
|
|
112
|
+
key(name: string): string;
|
|
113
|
+
/** An authoring helper (`lit`, `input`, …) by name: imported into the printed source, and its identifier. */
|
|
114
|
+
helper(name: string): string;
|
|
115
|
+
}
|
|
116
|
+
/** What a node-local `check` may ask of the checker. */
|
|
117
|
+
export interface FlowCheckContext {
|
|
118
|
+
/** The step being checked. */
|
|
119
|
+
readonly step: string;
|
|
120
|
+
/** The version the node will be emitted at. */
|
|
121
|
+
readonly version: string;
|
|
122
|
+
/** Report a diagnostic on this step. Its severity is the family catalog's for `code`. */
|
|
123
|
+
report(code: string, message: string, suggestion?: string): void;
|
|
124
|
+
/**
|
|
125
|
+
* The flow input or variable a bare reference (`$vars.x`, or an input's
|
|
126
|
+
* `$vars.<trigger>.output.x`) names, with its declared type when it has one;
|
|
127
|
+
* undefined for anything else — a step output's type is not known offline.
|
|
128
|
+
*/
|
|
129
|
+
declaredRef(js: string): {
|
|
130
|
+
name: string;
|
|
131
|
+
type: string | undefined;
|
|
132
|
+
} | undefined;
|
|
133
|
+
/** The options `check` was called with (the connector-library views among them). */
|
|
134
|
+
readonly options: CheckOpts;
|
|
135
|
+
}
|
|
136
|
+
/** What a family-level `check` may ask of the checker. */
|
|
137
|
+
export interface FlowFamilyCheckContext {
|
|
138
|
+
/** Report a diagnostic on `step`. Its severity is the family catalog's for `code`. */
|
|
139
|
+
report(step: string, code: string, message: string, suggestion?: string): void;
|
|
140
|
+
/** Whether the flow has a step of that name, in any scope the family's placements can see. */
|
|
141
|
+
hasStep(step: string): boolean;
|
|
142
|
+
/** Where a step of that name is placed, when it is one of this registry's node types. */
|
|
143
|
+
placementOf(step: string): Placement | undefined;
|
|
144
|
+
/**
|
|
145
|
+
* Whether that step is one of this registry's node types whose `{ version }` did
|
|
146
|
+
* not resolve. It has no placement, and `NODE_VERSION_UNREGISTERED` already
|
|
147
|
+
* reports it, so a rule about it should stay silent rather than say it is missing.
|
|
148
|
+
*/
|
|
149
|
+
versionUnresolved(step: string): boolean;
|
|
150
|
+
}
|
|
151
|
+
export interface FlowContexts extends ArtifactContexts {
|
|
152
|
+
serialize: FlowSerializeContext;
|
|
153
|
+
deserialize: FlowDeserializeContext;
|
|
154
|
+
print: FlowPrintContext;
|
|
155
|
+
check: FlowCheckContext;
|
|
156
|
+
familyCheck: FlowFamilyCheckContext;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* What `rawNode` reports for a raw node of a registered type: the typed spelling
|
|
160
|
+
* to prefer (RAW_NODE_TYPED_FAMILY), and the inputs the product never reads
|
|
161
|
+
* (RAW_NODE_UNKNOWN_INPUT). Both apply to every version, registered or not —
|
|
162
|
+
* a raw node is often how an author reaches a version the SDK does not bundle.
|
|
163
|
+
*/
|
|
164
|
+
export interface FlowRawNodeAdvice {
|
|
165
|
+
/** The typed spelling the warning names, e.g. `dataFabricRead({ entity, … })`. */
|
|
166
|
+
readonly factory: string;
|
|
167
|
+
/** Appended to the warning: what the factory writes, and what still needs a raw node. */
|
|
168
|
+
readonly hint?: string;
|
|
169
|
+
/**
|
|
170
|
+
* A raw node's inputs carry a key the product never reads: an `error` at a version
|
|
171
|
+
* the SDK bundles (`bundled`), where the key set is known, else a `warning`.
|
|
172
|
+
*/
|
|
173
|
+
inputProblem?(inputs: unknown, version: string, bundled: boolean): {
|
|
174
|
+
severity: 'error' | 'warning';
|
|
175
|
+
message: string;
|
|
176
|
+
} | undefined;
|
|
177
|
+
}
|
|
178
|
+
/** One Flow node type at one version. */
|
|
179
|
+
export interface FlowNodeType<Spec> extends NodeType<Spec, FlowNodeContribution, FlowContexts> {
|
|
180
|
+
/**
|
|
181
|
+
* The node-level `model` every node of this type carries, whichever path emits
|
|
182
|
+
* it — this type's `serialize`, or a `rawNode` of its definition. `'omit'`: none
|
|
183
|
+
* (Data Fabric). Default `'definition'`; a contribution's own `model` wins.
|
|
184
|
+
*/
|
|
185
|
+
readonly nodeModel?: 'definition' | 'omit';
|
|
186
|
+
/** What `rawNode` reports for a raw node of this type. */
|
|
187
|
+
readonly rawNode?: FlowRawNodeAdvice;
|
|
188
|
+
}
|
|
189
|
+
/** A Flow node type with several versions. */
|
|
190
|
+
export type FlowVersionedNodeType<Spec> = VersionedNodeType<Spec, FlowNodeContribution, FlowContexts, FlowNodeType<Spec>>;
|
|
191
|
+
/** A Flow node family. */
|
|
192
|
+
export type FlowNodeFamily = NodeFamily<FlowContexts>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/flow-sdk.d.ts
CHANGED
|
@@ -18,11 +18,18 @@
|
|
|
18
18
|
*/
|
|
19
19
|
export * from './core/expr.js';
|
|
20
20
|
export * from './core/actions.js';
|
|
21
|
+
export * from './nodes/data-fabric/flow/index.js';
|
|
22
|
+
export * from './nodes/delay/flow/index.js';
|
|
23
|
+
export * from './nodes/document/flow/index.js';
|
|
24
|
+
export * from './nodes/mock/flow/index.js';
|
|
25
|
+
export * from './nodes/script/flow/index.js';
|
|
26
|
+
export * from './nodes/transform/flow/index.js';
|
|
21
27
|
export { resolveFlowRefs, resolveRefPath, hasFileRefs } from './ref-resolve.js';
|
|
22
28
|
export type { RefReader, ResolveRefsOptions } from './ref-resolve.js';
|
|
23
29
|
export * from './core/connectors.js';
|
|
24
30
|
export * from './core/lookups.js';
|
|
25
31
|
export * from './core/node-classes.js';
|
|
32
|
+
export * from './raw-node.js';
|
|
26
33
|
import { Expr } from './core/expr.js';
|
|
27
34
|
import type { ErrorEnvelopeField, TypeDesc } from './core/expr.js';
|
|
28
35
|
import type { ActionSpec, EventSubscription, TriggerOptions } from './core/actions.js';
|
package/dist/flow-sdk.js
CHANGED
|
@@ -21,12 +21,20 @@
|
|
|
21
21
|
// single import an author needs.
|
|
22
22
|
export * from './core/expr.js';
|
|
23
23
|
export * from './core/actions.js';
|
|
24
|
+
// Node families' public surfaces (docs/NODE_TYPE_ARCHITECTURE_DESIGN.md §8).
|
|
25
|
+
export * from './nodes/data-fabric/flow/index.js';
|
|
26
|
+
export * from './nodes/delay/flow/index.js';
|
|
27
|
+
export * from './nodes/document/flow/index.js';
|
|
28
|
+
export * from './nodes/mock/flow/index.js';
|
|
29
|
+
export * from './nodes/script/flow/index.js';
|
|
30
|
+
export * from './nodes/transform/flow/index.js';
|
|
24
31
|
// `$ref`-split ingestion (design §5): decompile resolves local-file refs into
|
|
25
32
|
// one object model. Exported so a host doing its own file reading can too.
|
|
26
33
|
export { resolveFlowRefs, resolveRefPath, hasFileRefs } from './ref-resolve.js';
|
|
27
34
|
export * from './core/connectors.js';
|
|
28
35
|
export * from './core/lookups.js';
|
|
29
36
|
export * from './core/node-classes.js';
|
|
37
|
+
export * from './raw-node.js';
|
|
30
38
|
import { err as errRef, toExpr, types } from './core/expr.js';
|
|
31
39
|
import { builtinActionSpec, builtinTriggerSpec, subscriptionFrom } from './core/actions.js';
|
|
32
40
|
import { checkFlowExpressions, FlowBuildError } from './flow-expr-check.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DataFabricCreateInputs, DataFabricDeleteInputs, DataFabricReadInputs, DataFabricUpdateInputs } from './spec.js';
|
|
2
|
+
import type { DiagnosticCatalog, Placement } from '../../../core/nodes/family.js';
|
|
3
|
+
import type { FlowCheckContext, FlowFamilyCheckContext } from '../../../flow-node-type.js';
|
|
4
|
+
export declare const DATA_FABRIC_DIAGNOSTICS: DiagnosticCatalog;
|
|
5
|
+
export declare function checkRead(inputs: DataFabricReadInputs, ctx: FlowCheckContext): void;
|
|
6
|
+
export declare function checkCreate(inputs: DataFabricCreateInputs, ctx: FlowCheckContext): void;
|
|
7
|
+
export declare function checkUpdate(inputs: DataFabricUpdateInputs, ctx: FlowCheckContext): void;
|
|
8
|
+
export declare function checkWrite(inputs: DataFabricDeleteInputs, ctx: FlowCheckContext): void;
|
|
9
|
+
/**
|
|
10
|
+
* Update and delete target a record `{ fromRead: '<step>' }` with the same
|
|
11
|
+
* selector, so they share the check: the step must be a read, and not a list.
|
|
12
|
+
*/
|
|
13
|
+
export declare function checkFromRead(placements: readonly Placement[], ctx: FlowFamilyCheckContext): void;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Flow Data Fabric family's rules: the per-step checks each verb runs, and
|
|
3
|
+
* the family-level `{ fromRead }` rules that need every placement at once. Moved
|
|
4
|
+
* verbatim from check.ts (Phase 2 of docs/NODE_TYPE_ARCHITECTURE_DESIGN.md);
|
|
5
|
+
* codes, messages and order are unchanged.
|
|
6
|
+
*/
|
|
7
|
+
import { Expr } from '../../../core/expr.js';
|
|
8
|
+
export const DATA_FABRIC_DIAGNOSTICS = {
|
|
9
|
+
DATAFABRIC_NO_ENTITY: { severity: 'error', summary: 'a verb names no entity' },
|
|
10
|
+
DATAFABRIC_EMPTY_VALUES: { severity: 'error', summary: 'a create writes no non-blank column' },
|
|
11
|
+
DATAFABRIC_EMPTY_SET: { severity: 'error', summary: 'an update writes no column' },
|
|
12
|
+
DATAFABRIC_SYSTEM_COLUMN: { severity: 'error', summary: 'a write targets a system column' },
|
|
13
|
+
DATAFABRIC_FOLDER_NO_RESOURCE_KEY: { severity: 'error', summary: 'folderKey without resourceKey' },
|
|
14
|
+
DATAFABRIC_RESOURCE_KEY_NO_FOLDER: { severity: 'error', summary: 'resourceKey without folderKey' },
|
|
15
|
+
DATAFABRIC_QUERY_OPTS_WITHOUT_MULTIPLE: { severity: 'error', summary: 'list-query options on a single read' },
|
|
16
|
+
DATAFABRIC_LIMIT_RANGE: { severity: 'error', summary: 'limit outside 1–1000' },
|
|
17
|
+
DATAFABRIC_IN_REQUIRES_MULTIPLE: { severity: 'error', summary: "an 'in' filter on a single read" },
|
|
18
|
+
DATAFABRIC_FILTER_BLANK_VALUE: { severity: 'error', summary: 'a filter with a blank value' },
|
|
19
|
+
DATAFABRIC_FROMREAD_UNKNOWN: { severity: 'error', summary: '{ fromRead } names no read step' },
|
|
20
|
+
DATAFABRIC_FROMREAD_MULTIPLE: { severity: 'error', summary: "{ fromRead } names a resultMode: 'multiple' query" },
|
|
21
|
+
DATAFABRIC_DELETE_HAS_NO_OUTPUT: { severity: 'error', summary: "a read of a delete's output" },
|
|
22
|
+
};
|
|
23
|
+
function checkEntity(inputs, ctx) {
|
|
24
|
+
if (!String(inputs.entity ?? '').trim()) {
|
|
25
|
+
ctx.report('DATAFABRIC_NO_ENTITY', `"${ctx.step}" names no Data Fabric entity. Set { entity: '<entity name>' }.`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export function checkRead(inputs, ctx) {
|
|
29
|
+
checkEntity(inputs, ctx);
|
|
30
|
+
checkQuery(inputs, ctx);
|
|
31
|
+
checkScope(inputs, ctx);
|
|
32
|
+
}
|
|
33
|
+
export function checkCreate(inputs, ctx) {
|
|
34
|
+
checkEntity(inputs, ctx);
|
|
35
|
+
// Not the same failure as an empty update: a BLANK value is omitted from the
|
|
36
|
+
// insert so the column default applies, so an all-blank `fieldValues`
|
|
37
|
+
// serializes to an empty body and runs green having inserted nothing. The
|
|
38
|
+
// node's schema rejects that — and the fix is a real value, never a
|
|
39
|
+
// placeholder to satisfy the rule.
|
|
40
|
+
const written = Object.values(inputs.values ?? {})
|
|
41
|
+
.filter((v) => (v instanceof Expr ? true : String(v ?? '').trim() !== ''));
|
|
42
|
+
if (written.length === 0) {
|
|
43
|
+
ctx.report('DATAFABRIC_EMPTY_VALUES', `"${ctx.step}" sets no column to a non-blank value, so it would insert nothing and run green. `
|
|
44
|
+
+ 'The node\'s schema rejects that — give a real column a real value rather than a placeholder.');
|
|
45
|
+
}
|
|
46
|
+
checkColumns(Object.keys(inputs.values ?? {}), 'values', ctx);
|
|
47
|
+
checkScope(inputs, ctx);
|
|
48
|
+
}
|
|
49
|
+
export function checkUpdate(inputs, ctx) {
|
|
50
|
+
checkEntity(inputs, ctx);
|
|
51
|
+
if (Object.keys(inputs.set ?? {}).length === 0) {
|
|
52
|
+
ctx.report('DATAFABRIC_EMPTY_SET', `"${ctx.step}" writes no columns — { set } is empty, so the update would no-op green.`);
|
|
53
|
+
}
|
|
54
|
+
checkColumns(Object.keys(inputs.set ?? {}), 'set', ctx);
|
|
55
|
+
checkScope(inputs, ctx);
|
|
56
|
+
}
|
|
57
|
+
export function checkWrite(inputs, ctx) {
|
|
58
|
+
checkEntity(inputs, ctx);
|
|
59
|
+
checkScope(inputs, ctx);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Columns Data Fabric assigns and never accepts a write for.
|
|
63
|
+
*
|
|
64
|
+
* The canvas hides them from both write editors, but the serializer has no
|
|
65
|
+
* guard: a hand-authored `Id` row satisfies the node's own "at least one field"
|
|
66
|
+
* rule, ships in the body, and is rejected — and the rejection is only logged,
|
|
67
|
+
* so the row comes back unchanged and the run goes green.
|
|
68
|
+
*/
|
|
69
|
+
const SYSTEM_COLUMNS = new Set(['Id', 'CreateTime', 'CreatedBy', 'UpdateTime', 'UpdatedBy']);
|
|
70
|
+
function checkColumns(columns, option, ctx) {
|
|
71
|
+
const system = columns.filter((c) => SYSTEM_COLUMNS.has(c));
|
|
72
|
+
if (system.length) {
|
|
73
|
+
ctx.report('DATAFABRIC_SYSTEM_COLUMN', `"${ctx.step}" writes ${system.map((c) => JSON.stringify(c)).join(', ')} in { ${option} }. `
|
|
74
|
+
+ 'Data Fabric assigns its system columns (Id, CreateTime, CreatedBy, UpdateTime, UpdatedBy) and rejects a '
|
|
75
|
+
+ 'write to them — and it only LOGS the rejection, so the row comes back unchanged and the run goes green.');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* A folder-scoped entity is portable only with its `Entity` bindings.
|
|
80
|
+
*
|
|
81
|
+
* `_folderKey` on its own still serializes — it falls back to a source-org
|
|
82
|
+
* literal and logs a warning — so the flow looks fine until it is deployed to
|
|
83
|
+
* another org. Refusing the half-authored pair here is the whole point: the
|
|
84
|
+
* alternative is a defect that only appears at deploy time, in a different org,
|
|
85
|
+
* to somebody else.
|
|
86
|
+
*/
|
|
87
|
+
function checkScope(inputs, ctx) {
|
|
88
|
+
if (inputs.folderKey !== undefined && inputs.resourceKey === undefined) {
|
|
89
|
+
ctx.report('DATAFABRIC_FOLDER_NO_RESOURCE_KEY', `"${ctx.step}" sets { folderKey } without { resourceKey }. A folder-scoped entity needs both — with only `
|
|
90
|
+
+ 'the folder key the entity serializes as a source-org literal, which validates, runs in this org, and '
|
|
91
|
+
+ 'breaks on deploy to another one.', 'resolve the key with `uip solution resources list --kind Entity`, or drop { folderKey } and keep '
|
|
92
|
+
+ 'the entity tenant-scoped');
|
|
93
|
+
}
|
|
94
|
+
if (inputs.resourceKey !== undefined && inputs.folderKey === undefined) {
|
|
95
|
+
ctx.report('DATAFABRIC_RESOURCE_KEY_NO_FOLDER', `"${ctx.step}" sets { resourceKey } without { folderKey }. The pair exists to scope a FOLDER entity; a `
|
|
96
|
+
+ 'tenant-scoped entity needs neither and serializes as a dotted literal.');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* The query options, none of which the node's `inputDefinition` declares — they
|
|
101
|
+
* are `_`-prefixed extras, so `uip maestro flow validate` checks none of them
|
|
102
|
+
* and every mistake here is silent at run time.
|
|
103
|
+
*/
|
|
104
|
+
function checkQuery(inputs, ctx) {
|
|
105
|
+
const step = ctx.step;
|
|
106
|
+
const listOnly = ['limit', 'skip', 'sort', 'fields'].filter((k) => inputs[k] !== undefined);
|
|
107
|
+
if (listOnly.length && inputs.resultMode !== 'multiple') {
|
|
108
|
+
ctx.report('DATAFABRIC_QUERY_OPTS_WITHOUT_MULTIPLE', `"${step}" sets { ${listOnly.join(', ')} }, which only a list query uses, but its resultMode is `
|
|
109
|
+
+ `${inputs.resultMode ? JSON.stringify(inputs.resultMode) : 'unset (a single-record read)'}.`, "resultMode: 'multiple'");
|
|
110
|
+
}
|
|
111
|
+
// The emitted query ALWAYS carries a limit — omitted it resolves to 100 — and
|
|
112
|
+
// 1000 is a hard ceiling that TRUNCATES rather than erroring above it.
|
|
113
|
+
if (inputs.limit !== undefined && (!Number.isInteger(inputs.limit) || inputs.limit < 1 || inputs.limit > 1000)) {
|
|
114
|
+
ctx.report('DATAFABRIC_LIMIT_RANGE', `"${step}": limit must be a whole number between 1 and 1000 (got ${inputs.limit}). 1000 is a hard `
|
|
115
|
+
+ 'ceiling — a larger value truncates silently, so page with { skip } instead.');
|
|
116
|
+
}
|
|
117
|
+
// `in` is honoured only on a list query; on a single read the row compiles
|
|
118
|
+
// away, and a read whose filters compiled away returns EVERY record.
|
|
119
|
+
if (inputs.resultMode !== 'multiple' && (inputs.filters ?? []).some((f) => f.operator === 'in')) {
|
|
120
|
+
ctx.report('DATAFABRIC_IN_REQUIRES_MULTIPLE', `"${step}" filters with the 'in' operator, which is honoured only when resultMode is 'multiple'. `
|
|
121
|
+
+ 'On a single-record read that row compiles away — and a read whose filters compiled away matches every record.');
|
|
122
|
+
}
|
|
123
|
+
// A filter expression switched on and left blank is refused by the serializer,
|
|
124
|
+
// and it refuses the WHOLE query rather than dropping the row, which strands
|
|
125
|
+
// every downstream reference to this step.
|
|
126
|
+
for (const f of inputs.filters ?? []) {
|
|
127
|
+
const blank = f.value instanceof Expr ? f.value.js.trim() === '' : String(f.value ?? '').trim() === '';
|
|
128
|
+
if (blank) {
|
|
129
|
+
ctx.report('DATAFABRIC_FILTER_BLANK_VALUE', `"${step}" has a filter on ${JSON.stringify(f.field)} with a blank value. The serializer refuses the `
|
|
130
|
+
+ 'ENTIRE query rather than dropping the row, so the step emits nothing and every downstream $vars read of '
|
|
131
|
+
+ 'it breaks.');
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Update and delete target a record `{ fromRead: '<step>' }` with the same
|
|
137
|
+
* selector, so they share the check: the step must be a read, and not a list.
|
|
138
|
+
*/
|
|
139
|
+
export function checkFromRead(placements, ctx) {
|
|
140
|
+
for (const p of placements) {
|
|
141
|
+
if (p.kind !== 'dataFabricUpdate' && p.kind !== 'dataFabricDelete')
|
|
142
|
+
continue;
|
|
143
|
+
const fromRead = p.spec.inputs?.record?.fromRead;
|
|
144
|
+
if (typeof fromRead !== 'string')
|
|
145
|
+
continue;
|
|
146
|
+
const factory = p.kind;
|
|
147
|
+
// A step whose version did not resolve is already an error; saying it does
|
|
148
|
+
// not exist would send the author to the selector instead of the pin.
|
|
149
|
+
if (ctx.versionUnresolved(fromRead))
|
|
150
|
+
continue;
|
|
151
|
+
const read = ctx.placementOf(fromRead);
|
|
152
|
+
if (read?.kind !== 'dataFabricRead') {
|
|
153
|
+
ctx.report(p.step, 'DATAFABRIC_FROMREAD_UNKNOWN', `"${p.step}" targets record: { fromRead: ${JSON.stringify(fromRead)} }, but no dataFabricRead step has that name.`, `${factory}({ …, record: { byId: '<record id>' } })`);
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
// A LIST is not a write target: the serializer refuses it and emits a plain
|
|
157
|
+
// no-op task, so the flow validates, runs green, and writes nothing.
|
|
158
|
+
if (read.spec.inputs?.resultMode === 'multiple') {
|
|
159
|
+
ctx.report(p.step, 'DATAFABRIC_FROMREAD_MULTIPLE', `"${p.step}" targets record: { fromRead: ${JSON.stringify(fromRead)} }, but "${fromRead}" is a `
|
|
160
|
+
+ "resultMode: 'multiple' query. A multi-record read is refused as a write target — the step compiles to "
|
|
161
|
+
+ 'a no-op and the run goes green having written nothing.', `loop the results and target each record with ${factory}({ …, record: { byId: … } })`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Flow Data Fabric factories: `dataFabricRead()`, `dataFabricCreate()`,
|
|
3
|
+
* `dataFabricUpdate()` and `dataFabricDelete()`. Moved from core/actions.ts in
|
|
4
|
+
* Phase 2c of docs/NODE_TYPE_ARCHITECTURE_DESIGN.md; the package entry re-exports
|
|
5
|
+
* them, so authors import them exactly as before.
|
|
6
|
+
*/
|
|
7
|
+
import { type ActionSpec } from '../../../core/actions.js';
|
|
8
|
+
import type { DataFabricCreateInputs, DataFabricDeleteInputs, DataFabricReadInputs, DataFabricUpdateInputs } from './spec.js';
|
|
9
|
+
/**
|
|
10
|
+
* Query entity records from Data Fabric (`core.datafabric.read`). The result
|
|
11
|
+
* publishes to the step's `output`; downstream references re-fetch fresh data
|
|
12
|
+
* at activation time (the engine re-runs the query rather than caching).
|
|
13
|
+
*
|
|
14
|
+
* @remarks
|
|
15
|
+
* This node is **read-one AND query-many**, on its 1.4 definition: `resultMode:
|
|
16
|
+
* 'multiple'` publishes the matching records under `output.results`, and the
|
|
17
|
+
* platform renames the node "Query entity records" to say so. The SDK still
|
|
18
|
+
* pins 1.0 — read-one — as the no-`{ version }` default, so passing
|
|
19
|
+
* `resultMode` is what selects 1.4; see {@link DataFabricReadInputs.resultMode}.
|
|
20
|
+
*
|
|
21
|
+
* The native family covers all four CRUD verbs: this one,
|
|
22
|
+
* {@link dataFabricCreate}, {@link dataFabricUpdate} and
|
|
23
|
+
* {@link dataFabricDelete}. What it does NOT cover is get-by-id, a query row
|
|
24
|
+
* limit, file record fields, and entity events — those are operations on the
|
|
25
|
+
* SAME product reached through its Integration Service connector,
|
|
26
|
+
* `uipath-uipath-dataservice` (the tenant displays it as **UiPath Data
|
|
27
|
+
* Fabric**). So a flow that needs one of those still straddles two surfaces,
|
|
28
|
+
* and the connector remains the one surface that covers everything:
|
|
29
|
+
*
|
|
30
|
+
* ```ts
|
|
31
|
+
* .step('byId', connector('uipath-uipath-dataservice', 'get-entity-record-by-id',
|
|
32
|
+
* { entityName: 'Contracts', recordId: input('id') }, { connection: 'df' }))
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* Get-by-id matters for long text. This node is a query even when it reads one
|
|
36
|
+
* record by an `Id` filter, and a Data Service query returns a PREVIEW of a
|
|
37
|
+
* long-text (`MULTILINE_MAX`) field: the first 10,000 characters plus
|
|
38
|
+
* `...[Truncated]`, with no flag in the output. A 15,551-character value comes
|
|
39
|
+
* back as 10,014 characters. When a field may exceed 10,000 characters, read
|
|
40
|
+
* it with `get-entity-record-by-id`, which returns the whole value
|
|
41
|
+
* (flow-builder-sdk#954).
|
|
42
|
+
*
|
|
43
|
+
* A connector operation's body fields come from the entity, so the library
|
|
44
|
+
* cannot carry them: run `uip maestro registry prepare uipath-uipath-dataservice
|
|
45
|
+
* get-entity-record-by-id -f entityName=<Entity>` first.
|
|
46
|
+
* The routing table is in the `data-fabric.md` reference and the parent-field
|
|
47
|
+
* loop in `connector-params.md` — cited by name rather than linked, because this
|
|
48
|
+
* comment renders both into the flat corpus, where those files sit alongside
|
|
49
|
+
* it, and onto the site, where each symbol is its own page and a relative
|
|
50
|
+
* `./data-fabric` resolves to nothing.
|
|
51
|
+
*
|
|
52
|
+
* @param inputs - The entity, optional filter rows, result mode, and folder scope.
|
|
53
|
+
* @returns An action spec to pass to `.step(name, …)`.
|
|
54
|
+
*/
|
|
55
|
+
export declare function dataFabricRead(inputs: DataFabricReadInputs): ActionSpec;
|
|
56
|
+
/**
|
|
57
|
+
* Create an entity record in Data Fabric (`core.datafabric.create`). The new
|
|
58
|
+
* record publishes to the step's `output`, so a following
|
|
59
|
+
* {@link dataFabricUpdate} or {@link dataFabricDelete} can read its id.
|
|
60
|
+
*
|
|
61
|
+
* @remarks
|
|
62
|
+
* `values` must name at least one column — the node's schema rejects an empty
|
|
63
|
+
* field list rather than inserting a blank row, and `check` says so before the
|
|
64
|
+
* platform does. Field names are the ENTITY's, so copy them from the scenario
|
|
65
|
+
* or the tenant; nothing offline can tell a real column from a typo.
|
|
66
|
+
*
|
|
67
|
+
* The published `output` is the record as a query returns it, so a long-text
|
|
68
|
+
* (`MULTILINE_MAX`) field longer than 10,000 characters comes back cut, with
|
|
69
|
+
* `...[Truncated]` appended, even though the whole value was stored. Use the
|
|
70
|
+
* value you passed in, or re-read the record with the connector's
|
|
71
|
+
* `get-entity-record-by-id`, when the whole text is needed (flow-builder-sdk#954).
|
|
72
|
+
*
|
|
73
|
+
* See {@link dataFabricRead} for what the native family still does not cover
|
|
74
|
+
* and which connector operation covers it.
|
|
75
|
+
*
|
|
76
|
+
* @param inputs - The entity, the columns the record starts with, and folder scope.
|
|
77
|
+
* @returns An action spec to pass to `.step(name, …)`.
|
|
78
|
+
*/
|
|
79
|
+
export declare function dataFabricCreate(inputs: DataFabricCreateInputs): ActionSpec;
|
|
80
|
+
/**
|
|
81
|
+
* Update an entity record in Data Fabric (`core.datafabric.update`). Target the
|
|
82
|
+
* record by id or through an earlier {@link dataFabricRead} step; downstream
|
|
83
|
+
* reads of this step observe the record AFTER the write.
|
|
84
|
+
*
|
|
85
|
+
* @remarks
|
|
86
|
+
* `set` must write at least one column: an empty `set` is a no-op the platform
|
|
87
|
+
* reports as success, so `check` rejects it.
|
|
88
|
+
*
|
|
89
|
+
* See {@link dataFabricRead} for what the native family still does not cover
|
|
90
|
+
* and which connector operation covers it.
|
|
91
|
+
*
|
|
92
|
+
* @param inputs - The entity, the record selector, and the columns to write.
|
|
93
|
+
* @returns An action spec to pass to `.step(name, …)`.
|
|
94
|
+
*/
|
|
95
|
+
export declare function dataFabricUpdate(inputs: DataFabricUpdateInputs): ActionSpec;
|
|
96
|
+
/**
|
|
97
|
+
* Delete an entity record from Data Fabric (`core.datafabric.delete`). Target
|
|
98
|
+
* the record by id or through an earlier {@link dataFabricRead} step, exactly
|
|
99
|
+
* as {@link dataFabricUpdate} does.
|
|
100
|
+
*
|
|
101
|
+
* @remarks
|
|
102
|
+
* A delete **publishes nothing** — its definition declares no output — so
|
|
103
|
+
* `$vars.<step>.output` is undefined at run time and `check` rejects a read of
|
|
104
|
+
* it. Take what you need off the read step that found the record, before the
|
|
105
|
+
* delete.
|
|
106
|
+
*
|
|
107
|
+
* See {@link dataFabricRead} for what the native family still does not cover
|
|
108
|
+
* and which connector operation covers it.
|
|
109
|
+
*
|
|
110
|
+
* @param inputs - The entity, the record selector, and folder scope.
|
|
111
|
+
* @returns An action spec to pass to `.step(name, …)`.
|
|
112
|
+
*/
|
|
113
|
+
export declare function dataFabricDelete(inputs: DataFabricDeleteInputs): ActionSpec;
|