@stndrds/schema 0.1.0-alpha.66 → 1.0.0-alpha.100
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/attributes-CH89Z_J-.d.mts +675 -0
- package/dist/attributes-dw-jLtYS.d.ts +675 -0
- package/dist/chunk-2LUHLHLE.mjs +8 -0
- package/dist/chunk-3RFFA4EV.mjs +14 -0
- package/dist/chunk-4DMDOSFN.js +10 -0
- package/dist/chunk-4IVCBFJA.mjs +12 -0
- package/dist/chunk-5CBTJS7J.js +22 -0
- package/dist/chunk-5SQEKHPW.js +78 -0
- package/dist/chunk-6IFD5732.js +10 -0
- package/dist/chunk-6MXQAQBB.mjs +18 -0
- package/dist/chunk-7FSIBNRH.mjs +25 -0
- package/dist/chunk-ALV6GETG.mjs +10 -0
- package/dist/chunk-ANP6HGMJ.js +64 -0
- package/dist/chunk-ATA4XHB4.js +20 -0
- package/dist/chunk-BEN6TE7Y.js +11 -0
- package/dist/chunk-BZTLI773.mjs +8 -0
- package/dist/chunk-C7KW4NAD.js +20 -0
- package/dist/chunk-CE25ADK5.js +212 -0
- package/dist/chunk-E6XO2STS.js +61 -0
- package/dist/chunk-EKG35CSO.mjs +1 -0
- package/dist/chunk-ERG77ADK.mjs +18 -0
- package/dist/chunk-FKETRWAF.js +10 -0
- package/dist/chunk-FKPYFM6G.mjs +14 -0
- package/dist/chunk-H3VBSMVW.js +105 -0
- package/dist/chunk-HJNLL34O.js +12 -0
- package/dist/chunk-IMEPIVTR.js +217 -0
- package/dist/chunk-JEDANRCG.mjs +74 -0
- package/dist/chunk-KC2FFNL4.js +16 -0
- package/dist/chunk-OO2LJ6GP.js +32 -0
- package/dist/chunk-P4NGPF5L.mjs +99 -0
- package/dist/chunk-PGHTIMRD.mjs +199 -0
- package/dist/chunk-PZT3CIHD.mjs +192 -0
- package/dist/chunk-QPDXDX7A.js +16 -0
- package/dist/chunk-R6JFUC32.js +2 -0
- package/dist/chunk-RDGBQM3N.mjs +20 -0
- package/dist/chunk-RDXQ4CYT.mjs +9 -0
- package/dist/chunk-STKN6A5M.js +14 -0
- package/dist/chunk-TV4G2KMD.mjs +8 -0
- package/dist/chunk-UPEQEX2D.js +10 -0
- package/dist/chunk-VC4E3OSZ.mjs +8 -0
- package/dist/{chunk-V2RPPE2Y.mjs → chunk-XAORXFAX.mjs} +20 -9
- package/dist/chunk-XPFWKISJ.mjs +60 -0
- package/dist/chunk-ZJNX6UXB.mjs +28 -0
- package/dist/chunk-ZWMMEQI7.js +28 -0
- package/dist/index-CftmKoRP.d.mts +2053 -0
- package/dist/index-Dh_XiNFt.d.ts +2053 -0
- package/dist/index.d.mts +4406 -490
- package/dist/index.d.ts +4406 -490
- package/dist/index.js +6598 -1729
- package/dist/index.mjs +5260 -938
- package/dist/types-D-0QbsA9.d.ts +39 -0
- package/dist/types-Ms3HtAmo.d.mts +39 -0
- package/dist/utils.d.mts +20 -1
- package/dist/utils.d.ts +20 -1
- package/dist/utils.js +38 -19
- package/dist/utils.mjs +1 -19
- package/dist/validation/all.d.mts +23 -0
- package/dist/validation/all.d.ts +23 -0
- package/dist/validation/all.js +265 -0
- package/dist/validation/all.mjs +20 -0
- package/dist/validation/complex/currency.d.mts +15 -0
- package/dist/validation/complex/currency.d.ts +15 -0
- package/dist/validation/complex/currency.js +12 -0
- package/dist/validation/complex/currency.mjs +3 -0
- package/dist/validation/complex/file.d.mts +13 -0
- package/dist/validation/complex/file.d.ts +13 -0
- package/dist/validation/complex/file.js +12 -0
- package/dist/validation/complex/file.mjs +3 -0
- package/dist/validation/complex/location.d.mts +22 -0
- package/dist/validation/complex/location.d.ts +22 -0
- package/dist/validation/complex/location.js +12 -0
- package/dist/validation/complex/location.mjs +3 -0
- package/dist/validation/complex/phone.d.mts +22 -0
- package/dist/validation/complex/phone.d.ts +22 -0
- package/dist/validation/complex/phone.js +12 -0
- package/dist/validation/complex/phone.mjs +3 -0
- package/dist/validation/complex/relation.d.mts +25 -0
- package/dist/validation/complex/relation.d.ts +25 -0
- package/dist/validation/complex/relation.js +20 -0
- package/dist/validation/complex/relation.mjs +3 -0
- package/dist/validation/complex/richtext.d.mts +13 -0
- package/dist/validation/complex/richtext.d.ts +13 -0
- package/dist/validation/complex/richtext.js +12 -0
- package/dist/validation/complex/richtext.mjs +3 -0
- package/dist/validation/complex/select.d.mts +20 -0
- package/dist/validation/complex/select.d.ts +20 -0
- package/dist/validation/complex/select.js +20 -0
- package/dist/validation/complex/select.mjs +3 -0
- package/dist/validation/complex/user.d.mts +13 -0
- package/dist/validation/complex/user.d.ts +13 -0
- package/dist/validation/complex/user.js +12 -0
- package/dist/validation/complex/user.mjs +3 -0
- package/dist/validation/computed/formula.d.mts +14 -0
- package/dist/validation/computed/formula.d.ts +14 -0
- package/dist/validation/computed/formula.js +12 -0
- package/dist/validation/computed/formula.mjs +3 -0
- package/dist/validation/computed/rollup.d.mts +14 -0
- package/dist/validation/computed/rollup.d.ts +14 -0
- package/dist/validation/computed/rollup.js +12 -0
- package/dist/validation/computed/rollup.mjs +3 -0
- package/dist/validation/config/index.d.mts +421 -0
- package/dist/validation/config/index.d.ts +421 -0
- package/dist/validation/config/index.js +103 -0
- package/dist/validation/config/index.mjs +2 -0
- package/dist/validation/core/index.d.mts +68 -0
- package/dist/validation/core/index.d.ts +68 -0
- package/dist/validation/core/index.js +23 -0
- package/dist/validation/core/index.mjs +2 -0
- package/dist/validation/object/index.d.mts +6 -0
- package/dist/validation/object/index.d.ts +6 -0
- package/dist/validation/object/index.js +71 -0
- package/dist/validation/object/index.mjs +18 -0
- package/dist/validation/primitives/checkbox.d.mts +12 -0
- package/dist/validation/primitives/checkbox.d.ts +12 -0
- package/dist/validation/primitives/checkbox.js +12 -0
- package/dist/validation/primitives/checkbox.mjs +3 -0
- package/dist/validation/primitives/date.d.mts +12 -0
- package/dist/validation/primitives/date.d.ts +12 -0
- package/dist/validation/primitives/date.js +12 -0
- package/dist/validation/primitives/date.mjs +3 -0
- package/dist/validation/primitives/number.d.mts +12 -0
- package/dist/validation/primitives/number.d.ts +12 -0
- package/dist/validation/primitives/number.js +12 -0
- package/dist/validation/primitives/number.mjs +3 -0
- package/dist/validation/primitives/rating.d.mts +12 -0
- package/dist/validation/primitives/rating.d.ts +12 -0
- package/dist/validation/primitives/rating.js +12 -0
- package/dist/validation/primitives/rating.mjs +3 -0
- package/dist/validation/primitives/text.d.mts +17 -0
- package/dist/validation/primitives/text.d.ts +17 -0
- package/dist/validation/primitives/text.js +16 -0
- package/dist/validation/primitives/text.mjs +3 -0
- package/dist/validation/validators.d.mts +21 -2
- package/dist/validation/validators.d.ts +21 -2
- package/dist/validation/validators.js +265 -121
- package/dist/validation/validators.mjs +20 -121
- package/package.json +109 -13
- package/dist/chunk-36UBIXJN.js +0 -82
- package/dist/chunk-3RG5ZIWI.js +0 -10
- package/dist/chunk-A6T4UUZ2.mjs +0 -18669
- package/dist/chunk-NEVERCM3.js +0 -41
- package/dist/chunk-SV4BCGQU.mjs +0 -617
- package/dist/chunk-TOTUS3YS.js +0 -18669
- package/dist/chunk-U4AB53AM.js +0 -617
- package/dist/chunk-V5QXU2OK.mjs +0 -82
- package/dist/chunk-Y6FXYEAI.mjs +0 -10
- package/dist/default-roles-42X3TJI5.mjs +0 -21
- package/dist/default-roles-C3FYDYMN.js +0 -21
- package/dist/runtime-BgtwoMx5.d.ts +0 -12759
- package/dist/runtime-DQlTgVZJ.d.mts +0 -12759
- package/dist/runtime.d.mts +0 -6
- package/dist/runtime.d.ts +0 -6
- package/dist/runtime.js +0 -323
- package/dist/runtime.mjs +0 -323
- package/dist/validators-BROsLGn4.d.mts +0 -1556
- package/dist/validators-CEzdvxEq.d.ts +0 -1556
|
@@ -0,0 +1,2053 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { A as Attribute, j as AttributeType, f as RollupAttribute } from './attributes-dw-jLtYS.js';
|
|
3
|
+
import { V as ValidationMessages, a as ValidationResult } from './types-D-0QbsA9.js';
|
|
4
|
+
import { IconName, ColorId } from '@stndrds/constants';
|
|
5
|
+
import { Uuid } from './utils.js';
|
|
6
|
+
|
|
7
|
+
/** Operators for text-based attributes */
|
|
8
|
+
type TextFilterOperator = "is" | "is_not" | "contains" | "not_contains" | "starts_with" | "ends_with" | "is_empty" | "is_not_empty";
|
|
9
|
+
/** Operators for number-based attributes */
|
|
10
|
+
type NumberFilterOperator = "eq" | "neq" | "lt" | "gt" | "lte" | "gte" | "is_empty" | "is_not_empty";
|
|
11
|
+
/** Operators for checkbox */
|
|
12
|
+
type CheckboxFilterOperator = "is_checked" | "is_not_checked";
|
|
13
|
+
/** Operators for date-based attributes */
|
|
14
|
+
type DateFilterOperator = "is" | "is_not" | "before" | "after" | "on_or_before" | "on_or_after" | "is_within" | "is_empty" | "is_not_empty";
|
|
15
|
+
/** Operators for select-based attributes (supports single or multi-value filtering) */
|
|
16
|
+
type SelectFilterOperator = "is" | "is_not" | "any_of" | "none_of" | "is_empty" | "is_not_empty";
|
|
17
|
+
/** Operators for multiselect-based attributes */
|
|
18
|
+
type MultiselectFilterOperator = "contains" | "not_contains" | "is_empty" | "is_not_empty";
|
|
19
|
+
/** Operators for relation-based attributes (supports single or multi-value filtering) */
|
|
20
|
+
type RelationFilterOperator = "any_of" | "none_of" | "contains" | "not_contains" | "is_empty" | "is_not_empty";
|
|
21
|
+
/** All possible filter operators */
|
|
22
|
+
type FilterOperator = TextFilterOperator | NumberFilterOperator | CheckboxFilterOperator | DateFilterOperator | SelectFilterOperator | MultiselectFilterOperator | RelationFilterOperator;
|
|
23
|
+
/** Relative date value for "is_within" operator */
|
|
24
|
+
interface RelativeDateValue {
|
|
25
|
+
amount: number;
|
|
26
|
+
unit: "days" | "weeks" | "months" | "years";
|
|
27
|
+
direction: "past" | "future";
|
|
28
|
+
}
|
|
29
|
+
/** Currency filter value with amount and optional currency codes
|
|
30
|
+
* - code: undefined or [] = any currency
|
|
31
|
+
* - code: string[] = filter by specific currencies
|
|
32
|
+
*/
|
|
33
|
+
interface CurrencyFilterValue {
|
|
34
|
+
value: number | null;
|
|
35
|
+
code?: string[];
|
|
36
|
+
}
|
|
37
|
+
/** Phone filter value with number and optional country code */
|
|
38
|
+
interface PhoneFilterValue {
|
|
39
|
+
phoneNumber: string | null;
|
|
40
|
+
countryCode?: string;
|
|
41
|
+
}
|
|
42
|
+
/** Filter value can be various types depending on the attribute */
|
|
43
|
+
type FilterValue = string | number | boolean | string[] | RelativeDateValue | CurrencyFilterValue | PhoneFilterValue | null;
|
|
44
|
+
/** A single filter rule */
|
|
45
|
+
interface FilterRule {
|
|
46
|
+
/** Attribute name to filter on */
|
|
47
|
+
attribute: string;
|
|
48
|
+
/** Filter operator */
|
|
49
|
+
operator: FilterOperator;
|
|
50
|
+
/** Filter value (null for operators like is_empty) */
|
|
51
|
+
value: FilterValue;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Extended filter rule with optional attribute definition.
|
|
55
|
+
* When provided, enables smarter type-aware filtering (e.g., array operators for multiselect).
|
|
56
|
+
*/
|
|
57
|
+
interface ExtendedFilterRule extends FilterRule {
|
|
58
|
+
/** Full attribute definition for type-aware filtering */
|
|
59
|
+
attributeDef?: Attribute;
|
|
60
|
+
}
|
|
61
|
+
/** Combinator for filter rules */
|
|
62
|
+
type FilterCombinator = "and" | "or";
|
|
63
|
+
/** Complete filter state (simple mode) */
|
|
64
|
+
interface FilterState {
|
|
65
|
+
/** How to combine rules */
|
|
66
|
+
combinator: FilterCombinator;
|
|
67
|
+
/** List of filter rules */
|
|
68
|
+
rules: FilterRule[];
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* A filter group containing rules (used in advanced mode)
|
|
72
|
+
* Groups can be nested up to 2 levels deep
|
|
73
|
+
*/
|
|
74
|
+
interface FilterGroup {
|
|
75
|
+
/** Unique identifier for this group */
|
|
76
|
+
id: string;
|
|
77
|
+
/** How to combine rules within this group */
|
|
78
|
+
combinator: FilterCombinator;
|
|
79
|
+
/** List of filter rules in this group */
|
|
80
|
+
rules: FilterRule[];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Advanced filter state with nested groups
|
|
84
|
+
* Structure: AdvancedFilterState -> FilterGroup[] -> FilterRule[]
|
|
85
|
+
* Maximum 2 levels of nesting
|
|
86
|
+
*/
|
|
87
|
+
interface AdvancedFilterState {
|
|
88
|
+
/** How to combine groups at the top level */
|
|
89
|
+
combinator: FilterCombinator;
|
|
90
|
+
/** List of filter groups */
|
|
91
|
+
groups: FilterGroup[];
|
|
92
|
+
}
|
|
93
|
+
/** Sort direction */
|
|
94
|
+
type SortDirection = "asc" | "desc";
|
|
95
|
+
/** A single sort rule */
|
|
96
|
+
interface SortRule {
|
|
97
|
+
/** Attribute name to sort by */
|
|
98
|
+
attribute: string;
|
|
99
|
+
/** Sort direction */
|
|
100
|
+
direction: SortDirection;
|
|
101
|
+
}
|
|
102
|
+
/** Complete query state with search, filters, sorts, and pagination */
|
|
103
|
+
interface QueryState {
|
|
104
|
+
/** Full-text search query */
|
|
105
|
+
search?: string;
|
|
106
|
+
/** Filter configuration (simple mode) */
|
|
107
|
+
filters?: FilterState;
|
|
108
|
+
/** Advanced filter configuration (grouped mode) */
|
|
109
|
+
advancedFilters?: AdvancedFilterState;
|
|
110
|
+
/** Sort configuration (multiple sorts supported) */
|
|
111
|
+
sorts?: SortRule[];
|
|
112
|
+
/** Pagination */
|
|
113
|
+
limit?: number;
|
|
114
|
+
offset?: number;
|
|
115
|
+
}
|
|
116
|
+
/** Mapping of attribute types to their valid operators */
|
|
117
|
+
declare const OPERATORS_BY_TYPE: Record<AttributeType, readonly FilterOperator[]>;
|
|
118
|
+
/** Check if an operator requires a value */
|
|
119
|
+
type NoValueOperator = "is_empty" | "is_not_empty" | "is_checked" | "is_not_checked";
|
|
120
|
+
/** Operators that don't require a value */
|
|
121
|
+
declare const NO_VALUE_OPERATORS: readonly NoValueOperator[];
|
|
122
|
+
/**
|
|
123
|
+
* Check if an operator requires a value
|
|
124
|
+
*/
|
|
125
|
+
declare function isNoValueOperator(operator: FilterOperator): operator is NoValueOperator;
|
|
126
|
+
/**
|
|
127
|
+
* Get the filter operators for a rollup attribute based on its aggregation function and target type.
|
|
128
|
+
*
|
|
129
|
+
* - earliest / latest → date operators
|
|
130
|
+
* - original → operators matching targetAttributeType (falls back to numeric if unknown)
|
|
131
|
+
* - all other functions → numeric operators (sum, avg, count, percent, etc.)
|
|
132
|
+
*/
|
|
133
|
+
declare function getRollupFilterOperators(attr: RollupAttribute): readonly FilterOperator[];
|
|
134
|
+
|
|
135
|
+
interface BufferedRecord {
|
|
136
|
+
id: string;
|
|
137
|
+
objectName: string;
|
|
138
|
+
values: Record<string, unknown>;
|
|
139
|
+
}
|
|
140
|
+
interface RecordPatch {
|
|
141
|
+
values: Record<string, unknown>;
|
|
142
|
+
}
|
|
143
|
+
type RelationQualifierPatch = Record<string, unknown>;
|
|
144
|
+
interface RelationBuffer {
|
|
145
|
+
preloaded: BufferedRecord[];
|
|
146
|
+
added: BufferedRecord[];
|
|
147
|
+
modified: Record<string, RecordPatch>;
|
|
148
|
+
removed: string[];
|
|
149
|
+
qualifiers: Record<string, RelationQualifierPatch>;
|
|
150
|
+
}
|
|
151
|
+
type RelationBufferMap = Record<string, RelationBuffer>;
|
|
152
|
+
interface DisplayRecord {
|
|
153
|
+
id: string;
|
|
154
|
+
objectName: string;
|
|
155
|
+
values: Record<string, unknown>;
|
|
156
|
+
qualifiers: Record<string, unknown>;
|
|
157
|
+
status: "existing" | "added" | "modified";
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Document generated during workflow execution
|
|
162
|
+
*/
|
|
163
|
+
interface GeneratedDocument {
|
|
164
|
+
/** Document ID (file ID) */
|
|
165
|
+
id: string;
|
|
166
|
+
/** URL to access the document */
|
|
167
|
+
url: string;
|
|
168
|
+
/** Document filename */
|
|
169
|
+
filename?: string;
|
|
170
|
+
/** MIME type */
|
|
171
|
+
mimeType?: string;
|
|
172
|
+
/** File size in bytes */
|
|
173
|
+
size?: number;
|
|
174
|
+
/** Additional metadata */
|
|
175
|
+
metadata?: Record<string, unknown>;
|
|
176
|
+
/** IDs of Document records created (one per target slot) */
|
|
177
|
+
attachedDocumentIds?: string[];
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Accumulated context during workflow execution.
|
|
181
|
+
*
|
|
182
|
+
* This context is built up as nodes execute and is passed to each node.
|
|
183
|
+
* It contains all the data collected and generated during the workflow.
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* ```typescript
|
|
187
|
+
* const context: WorkflowExecutionContext = {
|
|
188
|
+
* slots: {
|
|
189
|
+
* client: {
|
|
190
|
+
* id: "rec_123",
|
|
191
|
+
* firstName: "John",
|
|
192
|
+
* lastName: "Doe",
|
|
193
|
+
* email: "john@example.com",
|
|
194
|
+
* type: "vip"
|
|
195
|
+
* }
|
|
196
|
+
* },
|
|
197
|
+
* forms: {
|
|
198
|
+
* "client-form": {
|
|
199
|
+
* firstName: "John",
|
|
200
|
+
* lastName: "Doe"
|
|
201
|
+
* }
|
|
202
|
+
* },
|
|
203
|
+
* documents: {},
|
|
204
|
+
* variables: {
|
|
205
|
+
* totalAmount: 15000
|
|
206
|
+
* },
|
|
207
|
+
* conditionResults: {
|
|
208
|
+
* "check-vip": true
|
|
209
|
+
* }
|
|
210
|
+
* };
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
interface WorkflowExecutionContext {
|
|
214
|
+
/**
|
|
215
|
+
* Records created/modified during execution, indexed by slot ID.
|
|
216
|
+
* Contains the full record data for each slot.
|
|
217
|
+
*/
|
|
218
|
+
slots: Record<string, Record<string, unknown>>;
|
|
219
|
+
/**
|
|
220
|
+
* Form submissions indexed by node ID.
|
|
221
|
+
* Contains the raw form data submitted at each form node.
|
|
222
|
+
*/
|
|
223
|
+
forms: Record<string, Record<string, unknown>>;
|
|
224
|
+
/**
|
|
225
|
+
* Documents generated during execution, indexed by node ID.
|
|
226
|
+
* Contains document metadata and URLs.
|
|
227
|
+
*/
|
|
228
|
+
documents: Record<string, GeneratedDocument>;
|
|
229
|
+
/**
|
|
230
|
+
* Custom variables set during execution.
|
|
231
|
+
* Can be used by action nodes to store computed values.
|
|
232
|
+
*/
|
|
233
|
+
variables: Record<string, unknown>;
|
|
234
|
+
/**
|
|
235
|
+
* Results of condition evaluations for debugging.
|
|
236
|
+
* Indexed by condition node ID.
|
|
237
|
+
*/
|
|
238
|
+
conditionResults: Record<string, boolean>;
|
|
239
|
+
/**
|
|
240
|
+
* IDs of records created during workflow completion.
|
|
241
|
+
* Used for idempotence (avoid creating duplicates on retry).
|
|
242
|
+
* Indexed by slot ID.
|
|
243
|
+
*/
|
|
244
|
+
createdRecordIds: Record<string, string>;
|
|
245
|
+
/**
|
|
246
|
+
* Relation buffers for pending relation changes, indexed by slot ID then relation attribute name.
|
|
247
|
+
*/
|
|
248
|
+
relationBuffers: Record<string, RelationBufferMap>;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Create an empty execution context
|
|
252
|
+
*/
|
|
253
|
+
declare function createEmptyContext(): WorkflowExecutionContext;
|
|
254
|
+
/**
|
|
255
|
+
* Get a value from the context using dot notation path.
|
|
256
|
+
*
|
|
257
|
+
* Supports paths like:
|
|
258
|
+
* - "slots.client.email"
|
|
259
|
+
* - "forms.step1.amount"
|
|
260
|
+
* - "variables.customVar"
|
|
261
|
+
*
|
|
262
|
+
* @param context - The execution context
|
|
263
|
+
* @param path - Dot notation path to the value
|
|
264
|
+
* @returns The value at the path, or undefined if not found
|
|
265
|
+
*
|
|
266
|
+
* @example
|
|
267
|
+
* ```typescript
|
|
268
|
+
* const email = getContextValue(context, "slots.client.email");
|
|
269
|
+
* const amount = getContextValue(context, "forms.quote.amount");
|
|
270
|
+
* ```
|
|
271
|
+
*/
|
|
272
|
+
declare function getContextValue(context: WorkflowExecutionContext, path: string): unknown;
|
|
273
|
+
/**
|
|
274
|
+
* Set a value in the context using dot notation path.
|
|
275
|
+
*
|
|
276
|
+
* @param context - The execution context (mutated in place)
|
|
277
|
+
* @param path - Dot notation path to set
|
|
278
|
+
* @param value - Value to set
|
|
279
|
+
*
|
|
280
|
+
* @example
|
|
281
|
+
* ```typescript
|
|
282
|
+
* setContextValue(context, "variables.computed", 42);
|
|
283
|
+
* setContextValue(context, "slots.client.status", "active");
|
|
284
|
+
* ```
|
|
285
|
+
*/
|
|
286
|
+
declare function setContextValue(context: WorkflowExecutionContext, path: string, value: unknown): void;
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Represents a "slot" for an object to be created in the flow
|
|
290
|
+
* Ex: "mr" for the first contact, "company" for the company
|
|
291
|
+
*
|
|
292
|
+
* Note: Named "Slot" to avoid confusion with DB entities
|
|
293
|
+
*
|
|
294
|
+
* @deprecated Use WorkflowSlot from types/workflows instead
|
|
295
|
+
*/
|
|
296
|
+
interface FlowSlot {
|
|
297
|
+
/** Unique identifier for the slot (ex: "mr", "mme", "company") */
|
|
298
|
+
id: string;
|
|
299
|
+
/** Name of the object to create (ex: "contacts", "companies") */
|
|
300
|
+
objectName: string;
|
|
301
|
+
/** Display label (ex: "Monsieur", "Madame") */
|
|
302
|
+
label: string;
|
|
303
|
+
/** Color to visually distinguish in the builder (from COLORS palette) */
|
|
304
|
+
color?: ColorId;
|
|
305
|
+
/** Optional icon */
|
|
306
|
+
icon?: IconName;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Configuration for relation fields in workflow/flow forms.
|
|
310
|
+
* Controls which qualified properties are visible and whether
|
|
311
|
+
* inline record creation is allowed.
|
|
312
|
+
*/
|
|
313
|
+
interface RelationFieldConfig {
|
|
314
|
+
/** Which qualified properties to display (all if omitted) */
|
|
315
|
+
visibleProperties?: string[];
|
|
316
|
+
/** Allow creating new target records inline (default: true) */
|
|
317
|
+
allowCreate?: boolean;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Field within a row (simplified - no span, auto-calculated)
|
|
321
|
+
*/
|
|
322
|
+
interface FlowRowField {
|
|
323
|
+
/** Unique field ID */
|
|
324
|
+
id: string;
|
|
325
|
+
/** Reference to FlowSlot.id */
|
|
326
|
+
slotId: string;
|
|
327
|
+
/** Attribute name on the object */
|
|
328
|
+
attribute: string;
|
|
329
|
+
/** Override label for this flow */
|
|
330
|
+
label?: string;
|
|
331
|
+
/** Override tooltip/description for this flow */
|
|
332
|
+
tooltip?: string;
|
|
333
|
+
/** Override required */
|
|
334
|
+
required?: boolean;
|
|
335
|
+
/** Relation-specific configuration (only for relation attributes) */
|
|
336
|
+
relationConfig?: RelationFieldConfig;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Row type discriminator.
|
|
340
|
+
* - "fields" (or undefined): standard row with data fields
|
|
341
|
+
* - "heading": section heading
|
|
342
|
+
* - "separator": visual divider
|
|
343
|
+
* - "text": static descriptive text
|
|
344
|
+
*/
|
|
345
|
+
type FlowRowType = "fields" | "heading" | "separator" | "text" | "relationList";
|
|
346
|
+
/**
|
|
347
|
+
* Standard row containing data fields
|
|
348
|
+
*/
|
|
349
|
+
interface FlowFieldsRow {
|
|
350
|
+
/** Unique row ID */
|
|
351
|
+
id: string;
|
|
352
|
+
/** Display order within the page */
|
|
353
|
+
order: number;
|
|
354
|
+
/** Row type (optional for backward compat — defaults to "fields") */
|
|
355
|
+
type?: "fields";
|
|
356
|
+
/** Fields in this row (auto-distribute width) */
|
|
357
|
+
fields: FlowRowField[];
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Heading row — renders a section title in the form
|
|
361
|
+
*/
|
|
362
|
+
interface FlowHeadingRow {
|
|
363
|
+
id: string;
|
|
364
|
+
order: number;
|
|
365
|
+
type: "heading";
|
|
366
|
+
/** Heading text */
|
|
367
|
+
content: string;
|
|
368
|
+
/** Heading level (1 = large, 2 = medium, 3 = small) */
|
|
369
|
+
level?: 1 | 2 | 3;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Separator row — renders a visual divider
|
|
373
|
+
*/
|
|
374
|
+
interface FlowSeparatorRow {
|
|
375
|
+
id: string;
|
|
376
|
+
order: number;
|
|
377
|
+
type: "separator";
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Static text row — renders descriptive/instructional text
|
|
381
|
+
*/
|
|
382
|
+
interface FlowTextRow {
|
|
383
|
+
id: string;
|
|
384
|
+
order: number;
|
|
385
|
+
type: "text";
|
|
386
|
+
/** Text content (supports basic markdown) */
|
|
387
|
+
content: string;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Relation list row — renders an editable list of related records with preloading
|
|
391
|
+
*/
|
|
392
|
+
interface FlowRelationListRow {
|
|
393
|
+
id: string;
|
|
394
|
+
order: number;
|
|
395
|
+
type: "relationList";
|
|
396
|
+
slotId: string;
|
|
397
|
+
relationName: string;
|
|
398
|
+
preload: boolean;
|
|
399
|
+
columns: string[];
|
|
400
|
+
qualifiersInline: boolean;
|
|
401
|
+
modalFields: "all" | string[];
|
|
402
|
+
label?: string;
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Union of all row types.
|
|
406
|
+
* Use `isFlowFieldsRow()` / `isLayoutRow()` type guards for narrowing.
|
|
407
|
+
*/
|
|
408
|
+
type FlowRow = FlowFieldsRow | FlowHeadingRow | FlowSeparatorRow | FlowTextRow | FlowRelationListRow;
|
|
409
|
+
/** Check if a row is a standard fields row */
|
|
410
|
+
declare function isFlowFieldsRow(row: FlowRow): row is FlowFieldsRow;
|
|
411
|
+
/** Check if a row is a layout row (heading, separator, or text) */
|
|
412
|
+
declare function isLayoutRow(row: FlowRow): row is FlowHeadingRow | FlowSeparatorRow | FlowTextRow;
|
|
413
|
+
/** Check if a row is a relation list row */
|
|
414
|
+
declare function isFlowRelationListRow(row: FlowRow): row is FlowRelationListRow;
|
|
415
|
+
/**
|
|
416
|
+
* Page/step in a flow
|
|
417
|
+
*/
|
|
418
|
+
interface FlowPage {
|
|
419
|
+
/** Unique page ID */
|
|
420
|
+
id: string;
|
|
421
|
+
/** Display label */
|
|
422
|
+
label: string;
|
|
423
|
+
/** Optional description */
|
|
424
|
+
description?: string;
|
|
425
|
+
/** Display order */
|
|
426
|
+
order: number;
|
|
427
|
+
/** Rows in this page */
|
|
428
|
+
rows: FlowRow[];
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Defines how to link slots after creation
|
|
432
|
+
* Ex: Link "mr" and "mme" to "company" via their "company" attribute
|
|
433
|
+
*/
|
|
434
|
+
interface FlowRelation {
|
|
435
|
+
/** Unique relation ID */
|
|
436
|
+
id: string;
|
|
437
|
+
/** Source slot that has the relation attribute */
|
|
438
|
+
sourceSlotId: string;
|
|
439
|
+
/** Relation attribute on the source slot */
|
|
440
|
+
sourceAttribute: string;
|
|
441
|
+
/** Target slot created in the same flow */
|
|
442
|
+
targetSlotId: string;
|
|
443
|
+
}
|
|
444
|
+
/** Flow lifecycle status */
|
|
445
|
+
type FlowStatus = "draft" | "published" | "archived";
|
|
446
|
+
/**
|
|
447
|
+
* Complete flow definition for multi-object creation
|
|
448
|
+
*
|
|
449
|
+
* @example
|
|
450
|
+
* ```typescript
|
|
451
|
+
* const coupleFlow: FlowDefinition = {
|
|
452
|
+
* name: "couple-creation",
|
|
453
|
+
* label: "Création Couple",
|
|
454
|
+
* status: "published",
|
|
455
|
+
* version: 1,
|
|
456
|
+
* slots: [
|
|
457
|
+
* { id: "mr", objectName: "contacts", label: "Monsieur" },
|
|
458
|
+
* { id: "mme", objectName: "contacts", label: "Madame" },
|
|
459
|
+
* { id: "company", objectName: "companies", label: "Entreprise" },
|
|
460
|
+
* ],
|
|
461
|
+
* pages: [...],
|
|
462
|
+
* relations: [
|
|
463
|
+
* { id: "mr-company", sourceSlotId: "mr", sourceAttribute: "company", targetSlotId: "company" },
|
|
464
|
+
* ],
|
|
465
|
+
* system: true,
|
|
466
|
+
* };
|
|
467
|
+
* ```
|
|
468
|
+
*/
|
|
469
|
+
interface FlowDefinition {
|
|
470
|
+
/** Database ID */
|
|
471
|
+
id?: Uuid;
|
|
472
|
+
/** Technical name (kebab-case) */
|
|
473
|
+
name: string;
|
|
474
|
+
/** Display label */
|
|
475
|
+
label: string;
|
|
476
|
+
/** Optional description */
|
|
477
|
+
description?: string;
|
|
478
|
+
/** Optional icon */
|
|
479
|
+
icon?: IconName;
|
|
480
|
+
/** Flow status */
|
|
481
|
+
status: FlowStatus;
|
|
482
|
+
/** Version for tracking modifications */
|
|
483
|
+
version: number;
|
|
484
|
+
/** Slots (objects) to create in this flow */
|
|
485
|
+
slots: FlowSlot[];
|
|
486
|
+
/** Pages/steps of the flow */
|
|
487
|
+
pages: FlowPage[];
|
|
488
|
+
/** Relations between created slots */
|
|
489
|
+
relations: FlowRelation[];
|
|
490
|
+
/** If true, defined in code (protected) */
|
|
491
|
+
system?: boolean;
|
|
492
|
+
/** Tenant ID for multi-tenant (optional if single-tenant) */
|
|
493
|
+
tenantId?: string;
|
|
494
|
+
/** Extensible metadata */
|
|
495
|
+
metadata?: Record<string, unknown>;
|
|
496
|
+
/** Timestamps */
|
|
497
|
+
createdAt?: Date;
|
|
498
|
+
updatedAt?: Date;
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Check if an object is a FlowDefinition
|
|
502
|
+
*/
|
|
503
|
+
declare function isFlowDefinition(obj: unknown): obj is FlowDefinition;
|
|
504
|
+
/**
|
|
505
|
+
* Check if a flow is published and available for use
|
|
506
|
+
*/
|
|
507
|
+
declare function isFlowPublished(flow: FlowDefinition): boolean;
|
|
508
|
+
/**
|
|
509
|
+
* Check if a flow is a system flow (defined in code)
|
|
510
|
+
*/
|
|
511
|
+
declare function isSystemFlow(flow: FlowDefinition): boolean;
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* All supported comparison operators for condition rules
|
|
515
|
+
*/
|
|
516
|
+
type ConditionOperator = "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "contains" | "startsWith" | "endsWith" | "isEmpty" | "isNotEmpty" | "in" | "notIn";
|
|
517
|
+
/**
|
|
518
|
+
* A single condition rule that compares a field value against a target value.
|
|
519
|
+
*
|
|
520
|
+
* Field paths support dot notation for nested access:
|
|
521
|
+
* - `slots.client.type` - Access slot record attribute
|
|
522
|
+
* - `forms.step1.amount` - Access form submission data
|
|
523
|
+
* - `context.variables.customVar` - Access custom variables
|
|
524
|
+
*
|
|
525
|
+
* @example
|
|
526
|
+
* ```typescript
|
|
527
|
+
* const rule: ConditionRule = {
|
|
528
|
+
* field: "slots.client.type",
|
|
529
|
+
* operator: "eq",
|
|
530
|
+
* value: "vip"
|
|
531
|
+
* };
|
|
532
|
+
* ```
|
|
533
|
+
*/
|
|
534
|
+
interface ConditionRule {
|
|
535
|
+
/** Field path to evaluate (dot notation) */
|
|
536
|
+
field: string;
|
|
537
|
+
/** Comparison operator */
|
|
538
|
+
operator: ConditionOperator;
|
|
539
|
+
/** Value to compare against (type depends on operator) */
|
|
540
|
+
value: unknown;
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* A group of conditions combined with AND/OR logic.
|
|
544
|
+
* Groups can be nested for complex conditions.
|
|
545
|
+
*
|
|
546
|
+
* @example Simple AND condition
|
|
547
|
+
* ```typescript
|
|
548
|
+
* const condition: ConditionGroup = {
|
|
549
|
+
* operator: "and",
|
|
550
|
+
* rules: [
|
|
551
|
+
* { field: "slots.client.type", operator: "eq", value: "vip" },
|
|
552
|
+
* { field: "slots.client.active", operator: "eq", value: true }
|
|
553
|
+
* ]
|
|
554
|
+
* };
|
|
555
|
+
* ```
|
|
556
|
+
*
|
|
557
|
+
* @example Nested condition (VIP OR (Premium AND Active))
|
|
558
|
+
* ```typescript
|
|
559
|
+
* const condition: ConditionGroup = {
|
|
560
|
+
* operator: "or",
|
|
561
|
+
* rules: [
|
|
562
|
+
* { field: "slots.client.type", operator: "eq", value: "vip" },
|
|
563
|
+
* {
|
|
564
|
+
* operator: "and",
|
|
565
|
+
* rules: [
|
|
566
|
+
* { field: "slots.client.type", operator: "eq", value: "premium" },
|
|
567
|
+
* { field: "slots.client.active", operator: "eq", value: true }
|
|
568
|
+
* ]
|
|
569
|
+
* }
|
|
570
|
+
* ]
|
|
571
|
+
* };
|
|
572
|
+
* ```
|
|
573
|
+
*/
|
|
574
|
+
interface ConditionGroup {
|
|
575
|
+
/** Logical operator to combine rules */
|
|
576
|
+
operator: "and" | "or";
|
|
577
|
+
/** Array of rules or nested groups */
|
|
578
|
+
rules: Array<ConditionRule | ConditionGroup>;
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* Check if an item is a ConditionRule (not a ConditionGroup)
|
|
582
|
+
*/
|
|
583
|
+
declare function isConditionRule(item: ConditionRule | ConditionGroup): item is ConditionRule;
|
|
584
|
+
/**
|
|
585
|
+
* Check if an item is a ConditionGroup
|
|
586
|
+
*/
|
|
587
|
+
declare function isConditionGroup(item: ConditionRule | ConditionGroup): item is ConditionGroup;
|
|
588
|
+
/**
|
|
589
|
+
* Create a simple equality condition
|
|
590
|
+
*/
|
|
591
|
+
declare function eq(field: string, value: unknown): ConditionRule;
|
|
592
|
+
/**
|
|
593
|
+
* Create a simple inequality condition
|
|
594
|
+
*/
|
|
595
|
+
declare function neq(field: string, value: unknown): ConditionRule;
|
|
596
|
+
/**
|
|
597
|
+
* Create an AND condition group
|
|
598
|
+
*/
|
|
599
|
+
declare function and(...rules: Array<ConditionRule | ConditionGroup>): ConditionGroup;
|
|
600
|
+
/**
|
|
601
|
+
* Create an OR condition group
|
|
602
|
+
*/
|
|
603
|
+
declare function or(...rules: Array<ConditionRule | ConditionGroup>): ConditionGroup;
|
|
604
|
+
/**
|
|
605
|
+
* Create an "in" condition (value in array)
|
|
606
|
+
*/
|
|
607
|
+
declare function inValues(field: string, values: unknown[]): ConditionRule;
|
|
608
|
+
/**
|
|
609
|
+
* Create an isEmpty condition
|
|
610
|
+
*/
|
|
611
|
+
declare function isEmpty(field: string): ConditionRule;
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* Base properties shared by all workflow nodes
|
|
615
|
+
*/
|
|
616
|
+
interface BaseNode {
|
|
617
|
+
/** Unique node identifier */
|
|
618
|
+
id: string;
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Entry point of the workflow. Each workflow has exactly one StartNode.
|
|
622
|
+
*/
|
|
623
|
+
interface StartNode extends BaseNode {
|
|
624
|
+
type: "start";
|
|
625
|
+
/** ID of the next node to execute (optional for drafts) */
|
|
626
|
+
next?: string | null;
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Form node for collecting user input.
|
|
630
|
+
*
|
|
631
|
+
* Each FormNode acts as a "step" or "page" in the workflow.
|
|
632
|
+
* It can contain fields from multiple slots, allowing complex forms
|
|
633
|
+
* that collect data for different objects.
|
|
634
|
+
*
|
|
635
|
+
* @example Simple mode (single slot, quick setup)
|
|
636
|
+
* ```typescript
|
|
637
|
+
* const node: FormNode = {
|
|
638
|
+
* type: "form",
|
|
639
|
+
* id: "client-info",
|
|
640
|
+
* label: "Client Information",
|
|
641
|
+
* fields: [
|
|
642
|
+
* { slotId: "client", attribute: "firstName" },
|
|
643
|
+
* { slotId: "client", attribute: "lastName" },
|
|
644
|
+
* ],
|
|
645
|
+
* next: "check-vip"
|
|
646
|
+
* };
|
|
647
|
+
* ```
|
|
648
|
+
*
|
|
649
|
+
* @example Advanced mode (multiple slots, custom layout)
|
|
650
|
+
* ```typescript
|
|
651
|
+
* const node: FormNode = {
|
|
652
|
+
* type: "form",
|
|
653
|
+
* id: "couple-info",
|
|
654
|
+
* label: "Couple Information",
|
|
655
|
+
* rows: [
|
|
656
|
+
* { id: "row-1", order: 1, fields: [
|
|
657
|
+
* { id: "f1", slotId: "mr", attribute: "firstName" },
|
|
658
|
+
* { id: "f2", slotId: "mme", attribute: "firstName" },
|
|
659
|
+
* ]},
|
|
660
|
+
* { id: "row-2", order: 2, fields: [
|
|
661
|
+
* { id: "f3", slotId: "company", attribute: "name" },
|
|
662
|
+
* ]},
|
|
663
|
+
* ],
|
|
664
|
+
* next: "check-vip"
|
|
665
|
+
* };
|
|
666
|
+
* ```
|
|
667
|
+
*/
|
|
668
|
+
interface FormNode extends BaseNode {
|
|
669
|
+
type: "form";
|
|
670
|
+
/** Display label for the form step */
|
|
671
|
+
label: string;
|
|
672
|
+
/** Optional description */
|
|
673
|
+
description?: string;
|
|
674
|
+
/**
|
|
675
|
+
* Simple mode: list of field references.
|
|
676
|
+
* Each field specifies the slot and attribute.
|
|
677
|
+
* Creates one field per row with equal width.
|
|
678
|
+
* Mutually exclusive with `rows`.
|
|
679
|
+
*/
|
|
680
|
+
fields?: FormFieldRef[];
|
|
681
|
+
/**
|
|
682
|
+
* Advanced mode: full row/field structure for custom layouts.
|
|
683
|
+
* Each row can contain multiple fields from different slots.
|
|
684
|
+
* Mutually exclusive with `fields`.
|
|
685
|
+
*/
|
|
686
|
+
rows?: FlowRow[];
|
|
687
|
+
/**
|
|
688
|
+
* ID of the participant template allowed to fill this form.
|
|
689
|
+
* If set, only this participant can execute this node.
|
|
690
|
+
*/
|
|
691
|
+
participantId?: string | null;
|
|
692
|
+
/** ID of the next node to execute (optional for drafts) */
|
|
693
|
+
next?: string | null;
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Simple field reference for FormNode simple mode
|
|
697
|
+
*/
|
|
698
|
+
interface FormFieldRef {
|
|
699
|
+
/** Reference to WorkflowSlot.id */
|
|
700
|
+
slotId: string;
|
|
701
|
+
/** Attribute name on the object */
|
|
702
|
+
attribute: string;
|
|
703
|
+
/** Relation-specific config (only for relation attributes) */
|
|
704
|
+
relationConfig?: RelationFieldConfig;
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Check if a FormNode uses simple mode (fields array)
|
|
708
|
+
*/
|
|
709
|
+
declare function isSimpleFormNode(node: FormNode): boolean;
|
|
710
|
+
/**
|
|
711
|
+
* Check if a FormNode uses advanced mode (rows array)
|
|
712
|
+
*/
|
|
713
|
+
declare function isAdvancedFormNode(node: FormNode): boolean;
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* Conditional branching node.
|
|
717
|
+
* Evaluates a condition and routes to different nodes based on the result.
|
|
718
|
+
*
|
|
719
|
+
* @example
|
|
720
|
+
* ```typescript
|
|
721
|
+
* const node: ConditionNode = {
|
|
722
|
+
* type: "condition",
|
|
723
|
+
* id: "check-vip",
|
|
724
|
+
* label: "Is VIP Customer?",
|
|
725
|
+
* condition: {
|
|
726
|
+
* operator: "or",
|
|
727
|
+
* rules: [
|
|
728
|
+
* { field: "slots.client.type", operator: "eq", value: "vip" },
|
|
729
|
+
* { field: "slots.client.type", operator: "eq", value: "premium" }
|
|
730
|
+
* ]
|
|
731
|
+
* },
|
|
732
|
+
* onTrue: "premium-flow",
|
|
733
|
+
* onFalse: "standard-flow"
|
|
734
|
+
* };
|
|
735
|
+
* ```
|
|
736
|
+
*/
|
|
737
|
+
interface ConditionNode extends BaseNode {
|
|
738
|
+
type: "condition";
|
|
739
|
+
/** Display label for the condition */
|
|
740
|
+
label: string;
|
|
741
|
+
/** Condition to evaluate */
|
|
742
|
+
condition: ConditionGroup;
|
|
743
|
+
/** ID of node to execute if condition is true (optional for drafts) */
|
|
744
|
+
onTrue?: string | null;
|
|
745
|
+
/** ID of node to execute if condition is false (optional for drafts) */
|
|
746
|
+
onFalse?: string | null;
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* Terminal node marking the end of a workflow path.
|
|
750
|
+
* A workflow can have multiple EndNodes for different outcomes.
|
|
751
|
+
*
|
|
752
|
+
* @example
|
|
753
|
+
* ```typescript
|
|
754
|
+
* const successEnd: EndNode = {
|
|
755
|
+
* type: "end",
|
|
756
|
+
* id: "end-success",
|
|
757
|
+
* label: "Completed Successfully",
|
|
758
|
+
* status: "completed"
|
|
759
|
+
* };
|
|
760
|
+
*
|
|
761
|
+
* const declinedEnd: EndNode = {
|
|
762
|
+
* type: "end",
|
|
763
|
+
* id: "end-declined",
|
|
764
|
+
* label: "Customer Declined",
|
|
765
|
+
* status: "declined"
|
|
766
|
+
* };
|
|
767
|
+
* ```
|
|
768
|
+
*/
|
|
769
|
+
interface EndNode extends BaseNode {
|
|
770
|
+
type: "end";
|
|
771
|
+
/** Optional display label */
|
|
772
|
+
label?: string;
|
|
773
|
+
/**
|
|
774
|
+
* Final status for the workflow instance.
|
|
775
|
+
* Common values: "completed", "declined", "cancelled", "expired"
|
|
776
|
+
*/
|
|
777
|
+
status?: string;
|
|
778
|
+
}
|
|
779
|
+
/**
|
|
780
|
+
* Union of all workflow node types.
|
|
781
|
+
* Use discriminated union on `type` field for type narrowing.
|
|
782
|
+
*/
|
|
783
|
+
type WorkflowNode = StartNode | FormNode | ConditionNode | EndNode;
|
|
784
|
+
/**
|
|
785
|
+
* All possible node types
|
|
786
|
+
*/
|
|
787
|
+
type WorkflowNodeType = WorkflowNode["type"];
|
|
788
|
+
/**
|
|
789
|
+
* Check if a node is a StartNode
|
|
790
|
+
*/
|
|
791
|
+
declare function isStartNode(node: WorkflowNode): node is StartNode;
|
|
792
|
+
/**
|
|
793
|
+
* Check if a node is a FormNode
|
|
794
|
+
*/
|
|
795
|
+
declare function isFormNode(node: WorkflowNode): node is FormNode;
|
|
796
|
+
/**
|
|
797
|
+
* Check if a node is a ConditionNode
|
|
798
|
+
*/
|
|
799
|
+
declare function isConditionNode(node: WorkflowNode): node is ConditionNode;
|
|
800
|
+
/**
|
|
801
|
+
* Check if a node is an EndNode
|
|
802
|
+
*/
|
|
803
|
+
declare function isEndNode(node: WorkflowNode): node is EndNode;
|
|
804
|
+
|
|
805
|
+
/**
|
|
806
|
+
* Logo configuration for external-facing interface
|
|
807
|
+
*/
|
|
808
|
+
interface ThemeLogo {
|
|
809
|
+
/** URL to the logo image */
|
|
810
|
+
url: string;
|
|
811
|
+
/** Alt text for accessibility */
|
|
812
|
+
alt?: string;
|
|
813
|
+
/** Max height in pixels */
|
|
814
|
+
maxHeight?: number;
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* Color configuration for theming
|
|
818
|
+
*/
|
|
819
|
+
interface ThemeColors {
|
|
820
|
+
/** Primary brand color (hex) */
|
|
821
|
+
primary?: string;
|
|
822
|
+
/** Primary color for text on primary background */
|
|
823
|
+
primaryForeground?: string;
|
|
824
|
+
/** Background color */
|
|
825
|
+
background?: string;
|
|
826
|
+
/** Foreground/text color */
|
|
827
|
+
foreground?: string;
|
|
828
|
+
/** Muted/secondary color */
|
|
829
|
+
muted?: string;
|
|
830
|
+
/** Border color */
|
|
831
|
+
border?: string;
|
|
832
|
+
/** Accent color for highlights */
|
|
833
|
+
accent?: string;
|
|
834
|
+
}
|
|
835
|
+
/**
|
|
836
|
+
* Typography configuration
|
|
837
|
+
*/
|
|
838
|
+
interface ThemeTypography {
|
|
839
|
+
/** Font family for headings */
|
|
840
|
+
headingFont?: string;
|
|
841
|
+
/** Font family for body text */
|
|
842
|
+
bodyFont?: string;
|
|
843
|
+
/** Base font size in pixels */
|
|
844
|
+
baseFontSize?: number;
|
|
845
|
+
}
|
|
846
|
+
/**
|
|
847
|
+
* Complete theme configuration for external-facing workflow interface.
|
|
848
|
+
*
|
|
849
|
+
* Allows full branding customization for forms displayed to external users.
|
|
850
|
+
*
|
|
851
|
+
* @example
|
|
852
|
+
* ```typescript
|
|
853
|
+
* const theme: WorkflowTheme = {
|
|
854
|
+
* logo: {
|
|
855
|
+
* url: "https://example.com/logo.png",
|
|
856
|
+
* alt: "Company Logo",
|
|
857
|
+
* maxHeight: 48
|
|
858
|
+
* },
|
|
859
|
+
* colors: {
|
|
860
|
+
* primary: "#3B82F6",
|
|
861
|
+
* primaryForeground: "#FFFFFF",
|
|
862
|
+
* background: "#F8FAFC"
|
|
863
|
+
* },
|
|
864
|
+
* typography: {
|
|
865
|
+
* headingFont: "Inter, sans-serif",
|
|
866
|
+
* bodyFont: "Inter, sans-serif"
|
|
867
|
+
* },
|
|
868
|
+
* borderRadius: 8
|
|
869
|
+
* };
|
|
870
|
+
* ```
|
|
871
|
+
*/
|
|
872
|
+
interface WorkflowTheme {
|
|
873
|
+
/** Logo configuration */
|
|
874
|
+
logo?: ThemeLogo;
|
|
875
|
+
/** Color palette */
|
|
876
|
+
colors?: ThemeColors;
|
|
877
|
+
/** Typography settings */
|
|
878
|
+
typography?: ThemeTypography;
|
|
879
|
+
/** Border radius for cards/buttons in pixels */
|
|
880
|
+
borderRadius?: number;
|
|
881
|
+
/** Show powered by badge */
|
|
882
|
+
showPoweredBy?: boolean;
|
|
883
|
+
/** Custom CSS (advanced) */
|
|
884
|
+
customCss?: string;
|
|
885
|
+
}
|
|
886
|
+
/**
|
|
887
|
+
* Default theme values
|
|
888
|
+
*/
|
|
889
|
+
declare const DEFAULT_THEME: Required<Pick<WorkflowTheme, "borderRadius" | "showPoweredBy">>;
|
|
890
|
+
/**
|
|
891
|
+
* Merge a partial theme with defaults
|
|
892
|
+
*/
|
|
893
|
+
declare function mergeWithDefaults(theme?: WorkflowTheme): WorkflowTheme;
|
|
894
|
+
/**
|
|
895
|
+
* Generate CSS variables from theme colors
|
|
896
|
+
*/
|
|
897
|
+
declare function generateCssVariables(colors?: ThemeColors): Record<string, string>;
|
|
898
|
+
|
|
899
|
+
/**
|
|
900
|
+
* Mode for slot initialization when starting a workflow
|
|
901
|
+
*/
|
|
902
|
+
type SlotMode = "create" | "select" | "optional" | "create_if_not_empty";
|
|
903
|
+
/**
|
|
904
|
+
* Represents a "slot" for an object in the workflow.
|
|
905
|
+
* Slots define which objects are manipulated during workflow execution.
|
|
906
|
+
*
|
|
907
|
+
* @example
|
|
908
|
+
* ```typescript
|
|
909
|
+
* const clientSlot: WorkflowSlot = {
|
|
910
|
+
* id: "client",
|
|
911
|
+
* objectName: "contacts",
|
|
912
|
+
* label: "Client",
|
|
913
|
+
* mode: "optional",
|
|
914
|
+
* color: "blue",
|
|
915
|
+
* icon: "User"
|
|
916
|
+
* };
|
|
917
|
+
* ```
|
|
918
|
+
*/
|
|
919
|
+
interface WorkflowSlot {
|
|
920
|
+
/** Unique identifier for the slot */
|
|
921
|
+
id: string;
|
|
922
|
+
/** Name of the object definition (e.g., "contacts", "companies") */
|
|
923
|
+
objectName: string;
|
|
924
|
+
/** Display label */
|
|
925
|
+
label: string;
|
|
926
|
+
/** How the slot is initialized at workflow start */
|
|
927
|
+
mode: SlotMode;
|
|
928
|
+
/** Color for visual distinction in the builder */
|
|
929
|
+
color?: ColorId;
|
|
930
|
+
/** Optional icon */
|
|
931
|
+
icon?: IconName;
|
|
932
|
+
/** Resolved object label (set by the backend in form context responses) */
|
|
933
|
+
objectLabel?: string;
|
|
934
|
+
}
|
|
935
|
+
/**
|
|
936
|
+
* Position of a node in the visual builder
|
|
937
|
+
*/
|
|
938
|
+
interface NodePosition {
|
|
939
|
+
x: number;
|
|
940
|
+
y: number;
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* Viewport state for the canvas
|
|
944
|
+
*/
|
|
945
|
+
interface CanvasViewport {
|
|
946
|
+
x: number;
|
|
947
|
+
y: number;
|
|
948
|
+
zoom: number;
|
|
949
|
+
}
|
|
950
|
+
/**
|
|
951
|
+
* Layout information for the workflow builder.
|
|
952
|
+
* Separated from business data to allow different visualizations.
|
|
953
|
+
*/
|
|
954
|
+
interface WorkflowLayout {
|
|
955
|
+
/** Node positions by node ID */
|
|
956
|
+
positions: Record<string, NodePosition>;
|
|
957
|
+
/** Canvas viewport state */
|
|
958
|
+
viewport?: CanvasViewport;
|
|
959
|
+
}
|
|
960
|
+
/**
|
|
961
|
+
* Global configuration options for a workflow
|
|
962
|
+
*/
|
|
963
|
+
interface WorkflowConfig {
|
|
964
|
+
/** Time-to-live for workflow instances (e.g., "30d") */
|
|
965
|
+
instanceTtl?: string;
|
|
966
|
+
/** Time-to-live for external participation links (e.g., "7d") */
|
|
967
|
+
externalLinkTtl?: string;
|
|
968
|
+
/** Whether external participants are allowed */
|
|
969
|
+
allowExternalParticipants?: boolean;
|
|
970
|
+
}
|
|
971
|
+
/**
|
|
972
|
+
* Workflow lifecycle status
|
|
973
|
+
*/
|
|
974
|
+
type WorkflowStatus = "draft" | "published" | "archived";
|
|
975
|
+
/**
|
|
976
|
+
* Complete workflow definition (the "blueprint").
|
|
977
|
+
*
|
|
978
|
+
* This is the design-time representation of a workflow.
|
|
979
|
+
* When executed, a WorkflowInstance is created from this definition.
|
|
980
|
+
*
|
|
981
|
+
* @example
|
|
982
|
+
* ```typescript
|
|
983
|
+
* const workflow: WorkflowDefinition = {
|
|
984
|
+
* name: "client-onboarding",
|
|
985
|
+
* label: "Client Onboarding",
|
|
986
|
+
* status: "draft",
|
|
987
|
+
* version: 1,
|
|
988
|
+
* slots: [{ id: "client", objectName: "contacts", label: "Client", mode: "create" }],
|
|
989
|
+
* nodes: {
|
|
990
|
+
* "start": { type: "start", id: "start", next: "form-1" },
|
|
991
|
+
* "form-1": { type: "form", id: "form-1", label: "Info", slotId: "client", fields: ["name"], next: "end" },
|
|
992
|
+
* "end": { type: "end", id: "end" }
|
|
993
|
+
* },
|
|
994
|
+
* startNodeId: "start"
|
|
995
|
+
* };
|
|
996
|
+
* ```
|
|
997
|
+
*/
|
|
998
|
+
interface WorkflowDefinition {
|
|
999
|
+
/** Database ID */
|
|
1000
|
+
id?: Uuid;
|
|
1001
|
+
/** Technical name (kebab-case, unique per tenant) */
|
|
1002
|
+
name: string;
|
|
1003
|
+
/** Display label */
|
|
1004
|
+
label: string;
|
|
1005
|
+
/** Optional description */
|
|
1006
|
+
description?: string;
|
|
1007
|
+
/** Optional icon */
|
|
1008
|
+
icon?: IconName;
|
|
1009
|
+
/** Workflow lifecycle status */
|
|
1010
|
+
status: WorkflowStatus;
|
|
1011
|
+
/** Version number (incremented on publish) */
|
|
1012
|
+
version: number;
|
|
1013
|
+
/** Slots (objects) manipulated in this workflow */
|
|
1014
|
+
slots: WorkflowSlot[];
|
|
1015
|
+
/** Nodes indexed by ID for O(1) access */
|
|
1016
|
+
nodes: Record<string, WorkflowNode>;
|
|
1017
|
+
/** ID of the start node */
|
|
1018
|
+
startNodeId: string;
|
|
1019
|
+
/** Layout information for the visual builder (optional, used by legacy canvas) */
|
|
1020
|
+
layout?: WorkflowLayout;
|
|
1021
|
+
/** Theming for external-facing interface */
|
|
1022
|
+
theme?: WorkflowTheme;
|
|
1023
|
+
/** Global configuration options */
|
|
1024
|
+
config?: WorkflowConfig;
|
|
1025
|
+
/** Tenant ID for multi-tenant isolation */
|
|
1026
|
+
tenantId?: string;
|
|
1027
|
+
/** If true, defined in code (protected from UI deletion) */
|
|
1028
|
+
system?: boolean;
|
|
1029
|
+
/** Extensible metadata */
|
|
1030
|
+
metadata?: Record<string, unknown>;
|
|
1031
|
+
/** Timestamps */
|
|
1032
|
+
createdAt?: Date;
|
|
1033
|
+
updatedAt?: Date;
|
|
1034
|
+
}
|
|
1035
|
+
/**
|
|
1036
|
+
* Check if an object is a WorkflowDefinition
|
|
1037
|
+
*/
|
|
1038
|
+
declare function isWorkflowDefinition(obj: unknown): obj is WorkflowDefinition;
|
|
1039
|
+
/**
|
|
1040
|
+
* Check if a workflow is published
|
|
1041
|
+
*/
|
|
1042
|
+
declare function isWorkflowPublished(workflow: WorkflowDefinition): boolean;
|
|
1043
|
+
/**
|
|
1044
|
+
* Check if a workflow is a system workflow
|
|
1045
|
+
*/
|
|
1046
|
+
declare function isSystemWorkflow(workflow: WorkflowDefinition): boolean;
|
|
1047
|
+
|
|
1048
|
+
/**
|
|
1049
|
+
* Status of a workflow instance
|
|
1050
|
+
*/
|
|
1051
|
+
type InstanceStatus = "running" | "waiting" | "completed" | "failed" | "cancelled";
|
|
1052
|
+
/**
|
|
1053
|
+
* Record of a transition between nodes
|
|
1054
|
+
*/
|
|
1055
|
+
interface WorkflowTransition {
|
|
1056
|
+
/** Timestamp of the transition */
|
|
1057
|
+
timestamp: Date;
|
|
1058
|
+
/** ID of the source node */
|
|
1059
|
+
fromNodeId: string | null;
|
|
1060
|
+
/** ID of the target node */
|
|
1061
|
+
toNodeId: string;
|
|
1062
|
+
/** Type of the target node */
|
|
1063
|
+
nodeType: string;
|
|
1064
|
+
/** ID of the user/participant who triggered the transition */
|
|
1065
|
+
triggeredBy?: string;
|
|
1066
|
+
/** Duration of node execution in milliseconds */
|
|
1067
|
+
durationMs?: number;
|
|
1068
|
+
/** Metadata about the transition */
|
|
1069
|
+
metadata?: Record<string, unknown>;
|
|
1070
|
+
}
|
|
1071
|
+
/**
|
|
1072
|
+
* Error information when instance is in "failed" status
|
|
1073
|
+
*/
|
|
1074
|
+
interface WorkflowError {
|
|
1075
|
+
/** Error code for programmatic handling */
|
|
1076
|
+
code: string;
|
|
1077
|
+
/** Human-readable error message */
|
|
1078
|
+
message: string;
|
|
1079
|
+
/** ID of the node where error occurred */
|
|
1080
|
+
nodeId?: string;
|
|
1081
|
+
/** Stack trace (if available) */
|
|
1082
|
+
stack?: string;
|
|
1083
|
+
/** Additional error details */
|
|
1084
|
+
details?: Record<string, unknown>;
|
|
1085
|
+
/** Timestamp when error occurred */
|
|
1086
|
+
timestamp: Date;
|
|
1087
|
+
}
|
|
1088
|
+
/**
|
|
1089
|
+
* Information about the action the workflow is waiting for.
|
|
1090
|
+
* Populated when status is "waiting".
|
|
1091
|
+
*/
|
|
1092
|
+
interface PendingAction {
|
|
1093
|
+
/** ID of the node waiting for action */
|
|
1094
|
+
nodeId: string;
|
|
1095
|
+
/** Type of the waiting node */
|
|
1096
|
+
nodeType: "form" | "signature" | "approval";
|
|
1097
|
+
/** Display label for the action */
|
|
1098
|
+
nodeLabel: string;
|
|
1099
|
+
/** ID of the participation required to complete this action */
|
|
1100
|
+
requiredParticipationId?: string;
|
|
1101
|
+
/** When the pending action expires */
|
|
1102
|
+
expiresAt?: Date;
|
|
1103
|
+
}
|
|
1104
|
+
/**
|
|
1105
|
+
* A specific execution of a workflow.
|
|
1106
|
+
*
|
|
1107
|
+
* Each instance maintains its own state, context, and history.
|
|
1108
|
+
* The workflow definition is snapshotted at creation to ensure
|
|
1109
|
+
* consistent execution even if the definition is later modified.
|
|
1110
|
+
*
|
|
1111
|
+
* @example
|
|
1112
|
+
* ```typescript
|
|
1113
|
+
* const instance: WorkflowInstance = {
|
|
1114
|
+
* id: "inst_123",
|
|
1115
|
+
* workflowId: "wf_456",
|
|
1116
|
+
* workflowVersion: 3,
|
|
1117
|
+
* workflowSnapshot: { ... }, // Full definition at creation time
|
|
1118
|
+
* status: "waiting",
|
|
1119
|
+
* currentNodeId: "client-form",
|
|
1120
|
+
* context: { slots: {}, forms: {}, documents: {}, variables: {}, conditionResults: {} },
|
|
1121
|
+
* history: [{ timestamp: new Date(), fromNodeId: null, toNodeId: "start", nodeType: "start" }],
|
|
1122
|
+
* pendingAction: {
|
|
1123
|
+
* nodeId: "client-form",
|
|
1124
|
+
* nodeType: "form",
|
|
1125
|
+
* nodeLabel: "Client Information",
|
|
1126
|
+
* requiredParticipationId: "part_789"
|
|
1127
|
+
* },
|
|
1128
|
+
* startedBy: "user_001",
|
|
1129
|
+
* tenantId: "tenant_abc",
|
|
1130
|
+
* createdAt: new Date()
|
|
1131
|
+
* };
|
|
1132
|
+
* ```
|
|
1133
|
+
*/
|
|
1134
|
+
interface WorkflowInstance {
|
|
1135
|
+
/** Unique instance ID */
|
|
1136
|
+
id: Uuid;
|
|
1137
|
+
/** Reference to the workflow definition */
|
|
1138
|
+
workflowId: Uuid;
|
|
1139
|
+
/** Version of the workflow at creation time */
|
|
1140
|
+
workflowVersion: number;
|
|
1141
|
+
/** Complete snapshot of the workflow definition */
|
|
1142
|
+
workflowSnapshot: WorkflowDefinition;
|
|
1143
|
+
/** Current execution status */
|
|
1144
|
+
status: InstanceStatus;
|
|
1145
|
+
/** ID of the current node */
|
|
1146
|
+
currentNodeId: string;
|
|
1147
|
+
/** Accumulated execution context */
|
|
1148
|
+
context: WorkflowExecutionContext;
|
|
1149
|
+
/** History of node transitions */
|
|
1150
|
+
history: WorkflowTransition[];
|
|
1151
|
+
/** Current pending action (when status is "waiting") */
|
|
1152
|
+
pendingAction?: PendingAction;
|
|
1153
|
+
/** Error information (when status is "failed") */
|
|
1154
|
+
error?: WorkflowError;
|
|
1155
|
+
/** ID of the user who started the workflow */
|
|
1156
|
+
startedBy: string;
|
|
1157
|
+
/** Tenant ID for multi-tenant isolation */
|
|
1158
|
+
tenantId: string;
|
|
1159
|
+
/** When the instance expires */
|
|
1160
|
+
expiresAt?: Date;
|
|
1161
|
+
/** Timestamps */
|
|
1162
|
+
createdAt: Date;
|
|
1163
|
+
updatedAt: Date;
|
|
1164
|
+
completedAt?: Date;
|
|
1165
|
+
}
|
|
1166
|
+
/**
|
|
1167
|
+
* Check if an instance is in a terminal state
|
|
1168
|
+
*/
|
|
1169
|
+
declare function isInstanceTerminal(instance: WorkflowInstance): boolean;
|
|
1170
|
+
/**
|
|
1171
|
+
* Check if an instance is waiting for external action
|
|
1172
|
+
*/
|
|
1173
|
+
declare function isInstanceWaiting(instance: WorkflowInstance): boolean;
|
|
1174
|
+
/**
|
|
1175
|
+
* Check if an instance can be resumed
|
|
1176
|
+
*/
|
|
1177
|
+
declare function canResumeInstance(instance: WorkflowInstance): boolean;
|
|
1178
|
+
/**
|
|
1179
|
+
* Create initial transition record for workflow start
|
|
1180
|
+
*/
|
|
1181
|
+
declare function createStartTransition(startNodeId: string, startedBy: string): WorkflowTransition;
|
|
1182
|
+
|
|
1183
|
+
/**
|
|
1184
|
+
* Type of view - determines the config structure
|
|
1185
|
+
*/
|
|
1186
|
+
type ViewType = "detail" | "list" | "calendar" | "timeline" | "gallery";
|
|
1187
|
+
/**
|
|
1188
|
+
* Creation behavior when clicking the "+" button
|
|
1189
|
+
* - `redirect`: Create the record then navigate to its detail page
|
|
1190
|
+
* - `inline`: Insert an empty row in the table (no navigation)
|
|
1191
|
+
* - `modal`: Open a stacked modal for creation
|
|
1192
|
+
*/
|
|
1193
|
+
type CreateMode = "redirect" | "inline" | "modal";
|
|
1194
|
+
/**
|
|
1195
|
+
* Inline attribute group configuration
|
|
1196
|
+
* Groups multiple attributes into a single composite field with dropdown editing
|
|
1197
|
+
*/
|
|
1198
|
+
interface AttributeGroupField {
|
|
1199
|
+
/** Unique identifier for the group */
|
|
1200
|
+
id: string;
|
|
1201
|
+
/** Display label for the composite field */
|
|
1202
|
+
label: string;
|
|
1203
|
+
/** Description shown in the dropdown */
|
|
1204
|
+
description?: string;
|
|
1205
|
+
/** Attribute names to include in this group */
|
|
1206
|
+
attributes: string[];
|
|
1207
|
+
/**
|
|
1208
|
+
* Template for the display value
|
|
1209
|
+
* Uses {attributeName} syntax for interpolation
|
|
1210
|
+
* @example "{billing_street}, {billing_city} {billing_postal_code}"
|
|
1211
|
+
*/
|
|
1212
|
+
displayTemplate?: string;
|
|
1213
|
+
}
|
|
1214
|
+
/**
|
|
1215
|
+
* Field definition within a form group
|
|
1216
|
+
* Can be either a single attribute or an inline attribute group
|
|
1217
|
+
*/
|
|
1218
|
+
interface Field {
|
|
1219
|
+
/** Attribute name to display (for single attribute fields) */
|
|
1220
|
+
attribute?: string;
|
|
1221
|
+
/** Inline attribute group (groups multiple attributes into one composite field) */
|
|
1222
|
+
attributeGroup?: AttributeGroupField;
|
|
1223
|
+
/** Grid span (1-12 columns) */
|
|
1224
|
+
span?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
|
|
1225
|
+
/** Override label for this view (only for single attribute fields) */
|
|
1226
|
+
label?: string;
|
|
1227
|
+
/** Force read-only display */
|
|
1228
|
+
readOnly?: boolean;
|
|
1229
|
+
}
|
|
1230
|
+
/**
|
|
1231
|
+
* Base properties shared by all group types
|
|
1232
|
+
*/
|
|
1233
|
+
interface BaseGroup {
|
|
1234
|
+
id: string;
|
|
1235
|
+
label: string;
|
|
1236
|
+
description?: string;
|
|
1237
|
+
collapsible?: boolean;
|
|
1238
|
+
collapsed?: boolean;
|
|
1239
|
+
order?: number;
|
|
1240
|
+
}
|
|
1241
|
+
/**
|
|
1242
|
+
* Group of fields for organizing forms (default group type)
|
|
1243
|
+
*/
|
|
1244
|
+
interface FieldGroup extends BaseGroup {
|
|
1245
|
+
/** Discriminant — optional for backward compatibility with existing data */
|
|
1246
|
+
type?: "fields";
|
|
1247
|
+
fields: Field[];
|
|
1248
|
+
}
|
|
1249
|
+
/**
|
|
1250
|
+
* Group that displays related records for a relation attribute
|
|
1251
|
+
*/
|
|
1252
|
+
interface RelationGroup extends BaseGroup {
|
|
1253
|
+
type: "relation";
|
|
1254
|
+
/** Relation attribute name on the source object */
|
|
1255
|
+
attribute: string;
|
|
1256
|
+
/** Columns to display (auto-detected from target object if empty) */
|
|
1257
|
+
columns?: string[];
|
|
1258
|
+
/** Read-only mode */
|
|
1259
|
+
readOnly?: boolean;
|
|
1260
|
+
/** Allow creating new related records */
|
|
1261
|
+
allowCreate?: boolean;
|
|
1262
|
+
/**
|
|
1263
|
+
* Two-level traversal — display records from the target's relation.
|
|
1264
|
+
* When set, parent rows become grouping headers and the sub-rows
|
|
1265
|
+
* (from `through.attribute`) are the primary display.
|
|
1266
|
+
*
|
|
1267
|
+
* @example attribute = "members", through.attribute = "companies"
|
|
1268
|
+
* → displays companies of each member
|
|
1269
|
+
*/
|
|
1270
|
+
through?: {
|
|
1271
|
+
/** Relation attribute on the first-level target object */
|
|
1272
|
+
attribute: string;
|
|
1273
|
+
};
|
|
1274
|
+
}
|
|
1275
|
+
/**
|
|
1276
|
+
* Discriminated union of all group types
|
|
1277
|
+
*/
|
|
1278
|
+
type Group = FieldGroup | RelationGroup;
|
|
1279
|
+
type TabType = "form" | "table" | "custom" | "activity" | "richtext" | "flows" | "documents";
|
|
1280
|
+
/**
|
|
1281
|
+
* Base properties shared by all tab types
|
|
1282
|
+
*/
|
|
1283
|
+
interface BaseTab {
|
|
1284
|
+
id: string;
|
|
1285
|
+
name: string;
|
|
1286
|
+
label: string;
|
|
1287
|
+
icon?: IconName;
|
|
1288
|
+
order?: number;
|
|
1289
|
+
}
|
|
1290
|
+
/**
|
|
1291
|
+
* Form layout density
|
|
1292
|
+
*/
|
|
1293
|
+
type FormDensity = "compact" | "comfortable" | "spacious";
|
|
1294
|
+
/**
|
|
1295
|
+
* Form tab - displays attributes organized in groups
|
|
1296
|
+
*/
|
|
1297
|
+
interface FormTab extends BaseTab {
|
|
1298
|
+
type: "form";
|
|
1299
|
+
groups: Group[];
|
|
1300
|
+
/** Number of grid columns (1, 2, or 3). Default: 2 */
|
|
1301
|
+
formColumns?: 1 | 2 | 3;
|
|
1302
|
+
/** Layout density. Default: "comfortable" */
|
|
1303
|
+
density?: FormDensity;
|
|
1304
|
+
}
|
|
1305
|
+
/**
|
|
1306
|
+
* Direct relation on the current object
|
|
1307
|
+
*
|
|
1308
|
+
* @example Contact.companies → shows Companies linked via the "companies" relation
|
|
1309
|
+
*/
|
|
1310
|
+
interface RelationSource {
|
|
1311
|
+
type: "relation";
|
|
1312
|
+
/** Relation attribute name on the current object */
|
|
1313
|
+
attribute: string;
|
|
1314
|
+
}
|
|
1315
|
+
/**
|
|
1316
|
+
* Inverse lookup — records from another object that point to us
|
|
1317
|
+
*
|
|
1318
|
+
* @example On Company, show Contacts where Contact.company = this Company
|
|
1319
|
+
*/
|
|
1320
|
+
interface InverseSource {
|
|
1321
|
+
type: "inverse";
|
|
1322
|
+
/** Object name that has the relation to us */
|
|
1323
|
+
object: string;
|
|
1324
|
+
/** Relation attribute name on the source object that points to us */
|
|
1325
|
+
attribute: string;
|
|
1326
|
+
}
|
|
1327
|
+
/**
|
|
1328
|
+
* Where table data comes from — either a direct relation or an inverse lookup
|
|
1329
|
+
*/
|
|
1330
|
+
type TableSource = RelationSource | InverseSource;
|
|
1331
|
+
/**
|
|
1332
|
+
* Table tab - displays related records in a table
|
|
1333
|
+
*
|
|
1334
|
+
* The `source` field determines where data comes from.
|
|
1335
|
+
*
|
|
1336
|
+
* @example Direct: source = { type: "relation", attribute: "members" }
|
|
1337
|
+
* @example Inverse: source = { type: "inverse", object: "contacts", attribute: "company" }
|
|
1338
|
+
*/
|
|
1339
|
+
interface TableTab extends BaseTab {
|
|
1340
|
+
type: "table";
|
|
1341
|
+
/** Where the data comes from */
|
|
1342
|
+
source: TableSource;
|
|
1343
|
+
/** Columns to display (attribute names from the resolved target object) */
|
|
1344
|
+
columns: string[];
|
|
1345
|
+
/**
|
|
1346
|
+
* Traverse a 2nd-level relation to display nested data.
|
|
1347
|
+
* When active, `columns` stores the 2nd-level object's attribute names.
|
|
1348
|
+
*
|
|
1349
|
+
* @example source.attribute = "members", through.attribute = "companies"
|
|
1350
|
+
* → displays companies of each member
|
|
1351
|
+
*/
|
|
1352
|
+
through?: {
|
|
1353
|
+
/** Relation attribute on the first-level target object */
|
|
1354
|
+
attribute: string;
|
|
1355
|
+
/** Show _source and _target columns */
|
|
1356
|
+
showSourceTarget?: boolean;
|
|
1357
|
+
};
|
|
1358
|
+
/** Allow creating new records */
|
|
1359
|
+
allowCreate?: boolean;
|
|
1360
|
+
/** Creation behavior when allowCreate is true. Default: "redirect" */
|
|
1361
|
+
createMode?: CreateMode;
|
|
1362
|
+
/** Allow inline editing */
|
|
1363
|
+
allowEdit?: boolean;
|
|
1364
|
+
/** Allow deleting records */
|
|
1365
|
+
allowDelete?: boolean;
|
|
1366
|
+
/** Default filters applied to the table */
|
|
1367
|
+
filters?: FilterState;
|
|
1368
|
+
/** Default sort rules */
|
|
1369
|
+
sorts?: SortRule[];
|
|
1370
|
+
}
|
|
1371
|
+
/**
|
|
1372
|
+
* Custom tab - renders a developer-defined component
|
|
1373
|
+
*/
|
|
1374
|
+
interface CustomTab extends BaseTab {
|
|
1375
|
+
type: "custom";
|
|
1376
|
+
/** Component identifier to render */
|
|
1377
|
+
component: string;
|
|
1378
|
+
/** Props to pass to the component */
|
|
1379
|
+
props?: Record<string, unknown>;
|
|
1380
|
+
}
|
|
1381
|
+
/**
|
|
1382
|
+
* Activity tab - displays activity feed for the current record
|
|
1383
|
+
*/
|
|
1384
|
+
interface ActivityTab extends BaseTab {
|
|
1385
|
+
type: "activity";
|
|
1386
|
+
limit?: number;
|
|
1387
|
+
}
|
|
1388
|
+
/**
|
|
1389
|
+
* Richtext tab - displays a block editor for a richtext attribute
|
|
1390
|
+
*/
|
|
1391
|
+
interface RichtextTab extends BaseTab {
|
|
1392
|
+
type: "richtext";
|
|
1393
|
+
/** Richtext attribute to display in the BlockEditor */
|
|
1394
|
+
attribute: string;
|
|
1395
|
+
/** Optional text attribute for an editable title input above the editor */
|
|
1396
|
+
titleAttribute?: string;
|
|
1397
|
+
}
|
|
1398
|
+
/**
|
|
1399
|
+
* Flows tab - displays workflow instances linked to the current record
|
|
1400
|
+
*/
|
|
1401
|
+
interface FlowsTab extends BaseTab {
|
|
1402
|
+
type: "flows";
|
|
1403
|
+
allowStart?: boolean;
|
|
1404
|
+
allowCancel?: boolean;
|
|
1405
|
+
statusFilter?: InstanceStatus[];
|
|
1406
|
+
columns?: ("workflow" | "status" | "startedBy" | "createdAt" | "updatedAt")[];
|
|
1407
|
+
}
|
|
1408
|
+
/**
|
|
1409
|
+
* Documents tab - displays all documents attached to the record
|
|
1410
|
+
*/
|
|
1411
|
+
interface DocumentsTab extends BaseTab {
|
|
1412
|
+
type: "documents";
|
|
1413
|
+
allowUpload?: boolean;
|
|
1414
|
+
allowRemove?: boolean;
|
|
1415
|
+
showProcessing?: boolean;
|
|
1416
|
+
showRequiredWarnings?: boolean;
|
|
1417
|
+
hideAttachments?: boolean;
|
|
1418
|
+
}
|
|
1419
|
+
/**
|
|
1420
|
+
* Union of all tab types (for detail views)
|
|
1421
|
+
*/
|
|
1422
|
+
type Tab = FormTab | TableTab | CustomTab | ActivityTab | RichtextTab | FlowsTab | DocumentsTab;
|
|
1423
|
+
/**
|
|
1424
|
+
* Detail view layout mode
|
|
1425
|
+
* - `page`: Full view with multiple tabs
|
|
1426
|
+
* - `modal`: Simplified view for modals (single FormTab, no tabs UI)
|
|
1427
|
+
*/
|
|
1428
|
+
type DetailViewLayout = "page" | "modal";
|
|
1429
|
+
/**
|
|
1430
|
+
* List view layout mode
|
|
1431
|
+
* - `table`: Table/grid layout
|
|
1432
|
+
* - `kanban`: Kanban board layout (grouped by attribute)
|
|
1433
|
+
*/
|
|
1434
|
+
type ListViewLayout = "table" | "kanban";
|
|
1435
|
+
/**
|
|
1436
|
+
* Tab within a list view — each tab carries its own full display configuration.
|
|
1437
|
+
*
|
|
1438
|
+
* @example
|
|
1439
|
+
* ```typescript
|
|
1440
|
+
* const tabs: ListViewTab[] = [
|
|
1441
|
+
* { id: "all", label: "All Contacts", default: true, layout: "table", columns: ["name", "email", "status"] },
|
|
1442
|
+
* { id: "active", label: "Active", layout: "table", columns: ["name", "email"], filters: activeFilter },
|
|
1443
|
+
* { id: "pipeline", label: "Pipeline", layout: "kanban", columns: ["name", "amount"], groupByAttribute: "stage" },
|
|
1444
|
+
* ];
|
|
1445
|
+
* ```
|
|
1446
|
+
*/
|
|
1447
|
+
interface ListViewTab {
|
|
1448
|
+
/** Unique identifier */
|
|
1449
|
+
id: string;
|
|
1450
|
+
/** Display label */
|
|
1451
|
+
label: string;
|
|
1452
|
+
/** Icon */
|
|
1453
|
+
icon?: IconName;
|
|
1454
|
+
/** Default tab (shown on load) */
|
|
1455
|
+
default?: boolean;
|
|
1456
|
+
/** Layout mode */
|
|
1457
|
+
layout: ListViewLayout;
|
|
1458
|
+
/** Attribute names to display as columns */
|
|
1459
|
+
columns: string[];
|
|
1460
|
+
/** Column widths in pixels */
|
|
1461
|
+
columnSizing?: Record<string, number>;
|
|
1462
|
+
/** Filters applied to this tab */
|
|
1463
|
+
filters?: FilterGroup;
|
|
1464
|
+
/** Sort rules for this tab */
|
|
1465
|
+
sorts?: SortRule[];
|
|
1466
|
+
/** Attribute to group by (required when layout is "kanban") */
|
|
1467
|
+
groupByAttribute?: string;
|
|
1468
|
+
/** When true, the tab is read-only: no cell editing, no create, no delete */
|
|
1469
|
+
readOnly?: boolean;
|
|
1470
|
+
/** Creation behavior when clicking "+". Default: "redirect" */
|
|
1471
|
+
createMode?: CreateMode;
|
|
1472
|
+
/** User attribute to display on kanban cards (bottom-left) */
|
|
1473
|
+
cardUserAttribute?: string;
|
|
1474
|
+
/** Date attribute to display on kanban cards (bottom-right) */
|
|
1475
|
+
cardDateAttribute?: string;
|
|
1476
|
+
/** Order of kanban columns (by option value) - for kanban layout only */
|
|
1477
|
+
kanbanColumnOrder?: string[];
|
|
1478
|
+
/** Visibility of kanban columns (by option value) - for kanban layout only */
|
|
1479
|
+
kanbanColumnVisibility?: Record<string, boolean>;
|
|
1480
|
+
/** Pinned kanban columns (by option value) - for kanban layout only */
|
|
1481
|
+
kanbanPinnedColumns?: string[];
|
|
1482
|
+
}
|
|
1483
|
+
/**
|
|
1484
|
+
* Configuration for the side panel displayed alongside tab content.
|
|
1485
|
+
* When present, a right-side panel shows the configured attributes as flat fields.
|
|
1486
|
+
*/
|
|
1487
|
+
interface SidePanelConfig {
|
|
1488
|
+
/** Attribute names to display as flat fields in the panel */
|
|
1489
|
+
attributes: string[];
|
|
1490
|
+
/** Width in pixels. @default 320 */
|
|
1491
|
+
width?: number;
|
|
1492
|
+
}
|
|
1493
|
+
/**
|
|
1494
|
+
* Configuration for detail views (RecordEditView)
|
|
1495
|
+
*/
|
|
1496
|
+
interface DetailViewConfig {
|
|
1497
|
+
/** Layout mode */
|
|
1498
|
+
layout: DetailViewLayout;
|
|
1499
|
+
/** Tabs in this view */
|
|
1500
|
+
tabs: Tab[];
|
|
1501
|
+
/** Optional side panel with flat attribute fields (not available for modal layout) */
|
|
1502
|
+
sidePanel?: SidePanelConfig;
|
|
1503
|
+
}
|
|
1504
|
+
/**
|
|
1505
|
+
* Configuration for list views (RecordsView)
|
|
1506
|
+
*
|
|
1507
|
+
* Each tab carries its own full config (layout, columns, filters, sorts, groupBy).
|
|
1508
|
+
* The view only holds shared base filters applied to ALL tabs.
|
|
1509
|
+
*/
|
|
1510
|
+
interface ListViewConfig {
|
|
1511
|
+
/** Base filters applied to ALL tabs (scoping, tenant, etc.) */
|
|
1512
|
+
defaultFilters?: FilterGroup;
|
|
1513
|
+
/** Tabs — at least one required. Each carries its own full config. */
|
|
1514
|
+
tabs: ListViewTab[];
|
|
1515
|
+
}
|
|
1516
|
+
/**
|
|
1517
|
+
* Configuration for calendar views (future)
|
|
1518
|
+
*/
|
|
1519
|
+
interface CalendarViewConfig {
|
|
1520
|
+
/** Date attribute for positioning events */
|
|
1521
|
+
dateAttribute: string;
|
|
1522
|
+
/** End date attribute (for range events) */
|
|
1523
|
+
endDateAttribute?: string;
|
|
1524
|
+
/** Title attribute for event display */
|
|
1525
|
+
titleAttribute: string;
|
|
1526
|
+
/** Color attribute (status/select) */
|
|
1527
|
+
colorAttribute?: string;
|
|
1528
|
+
}
|
|
1529
|
+
/**
|
|
1530
|
+
* Configuration for timeline views (future)
|
|
1531
|
+
*/
|
|
1532
|
+
interface TimelineViewConfig {
|
|
1533
|
+
/** Date attribute for timeline positioning */
|
|
1534
|
+
dateAttribute: string;
|
|
1535
|
+
/** Group by attribute */
|
|
1536
|
+
groupByAttribute?: string;
|
|
1537
|
+
}
|
|
1538
|
+
/**
|
|
1539
|
+
* Configuration for gallery views (future)
|
|
1540
|
+
*/
|
|
1541
|
+
interface GalleryViewConfig {
|
|
1542
|
+
/** Image attribute to display */
|
|
1543
|
+
imageAttribute: string;
|
|
1544
|
+
/** Title attribute */
|
|
1545
|
+
titleAttribute?: string;
|
|
1546
|
+
/** Columns per row */
|
|
1547
|
+
columnsPerRow?: number;
|
|
1548
|
+
}
|
|
1549
|
+
/**
|
|
1550
|
+
* Union of all view configs
|
|
1551
|
+
*/
|
|
1552
|
+
type ViewConfig = DetailViewConfig | ListViewConfig | CalendarViewConfig | TimelineViewConfig | GalleryViewConfig;
|
|
1553
|
+
/**
|
|
1554
|
+
* Base view properties shared by all view types
|
|
1555
|
+
*/
|
|
1556
|
+
interface BaseViewDefinition {
|
|
1557
|
+
/** Unique identifier (UUID, assigned by database) */
|
|
1558
|
+
id?: string;
|
|
1559
|
+
/** Technical name (kebab-case) */
|
|
1560
|
+
name: string;
|
|
1561
|
+
/** Display label */
|
|
1562
|
+
label: string;
|
|
1563
|
+
/** Description */
|
|
1564
|
+
description?: string;
|
|
1565
|
+
/** Icon */
|
|
1566
|
+
icon?: IconName;
|
|
1567
|
+
/** Object this view belongs to (object name) */
|
|
1568
|
+
object: string;
|
|
1569
|
+
/** Default view for this object+type combination */
|
|
1570
|
+
default?: boolean;
|
|
1571
|
+
/** Extensible metadata */
|
|
1572
|
+
metadata?: Record<string, unknown>;
|
|
1573
|
+
/** Current schema version of this view definition */
|
|
1574
|
+
schema_version: number;
|
|
1575
|
+
}
|
|
1576
|
+
/**
|
|
1577
|
+
* Detail view definition
|
|
1578
|
+
*/
|
|
1579
|
+
interface DetailViewDefinition extends BaseViewDefinition {
|
|
1580
|
+
type: "detail";
|
|
1581
|
+
config: DetailViewConfig;
|
|
1582
|
+
}
|
|
1583
|
+
/**
|
|
1584
|
+
* List view definition
|
|
1585
|
+
*/
|
|
1586
|
+
interface ListViewDefinition extends BaseViewDefinition {
|
|
1587
|
+
type: "list";
|
|
1588
|
+
config: ListViewConfig;
|
|
1589
|
+
}
|
|
1590
|
+
/**
|
|
1591
|
+
* Calendar view definition (future)
|
|
1592
|
+
*/
|
|
1593
|
+
interface CalendarViewDefinition extends BaseViewDefinition {
|
|
1594
|
+
type: "calendar";
|
|
1595
|
+
config: CalendarViewConfig;
|
|
1596
|
+
}
|
|
1597
|
+
/**
|
|
1598
|
+
* Timeline view definition (future)
|
|
1599
|
+
*/
|
|
1600
|
+
interface TimelineViewDefinition extends BaseViewDefinition {
|
|
1601
|
+
type: "timeline";
|
|
1602
|
+
config: TimelineViewConfig;
|
|
1603
|
+
}
|
|
1604
|
+
/**
|
|
1605
|
+
* Gallery view definition (future)
|
|
1606
|
+
*/
|
|
1607
|
+
interface GalleryViewDefinition extends BaseViewDefinition {
|
|
1608
|
+
type: "gallery";
|
|
1609
|
+
config: GalleryViewConfig;
|
|
1610
|
+
}
|
|
1611
|
+
/**
|
|
1612
|
+
* Unified view definition - discriminated union by type
|
|
1613
|
+
*/
|
|
1614
|
+
type ViewDefinition = DetailViewDefinition | ListViewDefinition | CalendarViewDefinition | TimelineViewDefinition | GalleryViewDefinition;
|
|
1615
|
+
/**
|
|
1616
|
+
* Configuration overrides for user customizations
|
|
1617
|
+
* Only stores the delta from the source view
|
|
1618
|
+
*/
|
|
1619
|
+
interface ConfigOverrides {
|
|
1620
|
+
tabs?: ListViewTab[];
|
|
1621
|
+
hiddenTabIds?: string[];
|
|
1622
|
+
detailTabs?: Tab[];
|
|
1623
|
+
hiddenDetailTabIds?: string[];
|
|
1624
|
+
}
|
|
1625
|
+
/**
|
|
1626
|
+
* User customization overlay for a view
|
|
1627
|
+
* Stored per user, merged at runtime with the source view
|
|
1628
|
+
*/
|
|
1629
|
+
interface ViewOverlay {
|
|
1630
|
+
/** Unique identifier */
|
|
1631
|
+
id: string;
|
|
1632
|
+
/** View ID this overlay applies to (UUID or virtual ID) */
|
|
1633
|
+
viewId: string;
|
|
1634
|
+
/** User ID who owns this overlay */
|
|
1635
|
+
userId: string;
|
|
1636
|
+
/** Configuration overrides (delta only) */
|
|
1637
|
+
configOverrides: ConfigOverrides;
|
|
1638
|
+
/** User's default view for this object (stored in overlay) */
|
|
1639
|
+
isUserDefault?: boolean;
|
|
1640
|
+
/** Created timestamp */
|
|
1641
|
+
createdAt: Date;
|
|
1642
|
+
/** Updated timestamp */
|
|
1643
|
+
updatedAt: Date;
|
|
1644
|
+
}
|
|
1645
|
+
/**
|
|
1646
|
+
* Check if a view is a detail view
|
|
1647
|
+
*/
|
|
1648
|
+
declare function isDetailView(view: ViewDefinition): view is DetailViewDefinition;
|
|
1649
|
+
/**
|
|
1650
|
+
* Check if a view is a list view
|
|
1651
|
+
*/
|
|
1652
|
+
declare function isListView(view: ViewDefinition): view is ListViewDefinition;
|
|
1653
|
+
/**
|
|
1654
|
+
* Check if a view is a calendar view
|
|
1655
|
+
*/
|
|
1656
|
+
declare function isCalendarView(view: ViewDefinition): view is CalendarViewDefinition;
|
|
1657
|
+
/**
|
|
1658
|
+
* Check if a view is a timeline view
|
|
1659
|
+
*/
|
|
1660
|
+
declare function isTimelineView(view: ViewDefinition): view is TimelineViewDefinition;
|
|
1661
|
+
/**
|
|
1662
|
+
* Check if a view is a gallery view
|
|
1663
|
+
*/
|
|
1664
|
+
declare function isGalleryView(view: ViewDefinition): view is GalleryViewDefinition;
|
|
1665
|
+
/**
|
|
1666
|
+
* Check if a group is a field group (default type)
|
|
1667
|
+
*/
|
|
1668
|
+
declare function isFieldGroup(group: Group): group is FieldGroup;
|
|
1669
|
+
/**
|
|
1670
|
+
* Check if a group is a relation group
|
|
1671
|
+
*/
|
|
1672
|
+
declare function isRelationGroup(group: Group): group is RelationGroup;
|
|
1673
|
+
/**
|
|
1674
|
+
* Check if a tab is a form tab
|
|
1675
|
+
*/
|
|
1676
|
+
declare function isFormTab(tab: Tab): tab is FormTab;
|
|
1677
|
+
/**
|
|
1678
|
+
* Check if a tab is a table tab
|
|
1679
|
+
*/
|
|
1680
|
+
declare function isTableTab(tab: Tab): tab is TableTab;
|
|
1681
|
+
/**
|
|
1682
|
+
* Check if a table tab uses a direct relation source
|
|
1683
|
+
*/
|
|
1684
|
+
declare function isRelationSourceTab(tab: Tab): tab is TableTab & {
|
|
1685
|
+
source: RelationSource;
|
|
1686
|
+
};
|
|
1687
|
+
/**
|
|
1688
|
+
* Check if a table tab uses an inverse source
|
|
1689
|
+
*/
|
|
1690
|
+
declare function isInverseSourceTab(tab: Tab): tab is TableTab & {
|
|
1691
|
+
source: InverseSource;
|
|
1692
|
+
};
|
|
1693
|
+
/**
|
|
1694
|
+
* Check if a tab is a custom tab
|
|
1695
|
+
*/
|
|
1696
|
+
declare function isCustomTab(tab: Tab): tab is CustomTab;
|
|
1697
|
+
/**
|
|
1698
|
+
* Check if a tab is an activity tab
|
|
1699
|
+
*/
|
|
1700
|
+
declare function isActivityTab(tab: Tab): tab is ActivityTab;
|
|
1701
|
+
/**
|
|
1702
|
+
* Check if a tab is a richtext tab
|
|
1703
|
+
*/
|
|
1704
|
+
declare function isRichtextTab(tab: Tab): tab is RichtextTab;
|
|
1705
|
+
/**
|
|
1706
|
+
* Check if a tab is a flows tab
|
|
1707
|
+
*/
|
|
1708
|
+
declare function isFlowsTab(tab: Tab): tab is FlowsTab;
|
|
1709
|
+
/**
|
|
1710
|
+
* Check if a tab is a documents tab
|
|
1711
|
+
*/
|
|
1712
|
+
declare function isDocumentsTab(tab: Tab): tab is DocumentsTab;
|
|
1713
|
+
|
|
1714
|
+
type TransformSource = "system" | "runtime" | "rollback" | "seed";
|
|
1715
|
+
type BuiltInTransform = "toString" | "toNumber" | "toDate" | "toBoolean" | "toISOString";
|
|
1716
|
+
type SchemaOperation = {
|
|
1717
|
+
type: "add_attribute";
|
|
1718
|
+
attribute: Attribute;
|
|
1719
|
+
} | {
|
|
1720
|
+
type: "remove_attribute";
|
|
1721
|
+
name: string;
|
|
1722
|
+
backup_config: Attribute;
|
|
1723
|
+
} | {
|
|
1724
|
+
type: "rename_attribute";
|
|
1725
|
+
from: string;
|
|
1726
|
+
to: string;
|
|
1727
|
+
} | {
|
|
1728
|
+
type: "change_type";
|
|
1729
|
+
name: string;
|
|
1730
|
+
from: AttributeType;
|
|
1731
|
+
to: AttributeType;
|
|
1732
|
+
transform?: BuiltInTransform;
|
|
1733
|
+
} | {
|
|
1734
|
+
type: "update_config";
|
|
1735
|
+
name: string;
|
|
1736
|
+
from: Partial<Record<string, unknown>>;
|
|
1737
|
+
to: Partial<Record<string, unknown>>;
|
|
1738
|
+
} | {
|
|
1739
|
+
type: "remove_object";
|
|
1740
|
+
backup: Record<string, unknown>;
|
|
1741
|
+
} | {
|
|
1742
|
+
type: "rename_object";
|
|
1743
|
+
from: string;
|
|
1744
|
+
to: string;
|
|
1745
|
+
};
|
|
1746
|
+
type ViewOperation = {
|
|
1747
|
+
type: "update_config";
|
|
1748
|
+
from: ViewConfig;
|
|
1749
|
+
to: ViewConfig;
|
|
1750
|
+
} | {
|
|
1751
|
+
type: "update_tabs";
|
|
1752
|
+
from: (ListViewTab | Tab)[];
|
|
1753
|
+
to: (ListViewTab | Tab)[];
|
|
1754
|
+
} | {
|
|
1755
|
+
type: "force_reset";
|
|
1756
|
+
config: ViewConfig;
|
|
1757
|
+
} | {
|
|
1758
|
+
type: "remove_view";
|
|
1759
|
+
backup: Record<string, unknown>;
|
|
1760
|
+
};
|
|
1761
|
+
interface MigrationDefinition {
|
|
1762
|
+
version: number;
|
|
1763
|
+
operations: SchemaOperation[];
|
|
1764
|
+
reverse_operations: SchemaOperation[];
|
|
1765
|
+
}
|
|
1766
|
+
interface SchemaTransform {
|
|
1767
|
+
id: string;
|
|
1768
|
+
tenantId: string;
|
|
1769
|
+
objectId: string;
|
|
1770
|
+
fromVersion: number;
|
|
1771
|
+
toVersion: number;
|
|
1772
|
+
operations: SchemaOperation[];
|
|
1773
|
+
reverseOperations: SchemaOperation[];
|
|
1774
|
+
source: TransformSource;
|
|
1775
|
+
appliedAt: Date;
|
|
1776
|
+
fullyMigrated: boolean;
|
|
1777
|
+
}
|
|
1778
|
+
interface ViewTransform {
|
|
1779
|
+
id: string;
|
|
1780
|
+
tenantId: string;
|
|
1781
|
+
viewId: string;
|
|
1782
|
+
fromVersion: number;
|
|
1783
|
+
toVersion: number;
|
|
1784
|
+
operations: ViewOperation[];
|
|
1785
|
+
reverseOperations: ViewOperation[];
|
|
1786
|
+
source: TransformSource;
|
|
1787
|
+
appliedAt: Date;
|
|
1788
|
+
}
|
|
1789
|
+
interface MigrationError {
|
|
1790
|
+
id: string;
|
|
1791
|
+
tenantId: string;
|
|
1792
|
+
transformId: string;
|
|
1793
|
+
recordId: string;
|
|
1794
|
+
attributeName: string;
|
|
1795
|
+
originalValue: unknown;
|
|
1796
|
+
error: string;
|
|
1797
|
+
resolvedAt: Date | null;
|
|
1798
|
+
resolvedValue: unknown | null;
|
|
1799
|
+
}
|
|
1800
|
+
interface RetentionPolicy {
|
|
1801
|
+
attributeData: number;
|
|
1802
|
+
deletedObjects: number;
|
|
1803
|
+
transforms: number;
|
|
1804
|
+
migrationErrors: number;
|
|
1805
|
+
}
|
|
1806
|
+
declare const DEFAULT_RETENTION_POLICY: RetentionPolicy;
|
|
1807
|
+
interface MigrationPreview {
|
|
1808
|
+
affectedRecords: number;
|
|
1809
|
+
potentialErrors: number;
|
|
1810
|
+
reversible: boolean;
|
|
1811
|
+
estimatedDuration: string;
|
|
1812
|
+
sampleErrors: Array<{
|
|
1813
|
+
recordId: string;
|
|
1814
|
+
attribute: string;
|
|
1815
|
+
value: unknown;
|
|
1816
|
+
reason: string;
|
|
1817
|
+
}>;
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
/**
|
|
1821
|
+
* Timestamps for tracking creation and updates
|
|
1822
|
+
*/
|
|
1823
|
+
interface Timestamps {
|
|
1824
|
+
createdAt: Date;
|
|
1825
|
+
updatedAt: Date;
|
|
1826
|
+
}
|
|
1827
|
+
/**
|
|
1828
|
+
* Object definition - Represents a database table/entity
|
|
1829
|
+
*/
|
|
1830
|
+
interface ObjectDefinition {
|
|
1831
|
+
id?: Uuid;
|
|
1832
|
+
name: string;
|
|
1833
|
+
label: string;
|
|
1834
|
+
pluralLabel?: string;
|
|
1835
|
+
description?: string;
|
|
1836
|
+
icon?: IconName;
|
|
1837
|
+
/**
|
|
1838
|
+
* Template expression used to compute the object's display label.
|
|
1839
|
+
* Supports variable interpolation and pipes for formatting.
|
|
1840
|
+
*
|
|
1841
|
+
* @example
|
|
1842
|
+
* ```typescript
|
|
1843
|
+
* // Simple attribute reference
|
|
1844
|
+
* labelExpression: "{{ name }}"
|
|
1845
|
+
*
|
|
1846
|
+
* // Multiple attributes
|
|
1847
|
+
* labelExpression: "{{ firstName }} {{ lastName }}"
|
|
1848
|
+
*
|
|
1849
|
+
* // With pipes for formatting
|
|
1850
|
+
* labelExpression: "{{ code | UPPER }} - {{ name | capitalize }}"
|
|
1851
|
+
* ```
|
|
1852
|
+
*
|
|
1853
|
+
* Available pipes: UPPER, LOWER, capitalize, trim
|
|
1854
|
+
*/
|
|
1855
|
+
labelExpression: string;
|
|
1856
|
+
attributes: Attribute[];
|
|
1857
|
+
system?: boolean;
|
|
1858
|
+
metadata?: Record<string, unknown>;
|
|
1859
|
+
/** Current schema version (incremented with each migration) */
|
|
1860
|
+
schema_version: number;
|
|
1861
|
+
/** Ordered list of migrations applied to this object's schema */
|
|
1862
|
+
migrations: MigrationDefinition[];
|
|
1863
|
+
}
|
|
1864
|
+
/**
|
|
1865
|
+
* Links an attribute to an object
|
|
1866
|
+
*/
|
|
1867
|
+
interface ObjectAttribute {
|
|
1868
|
+
objectId: Uuid;
|
|
1869
|
+
attributeId: Uuid;
|
|
1870
|
+
order?: number;
|
|
1871
|
+
required?: boolean;
|
|
1872
|
+
}
|
|
1873
|
+
/**
|
|
1874
|
+
* Completion status of a record based on data completeness.
|
|
1875
|
+
*
|
|
1876
|
+
* - `draft`: Record is missing one or more required attribute values.
|
|
1877
|
+
* Can be saved but is considered incomplete.
|
|
1878
|
+
* - `complete`: All required attribute values are present and valid.
|
|
1879
|
+
* Record is ready for use.
|
|
1880
|
+
*
|
|
1881
|
+
* This is different from workflow status (e.g., "pending", "approved").
|
|
1882
|
+
* Completion status is computed dynamically based on the object schema.
|
|
1883
|
+
*/
|
|
1884
|
+
type CompletionStatus = "draft" | "complete";
|
|
1885
|
+
/**
|
|
1886
|
+
* Record - Instance of an Object (a row in the database)
|
|
1887
|
+
*/
|
|
1888
|
+
interface ObjectRecord extends Timestamps {
|
|
1889
|
+
id: Uuid;
|
|
1890
|
+
objectId: Uuid;
|
|
1891
|
+
/**
|
|
1892
|
+
* Display label computed from the object's labelExpression.
|
|
1893
|
+
* Computed dynamically based on record values.
|
|
1894
|
+
*
|
|
1895
|
+
* @example "John Doe" (from "{{ firstName }} {{ lastName }}")
|
|
1896
|
+
*/
|
|
1897
|
+
label: string;
|
|
1898
|
+
/**
|
|
1899
|
+
* Completion status of the record.
|
|
1900
|
+
* - `draft`: Missing required values, record is incomplete
|
|
1901
|
+
* - `complete`: All required values present and valid
|
|
1902
|
+
*
|
|
1903
|
+
* Computed dynamically based on the object's schema.
|
|
1904
|
+
*/
|
|
1905
|
+
completionStatus: CompletionStatus;
|
|
1906
|
+
values: Record<string, unknown>;
|
|
1907
|
+
/**
|
|
1908
|
+
* Custom metadata for the record.
|
|
1909
|
+
* Use this for UI/UX state, feature flags, or any application-specific data.
|
|
1910
|
+
* Unlike system fields (id, createdAt, updatedAt), metadata can be updated.
|
|
1911
|
+
*/
|
|
1912
|
+
metadata?: Record<string, unknown>;
|
|
1913
|
+
/**
|
|
1914
|
+
* Soft delete timestamp.
|
|
1915
|
+
* If set, the record is considered deleted but can be restored.
|
|
1916
|
+
* Queries exclude soft-deleted records by default.
|
|
1917
|
+
*/
|
|
1918
|
+
deletedAt?: Date | null;
|
|
1919
|
+
/**
|
|
1920
|
+
* User ID who created this record.
|
|
1921
|
+
* Automatically set by RecordService when userId is configured.
|
|
1922
|
+
* Optional for backward compatibility with existing records.
|
|
1923
|
+
*/
|
|
1924
|
+
createdBy?: string;
|
|
1925
|
+
/**
|
|
1926
|
+
* User ID who last updated this record.
|
|
1927
|
+
* Automatically set by RecordService when userId is configured.
|
|
1928
|
+
* Optional for backward compatibility with existing records.
|
|
1929
|
+
*/
|
|
1930
|
+
lastUpdatedBy?: string;
|
|
1931
|
+
/** Schema version at the time this record was last migrated */
|
|
1932
|
+
schemaVersion: number;
|
|
1933
|
+
/**
|
|
1934
|
+
* Values archived during attribute removal or type changes.
|
|
1935
|
+
* Retained according to the retention policy before permanent deletion.
|
|
1936
|
+
*/
|
|
1937
|
+
archivedValues?: Record<string, unknown>;
|
|
1938
|
+
}
|
|
1939
|
+
/**
|
|
1940
|
+
* System-managed field names on ObjectRecord.
|
|
1941
|
+
* These are stored as SQL columns (not in JSONB `values`).
|
|
1942
|
+
*
|
|
1943
|
+
* Use this in adapters to determine if a filter/sort attribute is a table column
|
|
1944
|
+
* vs. a JSONB value field.
|
|
1945
|
+
*
|
|
1946
|
+
* @example
|
|
1947
|
+
* ```typescript
|
|
1948
|
+
* if (SYSTEM_FIELD_NAMES.includes(filter.attribute)) {
|
|
1949
|
+
* // Filter on SQL column (e.g., WHERE created_at > ...)
|
|
1950
|
+
* } else {
|
|
1951
|
+
* // Filter on JSONB field (e.g., WHERE values->>'name' = ...)
|
|
1952
|
+
* }
|
|
1953
|
+
* ```
|
|
1954
|
+
*/
|
|
1955
|
+
declare const SYSTEM_FIELD_NAMES: readonly ["id", "createdAt", "updatedAt", "createdBy", "lastUpdatedBy"];
|
|
1956
|
+
/**
|
|
1957
|
+
* Type for system field names
|
|
1958
|
+
*/
|
|
1959
|
+
type SystemFieldName = (typeof SYSTEM_FIELD_NAMES)[number];
|
|
1960
|
+
/**
|
|
1961
|
+
* Reserved attribute names that cannot be used for custom attributes.
|
|
1962
|
+
* These names conflict with ObjectRecord properties.
|
|
1963
|
+
*
|
|
1964
|
+
* Includes:
|
|
1965
|
+
* - System fields (id, createdAt, updatedAt, createdBy, lastUpdatedBy)
|
|
1966
|
+
* - Other ObjectRecord properties (objectId, label, completionStatus, values, metadata, deletedAt)
|
|
1967
|
+
*
|
|
1968
|
+
* @example
|
|
1969
|
+
* ```typescript
|
|
1970
|
+
* if (RESERVED_ATTRIBUTE_NAMES.includes(attributeName)) {
|
|
1971
|
+
* throw new Error(`"${attributeName}" is a reserved name`);
|
|
1972
|
+
* }
|
|
1973
|
+
* ```
|
|
1974
|
+
*/
|
|
1975
|
+
declare const RESERVED_ATTRIBUTE_NAMES: readonly ["id", "createdAt", "updatedAt", "createdBy", "lastUpdatedBy", "objectId", "label", "completionStatus", "values", "metadata", "deletedAt", "schemaVersion", "archivedValues"];
|
|
1976
|
+
/**
|
|
1977
|
+
* Type for reserved attribute names
|
|
1978
|
+
*/
|
|
1979
|
+
type ReservedAttributeName = (typeof RESERVED_ATTRIBUTE_NAMES)[number];
|
|
1980
|
+
|
|
1981
|
+
/**
|
|
1982
|
+
* Create a Zod schema for any attribute type.
|
|
1983
|
+
* Returns a strict validator that does NOT handle optional fields.
|
|
1984
|
+
* Use createFormAttributeValidator for form validation with optional support.
|
|
1985
|
+
*
|
|
1986
|
+
* @param attr - The attribute to create a validator for
|
|
1987
|
+
* @param messages - Custom validation messages for i18n support
|
|
1988
|
+
*/
|
|
1989
|
+
declare function createAttributeValidator(attr: Attribute, messages?: ValidationMessages): z.ZodTypeAny;
|
|
1990
|
+
/**
|
|
1991
|
+
* Create a Zod schema for form validation.
|
|
1992
|
+
* - Normalizes empty values (empty strings, empty objects) to null for optional fields
|
|
1993
|
+
* - Accepts custom messages for i18n support
|
|
1994
|
+
*
|
|
1995
|
+
* Use this in UI forms where optional fields may have null/undefined values.
|
|
1996
|
+
*
|
|
1997
|
+
* @param attr - The attribute to create a validator for
|
|
1998
|
+
* @param messages - Custom validation messages for i18n support
|
|
1999
|
+
*/
|
|
2000
|
+
declare function createFormAttributeValidator(attr: Attribute, messages?: ValidationMessages): z.ZodTypeAny;
|
|
2001
|
+
|
|
2002
|
+
/**
|
|
2003
|
+
* Create a Zod schema for an entire object
|
|
2004
|
+
*
|
|
2005
|
+
* Uses passthrough mode to allow computed fields (formula, rollup) that may be
|
|
2006
|
+
* present in record data but are not part of the mutable schema.
|
|
2007
|
+
*/
|
|
2008
|
+
declare function createObjectValidator(objectDef: ObjectDefinition): z.ZodType<Record<string, unknown>>;
|
|
2009
|
+
/**
|
|
2010
|
+
* Create a Zod schema for draft validation.
|
|
2011
|
+
* All attributes become optional, but provided values are still validated.
|
|
2012
|
+
*
|
|
2013
|
+
* Uses passthrough mode to allow computed fields (formula, rollup) that may be
|
|
2014
|
+
* present in record data but are not part of the mutable schema.
|
|
2015
|
+
*/
|
|
2016
|
+
declare function createDraftValidator(objectDef: ObjectDefinition): z.ZodType<Record<string, unknown>>;
|
|
2017
|
+
|
|
2018
|
+
/**
|
|
2019
|
+
* Validate data against an attribute schema
|
|
2020
|
+
*/
|
|
2021
|
+
declare function validateAttribute(attr: Attribute, value: unknown): ValidationResult;
|
|
2022
|
+
/**
|
|
2023
|
+
* Validate data against an object schema
|
|
2024
|
+
*/
|
|
2025
|
+
declare function validateObject(objectDef: ObjectDefinition, data: Record<string, unknown>): ValidationResult;
|
|
2026
|
+
/**
|
|
2027
|
+
* Validate and throw if invalid
|
|
2028
|
+
*/
|
|
2029
|
+
declare function validateObjectOrThrow(objectDef: ObjectDefinition, data: Record<string, unknown>): Record<string, unknown>;
|
|
2030
|
+
/**
|
|
2031
|
+
* Validate data in draft mode.
|
|
2032
|
+
* - All attributes are treated as optional (no required validation)
|
|
2033
|
+
* - Provided values are still validated for format/type correctness
|
|
2034
|
+
*/
|
|
2035
|
+
declare function validateDraft(objectDef: ObjectDefinition, data: Record<string, unknown>): ValidationResult;
|
|
2036
|
+
/**
|
|
2037
|
+
* Validate draft data and throw if format validation fails.
|
|
2038
|
+
*/
|
|
2039
|
+
declare function validateDraftOrThrow(objectDef: ObjectDefinition, data: Record<string, unknown>): Record<string, unknown>;
|
|
2040
|
+
/**
|
|
2041
|
+
* Get the list of required attributes that are missing values.
|
|
2042
|
+
*/
|
|
2043
|
+
declare function getMissingRequiredAttributes(objectDef: ObjectDefinition, data: Record<string, unknown>): Attribute[];
|
|
2044
|
+
/**
|
|
2045
|
+
* Check if a record is complete (all required attributes have valid values).
|
|
2046
|
+
*/
|
|
2047
|
+
declare function isRecordComplete(objectDef: ObjectDefinition, data: Record<string, unknown>): boolean;
|
|
2048
|
+
/**
|
|
2049
|
+
* Compute the completion status of a record based on its data.
|
|
2050
|
+
*/
|
|
2051
|
+
declare function computeRecordStatus(objectDef: ObjectDefinition, data: Record<string, unknown>): CompletionStatus;
|
|
2052
|
+
|
|
2053
|
+
export { type ListViewConfig as $, type WorkflowExecutionContext as A, type WorkflowTransition as B, type ConfigOverrides as C, type CompletionStatus as D, type ObjectDefinition as E, type FilterState as F, type DetailViewConfig as G, type DetailViewDefinition as H, type InstanceStatus as I, type DetailViewLayout as J, type SidePanelConfig as K, type Field as L, type MigrationDefinition as M, type AttributeGroupField as N, type ObjectRecord as O, type PendingAction as P, type FieldGroup as Q, type RelationFieldConfig as R, type SortRule as S, type Timestamps as T, type RelationGroup as U, type ViewType as V, type WorkflowNode as W, type Group as X, type TableTab as Y, type CreateMode as Z, type Tab as _, createAttributeValidator as a, type RelationQualifierPatch as a$, type ListViewDefinition as a0, type SlotMode as a1, type FlowFieldsRow as a2, type ConditionGroup as a3, type ConditionRule as a4, type ViewDefinition as a5, type ListViewTab as a6, type ActivityTab as a7, type AdvancedFilterState as a8, type BufferedRecord as a9, type FlowRowType as aA, type FlowSlot as aB, type FlowStatus as aC, type FlowsTab as aD, type FormDensity as aE, type FormFieldRef as aF, type FormTab as aG, type GalleryViewConfig as aH, type GalleryViewDefinition as aI, type GeneratedDocument as aJ, type InverseSource as aK, type ListViewLayout as aL, type MigrationError as aM, type MigrationPreview as aN, type MultiselectFilterOperator as aO, NO_VALUE_OPERATORS as aP, type NoValueOperator as aQ, type NodePosition as aR, type NumberFilterOperator as aS, OPERATORS_BY_TYPE as aT, type ObjectAttribute as aU, type PhoneFilterValue as aV, type QueryState as aW, RESERVED_ATTRIBUTE_NAMES as aX, type RecordPatch as aY, type RelationBuffer as aZ, type RelationFilterOperator as a_, type BuiltInTransform as aa, type CalendarViewConfig as ab, type CalendarViewDefinition as ac, type CanvasViewport as ad, type CheckboxFilterOperator as ae, type ConditionNode as af, type ConditionOperator as ag, type CurrencyFilterValue as ah, type CustomTab as ai, DEFAULT_RETENTION_POLICY as aj, DEFAULT_THEME as ak, type DateFilterOperator as al, type DisplayRecord as am, type DocumentsTab as an, type EndNode as ao, type ExtendedFilterRule as ap, type FilterCombinator as aq, type FilterGroup as ar, type FilterOperator as as, type FilterRule as at, type FilterValue as au, type FlowDefinition as av, type FlowPage as aw, type FlowRelation as ax, type FlowRow as ay, type FlowRowField as az, createDraftValidator as b, isRichtextTab as b$, type RelationSource as b0, type RelativeDateValue as b1, type ReservedAttributeName as b2, type RetentionPolicy as b3, type RichtextTab as b4, SYSTEM_FIELD_NAMES as b5, type SchemaOperation as b6, type SchemaTransform as b7, type SelectFilterOperator as b8, type SortDirection as b9, isAdvancedFormNode as bA, isCalendarView as bB, isConditionGroup as bC, isConditionNode as bD, isConditionRule as bE, isCustomTab as bF, isDetailView as bG, isDocumentsTab as bH, isEmpty as bI, isEndNode as bJ, isFieldGroup as bK, isFlowDefinition as bL, isFlowFieldsRow as bM, isFlowPublished as bN, isFlowRelationListRow as bO, isFlowsTab as bP, isFormNode as bQ, isFormTab as bR, isGalleryView as bS, isInstanceTerminal as bT, isInstanceWaiting as bU, isInverseSourceTab as bV, isLayoutRow as bW, isListView as bX, isNoValueOperator as bY, isRelationGroup as bZ, isRelationSourceTab as b_, type StartNode as ba, type SystemFieldName as bb, type TabType as bc, type TableSource as bd, type TextFilterOperator as be, type ThemeColors as bf, type ThemeLogo as bg, type ThemeTypography as bh, type TimelineViewConfig as bi, type TimelineViewDefinition as bj, type TransformSource as bk, type ViewOperation as bl, type ViewOverlay as bm, type ViewTransform as bn, type WorkflowError as bo, type WorkflowInstance as bp, and as bq, canResumeInstance as br, createEmptyContext as bs, createStartTransition as bt, eq as bu, generateCssVariables as bv, getContextValue as bw, getRollupFilterOperators as bx, inValues as by, isActivityTab as bz, computeRecordStatus as c, isSimpleFormNode as c0, isStartNode as c1, isSystemFlow as c2, isSystemWorkflow as c3, isTableTab as c4, isTimelineView as c5, isWorkflowDefinition as c6, isWorkflowPublished as c7, mergeWithDefaults as c8, neq as c9, or as ca, setContextValue as cb, createFormAttributeValidator as d, createObjectValidator as e, validateDraft as f, getMissingRequiredAttributes as g, validateDraftOrThrow as h, isRecordComplete as i, validateObject as j, validateObjectOrThrow as k, type FormNode as l, type WorkflowNodeType as m, type FlowHeadingRow as n, type FlowSeparatorRow as o, type FlowTextRow as p, type FlowRelationListRow as q, type WorkflowSlot as r, type WorkflowTheme as s, type RelationBufferMap as t, type ViewConfig as u, validateAttribute as v, type WorkflowStatus as w, type WorkflowLayout as x, type WorkflowConfig as y, type WorkflowDefinition as z };
|