@uipath/maestro-builder-sdk 5.2.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/LICENSE +21 -0
- package/README.md +322 -0
- package/dist/bindings-v2.d.ts +37 -0
- package/dist/bindings-v2.js +155 -0
- package/dist/bindings.d.ts +6 -0
- package/dist/bindings.js +6 -0
- package/dist/bpmn/bpmn-expr-check.d.ts +41 -0
- package/dist/bpmn/bpmn-expr-check.js +218 -0
- package/dist/bpmn/bpmn-sdk.d.ts +2257 -0
- package/dist/bpmn/bpmn-sdk.js +1476 -0
- package/dist/bpmn/check-cli.d.ts +3 -0
- package/dist/bpmn/check-cli.js +32 -0
- package/dist/bpmn/check.d.ts +25 -0
- package/dist/bpmn/check.js +430 -0
- package/dist/bpmn/compile-cli.d.ts +3 -0
- package/dist/bpmn/compile-cli.js +60 -0
- package/dist/bpmn/connector.d.ts +56 -0
- package/dist/bpmn/connector.js +199 -0
- package/dist/bpmn/decompile-cli.d.ts +8 -0
- package/dist/bpmn/decompile-cli.js +54 -0
- package/dist/bpmn/decompile.d.ts +6 -0
- package/dist/bpmn/decompile.js +1108 -0
- package/dist/bpmn/format-profile.d.ts +27 -0
- package/dist/bpmn/format-profile.js +11 -0
- package/dist/bpmn/intsvc.d.ts +77 -0
- package/dist/bpmn/intsvc.js +155 -0
- package/dist/bpmn/load.d.ts +4 -0
- package/dist/bpmn/load.js +22 -0
- package/dist/bpmn/merge-cli.d.ts +3 -0
- package/dist/bpmn/merge-cli.js +45 -0
- package/dist/bpmn/merge.d.ts +19 -0
- package/dist/bpmn/merge.js +293 -0
- package/dist/bpmn/registry-types.json +1869 -0
- package/dist/bpmn/serialize.d.ts +28 -0
- package/dist/bpmn/serialize.js +757 -0
- package/dist/bpmn/tidy-cli.d.ts +2 -0
- package/dist/bpmn/tidy-cli.js +39 -0
- package/dist/bpmn/typed-node.d.ts +382 -0
- package/dist/bpmn/typed-node.js +551 -0
- package/dist/bpmn/uipath-moddle.v1.json +823 -0
- package/dist/bpmn/xml-ranges.d.ts +45 -0
- package/dist/bpmn/xml-ranges.js +151 -0
- package/dist/case/case-expr-check.d.ts +35 -0
- package/dist/case/case-expr-check.js +85 -0
- package/dist/case/case-sdk.d.ts +1282 -0
- package/dist/case/case-sdk.js +923 -0
- package/dist/case/check-cli.d.ts +3 -0
- package/dist/case/check-cli.js +31 -0
- package/dist/case/check.d.ts +18 -0
- package/dist/case/check.js +456 -0
- package/dist/case/compile-cli.d.ts +3 -0
- package/dist/case/compile-cli.js +291 -0
- package/dist/case/decompile-cli.d.ts +9 -0
- package/dist/case/decompile-cli.js +117 -0
- package/dist/case/decompile.d.ts +187 -0
- package/dist/case/decompile.js +1170 -0
- package/dist/case/entry-points.d.ts +79 -0
- package/dist/case/entry-points.js +118 -0
- package/dist/case/format-profile.d.ts +60 -0
- package/dist/case/format-profile.js +79 -0
- package/dist/case/ids.d.ts +24 -0
- package/dist/case/ids.js +76 -0
- package/dist/case/load.d.ts +12 -0
- package/dist/case/load.js +32 -0
- package/dist/case/preserve.d.ts +133 -0
- package/dist/case/preserve.js +105 -0
- package/dist/case/serialize.d.ts +10 -0
- package/dist/case/serialize.js +1414 -0
- package/dist/check-cli.d.ts +3 -0
- package/dist/check-cli.js +118 -0
- package/dist/check.d.ts +146 -0
- package/dist/check.js +4898 -0
- package/dist/cli/commands/bpmn.d.ts +2 -0
- package/dist/cli/commands/bpmn.js +73 -0
- package/dist/cli/commands/case.d.ts +2 -0
- package/dist/cli/commands/case.js +60 -0
- package/dist/cli/commands/flow.d.ts +2 -0
- package/dist/cli/commands/flow.js +99 -0
- package/dist/cli/commands/registry.d.ts +10 -0
- package/dist/cli/commands/registry.js +170 -0
- package/dist/cli/common.d.ts +30 -0
- package/dist/cli/common.js +92 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +18 -0
- package/dist/cli-run.d.ts +2 -0
- package/dist/cli-run.js +42 -0
- package/dist/compile-cli.d.ts +3 -0
- package/dist/compile-cli.js +160 -0
- package/dist/config.d.ts +47 -0
- package/dist/config.js +201 -0
- package/dist/core/actions.d.ts +3244 -0
- package/dist/core/actions.js +1062 -0
- package/dist/core/binding-messages.d.ts +1 -0
- package/dist/core/binding-messages.js +16 -0
- package/dist/core/bindings.d.ts +12 -0
- package/dist/core/bindings.js +67 -0
- package/dist/core/ceql.d.ts +73 -0
- package/dist/core/ceql.js +272 -0
- package/dist/core/cli-spelling.d.ts +39 -0
- package/dist/core/cli-spelling.js +62 -0
- package/dist/core/connector-raw-node.d.ts +21 -0
- package/dist/core/connector-raw-node.js +47 -0
- package/dist/core/connectors.d.ts +184 -0
- package/dist/core/connectors.js +128 -0
- package/dist/core/expr-check.d.ts +93 -0
- package/dist/core/expr-check.js +186 -0
- package/dist/core/expr.d.ts +323 -0
- package/dist/core/expr.js +400 -0
- package/dist/core/index.d.ts +10 -0
- package/dist/core/index.js +10 -0
- package/dist/core/library.d.ts +440 -0
- package/dist/core/library.js +1183 -0
- package/dist/core/list-envelope.d.ts +45 -0
- package/dist/core/list-envelope.js +97 -0
- package/dist/core/lookup-store.d.ts +22 -0
- package/dist/core/lookup-store.js +85 -0
- package/dist/core/lookups.d.ts +227 -0
- package/dist/core/lookups.js +231 -0
- package/dist/core/node-classes.d.ts +234 -0
- package/dist/core/node-classes.js +158 -0
- package/dist/core/script-return.d.ts +68 -0
- package/dist/core/script-return.js +197 -0
- package/dist/core/stable-id.d.ts +28 -0
- package/dist/core/stable-id.js +37 -0
- package/dist/core-definitions.json +16249 -0
- package/dist/decompile-cli.d.ts +3 -0
- package/dist/decompile-cli.js +131 -0
- package/dist/decompile.d.ts +138 -0
- package/dist/decompile.js +2482 -0
- package/dist/emit.d.ts +10 -0
- package/dist/emit.js +60 -0
- package/dist/event-filters.d.ts +130 -0
- package/dist/event-filters.js +137 -0
- package/dist/flow-expr-check.d.ts +17 -0
- package/dist/flow-expr-check.js +193 -0
- package/dist/flow-sdk.d.ts +1341 -0
- package/dist/flow-sdk.js +1164 -0
- package/dist/flow-variables.d.ts +13 -0
- package/dist/flow-variables.js +42 -0
- package/dist/format-profile.d.ts +72 -0
- package/dist/format-profile.js +97 -0
- package/dist/generators/_connections.py +287 -0
- package/dist/generators/_events.py +355 -0
- package/dist/generators/_lookups.py +114 -0
- package/dist/generators/_naming.py +185 -0
- package/dist/generators/_objects.py +299 -0
- package/dist/generators/_resolve.py +273 -0
- package/dist/generators/convert_library_to_md.py +1441 -0
- package/dist/generators/extract_library.py +125 -0
- package/dist/generators/generate_connectors_ts.py +936 -0
- package/dist/generators/generate_library_json.py +2527 -0
- package/dist/generators/generate_triggers_ts.py +110 -0
- package/dist/generators/materialize_registry.py +155 -0
- package/dist/generators/prepare_connector.py +1688 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +35 -0
- package/dist/ixp-definition.json +1982 -0
- package/dist/library.d.ts +6 -0
- package/dist/library.js +6 -0
- package/dist/load.d.ts +16 -0
- package/dist/load.js +95 -0
- package/dist/merge-cli.d.ts +3 -0
- package/dist/merge-cli.js +47 -0
- package/dist/merge.d.ts +125 -0
- package/dist/merge.js +0 -0
- package/dist/migrate.d.ts +15 -0
- package/dist/migrate.js +245 -0
- package/dist/node-runtime.d.ts +3 -0
- package/dist/node-runtime.js +22 -0
- package/dist/package-name.d.ts +17 -0
- package/dist/package-name.js +17 -0
- package/dist/ref-resolve.d.ts +77 -0
- package/dist/ref-resolve.js +170 -0
- package/dist/registry/cache.d.ts +55 -0
- package/dist/registry/cache.js +134 -0
- package/dist/registry/curated-overlay.d.ts +16 -0
- package/dist/registry/curated-overlay.js +62 -0
- package/dist/registry/extractor.d.ts +22 -0
- package/dist/registry/extractor.js +18 -0
- package/dist/registry/materialize-bin.d.ts +2 -0
- package/dist/registry/materialize-bin.js +7 -0
- package/dist/registry/materialize-cli.d.ts +1 -0
- package/dist/registry/materialize-cli.js +46 -0
- package/dist/registry/materializer.d.ts +23 -0
- package/dist/registry/materializer.js +34 -0
- package/dist/registry/path-cli.d.ts +1 -0
- package/dist/registry/path-cli.js +56 -0
- package/dist/registry/prepare-cli.d.ts +62 -0
- package/dist/registry/prepare-cli.js +185 -0
- package/dist/registry/pull-cli.d.ts +1 -0
- package/dist/registry/pull-cli.js +274 -0
- package/dist/registry/python.d.ts +26 -0
- package/dist/registry/python.js +46 -0
- package/dist/registry/search-cli.d.ts +52 -0
- package/dist/registry/search-cli.js +159 -0
- package/dist/schema-version.d.ts +165 -0
- package/dist/schema-version.js +148 -0
- package/dist/serialize.d.ts +64 -0
- package/dist/serialize.js +6398 -0
- package/lib/README.md +112 -0
- package/lib/library-json.samples/index.json +158 -0
- package/lib/library-json.samples/invariant-collections.json +83 -0
- package/lib/library-json.samples/list-envelopes.json +123 -0
- package/lib/library-json.samples/uipath-atlassian-jira/create-issue@1.0.0.json +131 -0
- package/lib/library-json.samples/uipath-atlassian-jira/create-issue@1.0.0.v1def.json +306 -0
- package/lib/library-json.samples/uipath-atlassian-jira/generic/create_issue/create@1.0.0.json +86 -0
- package/lib/library-json.samples/uipath-atlassian-jira/generic/create_issue/create@1.0.0.v1def.json +208 -0
- package/lib/library-json.samples/uipath-atlassian-jira/get-issue@1.0.0.json +2040 -0
- package/lib/library-json.samples/uipath-atlassian-jira/get-issue@1.0.0.v1def.json +195 -0
- package/lib/library-json.samples/uipath-google-vertex/execute-google-vertex-agent@1.0.0.json +169 -0
- package/lib/library-json.samples/uipath-google-vertex/execute-google-vertex-agent@1.0.0.v1def.json +209 -0
- package/lib/library-json.samples/uipath-http-webhook/event-http-webhook@1.0.0.json +63 -0
- package/lib/library-json.samples/uipath-http-webhook/event-http-webhook@1.0.0.v1def.json +262 -0
- package/lib/library-json.samples/uipath-http-webhook/trigger-http-webhook@1.0.0.json +63 -0
- package/lib/library-json.samples/uipath-http-webhook/trigger-http-webhook@1.0.0.v1def.json +213 -0
- package/lib/library-json.samples/uipath-microsoft-azureactivedirectory/list-groups@1.0.0.json +227 -0
- package/lib/library-json.samples/uipath-microsoft-azureactivedirectory/list-groups@1.0.0.v1def.json +373 -0
- package/lib/library-json.samples/uipath-microsoft-onedrive/event-file-created@1.0.0.json +116 -0
- package/lib/library-json.samples/uipath-microsoft-onedrive/event-file-created@1.0.0.v1def.json +369 -0
- package/lib/library-json.samples/uipath-microsoft-onedrive/event-list-item-added@1.0.0.json +56 -0
- package/lib/library-json.samples/uipath-microsoft-onedrive/event-list-item-added@1.0.0.v1def.json +256 -0
- package/lib/library-json.samples/uipath-microsoft-onedrive/trigger-file-created@1.0.0.json +116 -0
- package/lib/library-json.samples/uipath-microsoft-onedrive/trigger-file-created@1.0.0.v1def.json +320 -0
- package/lib/library-json.samples/uipath-microsoft-onedrive/trigger-list-item-added@1.0.0.json +56 -0
- package/lib/library-json.samples/uipath-microsoft-onedrive/trigger-list-item-added@1.0.0.v1def.json +207 -0
- package/lib/library-json.samples/uipath-microsoft-outlook365/event-email-received@1.0.0.json +107 -0
- package/lib/library-json.samples/uipath-microsoft-outlook365/event-email-received@1.0.0.v1def.json +264 -0
- package/lib/library-json.samples/uipath-microsoft-outlook365/send-email@1.0.0.json +142 -0
- package/lib/library-json.samples/uipath-microsoft-outlook365/send-email@1.0.0.v1def.json +306 -0
- package/lib/library-json.samples/uipath-microsoft-outlook365/trigger-email-received@1.0.0.json +107 -0
- package/lib/library-json.samples/uipath-microsoft-outlook365/trigger-email-received@1.0.0.v1def.json +217 -0
- package/lib/library-json.samples/uipath-microsoft-powerautomate/invoke-a-microsoft-power-automate-flow@1.0.0.json +85 -0
- package/lib/library-json.samples/uipath-microsoft-powerautomate/invoke-a-microsoft-power-automate-flow@1.0.0.v1def.json +209 -0
- package/lib/library-json.samples/uipath-salesforce-slack/send-message-to-user@1.0.0.json +755 -0
- package/lib/library-json.samples/uipath-salesforce-slack/send-message-to-user@1.0.0.v1def.json +513 -0
- package/lib/library-json.samples/uipath-uipath-dataservice/query-entity-records@1.0.0.json +122 -0
- package/lib/library-json.samples/uipath-uipath-dataservice/query-entity-records@1.0.0.v1def.json +227 -0
- package/package.json +85 -0
|
@@ -0,0 +1,1341 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* flow-sdk — a small fluent builder for UiPath Flow workflows.
|
|
3
|
+
*
|
|
4
|
+
* You author a workflow as TypeScript code that *constructs* a graph of nodes
|
|
5
|
+
* and edges. Calling `.build()` returns a plain description of that graph; the
|
|
6
|
+
* `compile` tool serializes it into a real `.flow` JSON file.
|
|
7
|
+
*
|
|
8
|
+
* This is deliberately a builder, not a program: control flow (branch/loop) is
|
|
9
|
+
* expressed by calling `.branch()` / `.loop()`, not with native `if`/`for`.
|
|
10
|
+
* Data references are expressed with the expression helpers (`input`, `out`,
|
|
11
|
+
* `v`, `js`, `tmpl`) rather than by reading real values — nothing actually runs
|
|
12
|
+
* at build time except the graph construction.
|
|
13
|
+
*
|
|
14
|
+
* The expression helpers and action specs are shared across all builder SDKs
|
|
15
|
+
* and live in `core/`; this module re-exports them so the historical
|
|
16
|
+
* `flow-sdk.js` authoring surface is unchanged, and adds the Flow-specific
|
|
17
|
+
* builder (steps, branches, loops, return).
|
|
18
|
+
*/
|
|
19
|
+
export * from './core/expr.js';
|
|
20
|
+
export * from './core/actions.js';
|
|
21
|
+
export { resolveFlowRefs, resolveRefPath, hasFileRefs } from './ref-resolve.js';
|
|
22
|
+
export type { RefReader, ResolveRefsOptions } from './ref-resolve.js';
|
|
23
|
+
export * from './core/connectors.js';
|
|
24
|
+
export * from './core/lookups.js';
|
|
25
|
+
export * from './core/node-classes.js';
|
|
26
|
+
import { Expr } from './core/expr.js';
|
|
27
|
+
import type { ErrorEnvelopeField, TypeDesc } from './core/expr.js';
|
|
28
|
+
import type { ActionSpec, EventSubscription, TriggerOptions } from './core/actions.js';
|
|
29
|
+
import type { FlowAction, FlowTrigger } from './core/node-classes.js';
|
|
30
|
+
import type { TriggerDescriptor } from './core/connectors.js';
|
|
31
|
+
export { FlowBuildError, checkFlowExpressions } from './flow-expr-check.js';
|
|
32
|
+
export type { LocatedDiagnostic } from './flow-expr-check.js';
|
|
33
|
+
/** A step that runs a child flow. Built by `subflow(child, inputs)`. */
|
|
34
|
+
export interface SubflowSpec {
|
|
35
|
+
kind: 'subflow';
|
|
36
|
+
/** The child flow's built description — its own inputs, outputs and steps. */
|
|
37
|
+
child: BuiltFlow;
|
|
38
|
+
/** One value per child input, keyed by the child's declared input name. */
|
|
39
|
+
inputs: Record<string, Expr>;
|
|
40
|
+
}
|
|
41
|
+
/** What `.step()` accepts here: the shared actions plus this SDK's subflow. */
|
|
42
|
+
export type FlowActionSpec = ActionSpec | SubflowSpec;
|
|
43
|
+
/** Anything `subflow()` accepts as the child: a builder, or an already-built flow. */
|
|
44
|
+
export type ChildFlow = BuiltFlow | {
|
|
45
|
+
build(): BuiltFlow;
|
|
46
|
+
};
|
|
47
|
+
export interface VarDecl {
|
|
48
|
+
name: string;
|
|
49
|
+
type: TypeDesc;
|
|
50
|
+
default?: unknown;
|
|
51
|
+
/** Human-readable description, persisted on the variable. */
|
|
52
|
+
description?: string;
|
|
53
|
+
/** Sub-type for complex types (e.g. an array's item type). */
|
|
54
|
+
subType?: string;
|
|
55
|
+
/** JSON schema for complex type validation (object/array shapes). */
|
|
56
|
+
schema?: Record<string, unknown>;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The rich spelling of a variable declaration: pass it instead of a bare
|
|
60
|
+
* `types.*` descriptor wherever `.input()` / `.output()` / `.var()` take one,
|
|
61
|
+
* to carry the metadata the `.flow` format persists on a global — a
|
|
62
|
+
* description, a `subType`, a JSON `schema` for object/array shapes, and (for
|
|
63
|
+
* inputs and vars) a `default`.
|
|
64
|
+
*/
|
|
65
|
+
export interface VarSpec {
|
|
66
|
+
/** The variable's type, one of the `types.*` descriptors. */
|
|
67
|
+
type: TypeDesc;
|
|
68
|
+
/** Human-readable description, persisted on the variable. */
|
|
69
|
+
description?: string;
|
|
70
|
+
/** Sub-type for complex types (e.g. an array's item type). */
|
|
71
|
+
subType?: string;
|
|
72
|
+
/** JSON schema for complex type validation (object/array shapes). */
|
|
73
|
+
schema?: Record<string, unknown>;
|
|
74
|
+
/** Default value — inputs and vars only; the format forbids it on outputs. */
|
|
75
|
+
default?: unknown;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The eight intervals the designer offers in its Frequency dropdown. Any other
|
|
79
|
+
* valid
|
|
80
|
+
* {@link https://docs.digi.com/resources/documentation/digidocs/90001488-13/reference/r_iso_8601_duration_format.htm | ISO-8601 repeating interval}
|
|
81
|
+
* works too (see `ScheduleEvery`) — these are
|
|
82
|
+
* just the ones that round-trip as a named preset rather than as "custom".
|
|
83
|
+
*/
|
|
84
|
+
export declare const SCHEDULE_PRESETS: readonly ["R/PT5M", "R/PT15M", "R/PT30M", "R/PT1H", "R/PT6H", "R/PT12H", "R/P1D", "R/P1W"];
|
|
85
|
+
export type SchedulePreset = (typeof SCHEDULE_PRESETS)[number];
|
|
86
|
+
/**
|
|
87
|
+
* How often a scheduled flow runs, as an
|
|
88
|
+
* {@link https://docs.digi.com/resources/documentation/digidocs/90001488-13/reference/r_iso_8601_duration_format.htm | ISO-8601 repeating interval}:
|
|
89
|
+
* `R/` followed by a duration. `R/PT1H` = every hour, `R/PT30M` = every half
|
|
90
|
+
* hour, `R/P1D` = daily, `R/P1W` = weekly.
|
|
91
|
+
*
|
|
92
|
+
* @remarks
|
|
93
|
+
* The union with `string` is deliberate — a preset autocompletes, and any other
|
|
94
|
+
* valid interval (`R/PT45M`, `R/P3D`, `R/2026-05-14T09:00:00Z/P1W`) is accepted.
|
|
95
|
+
* `check` validates the format and rejects a schedule that can never fire.
|
|
96
|
+
*/
|
|
97
|
+
export type ScheduleEvery = SchedulePreset | (string & {});
|
|
98
|
+
export interface ScheduledInputs {
|
|
99
|
+
/**
|
|
100
|
+
* The recurring interval, e.g. `'R/PT1H'` for hourly.
|
|
101
|
+
*
|
|
102
|
+
* @remarks
|
|
103
|
+
* ONE field, deliberately, where the emitted `.flow` has two: the platform
|
|
104
|
+
* encodes a preset in `timerPreset` and anything else as
|
|
105
|
+
* `timerPreset: 'custom'` + `timerValue`. That split is a designer-form
|
|
106
|
+
* artifact — the runtime collapses it right back to a single interval — so
|
|
107
|
+
* the serializer does the encoding and there is nothing here to get wrong.
|
|
108
|
+
*/
|
|
109
|
+
every: ScheduleEvery;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* What starts the flow. Three options: the manual trigger (the default — omit
|
|
113
|
+
* `.trigger()`), a schedule, or a CONNECTOR EVENT.
|
|
114
|
+
*/
|
|
115
|
+
export type TriggerSpec = {
|
|
116
|
+
kind: 'manual';
|
|
117
|
+
} | {
|
|
118
|
+
kind: 'scheduled';
|
|
119
|
+
inputs: ScheduledInputs;
|
|
120
|
+
} | {
|
|
121
|
+
kind: 'event';
|
|
122
|
+
subscription: EventSubscription;
|
|
123
|
+
} | {
|
|
124
|
+
kind: 'form';
|
|
125
|
+
} | {
|
|
126
|
+
kind: 'conversation';
|
|
127
|
+
} | {
|
|
128
|
+
kind: 'voice';
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* The manual trigger, explicitly. Omitting `.trigger(...)` means exactly this —
|
|
132
|
+
* the factory exists so decompiled source can carry the trigger's exact
|
|
133
|
+
* definition version (`.trigger(manual(), { version: '1.0.0' })`) instead of
|
|
134
|
+
* leaving the default implicit, and so hand-written flows can opt into the
|
|
135
|
+
* same explicitness.
|
|
136
|
+
*
|
|
137
|
+
* @returns A trigger spec to pass to `.trigger(...)`.
|
|
138
|
+
*/
|
|
139
|
+
export declare function manual(): TriggerSpec;
|
|
140
|
+
/**
|
|
141
|
+
* Start the flow when a connector event fires — e.g. an email arriving in a
|
|
142
|
+
* mailbox folder.
|
|
143
|
+
*
|
|
144
|
+
* @remarks
|
|
145
|
+
* ```ts
|
|
146
|
+
* export default flow('intake')
|
|
147
|
+
* .trigger(onEvent({
|
|
148
|
+
* connector: 'uipath-microsoft-outlook365',
|
|
149
|
+
* event: 'email-received',
|
|
150
|
+
* where: { parentFolderId: inboxId },
|
|
151
|
+
* }))
|
|
152
|
+
* .step('extract', script({ code: 'return { subject: $vars.start.output.subject };' }))
|
|
153
|
+
* .build();
|
|
154
|
+
* ```
|
|
155
|
+
*
|
|
156
|
+
* A generated {@link TriggerDescriptor} can supply the connector/event instead —
|
|
157
|
+
* `.trigger(onEvent(EmailReceived, { where: { parentFolderId: inboxId } }))` —
|
|
158
|
+
* see `sdk/connectors/<key>.triggers.ts`.
|
|
159
|
+
*
|
|
160
|
+
* The trigger's payload is read like any step output — `out('start', 'subject')`
|
|
161
|
+
* — and locally it is supplied as flow input (`--input`), because a start trigger
|
|
162
|
+
* produces no dispatch record. **No local rung fires a real event**: what a green
|
|
163
|
+
* ladder proves is the right trigger type, the right subscription, and that the
|
|
164
|
+
* graph runs. See `references/event-trigger.md`.
|
|
165
|
+
*
|
|
166
|
+
* To pause an already-running flow instead, use `waitForEvent(...)` as a step —
|
|
167
|
+
* the same subscription, the sibling node type.
|
|
168
|
+
*
|
|
169
|
+
* This is the TYPED form — a generated trigger descriptor identifies the event,
|
|
170
|
+
* as in `onEvent(EmailReceived, { where: { … } })`.
|
|
171
|
+
*
|
|
172
|
+
* @param descriptor - The generated trigger, from a prepared connector module.
|
|
173
|
+
* @param opts - The event's `where` scope, `filters`, and symbolic
|
|
174
|
+
* `connection` / `folder`.
|
|
175
|
+
* @returns A trigger spec to pass to `.trigger(...)`.
|
|
176
|
+
*/
|
|
177
|
+
export declare function onEvent<W>(descriptor: TriggerDescriptor<W, unknown>, opts?: TriggerOptions<W>): TriggerSpec;
|
|
178
|
+
/**
|
|
179
|
+
* Stringly form, for an event with no prepared module.
|
|
180
|
+
*
|
|
181
|
+
* @param subscription - The event to start on: `connector`, `event`, its `where`
|
|
182
|
+
* scope, and optional `filters`.
|
|
183
|
+
* @returns A trigger spec to pass to `.trigger(...)`.
|
|
184
|
+
*/
|
|
185
|
+
export declare function onEvent(subscription: EventSubscription): TriggerSpec;
|
|
186
|
+
/**
|
|
187
|
+
* Start the flow on a recurring schedule instead of on demand.
|
|
188
|
+
*
|
|
189
|
+
* @remarks
|
|
190
|
+
* Field shapes, the interval format, and what a local run does and does not
|
|
191
|
+
* prove: `references/scheduled-trigger.md`.
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* **Run a flow daily**
|
|
195
|
+
* ```ts
|
|
196
|
+
* export default flow('nightly-rollup')
|
|
197
|
+
* .trigger(scheduled({ every: 'R/P1D' }))
|
|
198
|
+
* .step('rollup', script({ code: 'return { ok: true };' }))
|
|
199
|
+
* .build();
|
|
200
|
+
* ```
|
|
201
|
+
*
|
|
202
|
+
* @param inputs - The recurring interval, e.g. `{ every: 'R/PT1H' }`.
|
|
203
|
+
* @returns A trigger spec to pass to `.trigger(...)`.
|
|
204
|
+
*/
|
|
205
|
+
export declare function scheduled(inputs: ScheduledInputs): TriggerSpec;
|
|
206
|
+
/**
|
|
207
|
+
* Start the flow from a FORM a person fills in (`core.trigger.form`) — the
|
|
208
|
+
* platform renders one field per flow input and the submitted values ARE the
|
|
209
|
+
* flow's inputs.
|
|
210
|
+
*
|
|
211
|
+
* ```ts
|
|
212
|
+
* export default flow('expense-request')
|
|
213
|
+
* .input({ amount: types.number, reason: types.string })
|
|
214
|
+
* .trigger(formTrigger())
|
|
215
|
+
* .step('review', hitl({ … }))
|
|
216
|
+
* .build();
|
|
217
|
+
* ```
|
|
218
|
+
*
|
|
219
|
+
* The form's fields are DERIVED from `.input()` — one per input, the same rule
|
|
220
|
+
* the designer's own form-trigger editor applies to a flow's arguments: the
|
|
221
|
+
* field id is the input's name (so submitted values line up by name), the label
|
|
222
|
+
* is the name sentence-cased, the field type follows the input's type, and a
|
|
223
|
+
* field is required exactly when its input declares no default.
|
|
224
|
+
*
|
|
225
|
+
* The definition is BUNDLED from the workbench manifest — the tenant registry
|
|
226
|
+
* does not serve the family (same availability note as do-while).
|
|
227
|
+
*
|
|
228
|
+
* No local rung renders a form: `--input` supplies the values locally, and a
|
|
229
|
+
* green ladder proves the trigger type, the derived schema, and that the graph
|
|
230
|
+
* runs — not that a person saw a form.
|
|
231
|
+
*
|
|
232
|
+
* @returns A trigger spec to pass to `.trigger(...)`.
|
|
233
|
+
*/
|
|
234
|
+
export declare function formTrigger(): TriggerSpec;
|
|
235
|
+
/**
|
|
236
|
+
* Start the flow when a new CONVERSATION is created
|
|
237
|
+
* (`core.trigger.conversation`) — the entry point for a chat-driven process.
|
|
238
|
+
*
|
|
239
|
+
* ```ts
|
|
240
|
+
* export default flow('support-chat')
|
|
241
|
+
* .trigger(conversationTrigger())
|
|
242
|
+
* .step('listen', waitForMessage({ conversationId: out('start', 'conversationId') }))
|
|
243
|
+
* .step('answer', sendMessage({
|
|
244
|
+
* conversationId: out('start', 'conversationId'),
|
|
245
|
+
* exchangeId: out('listen', 'conversationContext.latestExchangeId'),
|
|
246
|
+
* content: 'Looking into it.',
|
|
247
|
+
* }))
|
|
248
|
+
* .build();
|
|
249
|
+
* ```
|
|
250
|
+
*
|
|
251
|
+
* The trigger publishes the conversation it started —
|
|
252
|
+
* `out('start', 'conversationId')` — which is what every conversational step
|
|
253
|
+
* is keyed by. Nothing else is authored on it.
|
|
254
|
+
*
|
|
255
|
+
* The definition is BUNDLED from the workbench manifest: the family is
|
|
256
|
+
* `AvailableOnTenant: false` today, so a flow compiles and validates offline
|
|
257
|
+
* while the platform catches up (the do-while precedent).
|
|
258
|
+
*
|
|
259
|
+
* @returns A trigger spec to pass to `.trigger(...)`.
|
|
260
|
+
*/
|
|
261
|
+
export declare function conversationTrigger(): TriggerSpec;
|
|
262
|
+
/**
|
|
263
|
+
* Start the flow when a phone call comes IN (`core.trigger.voice`).
|
|
264
|
+
*
|
|
265
|
+
* ```ts
|
|
266
|
+
* export default flow('support-line')
|
|
267
|
+
* .trigger(voiceTrigger())
|
|
268
|
+
* .step('greet', voiceAgent({
|
|
269
|
+
* systemPrompt: 'Greet {{input.customerName}} and find out why they called.',
|
|
270
|
+
* inputs: { customerName: input('customerName') },
|
|
271
|
+
* callContext: out('start', 'callContext'),
|
|
272
|
+
* }))
|
|
273
|
+
* .step('hangUp', endCall({ callContext: out('start', 'callContext') }))
|
|
274
|
+
* .build();
|
|
275
|
+
* ```
|
|
276
|
+
*
|
|
277
|
+
* The trigger publishes the live call as `out('start', 'callContext')` — the
|
|
278
|
+
* object (`{ type, id, conversationId, … }`) every voice step is keyed by.
|
|
279
|
+
* Nothing else is authored on it.
|
|
280
|
+
*
|
|
281
|
+
* The definition is BUNDLED from the workbench manifest: the family is
|
|
282
|
+
* `AvailableOnTenant: false` today (the do-while precedent).
|
|
283
|
+
*
|
|
284
|
+
* @returns A trigger spec to pass to `.trigger(...)`.
|
|
285
|
+
*/
|
|
286
|
+
export declare function voiceTrigger(): TriggerSpec;
|
|
287
|
+
/** A value a `.switch` case compares the discriminant against. */
|
|
288
|
+
export type CaseValue = string | number | boolean;
|
|
289
|
+
/** One arm of a built `.switch` (the serializer's view: body already collected). */
|
|
290
|
+
export interface SwitchArm {
|
|
291
|
+
value: CaseValue;
|
|
292
|
+
label?: string;
|
|
293
|
+
body: Step[];
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Options shared by every builder method that creates a definition-backed node:
|
|
297
|
+
* `version` selects the exact node definition to compile against, and `updates`
|
|
298
|
+
* assigns flow variables when the node completes.
|
|
299
|
+
*/
|
|
300
|
+
export interface NodeOptions {
|
|
301
|
+
/**
|
|
302
|
+
* The EXACT `definitions[].version` (and node `typeVersion`) this node must
|
|
303
|
+
* compile against — a request and a constraint, never a "latest" selector.
|
|
304
|
+
* Omit it and the SDK uses its pinned default for the node family; name a
|
|
305
|
+
* version the SDK cannot resolve exactly and compilation fails rather than
|
|
306
|
+
* substituting another version.
|
|
307
|
+
*/
|
|
308
|
+
version?: string;
|
|
309
|
+
/**
|
|
310
|
+
* Flow-variable assignments applied when this node completes — the format's
|
|
311
|
+
* `variables.variableUpdates[nodeId]`, attached to the real node exactly as
|
|
312
|
+
* Flow JSON stores it. Keys name declared `.var()` variables (or flow
|
|
313
|
+
* outputs); values are `Expr`s or raw literals.
|
|
314
|
+
*
|
|
315
|
+
* @remarks
|
|
316
|
+
* Not accepted on `.branch()`, `.switch()`, `.parallel()`, or `.trigger()` —
|
|
317
|
+
* the platform strips updates from decision/switch/merge nodes on save, and a
|
|
318
|
+
* trigger has not run anything to assign from.
|
|
319
|
+
*/
|
|
320
|
+
updates?: Record<string, Expr | unknown>;
|
|
321
|
+
/**
|
|
322
|
+
* What the canvas shows on this node (`display.label`). Defaults to the step
|
|
323
|
+
* name.
|
|
324
|
+
*
|
|
325
|
+
* @remarks
|
|
326
|
+
* Purely cosmetic, and deliberately separate from the step name: the NAME is
|
|
327
|
+
* the node's identity — it becomes the node id and every `out('<step>', …)`
|
|
328
|
+
* reads through it — so renaming what a reviewer sees must not move the node
|
|
329
|
+
* or rewrite its expressions. Use a step name you want to write code against
|
|
330
|
+
* and a label you want to read on the canvas.
|
|
331
|
+
*
|
|
332
|
+
* ```ts
|
|
333
|
+
* .step('fetchInv', http({ url, managed: true }), { label: 'Fetch invoice' })
|
|
334
|
+
* ```
|
|
335
|
+
*
|
|
336
|
+
* `.branch()`, `.switch()`, `.loop()`, `.doWhile()`, `.parallel()` and
|
|
337
|
+
* `.terminate()` take their label as a positional argument instead.
|
|
338
|
+
*/
|
|
339
|
+
label?: string;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* `.return(...)`-specific options.
|
|
343
|
+
*
|
|
344
|
+
* @remarks
|
|
345
|
+
* An End is the one node the builder used to give no way to name: every other
|
|
346
|
+
* construct takes its id positionally (`.step('<name>', …)`, `.terminate('<name>')`),
|
|
347
|
+
* but a `.return()` always minted `end`, `end2`, … and labelled the node `End`.
|
|
348
|
+
* That made a decompile → compile round trip impossible for any flow whose Ends
|
|
349
|
+
* carry designer-chosen ids — the normal case, since the canvas names an End
|
|
350
|
+
* after the branch arm that reaches it, so `endNiceDay` / `endBringJacket` rather
|
|
351
|
+
* than `end` / `end2`. Decompile emitted a `.layout({ nodes: { endNiceDay: … } })`
|
|
352
|
+
* block naming ids the recompile then failed to produce, and compile rejected its
|
|
353
|
+
* own round trip with `layout: "endNiceDay" names no step or node in this flow`.
|
|
354
|
+
*/
|
|
355
|
+
export interface ReturnOptions extends NodeOptions {
|
|
356
|
+
/**
|
|
357
|
+
* The End node's id — what `layout` keys on and what `nodes[].id` becomes.
|
|
358
|
+
* Defaults to `end`, then `end2`, `end3`, … in emission order.
|
|
359
|
+
*
|
|
360
|
+
* @remarks
|
|
361
|
+
* Like a step name this is identity, not decoration: use {@link NodeOptions.label}
|
|
362
|
+
* for what the canvas shows. Ids are de-duplicated, so two Ends both asking for
|
|
363
|
+
* `done` become `done` and `done2`.
|
|
364
|
+
*
|
|
365
|
+
* ```ts
|
|
366
|
+
* .branch('checkTemperature', js`$vars.tempF > 60`,
|
|
367
|
+
* (t) => t.return({}, { name: 'endNiceDay', label: 'Nice Day' }),
|
|
368
|
+
* (e) => e.return({}, { name: 'endBringJacket', label: 'Bring a Jacket' }))
|
|
369
|
+
* ```
|
|
370
|
+
*/
|
|
371
|
+
name?: string;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Loop-specific options. Any of these — or a `b.break()` in the
|
|
375
|
+
* body — selects the loop's v2.4 definition (the current Workbench contract,
|
|
376
|
+
* with inner `start`/`continue`/`break` handles); a plain `.loop()` keeps the
|
|
377
|
+
* SDK's long-pinned 1.0.0 emission unchanged. An explicit `{ version: '1.0.0' }`
|
|
378
|
+
* combined with any of these fails compilation: that definition cannot express
|
|
379
|
+
* them.
|
|
380
|
+
*/
|
|
381
|
+
export interface LoopOptions extends NodeOptions {
|
|
382
|
+
/** Run iterations in parallel instead of sequentially. */
|
|
383
|
+
parallel?: boolean;
|
|
384
|
+
/**
|
|
385
|
+
* Stop early when this condition (evaluated after each iteration) is true —
|
|
386
|
+
* e.g. `js`$vars.hits.output.length >= 10``.
|
|
387
|
+
*/
|
|
388
|
+
completionCondition?: Expr;
|
|
389
|
+
/**
|
|
390
|
+
* Show the loop's break handle without wiring one — set automatically when
|
|
391
|
+
* the body calls `b.break()`.
|
|
392
|
+
*/
|
|
393
|
+
breakEnabled?: boolean;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Do-while options. `limit` caps iterations; the platform
|
|
397
|
+
* defaults a blank limit to 10,000 and rejects values outside 1–10,000.
|
|
398
|
+
*/
|
|
399
|
+
export interface DoWhileOptions extends NodeOptions {
|
|
400
|
+
/** Maximum iterations, 1–10,000. Blank means the platform default (10,000). */
|
|
401
|
+
limit?: number;
|
|
402
|
+
/** Show the break handle without wiring one — set automatically by `b.break()`. */
|
|
403
|
+
breakEnabled?: boolean;
|
|
404
|
+
}
|
|
405
|
+
export type Step = {
|
|
406
|
+
kind: 'action';
|
|
407
|
+
name: string;
|
|
408
|
+
spec: FlowActionSpec;
|
|
409
|
+
options?: NodeOptions;
|
|
410
|
+
} | {
|
|
411
|
+
kind: 'branch';
|
|
412
|
+
name: string;
|
|
413
|
+
label?: string;
|
|
414
|
+
trueLabel?: string;
|
|
415
|
+
falseLabel?: string;
|
|
416
|
+
cond: Expr;
|
|
417
|
+
then: Step[];
|
|
418
|
+
otherwise: Step[];
|
|
419
|
+
options?: NodeOptions;
|
|
420
|
+
} | {
|
|
421
|
+
kind: 'switch';
|
|
422
|
+
name: string;
|
|
423
|
+
label?: string;
|
|
424
|
+
on: Expr;
|
|
425
|
+
cases: SwitchArm[];
|
|
426
|
+
default?: Step[];
|
|
427
|
+
options?: NodeOptions;
|
|
428
|
+
} | {
|
|
429
|
+
kind: 'loop';
|
|
430
|
+
name: string;
|
|
431
|
+
label?: string;
|
|
432
|
+
collection: Expr;
|
|
433
|
+
body: Step[];
|
|
434
|
+
options?: LoopOptions;
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* A do-while container (`core.logic.dowhile`): run the body, then repeat
|
|
438
|
+
* while `condition` is true, up to `options.limit` iterations.
|
|
439
|
+
*/
|
|
440
|
+
| {
|
|
441
|
+
kind: 'doWhile';
|
|
442
|
+
name: string;
|
|
443
|
+
label?: string;
|
|
444
|
+
condition: Expr;
|
|
445
|
+
body: Step[];
|
|
446
|
+
options?: DoWhileOptions;
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Exit the enclosing loop/do-while through its break handle. Terminal on its
|
|
450
|
+
* path — nothing after it can run. Only valid inside a container body.
|
|
451
|
+
*/
|
|
452
|
+
| {
|
|
453
|
+
kind: 'break';
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* A fan-out and its join. `arms` is one step list per arm — an ARRAY, because
|
|
457
|
+
* arms are positional and carry no author-supplied keys — and `name` names the
|
|
458
|
+
* Merge node the arms converge on (the only node this step creates; the fork
|
|
459
|
+
* itself is just N edges out of one port).
|
|
460
|
+
*/
|
|
461
|
+
| {
|
|
462
|
+
kind: 'parallel';
|
|
463
|
+
name: string;
|
|
464
|
+
label?: string;
|
|
465
|
+
arms: Step[][];
|
|
466
|
+
options?: NodeOptions;
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* A hard stop: `core.logic.terminate`, a BPMN End event carrying a
|
|
470
|
+
* TerminateEventDefinition. Ends the whole RUN, not just this path — which is
|
|
471
|
+
* the only difference from `return`, and the reason it needs a node id.
|
|
472
|
+
*/
|
|
473
|
+
| {
|
|
474
|
+
kind: 'terminate';
|
|
475
|
+
name: string;
|
|
476
|
+
label?: string;
|
|
477
|
+
options?: NodeOptions;
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* An edge to another step, by name. Creates no node of its own: it is ONE
|
|
481
|
+
* EDGE, added after the whole flow is emitted, because the target is often
|
|
482
|
+
* declared later in the file than the step that names it.
|
|
483
|
+
*
|
|
484
|
+
* `port` is the port of the step this leaves — `'output'` (the default) hands
|
|
485
|
+
* the path off, so nothing may follow it in the same list; any other port is a
|
|
486
|
+
* side exit and the chain continues. See `StepList.stepToRef`.
|
|
487
|
+
*/
|
|
488
|
+
| {
|
|
489
|
+
kind: 'stepToRef';
|
|
490
|
+
port: string;
|
|
491
|
+
target: string;
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* A step list wired from a named PORT of the step this follows — the general
|
|
495
|
+
* form of an error handler. The body is its own path: it either ends in a
|
|
496
|
+
* terminal of its own or hands control back with a `stepToRef`.
|
|
497
|
+
*
|
|
498
|
+
* `.onError(...)` is this with `port: 'error'`, which is the case nearly every
|
|
499
|
+
* flow uses. See `StepList.stepToList`.
|
|
500
|
+
*/
|
|
501
|
+
| {
|
|
502
|
+
kind: 'stepToList';
|
|
503
|
+
port: string;
|
|
504
|
+
body: Step[];
|
|
505
|
+
} | {
|
|
506
|
+
kind: 'return';
|
|
507
|
+
name: string;
|
|
508
|
+
values: Record<string, Expr>;
|
|
509
|
+
options?: ReturnOptions;
|
|
510
|
+
};
|
|
511
|
+
/** One node's designer layout: canvas position, and optionally size and collapsed state. */
|
|
512
|
+
export interface NodeLayout {
|
|
513
|
+
/** Absolute canvas position. */
|
|
514
|
+
position: {
|
|
515
|
+
x: number;
|
|
516
|
+
y: number;
|
|
517
|
+
};
|
|
518
|
+
/** Node size; omit for the designer default. */
|
|
519
|
+
size?: {
|
|
520
|
+
width: number;
|
|
521
|
+
height: number;
|
|
522
|
+
};
|
|
523
|
+
/** Whether the node renders collapsed. */
|
|
524
|
+
collapsed?: boolean;
|
|
525
|
+
}
|
|
526
|
+
/** One edge's route: user-dragged bends and/or the auto-router's waypoints. */
|
|
527
|
+
export interface EdgeRoute {
|
|
528
|
+
/** Manually placed bends, in canvas coordinates. Win over the routed set. */
|
|
529
|
+
waypoints?: {
|
|
530
|
+
x: number;
|
|
531
|
+
y: number;
|
|
532
|
+
id?: string;
|
|
533
|
+
}[];
|
|
534
|
+
/** The layout engine's obstacle-avoiding route. */
|
|
535
|
+
routedWaypoints?: {
|
|
536
|
+
x: number;
|
|
537
|
+
y: number;
|
|
538
|
+
id?: string;
|
|
539
|
+
}[];
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* The designer's sticky-note palette. Any other string is passed through — the
|
|
543
|
+
* `.flow` format stores `inputs.color` unvalidated — but these five are what the
|
|
544
|
+
* canvas offers and what round-trips as a named swatch.
|
|
545
|
+
*/
|
|
546
|
+
export declare const STICKY_NOTE_COLORS: readonly ["yellow", "pink", "blue", "green", "white"];
|
|
547
|
+
/**
|
|
548
|
+
* A sticky note's swatch. One of {@link STICKY_NOTE_COLORS} autocompletes; any
|
|
549
|
+
* other string is accepted and passed straight through, because the format
|
|
550
|
+
* stores `inputs.color` without validating it.
|
|
551
|
+
*/
|
|
552
|
+
export type StickyNoteColor = (typeof STICKY_NOTE_COLORS)[number] | (string & {});
|
|
553
|
+
/**
|
|
554
|
+
* A canvas sticky note — free text pinned to the diagram, for the humans reading
|
|
555
|
+
* it.
|
|
556
|
+
*
|
|
557
|
+
* @remarks
|
|
558
|
+
* A note is a real entry in the file's `nodes[]` (type `stickyNote`), not a
|
|
559
|
+
* layout entry, which is why it carries an `id` and its own geometry. It has no
|
|
560
|
+
* manifest and no definition: the platform skips it during validation and
|
|
561
|
+
* conversion, and drops any edge touching it. So it is inert — it annotates the
|
|
562
|
+
* diagram and can never change what the flow does.
|
|
563
|
+
*/
|
|
564
|
+
export interface StickyNote {
|
|
565
|
+
/**
|
|
566
|
+
* The note's node id. Defaults to `stickyNote_1`, `stickyNote_2`, … in
|
|
567
|
+
* declaration order.
|
|
568
|
+
*
|
|
569
|
+
* @remarks
|
|
570
|
+
* Name it when the flow is round-tripped (decompile → edit → compile): the id
|
|
571
|
+
* is what makes a note the SAME note across compiles, so an unnamed note in an
|
|
572
|
+
* edited file can renumber and read as delete-plus-create.
|
|
573
|
+
*/
|
|
574
|
+
id?: string;
|
|
575
|
+
/** The note's text. */
|
|
576
|
+
content: string;
|
|
577
|
+
/** Swatch; defaults to `'yellow'`. */
|
|
578
|
+
color?: StickyNoteColor;
|
|
579
|
+
/** Canvas x of the note's top-left corner. */
|
|
580
|
+
x: number;
|
|
581
|
+
/** Canvas y of the note's top-left corner. */
|
|
582
|
+
y: number;
|
|
583
|
+
/** Note width. Pass it with `height` or not at all; omit for the designer default. */
|
|
584
|
+
width?: number;
|
|
585
|
+
/** Note height. Pass it with `width` or not at all; omit for the designer default. */
|
|
586
|
+
height?: number;
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* Designer layout for a flow, keyed by AUTHOR-level ids: node
|
|
590
|
+
* entries by step name (plus the trigger id and `end`), edge entries by
|
|
591
|
+
* `"<fromStep>-><toStep>"`. Serialization resolves the keys after node ids are
|
|
592
|
+
* finalized; an unknown key is a compile error, an omitted node simply stays
|
|
593
|
+
* where the serializer's default puts it. Layout is metadata — it never
|
|
594
|
+
* affects semantic checks.
|
|
595
|
+
*/
|
|
596
|
+
export interface FlowLayout {
|
|
597
|
+
/** Per-node layout, keyed by step name / trigger id / `end`. */
|
|
598
|
+
nodes?: Record<string, NodeLayout>;
|
|
599
|
+
/** Per-edge routes, keyed by `"<fromStep>-><toStep>"`. */
|
|
600
|
+
edges?: Record<string, EdgeRoute>;
|
|
601
|
+
}
|
|
602
|
+
/** One additional flow root, built by `.entryPoint()`. */
|
|
603
|
+
export interface BuiltEntryPoint {
|
|
604
|
+
/** The trigger node's id — also the root expressions read (`$vars.<id>.output.x`). */
|
|
605
|
+
id: string;
|
|
606
|
+
/** What fires this root: `manual()`, `scheduled(...)`, or `onEvent(...)`. */
|
|
607
|
+
trigger: TriggerSpec;
|
|
608
|
+
/** Node options for the trigger node — exact `version` selection. */
|
|
609
|
+
options?: NodeOptions;
|
|
610
|
+
/** Inputs scoped to this root (globals bound to it via `triggerNodeId`). */
|
|
611
|
+
inputs: VarDecl[];
|
|
612
|
+
/** The root's prefix steps, run before it joins the shared body. */
|
|
613
|
+
steps: Step[];
|
|
614
|
+
}
|
|
615
|
+
export interface BuiltFlow {
|
|
616
|
+
id: string;
|
|
617
|
+
name: string;
|
|
618
|
+
/** Human-readable description, persisted at the top of the .flow file. */
|
|
619
|
+
description?: string;
|
|
620
|
+
version: string;
|
|
621
|
+
/**
|
|
622
|
+
* The FILE-FORMAT version the emitted `.flow` declares, from
|
|
623
|
+
* `.schemaVersion()`. Absent means "the SDK's default write floor"
|
|
624
|
+
* (`FLOW_FORMAT_PROFILE.version`), which is what every flow authored before
|
|
625
|
+
* the method existed means too — so an absent value changes nothing.
|
|
626
|
+
*/
|
|
627
|
+
schemaVersion?: string;
|
|
628
|
+
inputs: VarDecl[];
|
|
629
|
+
outputs: VarDecl[];
|
|
630
|
+
vars: VarDecl[];
|
|
631
|
+
steps: Step[];
|
|
632
|
+
/** Omitted for the manual trigger (the default), so an existing flow's built
|
|
633
|
+
* description — and the `.flow` it serializes to — is unchanged. */
|
|
634
|
+
trigger?: TriggerSpec;
|
|
635
|
+
/** Node options given on `.trigger(spec, options)` — exact version selection. */
|
|
636
|
+
triggerOptions?: NodeOptions;
|
|
637
|
+
/** Designer layout from `.layout()`, resolved at serialization. */
|
|
638
|
+
layout?: FlowLayout;
|
|
639
|
+
/** Canvas sticky notes from `.stickyNotes()`. Inert annotations. */
|
|
640
|
+
stickyNotes?: StickyNote[];
|
|
641
|
+
/** Additional roots from `.entryPoint()`. The default root stays `.trigger()`/`.input()`. */
|
|
642
|
+
entryPoints?: BuiltEntryPoint[];
|
|
643
|
+
/**
|
|
644
|
+
* The trigger node's id. Defaults to `start`. It matters because a flow's
|
|
645
|
+
* declared inputs are published as this node's output, so `input('x')` reads
|
|
646
|
+
* `$vars.<triggerId>.output.x` — rename the node and every such reference
|
|
647
|
+
* follows.
|
|
648
|
+
*/
|
|
649
|
+
triggerId?: string;
|
|
650
|
+
}
|
|
651
|
+
/** Collects a sequence of steps. Used for the flow body and each branch/loop arm. */
|
|
652
|
+
declare class StepList {
|
|
653
|
+
steps: Step[];
|
|
654
|
+
/**
|
|
655
|
+
* The step whose failure led here, set only on the sub-builder `.onError(...)`
|
|
656
|
+
* hands its callback. `err()` on this builder needs no step name because of it.
|
|
657
|
+
*/
|
|
658
|
+
private errorSource?;
|
|
659
|
+
/**
|
|
660
|
+
* Read the failure that led into this handler → `err('<the failed step>', field)`.
|
|
661
|
+
*
|
|
662
|
+
* @remarks
|
|
663
|
+
* Only available on the sub-builder `.onError(...)` / `.stepToList('error', …)`
|
|
664
|
+
* passes to its callback, because only there is "the step that failed" a fact
|
|
665
|
+
* rather than a guess.
|
|
666
|
+
*
|
|
667
|
+
* Prefer it over the free `err('<step>', field)` inside a handler. It cannot
|
|
668
|
+
* name the wrong step, it cannot drift when the step is renamed, and — the
|
|
669
|
+
* reason it exists — it keeps the envelope's LOCATION out of author-visible
|
|
670
|
+
* code entirely. Which variable carries the envelope is per node family
|
|
671
|
+
* (measured: `<step>.error` on connectors, script, deep-rag, subflow and
|
|
672
|
+
* queue; `<step>.output` on managed http), and the compiler resolves it.
|
|
673
|
+
*
|
|
674
|
+
* ```ts
|
|
675
|
+
* .step('load', script({ code: 'return JSON.parse($vars.start.output.raw);' }))
|
|
676
|
+
* .onError((h) => h.return({ note: tmpl`bad payload: ${h.err('message')}` }))
|
|
677
|
+
* ```
|
|
678
|
+
*
|
|
679
|
+
* @param field - One of the envelope's fields. Omit it to test WHETHER the
|
|
680
|
+
* step failed (the boolean the platform sets when the boundary fires).
|
|
681
|
+
* @returns An {@link Expr} reading the failure of the step this handler guards.
|
|
682
|
+
* @see err
|
|
683
|
+
*/
|
|
684
|
+
err(field?: ErrorEnvelopeField): Expr;
|
|
685
|
+
/**
|
|
686
|
+
* Add an action node (see `http` / `script` / `subflow`).
|
|
687
|
+
*
|
|
688
|
+
* @param name - The step's id. Read its result downstream with `out('<name>')`,
|
|
689
|
+
* so it must be unique within the flow.
|
|
690
|
+
* @param spec - What the node does, from an action factory.
|
|
691
|
+
* @param options - Node options; `version` selects the exact definition
|
|
692
|
+
* version (see {@link NodeOptions}).
|
|
693
|
+
* @returns This builder, so calls chain.
|
|
694
|
+
*/
|
|
695
|
+
step(name: string, spec: FlowActionSpec | FlowAction, options?: NodeOptions): this;
|
|
696
|
+
/**
|
|
697
|
+
* Handle the PREVIOUS step's failure: if it fails, the flow runs `bodyFn`'s
|
|
698
|
+
* steps instead of continuing.
|
|
699
|
+
*
|
|
700
|
+
* @remarks
|
|
701
|
+
* ```ts
|
|
702
|
+
* .step('fetch', http({ url: apiUrl, managed: true, returns: { items: 'array' } }))
|
|
703
|
+
* .onError((h) => h.return({ result: lit('Article not found') }))
|
|
704
|
+
* .step('total', transform({ … })) // runs only when `fetch` SUCCEEDED
|
|
705
|
+
* .return({ result: out('total') })
|
|
706
|
+
* ```
|
|
707
|
+
*
|
|
708
|
+
* The handler is its own path — anything chained after `.onError(...)` belongs
|
|
709
|
+
* to the SUCCESS path only. Inside it, read the failure with
|
|
710
|
+
* {@link StepList.err} — `h.err('message')` — or with the free
|
|
711
|
+
* `err('<step>', 'message')` if you prefer to name the step. The envelope
|
|
712
|
+
* carries `code`, `message`, `detail`, `category` and `status` (`code` is a
|
|
713
|
+
* string even for an HTTP status, `status` a number), plus an undeclared
|
|
714
|
+
* `response` and `element` the runtime adds.
|
|
715
|
+
*
|
|
716
|
+
* Do NOT reach for `out('<step>', …)` in here. That reads the step's SUCCESS
|
|
717
|
+
* output, which was never written — the handler runs precisely because the
|
|
718
|
+
* step failed — and `check` refuses it (ERROR_ENVELOPE_VIA_OUTPUT). This doc
|
|
719
|
+
* line used to recommend `out('<step>', 'error', 'message')`, which is not
|
|
720
|
+
* even a legal call: `out(step, path?)` takes two arguments.
|
|
721
|
+
*
|
|
722
|
+
* **Three ways the handler can end**: `.return(...)` answers the flow,
|
|
723
|
+
* `.terminate(...)` stops the run, and `h.rejoin('<step>')` compensates and
|
|
724
|
+
* hands control back to a step the success path also reaches — the shape most
|
|
725
|
+
* deployed flows use. A handler that just runs out of steps still gets its own
|
|
726
|
+
* End: rejoining is something the author SAYS, never something wiring infers.
|
|
727
|
+
* See {@link StepList.stepToRef}.
|
|
728
|
+
*
|
|
729
|
+
* Two things this does for you, by construction: it sets
|
|
730
|
+
* `errorHandlingEnabled` on the node in the same write as the edge (without
|
|
731
|
+
* it the platform routes but Studio Web HIDES the handle, so no human can see
|
|
732
|
+
* your handler), and it refuses at build time on a step whose node type has no
|
|
733
|
+
* error port.
|
|
734
|
+
*
|
|
735
|
+
* **A `.loop()` container takes one too.** `core.logic.loop` declares the
|
|
736
|
+
* handle, and a body step's failure routes to it: the container's envelope
|
|
737
|
+
* carries the body's message in `detail` and the failing body step's id in
|
|
738
|
+
* `element`, and the instance completes rather than faulting. `.doWhile()` does
|
|
739
|
+
* NOT — it declares an error variable and no error handle — so that one is
|
|
740
|
+
* refused by name, and its failures belong to the body step that can fail.
|
|
741
|
+
*
|
|
742
|
+
* **A plain `http()` step is the trap worth knowing**: a 404 there is a
|
|
743
|
+
* SUCCESS with `statusCode: 404`, so the handler never runs — use
|
|
744
|
+
* `http({ …, managed: true })` when failures must route. `check` says so
|
|
745
|
+
* (HTTP_ONERROR_V1).
|
|
746
|
+
*
|
|
747
|
+
* Which node types can fail, what the envelope carries, and what a local run
|
|
748
|
+
* does and does not prove: `references/error-handling.md`.
|
|
749
|
+
*
|
|
750
|
+
* @param bodyFn - Receives a sub-builder for the handler's own path. Read the
|
|
751
|
+
* failure inside it with `h.err('message')` ({@link StepList.err}).
|
|
752
|
+
* @returns This builder, positioned on the SUCCESS path — anything chained after
|
|
753
|
+
* this call runs only when the step succeeded.
|
|
754
|
+
* @enforcedBy HTTP_ONERROR_V1 On an http step this needs `managed: true`; on the
|
|
755
|
+
* standalone node a 4xx arrives on the SUCCESS path and no handler runs.
|
|
756
|
+
*/
|
|
757
|
+
onError(bodyFn: (b: StepList) => void): this;
|
|
758
|
+
/**
|
|
759
|
+
* The step a port-scoped edge leaves, and the guard that it is allowed to.
|
|
760
|
+
*
|
|
761
|
+
* Scans BACK past edges already attached to the same step: after
|
|
762
|
+
* `.onError(...)` the last entry in the list is that handler, not the action it
|
|
763
|
+
* guards, so `steps.at(-1)` would refuse a second port-edge on the same step —
|
|
764
|
+
* and would attach `.stepToRef('error', …)` to the wrong thing.
|
|
765
|
+
*
|
|
766
|
+
* A port takes exactly one outgoing edge (the definitions say so:
|
|
767
|
+
* `maxConnections: 1`), so a second edge from the same port is refused here
|
|
768
|
+
* rather than emitted and silently dropped downstream.
|
|
769
|
+
*/
|
|
770
|
+
private portSource;
|
|
771
|
+
/**
|
|
772
|
+
* Run a step list from a named PORT of the step this follows — the general form
|
|
773
|
+
* of an error handler, and the reason `.onError()` needs no machinery of its own.
|
|
774
|
+
*
|
|
775
|
+
* @remarks
|
|
776
|
+
* The body is its own path. It ends by answering (`.return`), stopping the run
|
|
777
|
+
* (`.terminate`), or handing control back with `.stepToRef(...)`; a body that
|
|
778
|
+
* simply runs out of steps gets its own End, exactly as an error handler does.
|
|
779
|
+
*
|
|
780
|
+
* The main path is untouched — an edge out of a NON-default port is a side exit,
|
|
781
|
+
* so whatever you chain after this call still belongs to the step's normal
|
|
782
|
+
* continuation.
|
|
783
|
+
*
|
|
784
|
+
* ```ts
|
|
785
|
+
* .step('fetch', http({ … , managed: true }))
|
|
786
|
+
* .stepToList('error', (h) => h.step('log', script({ … })).stepToRef('settle'))
|
|
787
|
+
* .step('parse', script({ … })) // ← still the SUCCESS path
|
|
788
|
+
* ```
|
|
789
|
+
*
|
|
790
|
+
* @param port - The port of the preceding step to leave from, e.g. `'error'`.
|
|
791
|
+
* @param bodyFn - Receives a sub-builder for the path that port leads to.
|
|
792
|
+
* @returns This builder, so calls chain.
|
|
793
|
+
* @see stepToRef
|
|
794
|
+
*/
|
|
795
|
+
stepToList(port: string, bodyFn: (b: StepList) => void): this;
|
|
796
|
+
/**
|
|
797
|
+
* The shared body of `.stepToList()` and `.onError()`.
|
|
798
|
+
*
|
|
799
|
+
* Private because `called` and `noun` exist only so a refusal names the method
|
|
800
|
+
* the author actually called — they are not part of the surface, and a public
|
|
801
|
+
* parameter nobody should pass is a worse trade than one extra hop.
|
|
802
|
+
*/
|
|
803
|
+
private addPortList;
|
|
804
|
+
/**
|
|
805
|
+
* Branch on a condition. `thenFn`/`elseFn` receive a sub-builder for each arm.
|
|
806
|
+
*
|
|
807
|
+
* @remarks
|
|
808
|
+
* Each arm can name itself with `.label(...)` — the then-arm's label becomes the
|
|
809
|
+
* node's `trueLabel`, the else-arm's its `falseLabel` (the text the designer
|
|
810
|
+
* shows on the two outgoing edges). Omit it and the arms keep the default
|
|
811
|
+
* `"True"` / `"False"`.
|
|
812
|
+
*
|
|
813
|
+
* @param name - The decision node's id.
|
|
814
|
+
* @param cond - The condition, as an expression — typically `js\`…\``.
|
|
815
|
+
* @param thenFn - Receives a sub-builder for the TRUE arm.
|
|
816
|
+
* @param elseFn - Receives a sub-builder for the FALSE arm. Omit it for a
|
|
817
|
+
* decision whose false path simply continues.
|
|
818
|
+
* @param options - Node options; `version` selects the exact definition
|
|
819
|
+
* version (see {@link NodeOptions}).
|
|
820
|
+
* @returns This builder, after both arms have rejoined.
|
|
821
|
+
*/
|
|
822
|
+
branch(name: string, cond: Expr, thenFn: (b: ArmBuilder) => void, elseFn?: (b: ArmBuilder) => void, options?: NodeOptions): this;
|
|
823
|
+
/**
|
|
824
|
+
* N-way branch on the value of `on` — one arm per case, plus an optional
|
|
825
|
+
* default arm. Each arm gets its own sub-builder, exactly like `.branch`.
|
|
826
|
+
*
|
|
827
|
+
* @remarks
|
|
828
|
+
* A case matches when `on === case.value`, compared the way JavaScript's own
|
|
829
|
+
* `switch` compares: **strictly, so the type counts**. `value: 2` matches a
|
|
830
|
+
* `types.number` input carrying `2`; `value: '2'` does not. Cases are
|
|
831
|
+
* evaluated top to bottom and the first match wins.
|
|
832
|
+
*
|
|
833
|
+
* @example
|
|
834
|
+
* **Route on a value, with a default arm**
|
|
835
|
+
* ```ts
|
|
836
|
+
* .switch('routeQuarter', input('quarter'), [
|
|
837
|
+
* { value: 1, body: (b) => b.step('spring', script({ code: 'return "Spring";' })) },
|
|
838
|
+
* { value: 2, body: (b) => b.step('summer', script({ code: 'return "Summer";' })) },
|
|
839
|
+
* ], (other) => other.step('unknown', script({ code: 'return "Unknown";' })))
|
|
840
|
+
* ```
|
|
841
|
+
*
|
|
842
|
+
* @param name - The switch node's id.
|
|
843
|
+
* @param on - The value to compare each case against.
|
|
844
|
+
* @param cases - One entry per arm, evaluated top to bottom; the first strict
|
|
845
|
+
* match wins. `label` names the arm's outgoing edge.
|
|
846
|
+
* @param defaultFn - Receives a sub-builder for the arm taken when nothing
|
|
847
|
+
* matches. Omit it and an unmatched value simply continues.
|
|
848
|
+
* @param options - Node options; `version` selects the exact definition
|
|
849
|
+
* version (see {@link NodeOptions}).
|
|
850
|
+
* @returns This builder, after every arm has rejoined.
|
|
851
|
+
*/
|
|
852
|
+
switch(name: string, on: Expr, cases: {
|
|
853
|
+
value: CaseValue;
|
|
854
|
+
body: (b: ArmBuilder) => void;
|
|
855
|
+
label?: string;
|
|
856
|
+
}[], defaultFn?: (b: StepList) => void, options?: NodeOptions): this;
|
|
857
|
+
/**
|
|
858
|
+
* Run two or more arms **in parallel** from this point and join them back
|
|
859
|
+
* together on a Merge node — the one place the builder stops being a straight
|
|
860
|
+
* chain.
|
|
861
|
+
*
|
|
862
|
+
* @remarks
|
|
863
|
+
* `name` names the **Merge** node (the join). Each arm is a sub-builder, just
|
|
864
|
+
* like a `.branch` arm, and every arm starts from the same place the chain had
|
|
865
|
+
* reached, so the graph forks there and reconverges on the Merge.
|
|
866
|
+
*
|
|
867
|
+
* Anything you chain afterwards continues from the Merge, so it can read every
|
|
868
|
+
* arm's output. The Merge itself computes nothing and publishes nothing — read
|
|
869
|
+
* the steps inside the arms, never `$vars.<merge>`.
|
|
870
|
+
*
|
|
871
|
+
* Arm semantics, what a local run does and does not prove, and the rules
|
|
872
|
+
* `check` enforces: `references/parallel-merge.md`.
|
|
873
|
+
*
|
|
874
|
+
* @example
|
|
875
|
+
* **Fetch two things at once, then combine them after the join**
|
|
876
|
+
* ```ts
|
|
877
|
+
* .parallel('sync', [
|
|
878
|
+
* (a) => a.step('fetchWeather', script({ code: 'return "sunny";' })),
|
|
879
|
+
* (b) => b.step('fetchNews', script({ code: 'return "quiet";' })),
|
|
880
|
+
* ])
|
|
881
|
+
* .step('combine', script({ code: 'return $vars.fetchWeather.output + $vars.fetchNews.output;' }))
|
|
882
|
+
* ```
|
|
883
|
+
*
|
|
884
|
+
* @param name - The split node's id. The Merge node is derived from it.
|
|
885
|
+
* @param arms - One callback per parallel arm, each receiving its own
|
|
886
|
+
* sub-builder. Two or more.
|
|
887
|
+
* @param options - Node options; `version` selects the exact definition
|
|
888
|
+
* version (see {@link NodeOptions}).
|
|
889
|
+
* @returns This builder, positioned after the Merge — so what you chain next
|
|
890
|
+
* runs once, when every arm has finished.
|
|
891
|
+
*/
|
|
892
|
+
parallel(name: string, arms: ((b: StepList) => void)[], options?: NodeOptions): this;
|
|
893
|
+
/**
|
|
894
|
+
* Iterate `collection`; `bodyFn` receives a sub-builder for the loop body.
|
|
895
|
+
*
|
|
896
|
+
* @param name - The loop node's id.
|
|
897
|
+
* @param collection - The array to iterate, as a reference — `v('items')` or
|
|
898
|
+
* `out('fetch', 'body.items')`.
|
|
899
|
+
* @param bodyFn - Receives a sub-builder for the body, run once per element.
|
|
900
|
+
* @param options - Node options; `version` selects the exact definition
|
|
901
|
+
* version (see {@link NodeOptions}).
|
|
902
|
+
* @returns This builder, positioned after the loop.
|
|
903
|
+
*/
|
|
904
|
+
loop(name: string, collection: Expr, bodyFn: (b: StepList) => void, options?: LoopOptions): this;
|
|
905
|
+
/**
|
|
906
|
+
* Run the body, then repeat **while `condition` is true** — the condition is
|
|
907
|
+
* checked AFTER each iteration, so the body always runs at least once
|
|
908
|
+
* (`core.logic.dowhile`). The container publishes no data output; write
|
|
909
|
+
* results to a `.var()` from inside the body (`{ updates }`), and read the
|
|
910
|
+
* loop's progress nowhere — unlike `.loop()` there is no `currentItem`.
|
|
911
|
+
*
|
|
912
|
+
* @example
|
|
913
|
+
* **Paginate until the API says stop**
|
|
914
|
+
* ```ts
|
|
915
|
+
* .var('page', types.number, 1)
|
|
916
|
+
* .doWhile('paginate', js`$vars.fetch.output.hasNextPage === true`, (b) => b
|
|
917
|
+
* .step('fetch', http({ url: tmpl`https://api.example.test/items?page=${v('page')}`, method: 'GET', managed: false, returns: { hasNextPage: 'boolean' } }), {
|
|
918
|
+
* updates: { page: js`$vars.page + 1` },
|
|
919
|
+
* }), { limit: 50 })
|
|
920
|
+
* ```
|
|
921
|
+
*
|
|
922
|
+
* @param name - The container node's id.
|
|
923
|
+
* @param condition - Repeat while this is true, checked after each pass.
|
|
924
|
+
* @param bodyFn - Receives a sub-builder for the body, run once per pass.
|
|
925
|
+
* @param options - `limit` (1–10,000; blank = platform default 10,000),
|
|
926
|
+
* `breakEnabled`, and the common node options (see {@link DoWhileOptions}).
|
|
927
|
+
* @returns This builder, positioned after the loop.
|
|
928
|
+
*/
|
|
929
|
+
doWhile(name: string, condition: Expr, bodyFn: (b: StepList) => void, options?: DoWhileOptions): this;
|
|
930
|
+
/**
|
|
931
|
+
* Exit the enclosing `.loop()` / `.doWhile()` through its **break handle**,
|
|
932
|
+
* ending the whole loop now — not just this iteration. Terminal on its path:
|
|
933
|
+
* nothing may follow it, exactly like `.terminate()`. Using it enables the
|
|
934
|
+
* container's break handle automatically. Compilation fails when there is no
|
|
935
|
+
* enclosing container.
|
|
936
|
+
*
|
|
937
|
+
* @returns This builder. Nothing after this call on the same path can run.
|
|
938
|
+
*/
|
|
939
|
+
break(): this;
|
|
940
|
+
/**
|
|
941
|
+
* Stop the **whole run**, here and now — not just this path.
|
|
942
|
+
*
|
|
943
|
+
* @remarks
|
|
944
|
+
* That is the only difference from `.return()`, and it is a big one: inside a
|
|
945
|
+
* `.parallel` arm a terminate **aborts the sibling arms**, whatever they were
|
|
946
|
+
* in the middle of. A `.return()` in the same place would only end its own
|
|
947
|
+
* path and leave the others running.
|
|
948
|
+
*
|
|
949
|
+
* Nothing may follow a terminate: it publishes no value, and no step after it
|
|
950
|
+
* — in its arm or chained behind it — can ever run.
|
|
951
|
+
*
|
|
952
|
+
* What aborts, what the run reports, and what each local rung can prove:
|
|
953
|
+
* `references/terminate.md`.
|
|
954
|
+
*
|
|
955
|
+
* @example
|
|
956
|
+
* **Abort the sibling arm from inside a parallel**
|
|
957
|
+
* ```ts
|
|
958
|
+
* .parallel('branches', [
|
|
959
|
+
* (a) => a.terminate('stopEverything'),
|
|
960
|
+
* (b) => b.step('wait', delay({ duration: 'PT10S' })).return({ message: 'done' }),
|
|
961
|
+
* ])
|
|
962
|
+
* ```
|
|
963
|
+
*
|
|
964
|
+
* @param name - The terminate node's id.
|
|
965
|
+
* @param label - Text the designer shows on the node. Omit it for the default.
|
|
966
|
+
* @param options - Node options; `version` selects the exact definition
|
|
967
|
+
* version (see {@link NodeOptions}).
|
|
968
|
+
* @returns This builder. Nothing after this call on the same path can run.
|
|
969
|
+
*/
|
|
970
|
+
terminate(name: string, label?: string, options?: NodeOptions): this;
|
|
971
|
+
/**
|
|
972
|
+
* Go to another step, by name — an edge, not a node.
|
|
973
|
+
*
|
|
974
|
+
* @remarks
|
|
975
|
+
* With one argument it leaves the step's default `output` port, which HANDS THE
|
|
976
|
+
* PATH OFF: nothing may follow it in this list, because the flow continues at
|
|
977
|
+
* the target. With a port it is a side exit — the main path is untouched and
|
|
978
|
+
* chaining continues, which is how an error port reaches an existing step
|
|
979
|
+
* without a handler body.
|
|
980
|
+
*
|
|
981
|
+
* ```ts
|
|
982
|
+
* .step('fetch', http({ … }))
|
|
983
|
+
* .stepToRef('settle') // continue at "settle"
|
|
984
|
+
*
|
|
985
|
+
* .step('charge', http({ … , managed: true }))
|
|
986
|
+
* .stepToRef('error', 'refund') // its failure goes to "refund"
|
|
987
|
+
* .step('receipt', script({ … })) // ← still the SUCCESS path
|
|
988
|
+
* ```
|
|
989
|
+
*
|
|
990
|
+
* The target may be declared later in the file, and may be BACKWARD of this
|
|
991
|
+
* step: Flow JSON can express either, so this can author either. What `check`
|
|
992
|
+
* can prove it refuses; what depends on the runtime it warns about and leaves to
|
|
993
|
+
* `uip maestro flow validate`.
|
|
994
|
+
*
|
|
995
|
+
* @param target - The step to continue at, named as it was in `.step(...)`.
|
|
996
|
+
* @returns This builder. Nothing may follow: the path has been handed off.
|
|
997
|
+
* @see stepToList
|
|
998
|
+
*/
|
|
999
|
+
stepToRef(target: string): this;
|
|
1000
|
+
/**
|
|
1001
|
+
* Go to another step from a NAMED PORT — a side exit.
|
|
1002
|
+
*
|
|
1003
|
+
* @remarks
|
|
1004
|
+
* The main path is untouched, so whatever you chain after this call still
|
|
1005
|
+
* belongs to the step's normal continuation. This is how a failure reaches an
|
|
1006
|
+
* existing step without a handler body of its own.
|
|
1007
|
+
*
|
|
1008
|
+
* ```ts
|
|
1009
|
+
* .step('charge', http({ … , managed: true }))
|
|
1010
|
+
* .stepToRef('error', 'refund') // its failure goes to "refund"
|
|
1011
|
+
* .step('receipt', script({ … })) // ← still the SUCCESS path
|
|
1012
|
+
* ```
|
|
1013
|
+
*
|
|
1014
|
+
* @param port - The port of this step to leave, e.g. `'error'`.
|
|
1015
|
+
* @param target - The step to continue at, named as it was in `.step(...)`.
|
|
1016
|
+
* @returns This builder, so calls chain — a side exit ends nothing.
|
|
1017
|
+
* @see stepToList
|
|
1018
|
+
*/
|
|
1019
|
+
stepToRef(port: string, target: string): this;
|
|
1020
|
+
/**
|
|
1021
|
+
* Terminate this path, binding flow outputs to expressions.
|
|
1022
|
+
*
|
|
1023
|
+
* @param values - One entry per declared flow output. A raw value is wrapped as
|
|
1024
|
+
* a literal; an {@link Expr} is emitted as a reference.
|
|
1025
|
+
* @param options - Node options; `version` selects the exact definition
|
|
1026
|
+
* version (see {@link NodeOptions}).
|
|
1027
|
+
* @returns This builder. This path has answered, so nothing after it runs.
|
|
1028
|
+
*/
|
|
1029
|
+
return(values?: Record<string, Expr | unknown>, options?: ReturnOptions): this;
|
|
1030
|
+
}
|
|
1031
|
+
/**
|
|
1032
|
+
* The sub-builder an ARM callback receives — a `StepList` that can also name
|
|
1033
|
+
* itself with `.label(...)`.
|
|
1034
|
+
*
|
|
1035
|
+
* @remarks
|
|
1036
|
+
* It exists so `.label()` is available exactly where it means something (a
|
|
1037
|
+
* `.branch` or `.switch` arm) and NOT on the top-level flow, which names itself
|
|
1038
|
+
* with `.name(...)`. The parent's `branch`/`switch` reads `armLabel` back after
|
|
1039
|
+
* running the callback and lowers it to the node's arm label (`trueLabel` /
|
|
1040
|
+
* `falseLabel` for a decision, the case `label` for a switch).
|
|
1041
|
+
*/
|
|
1042
|
+
declare class ArmBuilder extends StepList {
|
|
1043
|
+
armLabel?: string;
|
|
1044
|
+
/**
|
|
1045
|
+
* Name this arm. The label is what the designer shows on the arm's outgoing
|
|
1046
|
+
* edge; it also survives a round-trip through Flow JSON, where a bare
|
|
1047
|
+
* `"True"` / `"False"` / `Case "<value>"` would not carry the author's intent.
|
|
1048
|
+
* Order-independent — call it anywhere in the arm's chain.
|
|
1049
|
+
*
|
|
1050
|
+
* @param text - The label the designer shows on this arm's outgoing edge.
|
|
1051
|
+
* @returns This builder, so calls chain.
|
|
1052
|
+
*/
|
|
1053
|
+
label(text: string): this;
|
|
1054
|
+
}
|
|
1055
|
+
declare class FlowBuilder extends StepList {
|
|
1056
|
+
private readonly _id;
|
|
1057
|
+
private _name;
|
|
1058
|
+
private _description?;
|
|
1059
|
+
private _layout?;
|
|
1060
|
+
private _stickyNotes?;
|
|
1061
|
+
private _version;
|
|
1062
|
+
private _schemaVersion?;
|
|
1063
|
+
private _inputs;
|
|
1064
|
+
private _outputs;
|
|
1065
|
+
private _vars;
|
|
1066
|
+
private _trigger?;
|
|
1067
|
+
private _triggerOptions?;
|
|
1068
|
+
private _entryPoints;
|
|
1069
|
+
private _triggerId?;
|
|
1070
|
+
constructor(_id: string);
|
|
1071
|
+
/**
|
|
1072
|
+
* Set the flow's display name.
|
|
1073
|
+
*
|
|
1074
|
+
* @param n - The name the designer shows. Defaults to the flow's id.
|
|
1075
|
+
* @returns This builder, so calls chain.
|
|
1076
|
+
* @defaultValue the flow's id
|
|
1077
|
+
*/
|
|
1078
|
+
name(n: string): this;
|
|
1079
|
+
/**
|
|
1080
|
+
* Set the flow's description — persisted as the top-level `description`
|
|
1081
|
+
* field of the emitted `.flow`, shown in the designer's flow header.
|
|
1082
|
+
*
|
|
1083
|
+
* @param text - What this flow does, for humans.
|
|
1084
|
+
* @returns This builder, so calls chain.
|
|
1085
|
+
*/
|
|
1086
|
+
description(text: string): this;
|
|
1087
|
+
/**
|
|
1088
|
+
* Set designer layout — node positions/sizes and edge routes — keyed by the
|
|
1089
|
+
* flow's own logical ids (step names, the trigger id, `end`). Optional pure
|
|
1090
|
+
* metadata: nothing here changes what the flow does, and omitting it leaves
|
|
1091
|
+
* the serializer's default arrangement. Unknown keys fail compilation rather
|
|
1092
|
+
* than being dropped.
|
|
1093
|
+
*
|
|
1094
|
+
* @param layout - Node layout by step name, edge routes by `"from->to"`.
|
|
1095
|
+
* @returns This builder, so calls chain.
|
|
1096
|
+
*/
|
|
1097
|
+
layout(layout: FlowLayout): this;
|
|
1098
|
+
/**
|
|
1099
|
+
* Pin free-text notes to the canvas, for whoever reads the diagram.
|
|
1100
|
+
*
|
|
1101
|
+
* @remarks
|
|
1102
|
+
* Sticky notes are the only annotation `.flow` has. Each becomes a real
|
|
1103
|
+
* `stickyNote` node, which the platform skips during validation and
|
|
1104
|
+
* conversion and whose edges it drops — so a note can never change what the
|
|
1105
|
+
* flow does, and `check` treats it as inert.
|
|
1106
|
+
*
|
|
1107
|
+
* Calling this twice REPLACES the set rather than appending, matching
|
|
1108
|
+
* `.layout()`.
|
|
1109
|
+
*
|
|
1110
|
+
* @example
|
|
1111
|
+
* ```ts
|
|
1112
|
+
* .stickyNotes([
|
|
1113
|
+
* { content: 'Rates refresh at 02:00 UTC', x: 240, y: 40 },
|
|
1114
|
+
* { id: 'why-retry', content: 'The vendor 502s under load.', color: 'pink',
|
|
1115
|
+
* x: 240, y: 320, width: 220, height: 120 },
|
|
1116
|
+
* ])
|
|
1117
|
+
* ```
|
|
1118
|
+
*
|
|
1119
|
+
* @param notes - The notes to pin. Position is required; `id`, `color` and
|
|
1120
|
+
* size have defaults.
|
|
1121
|
+
* @returns This builder, so calls chain.
|
|
1122
|
+
*/
|
|
1123
|
+
stickyNotes(notes: StickyNote[]): this;
|
|
1124
|
+
/**
|
|
1125
|
+
* Set what starts the flow. Omit this call for the **manual** trigger (a
|
|
1126
|
+
* caller starts the flow on demand) — that is the default and what most
|
|
1127
|
+
* flows want.
|
|
1128
|
+
*
|
|
1129
|
+
* @example
|
|
1130
|
+
* **Run the flow hourly instead of on demand**
|
|
1131
|
+
* ```ts
|
|
1132
|
+
* .trigger(scheduled({ every: 'R/PT1H' }))
|
|
1133
|
+
* ```
|
|
1134
|
+
*
|
|
1135
|
+
* @param spec - What starts the flow, from `scheduled(...)` or `onEvent(...)`.
|
|
1136
|
+
* @param options - Node options; `version` selects the exact definition
|
|
1137
|
+
* version (see {@link NodeOptions}).
|
|
1138
|
+
* @returns This builder, so calls chain.
|
|
1139
|
+
* @defaultValue the manual trigger
|
|
1140
|
+
*/
|
|
1141
|
+
trigger(spec: TriggerSpec | FlowTrigger, options?: NodeOptions): this;
|
|
1142
|
+
/**
|
|
1143
|
+
* Add an ADDITIONAL flow root: its own trigger node, its own
|
|
1144
|
+
* scoped inputs (read them with `entryInput('<id>', '<name>')`), and an
|
|
1145
|
+
* optional prefix that runs before the root joins the shared body. Without a
|
|
1146
|
+
* prefix the root connects straight to the first shared step; a prefix that
|
|
1147
|
+
* ends terminally (or hands off with `.stepToRef()`) joins nothing.
|
|
1148
|
+
*
|
|
1149
|
+
* @remarks
|
|
1150
|
+
* The DEFAULT root stays `.trigger()` / `.input()` — one flow, one default
|
|
1151
|
+
* entry point, marked `isDefaultEntryPoint` in the emitted file. Every root
|
|
1152
|
+
* (default included) gets its platform entry-point identity when a flow has
|
|
1153
|
+
* more than one.
|
|
1154
|
+
*
|
|
1155
|
+
* @example
|
|
1156
|
+
* **A manual flow with a second, nightly-scheduled root**
|
|
1157
|
+
* ```ts
|
|
1158
|
+
* flow('order-intake')
|
|
1159
|
+
* .input({ order: types.object }) // the default (manual) root
|
|
1160
|
+
* .entryPoint('nightly', scheduled({ every: 'R/P1D' }), {
|
|
1161
|
+
* inputs: { batchDate: types.string },
|
|
1162
|
+
* }, (b) => b.step('loadBatch', script({ code: 'return { order: { id: $vars.nightly.output.batchDate } };', returns: 'object' })))
|
|
1163
|
+
* .step('normalize', script({ code: 'return 1;' })) // shared body
|
|
1164
|
+
* ```
|
|
1165
|
+
*
|
|
1166
|
+
* @param id - The root's trigger-node id — unique among entry points, steps,
|
|
1167
|
+
* and the default trigger id. Expressions read it as `$vars.<id>.output.*`.
|
|
1168
|
+
* @param trigger - What fires this root: `manual()`, `scheduled(...)`, or
|
|
1169
|
+
* `onEvent(...)`.
|
|
1170
|
+
* @param options - `version` (exact trigger definition version) and `inputs`
|
|
1171
|
+
* — this root's scoped inputs, declared like `.input()`.
|
|
1172
|
+
* @param prefixFn - Optional sub-builder for the root's prefix steps.
|
|
1173
|
+
* @returns This builder, so calls chain.
|
|
1174
|
+
*/
|
|
1175
|
+
entryPoint(id: string, trigger: TriggerSpec | FlowTrigger, options?: {
|
|
1176
|
+
version?: string;
|
|
1177
|
+
inputs?: Record<string, TypeDesc | VarSpec>;
|
|
1178
|
+
}, prefixFn?: (b: StepList) => void): this;
|
|
1179
|
+
/**
|
|
1180
|
+
* Rename the trigger node. The designer can rename it, so the SDK can too.
|
|
1181
|
+
*
|
|
1182
|
+
* @remarks
|
|
1183
|
+
* The id is not cosmetic: a flow's declared inputs are published as the trigger
|
|
1184
|
+
* node's output, so `input('amount')` reads `$vars.<triggerId>.output.amount`.
|
|
1185
|
+
* Renaming the node rewrites every such reference with it.
|
|
1186
|
+
*
|
|
1187
|
+
* @example
|
|
1188
|
+
* **Rename the trigger; input reads follow**
|
|
1189
|
+
* ```ts
|
|
1190
|
+
* .triggerId('intake') // input('amount') → $vars.intake.output.amount
|
|
1191
|
+
* ```
|
|
1192
|
+
*
|
|
1193
|
+
* @param id - The trigger node's new id. Every `input(...)` reference is
|
|
1194
|
+
* rewritten to read through it.
|
|
1195
|
+
* @returns This builder, so calls chain.
|
|
1196
|
+
* @defaultValue `'start'`
|
|
1197
|
+
*/
|
|
1198
|
+
triggerId(id: string): this;
|
|
1199
|
+
/**
|
|
1200
|
+
* Set the flow's version.
|
|
1201
|
+
*
|
|
1202
|
+
* @param vsn - The version string. It does NOT reach the emitted `.flow`.
|
|
1203
|
+
* @returns This builder, so calls chain.
|
|
1204
|
+
* @deprecated Top-level `version` in a `.flow` file is the FILE-FORMAT
|
|
1205
|
+
* version, owned by the serializer's format profile (design §5.4) — it was
|
|
1206
|
+
* never an author-controlled artifact version, and the serializer has always
|
|
1207
|
+
* overwritten this value. The call is kept for source compatibility and
|
|
1208
|
+
* ignored. To target a specific file-format version, use
|
|
1209
|
+
* {@link FlowBuilder.schemaVersion}; there is no author-controlled artifact
|
|
1210
|
+
* version in the format for this to have meant.
|
|
1211
|
+
*/
|
|
1212
|
+
version(vsn: string): this;
|
|
1213
|
+
/**
|
|
1214
|
+
* Declare the `.flow` FILE-FORMAT (schema) version this flow targets.
|
|
1215
|
+
*
|
|
1216
|
+
* @remarks
|
|
1217
|
+
* This is the document's grammar version — the top-level `version` a `.flow`
|
|
1218
|
+
* carries — and it is the one version concept that IS the author's to set,
|
|
1219
|
+
* which is exactly what {@link FlowBuilder.version} is not. Omit it and the
|
|
1220
|
+
* flow declares the SDK's default (the fleet write floor, `1.9`), which is
|
|
1221
|
+
* what every flow authored before this method existed already did.
|
|
1222
|
+
*
|
|
1223
|
+
* Its real job is BROWNFIELD PRESERVATION. `flow-decompile` emits this call
|
|
1224
|
+
* with the version it read, so a decompile → edit → compile round-trip
|
|
1225
|
+
* re-declares the file's own version instead of silently rewriting a `1.10`
|
|
1226
|
+
* file as `1.9`. Migrating a document BETWEEN versions stays
|
|
1227
|
+
* `uip maestro flow migrate`'s job: a hop can carry data repairs (the
|
|
1228
|
+
* 1.9 → 1.10 hop repairs connector binding names) that this SDK has no way to
|
|
1229
|
+
* reproduce from the source alone.
|
|
1230
|
+
*
|
|
1231
|
+
* Only versions this build can actually write are accepted — `1.6` through
|
|
1232
|
+
* `1.10`, the band whose schemas are the same shape as what the serializer
|
|
1233
|
+
* emits. A version is a CLAIM that the whole document matches that schema,
|
|
1234
|
+
* not a switch that reshapes it, so declaring one the serializer cannot emit
|
|
1235
|
+
* would write a false claim; the call throws instead. Both directions off the
|
|
1236
|
+
* floor cost something — above it, a reader pinned lower (an older CLI, an
|
|
1237
|
+
* Automation Suite ring) refuses the file; below it, every reader migrates
|
|
1238
|
+
* forward on open — so `check()` reports `SCHEMA_VERSION_ABOVE_FLOOR` /
|
|
1239
|
+
* `SCHEMA_VERSION_BELOW_FLOOR` rather than deciding for you.
|
|
1240
|
+
*
|
|
1241
|
+
* @example
|
|
1242
|
+
* **Round-trip a 1.10 flow without downgrading it**
|
|
1243
|
+
* ```ts
|
|
1244
|
+
* flow('claims').schemaVersion('1.10')
|
|
1245
|
+
* ```
|
|
1246
|
+
*
|
|
1247
|
+
* @param version - A writable file-format version, e.g. `'1.9'` or `'1.10'`.
|
|
1248
|
+
* @returns This builder, so calls chain.
|
|
1249
|
+
* @throws Error when this SDK build cannot write `version`.
|
|
1250
|
+
* @defaultValue `'1.9'` — `FLOW_FORMAT_PROFILE.version`, the fleet write floor.
|
|
1251
|
+
*/
|
|
1252
|
+
schemaVersion(version: string): this;
|
|
1253
|
+
/**
|
|
1254
|
+
* Declare the flow's inputs. Read them with `input('<name>')`.
|
|
1255
|
+
*
|
|
1256
|
+
* @param shape - Input names to type descriptors, e.g. `{ amount: types.number }`.
|
|
1257
|
+
* @returns This builder, so calls chain.
|
|
1258
|
+
* @see input
|
|
1259
|
+
*/
|
|
1260
|
+
input(shape: Record<string, TypeDesc | VarSpec>): this;
|
|
1261
|
+
/**
|
|
1262
|
+
* Declare the flow's outputs — what `.return(...)` binds values to.
|
|
1263
|
+
*
|
|
1264
|
+
* @param shape - Output names to type descriptors, e.g. `{ total: types.number }`.
|
|
1265
|
+
* @returns This builder, so calls chain.
|
|
1266
|
+
*/
|
|
1267
|
+
output(shape: Record<string, TypeDesc | VarSpec>): this;
|
|
1268
|
+
/**
|
|
1269
|
+
* Declare a flow-level variable. Read it with `v('<name>')`.
|
|
1270
|
+
*
|
|
1271
|
+
* @param name - The variable's name.
|
|
1272
|
+
* @param type - One of the `types.*` descriptors.
|
|
1273
|
+
* @param defaultValue - Its initial value. Omit it to start undeclared.
|
|
1274
|
+
* @returns This builder, so calls chain.
|
|
1275
|
+
* @see v
|
|
1276
|
+
*/
|
|
1277
|
+
var(name: string, type: TypeDesc | VarSpec, defaultValue?: unknown): this;
|
|
1278
|
+
/**
|
|
1279
|
+
* Finish the flow and return the graph the compiler serializes.
|
|
1280
|
+
*
|
|
1281
|
+
* @returns The built description — inputs, outputs, variables, trigger and steps.
|
|
1282
|
+
* @throws FlowBuildError when an expression references something undeclared.
|
|
1283
|
+
*/
|
|
1284
|
+
build(): BuiltFlow;
|
|
1285
|
+
}
|
|
1286
|
+
/**
|
|
1287
|
+
* Start building a flow with the given id.
|
|
1288
|
+
*
|
|
1289
|
+
* @param id - The flow's stable identifier, and its display name until
|
|
1290
|
+
* `.name(...)` says otherwise.
|
|
1291
|
+
* @returns A {@link FlowBuilder} to declare inputs and chain steps onto.
|
|
1292
|
+
* @example
|
|
1293
|
+
* ```ts
|
|
1294
|
+
* export default flow('hello').name('Hello')
|
|
1295
|
+
* .output({ greeting: types.string })
|
|
1296
|
+
* .step('greet', script({ code: 'return "hi";', returns: 'string' }))
|
|
1297
|
+
* .return({ greeting: out('greet') })
|
|
1298
|
+
* .build();
|
|
1299
|
+
* ```
|
|
1300
|
+
*/
|
|
1301
|
+
export declare function flow(id: string): FlowBuilder;
|
|
1302
|
+
/**
|
|
1303
|
+
* Run another flow as one step, and read back what it returns.
|
|
1304
|
+
*
|
|
1305
|
+
* @remarks
|
|
1306
|
+
* The child is an ordinary `flow()` in the same file — its own inputs, steps
|
|
1307
|
+
* and `.return()`. Don't call `.build()` on it; the parent's `.build()` collects
|
|
1308
|
+
* it. Two scopes, joined only by this call: the child sees NOTHING of the
|
|
1309
|
+
* parent's variables except the values passed in here.
|
|
1310
|
+
*
|
|
1311
|
+
* `inputs` keys are the CHILD's declared input names; the values are
|
|
1312
|
+
* parent-scope expressions. A subflow's output is an OBJECT of the child's
|
|
1313
|
+
* declared outputs, so read it with the output's name —
|
|
1314
|
+
* `out('callReverse', 'reversed')`, never a bare `out('callReverse')`.
|
|
1315
|
+
*
|
|
1316
|
+
* Scopes, reuse, nesting, and what a local run does and does not prove:
|
|
1317
|
+
* `references/subflow.md`.
|
|
1318
|
+
*
|
|
1319
|
+
* @example
|
|
1320
|
+
* **Call a child flow and read its named output**
|
|
1321
|
+
* ```ts
|
|
1322
|
+
* const reverse = flow('reverse-text')
|
|
1323
|
+
* .input({ text: types.string })
|
|
1324
|
+
* .output({ reversed: types.string })
|
|
1325
|
+
* .step('rev', script({ code: 'return $vars.text.split("").reverse().join("");' }))
|
|
1326
|
+
* .return({ reversed: out('rev') });
|
|
1327
|
+
*
|
|
1328
|
+
* export default flow('reverse-outer')
|
|
1329
|
+
* .input({ text: types.string })
|
|
1330
|
+
* .output({ result: types.string })
|
|
1331
|
+
* .step('callReverse', subflow(reverse, { text: input('text') }))
|
|
1332
|
+
* .return({ result: out('callReverse', 'reversed') }) // NAME the child output
|
|
1333
|
+
* .build();
|
|
1334
|
+
* ```
|
|
1335
|
+
*
|
|
1336
|
+
* @param child - The child flow — a `flow()` builder or an already-built flow.
|
|
1337
|
+
* @param inputs - One value per the CHILD's declared input names, as parent-scope
|
|
1338
|
+
* expressions.
|
|
1339
|
+
* @returns An action spec for `.step(...)`.
|
|
1340
|
+
*/
|
|
1341
|
+
export declare function subflow(child: ChildFlow, inputs?: Record<string, Expr | unknown>): SubflowSpec;
|