@stndrds/schema 1.0.0-alpha.91 → 1.0.0-alpha.93
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/index.d.mts +314 -1996
- package/dist/index.d.ts +314 -1996
- package/dist/index.js +286 -33
- package/dist/index.mjs +263 -10
- package/dist/validation/validators.d.mts +1 -1
- package/dist/validation/validators.d.ts +1 -1
- package/dist/validators-BXWI__2n.d.ts +3543 -0
- package/dist/validators-CwhyfvP7.d.mts +3543 -0
- package/package.json +2 -2
- package/dist/validators-BFgj3O3w.d.mts +0 -1576
- package/dist/validators-C7i6EpQK.d.ts +0 -1576
|
@@ -0,0 +1,3543 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { IconName, CountryIso3, CurrencyCode, ColorId, MimeType } from '@stndrds/constants';
|
|
3
|
+
import { Uuid } from './utils.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Feature flag levels (resolution priority: user > tenant > global).
|
|
7
|
+
*
|
|
8
|
+
* - `global`: Applies to all tenants and users
|
|
9
|
+
* - `tenant`: Applies to a specific tenant
|
|
10
|
+
* - `user`: Applies to a specific user within a tenant
|
|
11
|
+
*/
|
|
12
|
+
type FlagLevel = "global" | "tenant" | "user";
|
|
13
|
+
/**
|
|
14
|
+
* Flag value types supported by the system.
|
|
15
|
+
*/
|
|
16
|
+
type FlagValueType = "boolean" | "string" | "number" | "json";
|
|
17
|
+
/**
|
|
18
|
+
* Definition of a feature flag.
|
|
19
|
+
* Created using the flag builders (booleanFlag, stringFlag, etc.)
|
|
20
|
+
*/
|
|
21
|
+
interface FeatureFlagDefinition<T = unknown> {
|
|
22
|
+
/** Unique identifier for the flag (kebab-case) */
|
|
23
|
+
name: string;
|
|
24
|
+
/** Human-readable label */
|
|
25
|
+
label: string;
|
|
26
|
+
/** Optional description */
|
|
27
|
+
description?: string;
|
|
28
|
+
/** Type of the flag value */
|
|
29
|
+
valueType: FlagValueType;
|
|
30
|
+
/** Default value when no override exists */
|
|
31
|
+
defaultValue: T;
|
|
32
|
+
/** Levels at which this flag can be overridden */
|
|
33
|
+
allowedLevels: FlagLevel[];
|
|
34
|
+
/** Grouping category for UI */
|
|
35
|
+
category?: string;
|
|
36
|
+
/** System flag - cannot be modified via API */
|
|
37
|
+
system?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Stored override for a feature flag.
|
|
41
|
+
* Represents a row in the feature_flag_overrides table.
|
|
42
|
+
*/
|
|
43
|
+
interface FlagOverride<T = unknown> {
|
|
44
|
+
/** Name of the flag being overridden */
|
|
45
|
+
flagName: string;
|
|
46
|
+
/** Level of the override */
|
|
47
|
+
level: FlagLevel;
|
|
48
|
+
/** Target ID (tenantId for tenant-level, userId for user-level) */
|
|
49
|
+
targetId?: string;
|
|
50
|
+
/** Override value */
|
|
51
|
+
value: T;
|
|
52
|
+
/** Optional expiration date */
|
|
53
|
+
expiresAt?: Date;
|
|
54
|
+
/** Who created this override */
|
|
55
|
+
createdBy?: string;
|
|
56
|
+
/** When the override was created */
|
|
57
|
+
createdAt: Date;
|
|
58
|
+
/** When the override was last updated */
|
|
59
|
+
updatedAt: Date;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Resolved flag value with source information.
|
|
63
|
+
* Result of flag resolution including where the value came from.
|
|
64
|
+
*/
|
|
65
|
+
interface ResolvedFlag<T = unknown> {
|
|
66
|
+
/** Flag name */
|
|
67
|
+
name: string;
|
|
68
|
+
/** Resolved value */
|
|
69
|
+
value: T;
|
|
70
|
+
/** Where the value came from */
|
|
71
|
+
source: FlagLevel | "default";
|
|
72
|
+
/** ID of the source (tenantId or userId) if not default */
|
|
73
|
+
sourceId?: string;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Feature gate configuration for conditional attribute visibility.
|
|
77
|
+
* Used with the `.featureGate()` builder method.
|
|
78
|
+
*/
|
|
79
|
+
interface FeatureGate {
|
|
80
|
+
/** Name of the flag to check */
|
|
81
|
+
flag: string;
|
|
82
|
+
/**
|
|
83
|
+
* Expected value for the gate to pass.
|
|
84
|
+
* For boolean flags, defaults to `true`.
|
|
85
|
+
* For other types, compares with strict equality.
|
|
86
|
+
*/
|
|
87
|
+
expectedValue?: unknown;
|
|
88
|
+
/**
|
|
89
|
+
* Behavior when the gate fails.
|
|
90
|
+
* - `hide`: Attribute is completely hidden (default)
|
|
91
|
+
* - `show`: Attribute is shown regardless (no gating)
|
|
92
|
+
* - `disable`: Attribute is visible but read-only
|
|
93
|
+
*/
|
|
94
|
+
fallback?: "hide" | "show" | "disable";
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Repository interface for feature flag overrides storage.
|
|
98
|
+
* Added to DatabaseAdapter as an optional repository.
|
|
99
|
+
*
|
|
100
|
+
* If not provided, only static defaults from module config are used.
|
|
101
|
+
*/
|
|
102
|
+
interface FeatureFlagsRepository {
|
|
103
|
+
/**
|
|
104
|
+
* Get all overrides matching the criteria.
|
|
105
|
+
* Returns overrides from the database (global, tenant, or user level).
|
|
106
|
+
*/
|
|
107
|
+
getOverrides(options: {
|
|
108
|
+
/** Filter by level */
|
|
109
|
+
level?: FlagLevel;
|
|
110
|
+
/** Filter by target ID (tenantId or userId) */
|
|
111
|
+
targetId?: string;
|
|
112
|
+
/** Filter by flag names (for efficient single/batch lookups) */
|
|
113
|
+
flagNames?: string[];
|
|
114
|
+
}): Promise<FlagOverride[]>;
|
|
115
|
+
/**
|
|
116
|
+
* Create or update an override.
|
|
117
|
+
* Uses upsert semantics based on (flagName, level, targetId).
|
|
118
|
+
*/
|
|
119
|
+
setOverride(override: Omit<FlagOverride, "createdAt" | "updatedAt">): Promise<FlagOverride>;
|
|
120
|
+
/**
|
|
121
|
+
* Delete an override.
|
|
122
|
+
*/
|
|
123
|
+
deleteOverride(flagName: string, level: FlagLevel, targetId?: string): Promise<void>;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Static flag default value for module configuration.
|
|
127
|
+
*/
|
|
128
|
+
interface StaticFlagDefault {
|
|
129
|
+
/** Flag name */
|
|
130
|
+
name: string;
|
|
131
|
+
/** Default value */
|
|
132
|
+
value: unknown;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Feature flags configuration for SchemaModule.
|
|
136
|
+
*/
|
|
137
|
+
interface FeatureFlagsConfig {
|
|
138
|
+
/**
|
|
139
|
+
* Static default values for flags.
|
|
140
|
+
* These are always applied and used when no database override exists.
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```typescript
|
|
144
|
+
* featureFlags: {
|
|
145
|
+
* defaults: [
|
|
146
|
+
* { name: "architect-mode", value: false },
|
|
147
|
+
* { name: "ai-chat", value: false },
|
|
148
|
+
* { name: "tier", value: "free" },
|
|
149
|
+
* ],
|
|
150
|
+
* }
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
defaults?: StaticFlagDefault[];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Allowed attribute types in .qualifyWith()
|
|
158
|
+
*
|
|
159
|
+
* IMPORTANT: Complex types (formula, rollup, relation, file, user, document, richtext)
|
|
160
|
+
* are NOT supported to avoid duplicating backend behavior.
|
|
161
|
+
*/
|
|
162
|
+
type PropertyType = "text" | "textarea" | "number" | "checkbox" | "date" | "phone" | "currency" | "status" | "select" | "multiselect" | "rating" | "location";
|
|
163
|
+
/**
|
|
164
|
+
* Forbidden property types that would require complex backend duplication
|
|
165
|
+
*/
|
|
166
|
+
declare const FORBIDDEN_PROPERTY_TYPES: readonly ["formula", "rollup", "relation", "file", "user", "document", "richtext"];
|
|
167
|
+
type ForbiddenPropertyType = (typeof FORBIDDEN_PROPERTY_TYPES)[number];
|
|
168
|
+
/**
|
|
169
|
+
* Union of attribute types allowed as qualified relation properties.
|
|
170
|
+
*
|
|
171
|
+
* These are the same Attribute types used for object attributes,
|
|
172
|
+
* restricted to simple types that don't require complex backend duplication.
|
|
173
|
+
*/
|
|
174
|
+
type PropertyAttribute = TextAttribute | TextAreaAttribute | NumberAttribute | CheckboxAttribute | DateAttribute | PhoneAttribute | CurrencyAttribute | StatusAttribute | SelectAttribute | MultiselectAttribute | RatingAttribute | LocationAttribute;
|
|
175
|
+
/**
|
|
176
|
+
* Schema defining properties for a qualified relation.
|
|
177
|
+
*
|
|
178
|
+
* Uses the same Attribute types as object attributes, enabling DRY builders:
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* ```typescript
|
|
182
|
+
* relation({ name: "companies", label: "Companies" })
|
|
183
|
+
* .to("companies").many()
|
|
184
|
+
* .qualifyWith(
|
|
185
|
+
* select({ name: "role", label: "Role" }).options([...]).required(),
|
|
186
|
+
* number({ name: "shares", label: "Shares" }).min(0),
|
|
187
|
+
* )
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
interface PropertySchema {
|
|
191
|
+
definitions: PropertyAttribute[];
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Property attribute types that have an `options` array.
|
|
195
|
+
*/
|
|
196
|
+
type OptionPropertyAttribute = SelectAttribute | StatusAttribute | MultiselectAttribute;
|
|
197
|
+
/**
|
|
198
|
+
* Type guard to check if a property attribute has options.
|
|
199
|
+
*
|
|
200
|
+
* @param attr - The property attribute to check
|
|
201
|
+
* @returns true if the attribute is a select, status, or multiselect type with options
|
|
202
|
+
*
|
|
203
|
+
* @example
|
|
204
|
+
* ```typescript
|
|
205
|
+
* for (const def of definitions) {
|
|
206
|
+
* if (hasOptions(def)) {
|
|
207
|
+
* // TypeScript knows def.options exists and is Option[]
|
|
208
|
+
* for (const option of def.options) {
|
|
209
|
+
* console.log(option.value);
|
|
210
|
+
* }
|
|
211
|
+
* }
|
|
212
|
+
* }
|
|
213
|
+
* ```
|
|
214
|
+
*/
|
|
215
|
+
declare function hasOptions(attr: PropertyAttribute): attr is OptionPropertyAttribute;
|
|
216
|
+
|
|
217
|
+
type AttributeType = "text" | "textarea" | "richtext" | "number" | "checkbox" | "date" | "phone" | "currency" | "status" | "location" | "select" | "multiselect" | "file" | "user" | "relation" | "rating" | "formula" | "rollup" | "document";
|
|
218
|
+
/**
|
|
219
|
+
* Status group categorization
|
|
220
|
+
*/
|
|
221
|
+
type StatusGroup = "idle" | "in_progress" | "finished";
|
|
222
|
+
/**
|
|
223
|
+
* Unified option type for select-like fields
|
|
224
|
+
*/
|
|
225
|
+
interface Option {
|
|
226
|
+
id: string;
|
|
227
|
+
label: string;
|
|
228
|
+
value: string;
|
|
229
|
+
color?: ColorId;
|
|
230
|
+
icon?: IconName;
|
|
231
|
+
description?: string;
|
|
232
|
+
group?: StatusGroup;
|
|
233
|
+
/** Value of the inverse option for bilateral relations (e.g. "parent" → "child") */
|
|
234
|
+
inverse?: string;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Attribute grouping for UI organization
|
|
238
|
+
*/
|
|
239
|
+
interface AttributeGroup {
|
|
240
|
+
id: string;
|
|
241
|
+
label: string;
|
|
242
|
+
description?: string;
|
|
243
|
+
attributeIds: string[];
|
|
244
|
+
collapsible?: boolean;
|
|
245
|
+
collapsed?: boolean;
|
|
246
|
+
order?: number;
|
|
247
|
+
}
|
|
248
|
+
interface BaseAttribute<DefaultValueType = unknown> {
|
|
249
|
+
id: Uuid;
|
|
250
|
+
name: string;
|
|
251
|
+
label: string;
|
|
252
|
+
type: AttributeType;
|
|
253
|
+
required: boolean;
|
|
254
|
+
disabled?: boolean;
|
|
255
|
+
placeholder?: string;
|
|
256
|
+
description?: string;
|
|
257
|
+
defaultValue?: DefaultValueType;
|
|
258
|
+
icon?: IconName;
|
|
259
|
+
order?: number;
|
|
260
|
+
hidden?: boolean;
|
|
261
|
+
archived?: boolean;
|
|
262
|
+
deprecated?: boolean;
|
|
263
|
+
system?: boolean;
|
|
264
|
+
/**
|
|
265
|
+
* Feature gate to conditionally show/hide/disable this attribute.
|
|
266
|
+
* When the flag condition is not met, the attribute behavior depends on `fallback`:
|
|
267
|
+
* - "hide" (default): Attribute is completely hidden
|
|
268
|
+
* - "disable": Attribute is visible but read-only
|
|
269
|
+
* - "show": No gating (useful for overriding parent settings)
|
|
270
|
+
*/
|
|
271
|
+
featureGate?: FeatureGate;
|
|
272
|
+
metadata?: Record<string, unknown>;
|
|
273
|
+
}
|
|
274
|
+
interface TextAttribute extends BaseAttribute<string> {
|
|
275
|
+
type: "text";
|
|
276
|
+
minLength?: number;
|
|
277
|
+
maxLength?: number;
|
|
278
|
+
pattern?: string;
|
|
279
|
+
}
|
|
280
|
+
type NumberUnit = "integer" | "decimal" | "percentage";
|
|
281
|
+
interface NumberAttribute extends BaseAttribute<number> {
|
|
282
|
+
type: "number";
|
|
283
|
+
min?: number;
|
|
284
|
+
max?: number;
|
|
285
|
+
unit?: NumberUnit;
|
|
286
|
+
decimals?: number;
|
|
287
|
+
}
|
|
288
|
+
interface CheckboxAttribute extends BaseAttribute<boolean> {
|
|
289
|
+
type: "checkbox";
|
|
290
|
+
}
|
|
291
|
+
type DateFormat = "short" | "long" | "full" | "relative";
|
|
292
|
+
type DateValue = string | "today";
|
|
293
|
+
interface DateAttribute extends BaseAttribute<string> {
|
|
294
|
+
type: "date";
|
|
295
|
+
dateFormat?: DateFormat;
|
|
296
|
+
minDate?: DateValue;
|
|
297
|
+
maxDate?: DateValue;
|
|
298
|
+
}
|
|
299
|
+
interface Phone {
|
|
300
|
+
countryCode: CountryIso3;
|
|
301
|
+
phoneNumber: string;
|
|
302
|
+
}
|
|
303
|
+
interface PhoneAttribute extends BaseAttribute<Phone> {
|
|
304
|
+
type: "phone";
|
|
305
|
+
defaultCountryCode?: CountryIso3;
|
|
306
|
+
}
|
|
307
|
+
interface Currency {
|
|
308
|
+
code: CurrencyCode;
|
|
309
|
+
value: number;
|
|
310
|
+
}
|
|
311
|
+
interface CurrencyAttribute extends BaseAttribute<Currency> {
|
|
312
|
+
type: "currency";
|
|
313
|
+
defaultCurrency?: CurrencyCode;
|
|
314
|
+
allowedCurrencies?: CurrencyCode[];
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* StatusAttribute - For workflow states with semantic grouping (idle/in_progress/finished)
|
|
318
|
+
* Use this for: Task status, Order status, Project phases, Process states
|
|
319
|
+
* Use SelectAttribute for: Categories, Types, simple choices without workflow
|
|
320
|
+
*/
|
|
321
|
+
interface StatusAttribute extends BaseAttribute<string> {
|
|
322
|
+
type: "status";
|
|
323
|
+
options: Option[];
|
|
324
|
+
}
|
|
325
|
+
interface Location {
|
|
326
|
+
address?: string;
|
|
327
|
+
address2?: string;
|
|
328
|
+
city?: string;
|
|
329
|
+
state?: string;
|
|
330
|
+
postalCode?: string;
|
|
331
|
+
country?: CountryIso3;
|
|
332
|
+
latitude?: number;
|
|
333
|
+
longitude?: number;
|
|
334
|
+
}
|
|
335
|
+
type LocationGranularity = "full" | "address" | "city" | "state" | "country" | "coordinates";
|
|
336
|
+
interface LocationAttribute extends BaseAttribute<Location> {
|
|
337
|
+
type: "location";
|
|
338
|
+
granularity: LocationGranularity;
|
|
339
|
+
enableAutocomplete?: boolean;
|
|
340
|
+
enableMap?: boolean;
|
|
341
|
+
defaultCountry?: CountryIso3;
|
|
342
|
+
allowedCountries?: CountryIso3[];
|
|
343
|
+
displayFormat?: "single_line" | "multi_line" | "compact";
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* SelectAttribute - For simple single-choice selection
|
|
347
|
+
* Use this for: Categories, Document types, Departments, Priorities
|
|
348
|
+
* Options can be grouped (e.g., countries by continent) but no workflow logic
|
|
349
|
+
*/
|
|
350
|
+
interface SelectAttribute extends BaseAttribute<string> {
|
|
351
|
+
type: "select";
|
|
352
|
+
options: Option[];
|
|
353
|
+
}
|
|
354
|
+
interface MultiselectAttribute extends BaseAttribute<string[]> {
|
|
355
|
+
type: "multiselect";
|
|
356
|
+
options: Option[];
|
|
357
|
+
}
|
|
358
|
+
interface FileAttribute extends BaseAttribute<string> {
|
|
359
|
+
type: "file";
|
|
360
|
+
maxFiles?: number;
|
|
361
|
+
maxSize?: number;
|
|
362
|
+
allowedTypes?: MimeType[] | readonly MimeType[];
|
|
363
|
+
multiple?: boolean;
|
|
364
|
+
}
|
|
365
|
+
interface UserAttribute extends BaseAttribute<string> {
|
|
366
|
+
type: "user";
|
|
367
|
+
allowedRoles?: string[];
|
|
368
|
+
multiple?: boolean;
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Wildcard marker for universal relations (can link to any object)
|
|
372
|
+
* Use with `.toAny()` builder method
|
|
373
|
+
*/
|
|
374
|
+
declare const RELATION_TARGET_ANY: "*";
|
|
375
|
+
/**
|
|
376
|
+
* Configuration for bilateral synchronization (bidirectional relations)
|
|
377
|
+
*/
|
|
378
|
+
interface BilateralConfig {
|
|
379
|
+
/** Target object containing the inverse attribute */
|
|
380
|
+
object: string;
|
|
381
|
+
/** Name of the inverse attribute */
|
|
382
|
+
attribute: string;
|
|
383
|
+
/** Optional cardinality override (inferred by default) */
|
|
384
|
+
cardinality?: "one" | "many";
|
|
385
|
+
/** When true, this side owns the storage direction for qualified properties.
|
|
386
|
+
* Set to false on the inverse side (enriched at read time). */
|
|
387
|
+
storageOwner?: boolean;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Target object for a relation - defines which objects can be linked
|
|
391
|
+
*/
|
|
392
|
+
interface RelationTarget {
|
|
393
|
+
/** Object name (e.g., "companies", "contacts") or "*" for any object */
|
|
394
|
+
object: string;
|
|
395
|
+
/**
|
|
396
|
+
* Display template for the label using mustache-like syntax
|
|
397
|
+
* @example "{name}" or "{firstName} {lastName} — {email}"
|
|
398
|
+
*/
|
|
399
|
+
displayTemplate?: string;
|
|
400
|
+
/**
|
|
401
|
+
* Optional filter to restrict available records
|
|
402
|
+
* @example { status: "active" }
|
|
403
|
+
*/
|
|
404
|
+
filter?: Record<string, unknown>;
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Base properties shared by both single and multi relation attributes
|
|
408
|
+
*
|
|
409
|
+
* Note: Deletion behavior is always "restrict" - if a record is referenced
|
|
410
|
+
* by other records, it cannot be deleted until those references are removed.
|
|
411
|
+
* This is enforced by RecordService.deleteRecord() which throws
|
|
412
|
+
* RecordReferencedError when attempting to delete a referenced record.
|
|
413
|
+
*/
|
|
414
|
+
interface RelationAttributeBase extends Omit<BaseAttribute<unknown>, "defaultValue"> {
|
|
415
|
+
type: "relation";
|
|
416
|
+
/** Target objects that can be linked */
|
|
417
|
+
targets: RelationTarget[];
|
|
418
|
+
/** Optional properties schema for qualified relations */
|
|
419
|
+
properties?: PropertySchema;
|
|
420
|
+
/** Configuration for bilateral synchronization (opt-in) */
|
|
421
|
+
bilateral?: BilateralConfig;
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Single relation attribute (one-to-one or many-to-one)
|
|
425
|
+
* Stores a single record ID or null
|
|
426
|
+
*/
|
|
427
|
+
interface SingleRelationAttribute extends RelationAttributeBase {
|
|
428
|
+
cardinality: "one";
|
|
429
|
+
defaultValue?: string | null;
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Multi relation attribute (one-to-many or many-to-many)
|
|
433
|
+
* Stores an array of record IDs
|
|
434
|
+
*/
|
|
435
|
+
interface MultiRelationAttribute extends RelationAttributeBase {
|
|
436
|
+
cardinality: "many";
|
|
437
|
+
defaultValue?: string[];
|
|
438
|
+
/** Minimum number of relations required */
|
|
439
|
+
minItems?: number;
|
|
440
|
+
/** Maximum number of relations allowed */
|
|
441
|
+
maxItems?: number;
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* RelationAttribute links to other objects/records
|
|
445
|
+
* Discriminated union by cardinality for type-safe value handling
|
|
446
|
+
*
|
|
447
|
+
* @example Single relation (many-to-one)
|
|
448
|
+
* ```typescript
|
|
449
|
+
* relation({ name: "company", label: "Company" })
|
|
450
|
+
* .to("companies")
|
|
451
|
+
* .required()
|
|
452
|
+
* // → Value: "rec-uuid-123" | null
|
|
453
|
+
* ```
|
|
454
|
+
*
|
|
455
|
+
* @example Multi relation (many-to-many)
|
|
456
|
+
* ```typescript
|
|
457
|
+
* relation({ name: "contacts", label: "Contacts" })
|
|
458
|
+
* .to("contacts", { displayTemplate: "{firstName} {lastName}" })
|
|
459
|
+
* .many()
|
|
460
|
+
* .maxItems(5)
|
|
461
|
+
* // → Value: ["rec-1", "rec-2", ...]
|
|
462
|
+
* ```
|
|
463
|
+
*
|
|
464
|
+
* @example Polymorphic relation (multiple target objects)
|
|
465
|
+
* ```typescript
|
|
466
|
+
* relation({ name: "linked", label: "Linked Items" })
|
|
467
|
+
* .to("companies")
|
|
468
|
+
* .to("contacts")
|
|
469
|
+
* .to("deals")
|
|
470
|
+
* .many()
|
|
471
|
+
* // → Can link to records from any of these objects
|
|
472
|
+
* ```
|
|
473
|
+
*/
|
|
474
|
+
type RelationAttribute = SingleRelationAttribute | MultiRelationAttribute;
|
|
475
|
+
/**
|
|
476
|
+
* Check if a relation attribute is universal (can link to any object)
|
|
477
|
+
* Universal relations have `targets: [{ object: "*" }]`
|
|
478
|
+
*/
|
|
479
|
+
declare function isUniversalRelation(attr: RelationAttribute): boolean;
|
|
480
|
+
/**
|
|
481
|
+
* Check if a relation attribute has bilateral synchronization enabled
|
|
482
|
+
*/
|
|
483
|
+
declare function isBilateralRelation(attr: RelationAttribute): attr is RelationAttribute & {
|
|
484
|
+
bilateral: BilateralConfig;
|
|
485
|
+
};
|
|
486
|
+
/**
|
|
487
|
+
* Infer the cardinality of the inverse relation
|
|
488
|
+
* - one → many (contact.company ↔ company.contacts)
|
|
489
|
+
* - many → many (contact.tags ↔ tag.contacts)
|
|
490
|
+
*/
|
|
491
|
+
declare function inferInverseCardinality(cardinality: "one" | "many"): "one" | "many";
|
|
492
|
+
interface TextAreaAttribute extends BaseAttribute<string> {
|
|
493
|
+
type: "textarea";
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Available features for richtext editor
|
|
497
|
+
*/
|
|
498
|
+
type RichtextFeature = "headings" | "bold" | "italic" | "lists" | "links" | "images" | "codeBlocks" | "tables";
|
|
499
|
+
/**
|
|
500
|
+
* RichtextAttribute - Rich text content using semantic markdown
|
|
501
|
+
*
|
|
502
|
+
* Stores content as semantic markdown string (with directives like :::callout).
|
|
503
|
+
* Parsed at runtime to Tiptap JSON for editing.
|
|
504
|
+
* Use this for: Notes, articles, descriptions, long-form content.
|
|
505
|
+
*
|
|
506
|
+
* @example
|
|
507
|
+
* ```typescript
|
|
508
|
+
* richtext({ name: "content", label: "Content" })
|
|
509
|
+
* .features(["headings", "bold", "italic", "lists", "links"])
|
|
510
|
+
* .required()
|
|
511
|
+
* ```
|
|
512
|
+
*/
|
|
513
|
+
interface RichtextAttribute extends BaseAttribute<string> {
|
|
514
|
+
type: "richtext";
|
|
515
|
+
/** Enabled features. If undefined, all features are enabled. */
|
|
516
|
+
features?: RichtextFeature[];
|
|
517
|
+
}
|
|
518
|
+
interface RatingAttribute extends BaseAttribute<number> {
|
|
519
|
+
type: "rating";
|
|
520
|
+
max?: number;
|
|
521
|
+
iconType?: "star" | "heart" | "thumbs" | "number";
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Return type for formula expressions
|
|
525
|
+
*/
|
|
526
|
+
type FormulaReturnType = "text" | "number" | "boolean" | "date";
|
|
527
|
+
/**
|
|
528
|
+
* FormulaAttribute - Computed value based on other attributes
|
|
529
|
+
*
|
|
530
|
+
* Formulas are calculated at read-time and are always read-only.
|
|
531
|
+
* Users cannot directly edit formula values.
|
|
532
|
+
*
|
|
533
|
+
* @example Simple calculation
|
|
534
|
+
* ```typescript
|
|
535
|
+
* formula({ name: "total", label: "Total" })
|
|
536
|
+
* .expression("price * quantity")
|
|
537
|
+
* .returns("number")
|
|
538
|
+
* .decimals(2)
|
|
539
|
+
* ```
|
|
540
|
+
*
|
|
541
|
+
* @example With functions
|
|
542
|
+
* ```typescript
|
|
543
|
+
* formula({ name: "fullName", label: "Full Name" })
|
|
544
|
+
* .expression("CONCAT(firstName, ' ', lastName)")
|
|
545
|
+
* .returns("text")
|
|
546
|
+
* ```
|
|
547
|
+
*/
|
|
548
|
+
interface FormulaAttribute extends Omit<BaseAttribute<never>, "defaultValue" | "required"> {
|
|
549
|
+
type: "formula";
|
|
550
|
+
/** Expression to evaluate (e.g., "price * quantity") */
|
|
551
|
+
expression: string;
|
|
552
|
+
/** Expected return type for formatting */
|
|
553
|
+
returnType: FormulaReturnType;
|
|
554
|
+
/** Decimal places for number results */
|
|
555
|
+
decimals?: number;
|
|
556
|
+
/** Whether to allow relation references in the expression (e.g., "company.name") */
|
|
557
|
+
allowRelations?: boolean;
|
|
558
|
+
/** Formula is always not required (read-only) */
|
|
559
|
+
required: false;
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Aggregation functions for rollup attributes
|
|
563
|
+
*
|
|
564
|
+
* Categories:
|
|
565
|
+
* - Numeric (sum, avg): Only for number, currency, rating types
|
|
566
|
+
* - Date (earliest, latest): Only for date type
|
|
567
|
+
* - Count (count, countValues, countUniqueValues, countEmpty): Universal
|
|
568
|
+
* - Percent (percentEmpty, percentNotEmpty): Universal
|
|
569
|
+
* - Lookup (original): Returns all values as array, rendered as target type
|
|
570
|
+
*/
|
|
571
|
+
type RollupFunction = "sum" | "avg" | "earliest" | "latest" | "count" | "countValues" | "countUniqueValues" | "countEmpty" | "percentEmpty" | "percentNotEmpty" | "original";
|
|
572
|
+
/**
|
|
573
|
+
* RollupAttribute - Aggregates values from related records
|
|
574
|
+
*
|
|
575
|
+
* Rollups are calculated and stored (denormalized) for performance.
|
|
576
|
+
* They are automatically recalculated when related records change.
|
|
577
|
+
* Users cannot directly edit rollup values.
|
|
578
|
+
*
|
|
579
|
+
* @example Sum of related amounts
|
|
580
|
+
* ```typescript
|
|
581
|
+
* rollup({ name: "totalOrders", label: "Total Orders" })
|
|
582
|
+
* .from("orders") // relation attribute name
|
|
583
|
+
* .aggregate("amount") // target attribute to sum
|
|
584
|
+
* .using("sum")
|
|
585
|
+
* .decimals(2)
|
|
586
|
+
* ```
|
|
587
|
+
*
|
|
588
|
+
* @example Count of related records
|
|
589
|
+
* ```typescript
|
|
590
|
+
* rollup({ name: "orderCount", label: "Number of Orders" })
|
|
591
|
+
* .from("orders")
|
|
592
|
+
* .using("count")
|
|
593
|
+
* ```
|
|
594
|
+
*/
|
|
595
|
+
interface RollupAttribute extends Omit<BaseAttribute<never>, "defaultValue" | "required"> {
|
|
596
|
+
type: "rollup";
|
|
597
|
+
/** Name of the relation attribute on this object */
|
|
598
|
+
relationAttribute: string;
|
|
599
|
+
/**
|
|
600
|
+
* Dot notation path for multi-level traversal (Phase 4+)
|
|
601
|
+
* @example "orders.items" - traverse through orders to items
|
|
602
|
+
*/
|
|
603
|
+
relationPath?: string;
|
|
604
|
+
/** Attribute name on the target object to aggregate */
|
|
605
|
+
targetAttribute: string;
|
|
606
|
+
/** Aggregation function to apply */
|
|
607
|
+
function: RollupFunction;
|
|
608
|
+
/** Decimal places for numeric results */
|
|
609
|
+
decimals?: number;
|
|
610
|
+
/** Rollup is always not required (read-only) */
|
|
611
|
+
required: false;
|
|
612
|
+
/**
|
|
613
|
+
* Cached type of the target attribute for display purposes
|
|
614
|
+
* Used when function="original" to render values as the target type
|
|
615
|
+
*/
|
|
616
|
+
targetAttributeType?: AttributeType;
|
|
617
|
+
/**
|
|
618
|
+
* Cached options from target attribute (for select/status/multiselect display)
|
|
619
|
+
* Required when function="original" and target is a select-like type
|
|
620
|
+
*/
|
|
621
|
+
targetAttributeOptions?: Option[];
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* DocumentAttribute - References one or multiple documents with templates.
|
|
625
|
+
*
|
|
626
|
+
* Unlike FileAttribute which stores raw file references, DocumentAttribute
|
|
627
|
+
* provides structured document handling with templates, multi-file support,
|
|
628
|
+
* and automatic processing (OCR, signature, identity verification).
|
|
629
|
+
*
|
|
630
|
+
* @example Single document with template choice
|
|
631
|
+
* ```typescript
|
|
632
|
+
* document({ name: "identityDocument", label: "Pièce d'identité" })
|
|
633
|
+
* .templates(["french_id_card", "passport"])
|
|
634
|
+
* .autoProcess()
|
|
635
|
+
* .required()
|
|
636
|
+
* ```
|
|
637
|
+
*
|
|
638
|
+
* @example Multiple documents
|
|
639
|
+
* ```typescript
|
|
640
|
+
* document({ name: "contracts", label: "Contrats" })
|
|
641
|
+
* .multiple()
|
|
642
|
+
* .maxDocuments(10)
|
|
643
|
+
* ```
|
|
644
|
+
*/
|
|
645
|
+
interface DocumentAttribute extends BaseAttribute<string | string[]> {
|
|
646
|
+
type: "document";
|
|
647
|
+
/**
|
|
648
|
+
* Allow multiple documents.
|
|
649
|
+
* If true, value is string[] (document IDs).
|
|
650
|
+
* If false/undefined, value is string (single document ID).
|
|
651
|
+
*/
|
|
652
|
+
multiple?: boolean;
|
|
653
|
+
/**
|
|
654
|
+
* Maximum number of documents when multiple: true.
|
|
655
|
+
*/
|
|
656
|
+
maxDocuments?: number;
|
|
657
|
+
/**
|
|
658
|
+
* Automatically trigger processing (OCR, verification) on upload.
|
|
659
|
+
*/
|
|
660
|
+
autoProcess?: boolean;
|
|
661
|
+
}
|
|
662
|
+
type Attribute = TextAttribute | TextAreaAttribute | RichtextAttribute | NumberAttribute | CheckboxAttribute | DateAttribute | PhoneAttribute | CurrencyAttribute | StatusAttribute | LocationAttribute | SelectAttribute | MultiselectAttribute | FileAttribute | UserAttribute | RelationAttribute | RatingAttribute | FormulaAttribute | RollupAttribute | DocumentAttribute;
|
|
663
|
+
/**
|
|
664
|
+
* Attribute types that are not sortable by default.
|
|
665
|
+
* These types have complex/binary values without a meaningful natural order.
|
|
666
|
+
*/
|
|
667
|
+
declare const NON_SORTABLE_TYPES: ReadonlySet<AttributeType>;
|
|
668
|
+
/**
|
|
669
|
+
* Check if an attribute supports sorting based on its type.
|
|
670
|
+
*/
|
|
671
|
+
declare function isAttributeSortable(attr: {
|
|
672
|
+
type: AttributeType;
|
|
673
|
+
}): boolean;
|
|
674
|
+
|
|
675
|
+
/** Operators for text-based attributes */
|
|
676
|
+
type TextFilterOperator = "is" | "is_not" | "contains" | "not_contains" | "starts_with" | "ends_with" | "is_empty" | "is_not_empty";
|
|
677
|
+
/** Operators for number-based attributes */
|
|
678
|
+
type NumberFilterOperator = "eq" | "neq" | "lt" | "gt" | "lte" | "gte" | "is_empty" | "is_not_empty";
|
|
679
|
+
/** Operators for checkbox */
|
|
680
|
+
type CheckboxFilterOperator = "is_checked" | "is_not_checked";
|
|
681
|
+
/** Operators for date-based attributes */
|
|
682
|
+
type DateFilterOperator = "is" | "is_not" | "before" | "after" | "on_or_before" | "on_or_after" | "is_within" | "is_empty" | "is_not_empty";
|
|
683
|
+
/** Operators for select-based attributes (supports single or multi-value filtering) */
|
|
684
|
+
type SelectFilterOperator = "is" | "is_not" | "any_of" | "none_of" | "is_empty" | "is_not_empty";
|
|
685
|
+
/** Operators for multiselect-based attributes */
|
|
686
|
+
type MultiselectFilterOperator = "contains" | "not_contains" | "is_empty" | "is_not_empty";
|
|
687
|
+
/** Operators for relation-based attributes (supports single or multi-value filtering) */
|
|
688
|
+
type RelationFilterOperator = "any_of" | "none_of" | "contains" | "not_contains" | "is_empty" | "is_not_empty";
|
|
689
|
+
/** All possible filter operators */
|
|
690
|
+
type FilterOperator = TextFilterOperator | NumberFilterOperator | CheckboxFilterOperator | DateFilterOperator | SelectFilterOperator | MultiselectFilterOperator | RelationFilterOperator;
|
|
691
|
+
/** Relative date value for "is_within" operator */
|
|
692
|
+
interface RelativeDateValue {
|
|
693
|
+
amount: number;
|
|
694
|
+
unit: "days" | "weeks" | "months" | "years";
|
|
695
|
+
direction: "past" | "future";
|
|
696
|
+
}
|
|
697
|
+
/** Currency filter value with amount and optional currency codes
|
|
698
|
+
* - code: undefined or [] = any currency
|
|
699
|
+
* - code: string[] = filter by specific currencies
|
|
700
|
+
*/
|
|
701
|
+
interface CurrencyFilterValue {
|
|
702
|
+
value: number | null;
|
|
703
|
+
code?: string[];
|
|
704
|
+
}
|
|
705
|
+
/** Phone filter value with number and optional country code */
|
|
706
|
+
interface PhoneFilterValue {
|
|
707
|
+
phoneNumber: string | null;
|
|
708
|
+
countryCode?: string;
|
|
709
|
+
}
|
|
710
|
+
/** Filter value can be various types depending on the attribute */
|
|
711
|
+
type FilterValue = string | number | boolean | string[] | RelativeDateValue | CurrencyFilterValue | PhoneFilterValue | null;
|
|
712
|
+
/** A single filter rule */
|
|
713
|
+
interface FilterRule {
|
|
714
|
+
/** Attribute name to filter on */
|
|
715
|
+
attribute: string;
|
|
716
|
+
/** Filter operator */
|
|
717
|
+
operator: FilterOperator;
|
|
718
|
+
/** Filter value (null for operators like is_empty) */
|
|
719
|
+
value: FilterValue;
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* Extended filter rule with optional attribute definition.
|
|
723
|
+
* When provided, enables smarter type-aware filtering (e.g., array operators for multiselect).
|
|
724
|
+
*/
|
|
725
|
+
interface ExtendedFilterRule extends FilterRule {
|
|
726
|
+
/** Full attribute definition for type-aware filtering */
|
|
727
|
+
attributeDef?: Attribute;
|
|
728
|
+
}
|
|
729
|
+
/** Combinator for filter rules */
|
|
730
|
+
type FilterCombinator = "and" | "or";
|
|
731
|
+
/** Complete filter state (simple mode) */
|
|
732
|
+
interface FilterState {
|
|
733
|
+
/** How to combine rules */
|
|
734
|
+
combinator: FilterCombinator;
|
|
735
|
+
/** List of filter rules */
|
|
736
|
+
rules: FilterRule[];
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* A filter group containing rules (used in advanced mode)
|
|
740
|
+
* Groups can be nested up to 2 levels deep
|
|
741
|
+
*/
|
|
742
|
+
interface FilterGroup {
|
|
743
|
+
/** Unique identifier for this group */
|
|
744
|
+
id: string;
|
|
745
|
+
/** How to combine rules within this group */
|
|
746
|
+
combinator: FilterCombinator;
|
|
747
|
+
/** List of filter rules in this group */
|
|
748
|
+
rules: FilterRule[];
|
|
749
|
+
}
|
|
750
|
+
/**
|
|
751
|
+
* Advanced filter state with nested groups
|
|
752
|
+
* Structure: AdvancedFilterState -> FilterGroup[] -> FilterRule[]
|
|
753
|
+
* Maximum 2 levels of nesting
|
|
754
|
+
*/
|
|
755
|
+
interface AdvancedFilterState {
|
|
756
|
+
/** How to combine groups at the top level */
|
|
757
|
+
combinator: FilterCombinator;
|
|
758
|
+
/** List of filter groups */
|
|
759
|
+
groups: FilterGroup[];
|
|
760
|
+
}
|
|
761
|
+
/** Sort direction */
|
|
762
|
+
type SortDirection = "asc" | "desc";
|
|
763
|
+
/** A single sort rule */
|
|
764
|
+
interface SortRule {
|
|
765
|
+
/** Attribute name to sort by */
|
|
766
|
+
attribute: string;
|
|
767
|
+
/** Sort direction */
|
|
768
|
+
direction: SortDirection;
|
|
769
|
+
}
|
|
770
|
+
/** Complete query state with search, filters, sorts, and pagination */
|
|
771
|
+
interface QueryState {
|
|
772
|
+
/** Full-text search query */
|
|
773
|
+
search?: string;
|
|
774
|
+
/** Filter configuration (simple mode) */
|
|
775
|
+
filters?: FilterState;
|
|
776
|
+
/** Advanced filter configuration (grouped mode) */
|
|
777
|
+
advancedFilters?: AdvancedFilterState;
|
|
778
|
+
/** Sort configuration (multiple sorts supported) */
|
|
779
|
+
sorts?: SortRule[];
|
|
780
|
+
/** Pagination */
|
|
781
|
+
limit?: number;
|
|
782
|
+
offset?: number;
|
|
783
|
+
}
|
|
784
|
+
/** Mapping of attribute types to their valid operators */
|
|
785
|
+
declare const OPERATORS_BY_TYPE: Record<AttributeType, readonly FilterOperator[]>;
|
|
786
|
+
/** Check if an operator requires a value */
|
|
787
|
+
type NoValueOperator = "is_empty" | "is_not_empty" | "is_checked" | "is_not_checked";
|
|
788
|
+
/** Operators that don't require a value */
|
|
789
|
+
declare const NO_VALUE_OPERATORS: readonly NoValueOperator[];
|
|
790
|
+
/**
|
|
791
|
+
* Check if an operator requires a value
|
|
792
|
+
*/
|
|
793
|
+
declare function isNoValueOperator(operator: FilterOperator): operator is NoValueOperator;
|
|
794
|
+
/**
|
|
795
|
+
* Get the filter operators for a rollup attribute based on its aggregation function and target type.
|
|
796
|
+
*
|
|
797
|
+
* - earliest / latest → date operators
|
|
798
|
+
* - original → operators matching targetAttributeType (falls back to numeric if unknown)
|
|
799
|
+
* - all other functions → numeric operators (sum, avg, count, percent, etc.)
|
|
800
|
+
*/
|
|
801
|
+
declare function getRollupFilterOperators(attr: RollupAttribute): readonly FilterOperator[];
|
|
802
|
+
|
|
803
|
+
interface BufferedRecord {
|
|
804
|
+
id: string;
|
|
805
|
+
objectName: string;
|
|
806
|
+
values: Record<string, unknown>;
|
|
807
|
+
}
|
|
808
|
+
interface RecordPatch {
|
|
809
|
+
values: Record<string, unknown>;
|
|
810
|
+
}
|
|
811
|
+
type RelationQualifierPatch = Record<string, unknown>;
|
|
812
|
+
interface RelationBuffer {
|
|
813
|
+
preloaded: BufferedRecord[];
|
|
814
|
+
added: BufferedRecord[];
|
|
815
|
+
modified: Record<string, RecordPatch>;
|
|
816
|
+
removed: string[];
|
|
817
|
+
qualifiers: Record<string, RelationQualifierPatch>;
|
|
818
|
+
}
|
|
819
|
+
type RelationBufferMap = Record<string, RelationBuffer>;
|
|
820
|
+
interface DisplayRecord {
|
|
821
|
+
id: string;
|
|
822
|
+
objectName: string;
|
|
823
|
+
values: Record<string, unknown>;
|
|
824
|
+
qualifiers: Record<string, unknown>;
|
|
825
|
+
status: "existing" | "added" | "modified";
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
/**
|
|
829
|
+
* Document generated during workflow execution
|
|
830
|
+
*/
|
|
831
|
+
interface GeneratedDocument {
|
|
832
|
+
/** Document ID (file ID) */
|
|
833
|
+
id: string;
|
|
834
|
+
/** URL to access the document */
|
|
835
|
+
url: string;
|
|
836
|
+
/** Document filename */
|
|
837
|
+
filename?: string;
|
|
838
|
+
/** MIME type */
|
|
839
|
+
mimeType?: string;
|
|
840
|
+
/** File size in bytes */
|
|
841
|
+
size?: number;
|
|
842
|
+
/** Additional metadata */
|
|
843
|
+
metadata?: Record<string, unknown>;
|
|
844
|
+
/** IDs of Document records created (one per target slot) */
|
|
845
|
+
attachedDocumentIds?: string[];
|
|
846
|
+
}
|
|
847
|
+
/**
|
|
848
|
+
* Accumulated context during workflow execution.
|
|
849
|
+
*
|
|
850
|
+
* This context is built up as nodes execute and is passed to each node.
|
|
851
|
+
* It contains all the data collected and generated during the workflow.
|
|
852
|
+
*
|
|
853
|
+
* @example
|
|
854
|
+
* ```typescript
|
|
855
|
+
* const context: WorkflowExecutionContext = {
|
|
856
|
+
* slots: {
|
|
857
|
+
* client: {
|
|
858
|
+
* id: "rec_123",
|
|
859
|
+
* firstName: "John",
|
|
860
|
+
* lastName: "Doe",
|
|
861
|
+
* email: "john@example.com",
|
|
862
|
+
* type: "vip"
|
|
863
|
+
* }
|
|
864
|
+
* },
|
|
865
|
+
* forms: {
|
|
866
|
+
* "client-form": {
|
|
867
|
+
* firstName: "John",
|
|
868
|
+
* lastName: "Doe"
|
|
869
|
+
* }
|
|
870
|
+
* },
|
|
871
|
+
* documents: {},
|
|
872
|
+
* variables: {
|
|
873
|
+
* totalAmount: 15000
|
|
874
|
+
* },
|
|
875
|
+
* conditionResults: {
|
|
876
|
+
* "check-vip": true
|
|
877
|
+
* }
|
|
878
|
+
* };
|
|
879
|
+
* ```
|
|
880
|
+
*/
|
|
881
|
+
interface WorkflowExecutionContext {
|
|
882
|
+
/**
|
|
883
|
+
* Records created/modified during execution, indexed by slot ID.
|
|
884
|
+
* Contains the full record data for each slot.
|
|
885
|
+
*/
|
|
886
|
+
slots: Record<string, Record<string, unknown>>;
|
|
887
|
+
/**
|
|
888
|
+
* Form submissions indexed by node ID.
|
|
889
|
+
* Contains the raw form data submitted at each form node.
|
|
890
|
+
*/
|
|
891
|
+
forms: Record<string, Record<string, unknown>>;
|
|
892
|
+
/**
|
|
893
|
+
* Documents generated during execution, indexed by node ID.
|
|
894
|
+
* Contains document metadata and URLs.
|
|
895
|
+
*/
|
|
896
|
+
documents: Record<string, GeneratedDocument>;
|
|
897
|
+
/**
|
|
898
|
+
* Custom variables set during execution.
|
|
899
|
+
* Can be used by action nodes to store computed values.
|
|
900
|
+
*/
|
|
901
|
+
variables: Record<string, unknown>;
|
|
902
|
+
/**
|
|
903
|
+
* Results of condition evaluations for debugging.
|
|
904
|
+
* Indexed by condition node ID.
|
|
905
|
+
*/
|
|
906
|
+
conditionResults: Record<string, boolean>;
|
|
907
|
+
/**
|
|
908
|
+
* IDs of records created during workflow completion.
|
|
909
|
+
* Used for idempotence (avoid creating duplicates on retry).
|
|
910
|
+
* Indexed by slot ID.
|
|
911
|
+
*/
|
|
912
|
+
createdRecordIds: Record<string, string>;
|
|
913
|
+
/**
|
|
914
|
+
* Relation buffers for pending relation changes, indexed by slot ID then relation attribute name.
|
|
915
|
+
*/
|
|
916
|
+
relationBuffers: Record<string, RelationBufferMap>;
|
|
917
|
+
}
|
|
918
|
+
/**
|
|
919
|
+
* Create an empty execution context
|
|
920
|
+
*/
|
|
921
|
+
declare function createEmptyContext(): WorkflowExecutionContext;
|
|
922
|
+
/**
|
|
923
|
+
* Get a value from the context using dot notation path.
|
|
924
|
+
*
|
|
925
|
+
* Supports paths like:
|
|
926
|
+
* - "slots.client.email"
|
|
927
|
+
* - "forms.step1.amount"
|
|
928
|
+
* - "variables.customVar"
|
|
929
|
+
*
|
|
930
|
+
* @param context - The execution context
|
|
931
|
+
* @param path - Dot notation path to the value
|
|
932
|
+
* @returns The value at the path, or undefined if not found
|
|
933
|
+
*
|
|
934
|
+
* @example
|
|
935
|
+
* ```typescript
|
|
936
|
+
* const email = getContextValue(context, "slots.client.email");
|
|
937
|
+
* const amount = getContextValue(context, "forms.quote.amount");
|
|
938
|
+
* ```
|
|
939
|
+
*/
|
|
940
|
+
declare function getContextValue(context: WorkflowExecutionContext, path: string): unknown;
|
|
941
|
+
/**
|
|
942
|
+
* Set a value in the context using dot notation path.
|
|
943
|
+
*
|
|
944
|
+
* @param context - The execution context (mutated in place)
|
|
945
|
+
* @param path - Dot notation path to set
|
|
946
|
+
* @param value - Value to set
|
|
947
|
+
*
|
|
948
|
+
* @example
|
|
949
|
+
* ```typescript
|
|
950
|
+
* setContextValue(context, "variables.computed", 42);
|
|
951
|
+
* setContextValue(context, "slots.client.status", "active");
|
|
952
|
+
* ```
|
|
953
|
+
*/
|
|
954
|
+
declare function setContextValue(context: WorkflowExecutionContext, path: string, value: unknown): void;
|
|
955
|
+
|
|
956
|
+
/**
|
|
957
|
+
* Represents a "slot" for an object to be created in the flow
|
|
958
|
+
* Ex: "mr" for the first contact, "company" for the company
|
|
959
|
+
*
|
|
960
|
+
* Note: Named "Slot" to avoid confusion with DB entities
|
|
961
|
+
*
|
|
962
|
+
* @deprecated Use WorkflowSlot from types/workflows instead
|
|
963
|
+
*/
|
|
964
|
+
interface FlowSlot {
|
|
965
|
+
/** Unique identifier for the slot (ex: "mr", "mme", "company") */
|
|
966
|
+
id: string;
|
|
967
|
+
/** Name of the object to create (ex: "contacts", "companies") */
|
|
968
|
+
objectName: string;
|
|
969
|
+
/** Display label (ex: "Monsieur", "Madame") */
|
|
970
|
+
label: string;
|
|
971
|
+
/** Color to visually distinguish in the builder (from COLORS palette) */
|
|
972
|
+
color?: ColorId;
|
|
973
|
+
/** Optional icon */
|
|
974
|
+
icon?: IconName;
|
|
975
|
+
}
|
|
976
|
+
/**
|
|
977
|
+
* Configuration for relation fields in workflow/flow forms.
|
|
978
|
+
* Controls which qualified properties are visible and whether
|
|
979
|
+
* inline record creation is allowed.
|
|
980
|
+
*/
|
|
981
|
+
interface RelationFieldConfig {
|
|
982
|
+
/** Which qualified properties to display (all if omitted) */
|
|
983
|
+
visibleProperties?: string[];
|
|
984
|
+
/** Allow creating new target records inline (default: true) */
|
|
985
|
+
allowCreate?: boolean;
|
|
986
|
+
}
|
|
987
|
+
/**
|
|
988
|
+
* Field within a row (simplified - no span, auto-calculated)
|
|
989
|
+
*/
|
|
990
|
+
interface FlowRowField {
|
|
991
|
+
/** Unique field ID */
|
|
992
|
+
id: string;
|
|
993
|
+
/** Reference to FlowSlot.id */
|
|
994
|
+
slotId: string;
|
|
995
|
+
/** Attribute name on the object */
|
|
996
|
+
attribute: string;
|
|
997
|
+
/** Override label for this flow */
|
|
998
|
+
label?: string;
|
|
999
|
+
/** Override tooltip/description for this flow */
|
|
1000
|
+
tooltip?: string;
|
|
1001
|
+
/** Override required */
|
|
1002
|
+
required?: boolean;
|
|
1003
|
+
/** Relation-specific configuration (only for relation attributes) */
|
|
1004
|
+
relationConfig?: RelationFieldConfig;
|
|
1005
|
+
}
|
|
1006
|
+
/**
|
|
1007
|
+
* Row type discriminator.
|
|
1008
|
+
* - "fields" (or undefined): standard row with data fields
|
|
1009
|
+
* - "heading": section heading
|
|
1010
|
+
* - "separator": visual divider
|
|
1011
|
+
* - "text": static descriptive text
|
|
1012
|
+
*/
|
|
1013
|
+
type FlowRowType = "fields" | "heading" | "separator" | "text" | "relationList";
|
|
1014
|
+
/**
|
|
1015
|
+
* Standard row containing data fields
|
|
1016
|
+
*/
|
|
1017
|
+
interface FlowFieldsRow {
|
|
1018
|
+
/** Unique row ID */
|
|
1019
|
+
id: string;
|
|
1020
|
+
/** Display order within the page */
|
|
1021
|
+
order: number;
|
|
1022
|
+
/** Row type (optional for backward compat — defaults to "fields") */
|
|
1023
|
+
type?: "fields";
|
|
1024
|
+
/** Fields in this row (auto-distribute width) */
|
|
1025
|
+
fields: FlowRowField[];
|
|
1026
|
+
}
|
|
1027
|
+
/**
|
|
1028
|
+
* Heading row — renders a section title in the form
|
|
1029
|
+
*/
|
|
1030
|
+
interface FlowHeadingRow {
|
|
1031
|
+
id: string;
|
|
1032
|
+
order: number;
|
|
1033
|
+
type: "heading";
|
|
1034
|
+
/** Heading text */
|
|
1035
|
+
content: string;
|
|
1036
|
+
/** Heading level (1 = large, 2 = medium, 3 = small) */
|
|
1037
|
+
level?: 1 | 2 | 3;
|
|
1038
|
+
}
|
|
1039
|
+
/**
|
|
1040
|
+
* Separator row — renders a visual divider
|
|
1041
|
+
*/
|
|
1042
|
+
interface FlowSeparatorRow {
|
|
1043
|
+
id: string;
|
|
1044
|
+
order: number;
|
|
1045
|
+
type: "separator";
|
|
1046
|
+
}
|
|
1047
|
+
/**
|
|
1048
|
+
* Static text row — renders descriptive/instructional text
|
|
1049
|
+
*/
|
|
1050
|
+
interface FlowTextRow {
|
|
1051
|
+
id: string;
|
|
1052
|
+
order: number;
|
|
1053
|
+
type: "text";
|
|
1054
|
+
/** Text content (supports basic markdown) */
|
|
1055
|
+
content: string;
|
|
1056
|
+
}
|
|
1057
|
+
/**
|
|
1058
|
+
* Relation list row — renders an editable list of related records with preloading
|
|
1059
|
+
*/
|
|
1060
|
+
interface FlowRelationListRow {
|
|
1061
|
+
id: string;
|
|
1062
|
+
order: number;
|
|
1063
|
+
type: "relationList";
|
|
1064
|
+
slotId: string;
|
|
1065
|
+
relationName: string;
|
|
1066
|
+
preload: boolean;
|
|
1067
|
+
columns: string[];
|
|
1068
|
+
qualifiersInline: boolean;
|
|
1069
|
+
modalFields: "all" | string[];
|
|
1070
|
+
label?: string;
|
|
1071
|
+
}
|
|
1072
|
+
/**
|
|
1073
|
+
* Union of all row types.
|
|
1074
|
+
* Use `isFlowFieldsRow()` / `isLayoutRow()` type guards for narrowing.
|
|
1075
|
+
*/
|
|
1076
|
+
type FlowRow = FlowFieldsRow | FlowHeadingRow | FlowSeparatorRow | FlowTextRow | FlowRelationListRow;
|
|
1077
|
+
/** Check if a row is a standard fields row */
|
|
1078
|
+
declare function isFlowFieldsRow(row: FlowRow): row is FlowFieldsRow;
|
|
1079
|
+
/** Check if a row is a layout row (heading, separator, or text) */
|
|
1080
|
+
declare function isLayoutRow(row: FlowRow): row is FlowHeadingRow | FlowSeparatorRow | FlowTextRow;
|
|
1081
|
+
/** Check if a row is a relation list row */
|
|
1082
|
+
declare function isFlowRelationListRow(row: FlowRow): row is FlowRelationListRow;
|
|
1083
|
+
/**
|
|
1084
|
+
* Page/step in a flow
|
|
1085
|
+
*/
|
|
1086
|
+
interface FlowPage {
|
|
1087
|
+
/** Unique page ID */
|
|
1088
|
+
id: string;
|
|
1089
|
+
/** Display label */
|
|
1090
|
+
label: string;
|
|
1091
|
+
/** Optional description */
|
|
1092
|
+
description?: string;
|
|
1093
|
+
/** Display order */
|
|
1094
|
+
order: number;
|
|
1095
|
+
/** Rows in this page */
|
|
1096
|
+
rows: FlowRow[];
|
|
1097
|
+
}
|
|
1098
|
+
/**
|
|
1099
|
+
* Defines how to link slots after creation
|
|
1100
|
+
* Ex: Link "mr" and "mme" to "company" via their "company" attribute
|
|
1101
|
+
*/
|
|
1102
|
+
interface FlowRelation {
|
|
1103
|
+
/** Unique relation ID */
|
|
1104
|
+
id: string;
|
|
1105
|
+
/** Source slot that has the relation attribute */
|
|
1106
|
+
sourceSlotId: string;
|
|
1107
|
+
/** Relation attribute on the source slot */
|
|
1108
|
+
sourceAttribute: string;
|
|
1109
|
+
/** Target slot created in the same flow */
|
|
1110
|
+
targetSlotId: string;
|
|
1111
|
+
}
|
|
1112
|
+
/** Flow lifecycle status */
|
|
1113
|
+
type FlowStatus = "draft" | "published" | "archived";
|
|
1114
|
+
/**
|
|
1115
|
+
* Complete flow definition for multi-object creation
|
|
1116
|
+
*
|
|
1117
|
+
* @example
|
|
1118
|
+
* ```typescript
|
|
1119
|
+
* const coupleFlow: FlowDefinition = {
|
|
1120
|
+
* name: "couple-creation",
|
|
1121
|
+
* label: "Création Couple",
|
|
1122
|
+
* status: "published",
|
|
1123
|
+
* version: 1,
|
|
1124
|
+
* slots: [
|
|
1125
|
+
* { id: "mr", objectName: "contacts", label: "Monsieur" },
|
|
1126
|
+
* { id: "mme", objectName: "contacts", label: "Madame" },
|
|
1127
|
+
* { id: "company", objectName: "companies", label: "Entreprise" },
|
|
1128
|
+
* ],
|
|
1129
|
+
* pages: [...],
|
|
1130
|
+
* relations: [
|
|
1131
|
+
* { id: "mr-company", sourceSlotId: "mr", sourceAttribute: "company", targetSlotId: "company" },
|
|
1132
|
+
* ],
|
|
1133
|
+
* system: true,
|
|
1134
|
+
* };
|
|
1135
|
+
* ```
|
|
1136
|
+
*/
|
|
1137
|
+
interface FlowDefinition {
|
|
1138
|
+
/** Database ID */
|
|
1139
|
+
id?: Uuid;
|
|
1140
|
+
/** Technical name (kebab-case) */
|
|
1141
|
+
name: string;
|
|
1142
|
+
/** Display label */
|
|
1143
|
+
label: string;
|
|
1144
|
+
/** Optional description */
|
|
1145
|
+
description?: string;
|
|
1146
|
+
/** Optional icon */
|
|
1147
|
+
icon?: IconName;
|
|
1148
|
+
/** Flow status */
|
|
1149
|
+
status: FlowStatus;
|
|
1150
|
+
/** Version for tracking modifications */
|
|
1151
|
+
version: number;
|
|
1152
|
+
/** Slots (objects) to create in this flow */
|
|
1153
|
+
slots: FlowSlot[];
|
|
1154
|
+
/** Pages/steps of the flow */
|
|
1155
|
+
pages: FlowPage[];
|
|
1156
|
+
/** Relations between created slots */
|
|
1157
|
+
relations: FlowRelation[];
|
|
1158
|
+
/** If true, defined in code (protected) */
|
|
1159
|
+
system?: boolean;
|
|
1160
|
+
/** Tenant ID for multi-tenant (optional if single-tenant) */
|
|
1161
|
+
tenantId?: string;
|
|
1162
|
+
/** Extensible metadata */
|
|
1163
|
+
metadata?: Record<string, unknown>;
|
|
1164
|
+
/** Timestamps */
|
|
1165
|
+
createdAt?: Date;
|
|
1166
|
+
updatedAt?: Date;
|
|
1167
|
+
}
|
|
1168
|
+
/**
|
|
1169
|
+
* Check if an object is a FlowDefinition
|
|
1170
|
+
*/
|
|
1171
|
+
declare function isFlowDefinition(obj: unknown): obj is FlowDefinition;
|
|
1172
|
+
/**
|
|
1173
|
+
* Check if a flow is published and available for use
|
|
1174
|
+
*/
|
|
1175
|
+
declare function isFlowPublished(flow: FlowDefinition): boolean;
|
|
1176
|
+
/**
|
|
1177
|
+
* Check if a flow is a system flow (defined in code)
|
|
1178
|
+
*/
|
|
1179
|
+
declare function isSystemFlow(flow: FlowDefinition): boolean;
|
|
1180
|
+
|
|
1181
|
+
/**
|
|
1182
|
+
* All supported comparison operators for condition rules
|
|
1183
|
+
*/
|
|
1184
|
+
type ConditionOperator = "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "contains" | "startsWith" | "endsWith" | "isEmpty" | "isNotEmpty" | "in" | "notIn";
|
|
1185
|
+
/**
|
|
1186
|
+
* A single condition rule that compares a field value against a target value.
|
|
1187
|
+
*
|
|
1188
|
+
* Field paths support dot notation for nested access:
|
|
1189
|
+
* - `slots.client.type` - Access slot record attribute
|
|
1190
|
+
* - `forms.step1.amount` - Access form submission data
|
|
1191
|
+
* - `context.variables.customVar` - Access custom variables
|
|
1192
|
+
*
|
|
1193
|
+
* @example
|
|
1194
|
+
* ```typescript
|
|
1195
|
+
* const rule: ConditionRule = {
|
|
1196
|
+
* field: "slots.client.type",
|
|
1197
|
+
* operator: "eq",
|
|
1198
|
+
* value: "vip"
|
|
1199
|
+
* };
|
|
1200
|
+
* ```
|
|
1201
|
+
*/
|
|
1202
|
+
interface ConditionRule {
|
|
1203
|
+
/** Field path to evaluate (dot notation) */
|
|
1204
|
+
field: string;
|
|
1205
|
+
/** Comparison operator */
|
|
1206
|
+
operator: ConditionOperator;
|
|
1207
|
+
/** Value to compare against (type depends on operator) */
|
|
1208
|
+
value: unknown;
|
|
1209
|
+
}
|
|
1210
|
+
/**
|
|
1211
|
+
* A group of conditions combined with AND/OR logic.
|
|
1212
|
+
* Groups can be nested for complex conditions.
|
|
1213
|
+
*
|
|
1214
|
+
* @example Simple AND condition
|
|
1215
|
+
* ```typescript
|
|
1216
|
+
* const condition: ConditionGroup = {
|
|
1217
|
+
* operator: "and",
|
|
1218
|
+
* rules: [
|
|
1219
|
+
* { field: "slots.client.type", operator: "eq", value: "vip" },
|
|
1220
|
+
* { field: "slots.client.active", operator: "eq", value: true }
|
|
1221
|
+
* ]
|
|
1222
|
+
* };
|
|
1223
|
+
* ```
|
|
1224
|
+
*
|
|
1225
|
+
* @example Nested condition (VIP OR (Premium AND Active))
|
|
1226
|
+
* ```typescript
|
|
1227
|
+
* const condition: ConditionGroup = {
|
|
1228
|
+
* operator: "or",
|
|
1229
|
+
* rules: [
|
|
1230
|
+
* { field: "slots.client.type", operator: "eq", value: "vip" },
|
|
1231
|
+
* {
|
|
1232
|
+
* operator: "and",
|
|
1233
|
+
* rules: [
|
|
1234
|
+
* { field: "slots.client.type", operator: "eq", value: "premium" },
|
|
1235
|
+
* { field: "slots.client.active", operator: "eq", value: true }
|
|
1236
|
+
* ]
|
|
1237
|
+
* }
|
|
1238
|
+
* ]
|
|
1239
|
+
* };
|
|
1240
|
+
* ```
|
|
1241
|
+
*/
|
|
1242
|
+
interface ConditionGroup {
|
|
1243
|
+
/** Logical operator to combine rules */
|
|
1244
|
+
operator: "and" | "or";
|
|
1245
|
+
/** Array of rules or nested groups */
|
|
1246
|
+
rules: Array<ConditionRule | ConditionGroup>;
|
|
1247
|
+
}
|
|
1248
|
+
/**
|
|
1249
|
+
* Check if an item is a ConditionRule (not a ConditionGroup)
|
|
1250
|
+
*/
|
|
1251
|
+
declare function isConditionRule(item: ConditionRule | ConditionGroup): item is ConditionRule;
|
|
1252
|
+
/**
|
|
1253
|
+
* Check if an item is a ConditionGroup
|
|
1254
|
+
*/
|
|
1255
|
+
declare function isConditionGroup(item: ConditionRule | ConditionGroup): item is ConditionGroup;
|
|
1256
|
+
/**
|
|
1257
|
+
* Create a simple equality condition
|
|
1258
|
+
*/
|
|
1259
|
+
declare function eq(field: string, value: unknown): ConditionRule;
|
|
1260
|
+
/**
|
|
1261
|
+
* Create a simple inequality condition
|
|
1262
|
+
*/
|
|
1263
|
+
declare function neq(field: string, value: unknown): ConditionRule;
|
|
1264
|
+
/**
|
|
1265
|
+
* Create an AND condition group
|
|
1266
|
+
*/
|
|
1267
|
+
declare function and(...rules: Array<ConditionRule | ConditionGroup>): ConditionGroup;
|
|
1268
|
+
/**
|
|
1269
|
+
* Create an OR condition group
|
|
1270
|
+
*/
|
|
1271
|
+
declare function or(...rules: Array<ConditionRule | ConditionGroup>): ConditionGroup;
|
|
1272
|
+
/**
|
|
1273
|
+
* Create an "in" condition (value in array)
|
|
1274
|
+
*/
|
|
1275
|
+
declare function inValues(field: string, values: unknown[]): ConditionRule;
|
|
1276
|
+
|
|
1277
|
+
/**
|
|
1278
|
+
* Base properties shared by all workflow nodes
|
|
1279
|
+
*/
|
|
1280
|
+
interface BaseNode {
|
|
1281
|
+
/** Unique node identifier */
|
|
1282
|
+
id: string;
|
|
1283
|
+
}
|
|
1284
|
+
/**
|
|
1285
|
+
* Entry point of the workflow. Each workflow has exactly one StartNode.
|
|
1286
|
+
*/
|
|
1287
|
+
interface StartNode extends BaseNode {
|
|
1288
|
+
type: "start";
|
|
1289
|
+
/** ID of the next node to execute (optional for drafts) */
|
|
1290
|
+
next?: string | null;
|
|
1291
|
+
}
|
|
1292
|
+
/**
|
|
1293
|
+
* Form node for collecting user input.
|
|
1294
|
+
*
|
|
1295
|
+
* Each FormNode acts as a "step" or "page" in the workflow.
|
|
1296
|
+
* It can contain fields from multiple slots, allowing complex forms
|
|
1297
|
+
* that collect data for different objects.
|
|
1298
|
+
*
|
|
1299
|
+
* @example Simple mode (single slot, quick setup)
|
|
1300
|
+
* ```typescript
|
|
1301
|
+
* const node: FormNode = {
|
|
1302
|
+
* type: "form",
|
|
1303
|
+
* id: "client-info",
|
|
1304
|
+
* label: "Client Information",
|
|
1305
|
+
* fields: [
|
|
1306
|
+
* { slotId: "client", attribute: "firstName" },
|
|
1307
|
+
* { slotId: "client", attribute: "lastName" },
|
|
1308
|
+
* ],
|
|
1309
|
+
* next: "check-vip"
|
|
1310
|
+
* };
|
|
1311
|
+
* ```
|
|
1312
|
+
*
|
|
1313
|
+
* @example Advanced mode (multiple slots, custom layout)
|
|
1314
|
+
* ```typescript
|
|
1315
|
+
* const node: FormNode = {
|
|
1316
|
+
* type: "form",
|
|
1317
|
+
* id: "couple-info",
|
|
1318
|
+
* label: "Couple Information",
|
|
1319
|
+
* rows: [
|
|
1320
|
+
* { id: "row-1", order: 1, fields: [
|
|
1321
|
+
* { id: "f1", slotId: "mr", attribute: "firstName" },
|
|
1322
|
+
* { id: "f2", slotId: "mme", attribute: "firstName" },
|
|
1323
|
+
* ]},
|
|
1324
|
+
* { id: "row-2", order: 2, fields: [
|
|
1325
|
+
* { id: "f3", slotId: "company", attribute: "name" },
|
|
1326
|
+
* ]},
|
|
1327
|
+
* ],
|
|
1328
|
+
* next: "check-vip"
|
|
1329
|
+
* };
|
|
1330
|
+
* ```
|
|
1331
|
+
*/
|
|
1332
|
+
interface FormNode extends BaseNode {
|
|
1333
|
+
type: "form";
|
|
1334
|
+
/** Display label for the form step */
|
|
1335
|
+
label: string;
|
|
1336
|
+
/** Optional description */
|
|
1337
|
+
description?: string;
|
|
1338
|
+
/**
|
|
1339
|
+
* Simple mode: list of field references.
|
|
1340
|
+
* Each field specifies the slot and attribute.
|
|
1341
|
+
* Creates one field per row with equal width.
|
|
1342
|
+
* Mutually exclusive with `rows`.
|
|
1343
|
+
*/
|
|
1344
|
+
fields?: FormFieldRef[];
|
|
1345
|
+
/**
|
|
1346
|
+
* Advanced mode: full row/field structure for custom layouts.
|
|
1347
|
+
* Each row can contain multiple fields from different slots.
|
|
1348
|
+
* Mutually exclusive with `fields`.
|
|
1349
|
+
*/
|
|
1350
|
+
rows?: FlowRow[];
|
|
1351
|
+
/**
|
|
1352
|
+
* ID of the participant template allowed to fill this form.
|
|
1353
|
+
* If set, only this participant can execute this node.
|
|
1354
|
+
*/
|
|
1355
|
+
participantId?: string | null;
|
|
1356
|
+
/** ID of the next node to execute (optional for drafts) */
|
|
1357
|
+
next?: string | null;
|
|
1358
|
+
}
|
|
1359
|
+
/**
|
|
1360
|
+
* Simple field reference for FormNode simple mode
|
|
1361
|
+
*/
|
|
1362
|
+
interface FormFieldRef {
|
|
1363
|
+
/** Reference to WorkflowSlot.id */
|
|
1364
|
+
slotId: string;
|
|
1365
|
+
/** Attribute name on the object */
|
|
1366
|
+
attribute: string;
|
|
1367
|
+
/** Relation-specific config (only for relation attributes) */
|
|
1368
|
+
relationConfig?: RelationFieldConfig;
|
|
1369
|
+
}
|
|
1370
|
+
/**
|
|
1371
|
+
* Check if a FormNode uses simple mode (fields array)
|
|
1372
|
+
*/
|
|
1373
|
+
declare function isSimpleFormNode(node: FormNode): boolean;
|
|
1374
|
+
/**
|
|
1375
|
+
* Check if a FormNode uses advanced mode (rows array)
|
|
1376
|
+
*/
|
|
1377
|
+
declare function isAdvancedFormNode(node: FormNode): boolean;
|
|
1378
|
+
|
|
1379
|
+
/**
|
|
1380
|
+
* Conditional branching node.
|
|
1381
|
+
* Evaluates a condition and routes to different nodes based on the result.
|
|
1382
|
+
*
|
|
1383
|
+
* @example
|
|
1384
|
+
* ```typescript
|
|
1385
|
+
* const node: ConditionNode = {
|
|
1386
|
+
* type: "condition",
|
|
1387
|
+
* id: "check-vip",
|
|
1388
|
+
* label: "Is VIP Customer?",
|
|
1389
|
+
* condition: {
|
|
1390
|
+
* operator: "or",
|
|
1391
|
+
* rules: [
|
|
1392
|
+
* { field: "slots.client.type", operator: "eq", value: "vip" },
|
|
1393
|
+
* { field: "slots.client.type", operator: "eq", value: "premium" }
|
|
1394
|
+
* ]
|
|
1395
|
+
* },
|
|
1396
|
+
* onTrue: "premium-flow",
|
|
1397
|
+
* onFalse: "standard-flow"
|
|
1398
|
+
* };
|
|
1399
|
+
* ```
|
|
1400
|
+
*/
|
|
1401
|
+
interface ConditionNode extends BaseNode {
|
|
1402
|
+
type: "condition";
|
|
1403
|
+
/** Display label for the condition */
|
|
1404
|
+
label: string;
|
|
1405
|
+
/** Condition to evaluate */
|
|
1406
|
+
condition: ConditionGroup;
|
|
1407
|
+
/** ID of node to execute if condition is true (optional for drafts) */
|
|
1408
|
+
onTrue?: string | null;
|
|
1409
|
+
/** ID of node to execute if condition is false (optional for drafts) */
|
|
1410
|
+
onFalse?: string | null;
|
|
1411
|
+
}
|
|
1412
|
+
/**
|
|
1413
|
+
* Source for an assignment value.
|
|
1414
|
+
*
|
|
1415
|
+
* - `expression`: mustache template resolved at execution (text-like attrs only).
|
|
1416
|
+
* Uses `{{ slotId.attribute }}` dot notation, resolved via `renderLabelExpression`.
|
|
1417
|
+
* - `slot-ref`: reference to a slot's record for relation attributes.
|
|
1418
|
+
* Resolved at persistence time via `$slot:slotId` placeholder.
|
|
1419
|
+
* - `static`: fixed value set directly.
|
|
1420
|
+
*/
|
|
1421
|
+
type AssignmentSource = {
|
|
1422
|
+
type: "expression";
|
|
1423
|
+
template: string;
|
|
1424
|
+
} | {
|
|
1425
|
+
type: "slot-ref";
|
|
1426
|
+
slotId: string;
|
|
1427
|
+
properties?: Record<string, unknown>;
|
|
1428
|
+
} | {
|
|
1429
|
+
type: "static";
|
|
1430
|
+
value: unknown;
|
|
1431
|
+
};
|
|
1432
|
+
/**
|
|
1433
|
+
* Single assignment: set one attribute on the target slot.
|
|
1434
|
+
*/
|
|
1435
|
+
interface AssignmentMapping {
|
|
1436
|
+
/** Attribute name on the target slot's object */
|
|
1437
|
+
targetAttribute: string;
|
|
1438
|
+
/** Source of the value */
|
|
1439
|
+
source: AssignmentSource;
|
|
1440
|
+
}
|
|
1441
|
+
/**
|
|
1442
|
+
* Assign node: set values on a target slot's record.
|
|
1443
|
+
* All assignments target the same slot, selected at the node level.
|
|
1444
|
+
*
|
|
1445
|
+
* @example
|
|
1446
|
+
* ```typescript
|
|
1447
|
+
* const node: AssignNode = {
|
|
1448
|
+
* type: "assign",
|
|
1449
|
+
* id: "assign-client-data",
|
|
1450
|
+
* label: "Set Client Data",
|
|
1451
|
+
* targetSlotId: "client",
|
|
1452
|
+
* assignments: [
|
|
1453
|
+
* { targetAttribute: "company", source: { type: "slot-ref", slotId: "company" } },
|
|
1454
|
+
* { targetAttribute: "fullName", source: { type: "expression", template: "{{ client.firstName }} {{ client.lastName }}" } },
|
|
1455
|
+
* { targetAttribute: "status", source: { type: "static", value: "active" } },
|
|
1456
|
+
* ],
|
|
1457
|
+
* next: "end"
|
|
1458
|
+
* };
|
|
1459
|
+
* ```
|
|
1460
|
+
*/
|
|
1461
|
+
interface AssignNode extends BaseNode {
|
|
1462
|
+
type: "assign";
|
|
1463
|
+
label: string;
|
|
1464
|
+
description?: string;
|
|
1465
|
+
/** Single target slot for all assignments */
|
|
1466
|
+
targetSlotId: string;
|
|
1467
|
+
/** List of attribute assignments */
|
|
1468
|
+
assignments: AssignmentMapping[];
|
|
1469
|
+
next?: string | null;
|
|
1470
|
+
}
|
|
1471
|
+
/**
|
|
1472
|
+
* AI action config — discriminated union for different AI capabilities.
|
|
1473
|
+
*
|
|
1474
|
+
* @example Document generation
|
|
1475
|
+
* ```typescript
|
|
1476
|
+
* const action: AIActionConfig = {
|
|
1477
|
+
* type: "document-generation",
|
|
1478
|
+
* templateId: "template-contract-v1",
|
|
1479
|
+
* inputSlotIds: ["client", "company"],
|
|
1480
|
+
* targetSlotIds: ["client"],
|
|
1481
|
+
* outputFormat: "pdf",
|
|
1482
|
+
* aiInstructions: "Generate a professional contract",
|
|
1483
|
+
* };
|
|
1484
|
+
* ```
|
|
1485
|
+
*/
|
|
1486
|
+
type AIActionConfig = DocumentGenerationAction | CodeExecutionAction;
|
|
1487
|
+
/**
|
|
1488
|
+
* AI action type discriminant
|
|
1489
|
+
*/
|
|
1490
|
+
type AIActionType = AIActionConfig["type"];
|
|
1491
|
+
/**
|
|
1492
|
+
* Generate a document (PDF/DOCX) from a template using an AI agent session.
|
|
1493
|
+
*/
|
|
1494
|
+
interface DocumentGenerationAction {
|
|
1495
|
+
type: "document-generation";
|
|
1496
|
+
/** File ID of the uploaded DOCX template in storage */
|
|
1497
|
+
templateId: string;
|
|
1498
|
+
/** Slots whose data is context for the AI */
|
|
1499
|
+
inputSlotIds: string[];
|
|
1500
|
+
/** Slots to attach the generated document to */
|
|
1501
|
+
targetSlotIds: string[];
|
|
1502
|
+
/** Output format */
|
|
1503
|
+
outputFormat: "pdf" | "docx";
|
|
1504
|
+
/** Instructions for the AI agent on how to generate content */
|
|
1505
|
+
aiInstructions?: string;
|
|
1506
|
+
}
|
|
1507
|
+
/**
|
|
1508
|
+
* Execute code in a sandbox without AI (mode "code").
|
|
1509
|
+
*/
|
|
1510
|
+
interface CodeExecutionAction {
|
|
1511
|
+
type: "code-execution";
|
|
1512
|
+
/** Code to execute (may contain Mustache expressions resolved from slots) */
|
|
1513
|
+
code: string;
|
|
1514
|
+
language: "javascript" | "typescript" | "python";
|
|
1515
|
+
/** Slots injected as JSON environment variables */
|
|
1516
|
+
inputSlotIds?: string[];
|
|
1517
|
+
/** Variable name to capture stdout into the execution context */
|
|
1518
|
+
outputVariable?: string;
|
|
1519
|
+
/** Packages to install before execution */
|
|
1520
|
+
packages?: string[];
|
|
1521
|
+
}
|
|
1522
|
+
/**
|
|
1523
|
+
* AI node — runs an AI action (document generation, code execution, etc.)
|
|
1524
|
+
*
|
|
1525
|
+
* @example
|
|
1526
|
+
* ```typescript
|
|
1527
|
+
* const node: AINode = {
|
|
1528
|
+
* type: "ai",
|
|
1529
|
+
* id: "generate-contract",
|
|
1530
|
+
* label: "Generate Contract",
|
|
1531
|
+
* action: {
|
|
1532
|
+
* type: "document-generation",
|
|
1533
|
+
* templateId: "template-contract-v1",
|
|
1534
|
+
* inputSlotIds: ["client", "company"],
|
|
1535
|
+
* targetSlotIds: ["client"],
|
|
1536
|
+
* outputFormat: "pdf",
|
|
1537
|
+
* },
|
|
1538
|
+
* next: "end-success",
|
|
1539
|
+
* };
|
|
1540
|
+
* ```
|
|
1541
|
+
*/
|
|
1542
|
+
interface AINode extends BaseNode {
|
|
1543
|
+
type: "ai";
|
|
1544
|
+
label: string;
|
|
1545
|
+
description?: string;
|
|
1546
|
+
action: AIActionConfig;
|
|
1547
|
+
/** Timeout in milliseconds (default: 120_000) */
|
|
1548
|
+
timeoutMs?: number;
|
|
1549
|
+
next?: string | null;
|
|
1550
|
+
}
|
|
1551
|
+
/**
|
|
1552
|
+
* Terminal node marking the end of a workflow path.
|
|
1553
|
+
* A workflow can have multiple EndNodes for different outcomes.
|
|
1554
|
+
*
|
|
1555
|
+
* @example
|
|
1556
|
+
* ```typescript
|
|
1557
|
+
* const successEnd: EndNode = {
|
|
1558
|
+
* type: "end",
|
|
1559
|
+
* id: "end-success",
|
|
1560
|
+
* label: "Completed Successfully",
|
|
1561
|
+
* status: "completed"
|
|
1562
|
+
* };
|
|
1563
|
+
*
|
|
1564
|
+
* const declinedEnd: EndNode = {
|
|
1565
|
+
* type: "end",
|
|
1566
|
+
* id: "end-declined",
|
|
1567
|
+
* label: "Customer Declined",
|
|
1568
|
+
* status: "declined"
|
|
1569
|
+
* };
|
|
1570
|
+
* ```
|
|
1571
|
+
*/
|
|
1572
|
+
interface EndNode extends BaseNode {
|
|
1573
|
+
type: "end";
|
|
1574
|
+
/** Optional display label */
|
|
1575
|
+
label?: string;
|
|
1576
|
+
/**
|
|
1577
|
+
* Final status for the workflow instance.
|
|
1578
|
+
* Common values: "completed", "declined", "cancelled", "expired"
|
|
1579
|
+
*/
|
|
1580
|
+
status?: string;
|
|
1581
|
+
}
|
|
1582
|
+
/**
|
|
1583
|
+
* Union of all workflow node types.
|
|
1584
|
+
* Use discriminated union on `type` field for type narrowing.
|
|
1585
|
+
*/
|
|
1586
|
+
type WorkflowNode = StartNode | FormNode | ConditionNode | AssignNode | AINode | EndNode;
|
|
1587
|
+
/**
|
|
1588
|
+
* All possible node types
|
|
1589
|
+
*/
|
|
1590
|
+
type WorkflowNodeType = WorkflowNode["type"];
|
|
1591
|
+
/**
|
|
1592
|
+
* Check if a node is a StartNode
|
|
1593
|
+
*/
|
|
1594
|
+
declare function isStartNode(node: WorkflowNode): node is StartNode;
|
|
1595
|
+
/**
|
|
1596
|
+
* Check if a node is a FormNode
|
|
1597
|
+
*/
|
|
1598
|
+
declare function isFormNode(node: WorkflowNode): node is FormNode;
|
|
1599
|
+
/**
|
|
1600
|
+
* Check if a node is a ConditionNode
|
|
1601
|
+
*/
|
|
1602
|
+
declare function isConditionNode(node: WorkflowNode): node is ConditionNode;
|
|
1603
|
+
/**
|
|
1604
|
+
* Check if a node is an AssignNode
|
|
1605
|
+
*/
|
|
1606
|
+
declare function isAssignNode(node: WorkflowNode): node is AssignNode;
|
|
1607
|
+
/**
|
|
1608
|
+
* Check if a node is an AINode
|
|
1609
|
+
*/
|
|
1610
|
+
declare function isAINode(node: WorkflowNode): node is AINode;
|
|
1611
|
+
/**
|
|
1612
|
+
* Check if a node is an EndNode
|
|
1613
|
+
*/
|
|
1614
|
+
declare function isEndNode(node: WorkflowNode): node is EndNode;
|
|
1615
|
+
|
|
1616
|
+
/**
|
|
1617
|
+
* Logo configuration for external-facing interface
|
|
1618
|
+
*/
|
|
1619
|
+
interface ThemeLogo {
|
|
1620
|
+
/** URL to the logo image */
|
|
1621
|
+
url: string;
|
|
1622
|
+
/** Alt text for accessibility */
|
|
1623
|
+
alt?: string;
|
|
1624
|
+
/** Max height in pixels */
|
|
1625
|
+
maxHeight?: number;
|
|
1626
|
+
}
|
|
1627
|
+
/**
|
|
1628
|
+
* Color configuration for theming
|
|
1629
|
+
*/
|
|
1630
|
+
interface ThemeColors {
|
|
1631
|
+
/** Primary brand color (hex) */
|
|
1632
|
+
primary?: string;
|
|
1633
|
+
/** Primary color for text on primary background */
|
|
1634
|
+
primaryForeground?: string;
|
|
1635
|
+
/** Background color */
|
|
1636
|
+
background?: string;
|
|
1637
|
+
/** Foreground/text color */
|
|
1638
|
+
foreground?: string;
|
|
1639
|
+
/** Muted/secondary color */
|
|
1640
|
+
muted?: string;
|
|
1641
|
+
/** Border color */
|
|
1642
|
+
border?: string;
|
|
1643
|
+
/** Accent color for highlights */
|
|
1644
|
+
accent?: string;
|
|
1645
|
+
}
|
|
1646
|
+
/**
|
|
1647
|
+
* Typography configuration
|
|
1648
|
+
*/
|
|
1649
|
+
interface ThemeTypography {
|
|
1650
|
+
/** Font family for headings */
|
|
1651
|
+
headingFont?: string;
|
|
1652
|
+
/** Font family for body text */
|
|
1653
|
+
bodyFont?: string;
|
|
1654
|
+
/** Base font size in pixels */
|
|
1655
|
+
baseFontSize?: number;
|
|
1656
|
+
}
|
|
1657
|
+
/**
|
|
1658
|
+
* Complete theme configuration for external-facing workflow interface.
|
|
1659
|
+
*
|
|
1660
|
+
* Allows full branding customization for forms displayed to external users.
|
|
1661
|
+
*
|
|
1662
|
+
* @example
|
|
1663
|
+
* ```typescript
|
|
1664
|
+
* const theme: WorkflowTheme = {
|
|
1665
|
+
* logo: {
|
|
1666
|
+
* url: "https://example.com/logo.png",
|
|
1667
|
+
* alt: "Company Logo",
|
|
1668
|
+
* maxHeight: 48
|
|
1669
|
+
* },
|
|
1670
|
+
* colors: {
|
|
1671
|
+
* primary: "#3B82F6",
|
|
1672
|
+
* primaryForeground: "#FFFFFF",
|
|
1673
|
+
* background: "#F8FAFC"
|
|
1674
|
+
* },
|
|
1675
|
+
* typography: {
|
|
1676
|
+
* headingFont: "Inter, sans-serif",
|
|
1677
|
+
* bodyFont: "Inter, sans-serif"
|
|
1678
|
+
* },
|
|
1679
|
+
* borderRadius: 8
|
|
1680
|
+
* };
|
|
1681
|
+
* ```
|
|
1682
|
+
*/
|
|
1683
|
+
interface WorkflowTheme {
|
|
1684
|
+
/** Logo configuration */
|
|
1685
|
+
logo?: ThemeLogo;
|
|
1686
|
+
/** Color palette */
|
|
1687
|
+
colors?: ThemeColors;
|
|
1688
|
+
/** Typography settings */
|
|
1689
|
+
typography?: ThemeTypography;
|
|
1690
|
+
/** Border radius for cards/buttons in pixels */
|
|
1691
|
+
borderRadius?: number;
|
|
1692
|
+
/** Show powered by badge */
|
|
1693
|
+
showPoweredBy?: boolean;
|
|
1694
|
+
/** Custom CSS (advanced) */
|
|
1695
|
+
customCss?: string;
|
|
1696
|
+
}
|
|
1697
|
+
/**
|
|
1698
|
+
* Default theme values
|
|
1699
|
+
*/
|
|
1700
|
+
declare const DEFAULT_THEME: Required<Pick<WorkflowTheme, "borderRadius" | "showPoweredBy">>;
|
|
1701
|
+
/**
|
|
1702
|
+
* Merge a partial theme with defaults
|
|
1703
|
+
*/
|
|
1704
|
+
declare function mergeWithDefaults(theme?: WorkflowTheme): WorkflowTheme;
|
|
1705
|
+
/**
|
|
1706
|
+
* Generate CSS variables from theme colors
|
|
1707
|
+
*/
|
|
1708
|
+
declare function generateCssVariables(colors?: ThemeColors): Record<string, string>;
|
|
1709
|
+
|
|
1710
|
+
/**
|
|
1711
|
+
* Mode for slot initialization when starting a workflow
|
|
1712
|
+
*/
|
|
1713
|
+
type SlotMode = "create" | "select" | "optional" | "create_if_not_empty";
|
|
1714
|
+
/**
|
|
1715
|
+
* Represents a "slot" for an object in the workflow.
|
|
1716
|
+
* Slots define which objects are manipulated during workflow execution.
|
|
1717
|
+
*
|
|
1718
|
+
* @example
|
|
1719
|
+
* ```typescript
|
|
1720
|
+
* const clientSlot: WorkflowSlot = {
|
|
1721
|
+
* id: "client",
|
|
1722
|
+
* objectName: "contacts",
|
|
1723
|
+
* label: "Client",
|
|
1724
|
+
* mode: "optional",
|
|
1725
|
+
* color: "blue",
|
|
1726
|
+
* icon: "User"
|
|
1727
|
+
* };
|
|
1728
|
+
* ```
|
|
1729
|
+
*/
|
|
1730
|
+
interface WorkflowSlot {
|
|
1731
|
+
/** Unique identifier for the slot */
|
|
1732
|
+
id: string;
|
|
1733
|
+
/** Name of the object definition (e.g., "contacts", "companies") */
|
|
1734
|
+
objectName: string;
|
|
1735
|
+
/** Display label */
|
|
1736
|
+
label: string;
|
|
1737
|
+
/** How the slot is initialized at workflow start */
|
|
1738
|
+
mode: SlotMode;
|
|
1739
|
+
/** Color for visual distinction in the builder */
|
|
1740
|
+
color?: ColorId;
|
|
1741
|
+
/** Optional icon */
|
|
1742
|
+
icon?: IconName;
|
|
1743
|
+
/** Resolved object label (set by the backend in form context responses) */
|
|
1744
|
+
objectLabel?: string;
|
|
1745
|
+
}
|
|
1746
|
+
/**
|
|
1747
|
+
* Position of a node in the visual builder
|
|
1748
|
+
*/
|
|
1749
|
+
interface NodePosition {
|
|
1750
|
+
x: number;
|
|
1751
|
+
y: number;
|
|
1752
|
+
}
|
|
1753
|
+
/**
|
|
1754
|
+
* Viewport state for the canvas
|
|
1755
|
+
*/
|
|
1756
|
+
interface CanvasViewport {
|
|
1757
|
+
x: number;
|
|
1758
|
+
y: number;
|
|
1759
|
+
zoom: number;
|
|
1760
|
+
}
|
|
1761
|
+
/**
|
|
1762
|
+
* Layout information for the workflow builder.
|
|
1763
|
+
* Separated from business data to allow different visualizations.
|
|
1764
|
+
*/
|
|
1765
|
+
interface WorkflowLayout {
|
|
1766
|
+
/** Node positions by node ID */
|
|
1767
|
+
positions: Record<string, NodePosition>;
|
|
1768
|
+
/** Canvas viewport state */
|
|
1769
|
+
viewport?: CanvasViewport;
|
|
1770
|
+
}
|
|
1771
|
+
/**
|
|
1772
|
+
* Global configuration options for a workflow
|
|
1773
|
+
*/
|
|
1774
|
+
interface WorkflowConfig {
|
|
1775
|
+
/** Time-to-live for workflow instances (e.g., "30d") */
|
|
1776
|
+
instanceTtl?: string;
|
|
1777
|
+
/** Time-to-live for external participation links (e.g., "7d") */
|
|
1778
|
+
externalLinkTtl?: string;
|
|
1779
|
+
/** Whether external participants are allowed */
|
|
1780
|
+
allowExternalParticipants?: boolean;
|
|
1781
|
+
}
|
|
1782
|
+
/**
|
|
1783
|
+
* Workflow lifecycle status
|
|
1784
|
+
*/
|
|
1785
|
+
type WorkflowStatus = "draft" | "published" | "archived";
|
|
1786
|
+
/**
|
|
1787
|
+
* Complete workflow definition (the "blueprint").
|
|
1788
|
+
*
|
|
1789
|
+
* This is the design-time representation of a workflow.
|
|
1790
|
+
* When executed, a WorkflowInstance is created from this definition.
|
|
1791
|
+
*
|
|
1792
|
+
* @example
|
|
1793
|
+
* ```typescript
|
|
1794
|
+
* const workflow: WorkflowDefinition = {
|
|
1795
|
+
* name: "client-onboarding",
|
|
1796
|
+
* label: "Client Onboarding",
|
|
1797
|
+
* status: "draft",
|
|
1798
|
+
* version: 1,
|
|
1799
|
+
* slots: [{ id: "client", objectName: "contacts", label: "Client", mode: "create" }],
|
|
1800
|
+
* nodes: {
|
|
1801
|
+
* "start": { type: "start", id: "start", next: "form-1" },
|
|
1802
|
+
* "form-1": { type: "form", id: "form-1", label: "Info", slotId: "client", fields: ["name"], next: "end" },
|
|
1803
|
+
* "end": { type: "end", id: "end" }
|
|
1804
|
+
* },
|
|
1805
|
+
* startNodeId: "start"
|
|
1806
|
+
* };
|
|
1807
|
+
* ```
|
|
1808
|
+
*/
|
|
1809
|
+
interface WorkflowDefinition {
|
|
1810
|
+
/** Database ID */
|
|
1811
|
+
id?: Uuid;
|
|
1812
|
+
/** Technical name (kebab-case, unique per tenant) */
|
|
1813
|
+
name: string;
|
|
1814
|
+
/** Display label */
|
|
1815
|
+
label: string;
|
|
1816
|
+
/** Optional description */
|
|
1817
|
+
description?: string;
|
|
1818
|
+
/** Optional icon */
|
|
1819
|
+
icon?: IconName;
|
|
1820
|
+
/** Workflow lifecycle status */
|
|
1821
|
+
status: WorkflowStatus;
|
|
1822
|
+
/** Version number (incremented on publish) */
|
|
1823
|
+
version: number;
|
|
1824
|
+
/** Slots (objects) manipulated in this workflow */
|
|
1825
|
+
slots: WorkflowSlot[];
|
|
1826
|
+
/** Nodes indexed by ID for O(1) access */
|
|
1827
|
+
nodes: Record<string, WorkflowNode>;
|
|
1828
|
+
/** ID of the start node */
|
|
1829
|
+
startNodeId: string;
|
|
1830
|
+
/** Layout information for the visual builder (optional, used by legacy canvas) */
|
|
1831
|
+
layout?: WorkflowLayout;
|
|
1832
|
+
/** Theming for external-facing interface */
|
|
1833
|
+
theme?: WorkflowTheme;
|
|
1834
|
+
/** Global configuration options */
|
|
1835
|
+
config?: WorkflowConfig;
|
|
1836
|
+
/** Tenant ID for multi-tenant isolation */
|
|
1837
|
+
tenantId?: string;
|
|
1838
|
+
/** If true, defined in code (protected from UI deletion) */
|
|
1839
|
+
system?: boolean;
|
|
1840
|
+
/** Extensible metadata */
|
|
1841
|
+
metadata?: Record<string, unknown>;
|
|
1842
|
+
/** Timestamps */
|
|
1843
|
+
createdAt?: Date;
|
|
1844
|
+
updatedAt?: Date;
|
|
1845
|
+
}
|
|
1846
|
+
/**
|
|
1847
|
+
* Check if an object is a WorkflowDefinition
|
|
1848
|
+
*/
|
|
1849
|
+
declare function isWorkflowDefinition(obj: unknown): obj is WorkflowDefinition;
|
|
1850
|
+
/**
|
|
1851
|
+
* Check if a workflow is published
|
|
1852
|
+
*/
|
|
1853
|
+
declare function isWorkflowPublished(workflow: WorkflowDefinition): boolean;
|
|
1854
|
+
/**
|
|
1855
|
+
* Check if a workflow is a system workflow
|
|
1856
|
+
*/
|
|
1857
|
+
declare function isSystemWorkflow(workflow: WorkflowDefinition): boolean;
|
|
1858
|
+
|
|
1859
|
+
/**
|
|
1860
|
+
* Status of a workflow instance
|
|
1861
|
+
*/
|
|
1862
|
+
type InstanceStatus = "running" | "waiting" | "completed" | "failed" | "cancelled";
|
|
1863
|
+
/**
|
|
1864
|
+
* Record of a transition between nodes
|
|
1865
|
+
*/
|
|
1866
|
+
interface WorkflowTransition {
|
|
1867
|
+
/** Timestamp of the transition */
|
|
1868
|
+
timestamp: Date;
|
|
1869
|
+
/** ID of the source node */
|
|
1870
|
+
fromNodeId: string | null;
|
|
1871
|
+
/** ID of the target node */
|
|
1872
|
+
toNodeId: string;
|
|
1873
|
+
/** Type of the target node */
|
|
1874
|
+
nodeType: string;
|
|
1875
|
+
/** ID of the user/participant who triggered the transition */
|
|
1876
|
+
triggeredBy?: string;
|
|
1877
|
+
/** Duration of node execution in milliseconds */
|
|
1878
|
+
durationMs?: number;
|
|
1879
|
+
/** Metadata about the transition */
|
|
1880
|
+
metadata?: Record<string, unknown>;
|
|
1881
|
+
}
|
|
1882
|
+
/**
|
|
1883
|
+
* Error information when instance is in "failed" status
|
|
1884
|
+
*/
|
|
1885
|
+
interface WorkflowError {
|
|
1886
|
+
/** Error code for programmatic handling */
|
|
1887
|
+
code: string;
|
|
1888
|
+
/** Human-readable error message */
|
|
1889
|
+
message: string;
|
|
1890
|
+
/** ID of the node where error occurred */
|
|
1891
|
+
nodeId?: string;
|
|
1892
|
+
/** Stack trace (if available) */
|
|
1893
|
+
stack?: string;
|
|
1894
|
+
/** Additional error details */
|
|
1895
|
+
details?: Record<string, unknown>;
|
|
1896
|
+
/** Timestamp when error occurred */
|
|
1897
|
+
timestamp: Date;
|
|
1898
|
+
}
|
|
1899
|
+
/**
|
|
1900
|
+
* Information about the action the workflow is waiting for.
|
|
1901
|
+
* Populated when status is "waiting".
|
|
1902
|
+
*/
|
|
1903
|
+
interface PendingAction {
|
|
1904
|
+
/** ID of the node waiting for action */
|
|
1905
|
+
nodeId: string;
|
|
1906
|
+
/** Type of the waiting node */
|
|
1907
|
+
nodeType: "form" | "signature" | "approval";
|
|
1908
|
+
/** Display label for the action */
|
|
1909
|
+
nodeLabel: string;
|
|
1910
|
+
/** ID of the participation required to complete this action */
|
|
1911
|
+
requiredParticipationId?: string;
|
|
1912
|
+
/** When the pending action expires */
|
|
1913
|
+
expiresAt?: Date;
|
|
1914
|
+
}
|
|
1915
|
+
/**
|
|
1916
|
+
* A specific execution of a workflow.
|
|
1917
|
+
*
|
|
1918
|
+
* Each instance maintains its own state, context, and history.
|
|
1919
|
+
* The workflow definition is snapshotted at creation to ensure
|
|
1920
|
+
* consistent execution even if the definition is later modified.
|
|
1921
|
+
*
|
|
1922
|
+
* @example
|
|
1923
|
+
* ```typescript
|
|
1924
|
+
* const instance: WorkflowInstance = {
|
|
1925
|
+
* id: "inst_123",
|
|
1926
|
+
* workflowId: "wf_456",
|
|
1927
|
+
* workflowVersion: 3,
|
|
1928
|
+
* workflowSnapshot: { ... }, // Full definition at creation time
|
|
1929
|
+
* status: "waiting",
|
|
1930
|
+
* currentNodeId: "client-form",
|
|
1931
|
+
* context: { slots: {}, forms: {}, documents: {}, variables: {}, conditionResults: {} },
|
|
1932
|
+
* history: [{ timestamp: new Date(), fromNodeId: null, toNodeId: "start", nodeType: "start" }],
|
|
1933
|
+
* pendingAction: {
|
|
1934
|
+
* nodeId: "client-form",
|
|
1935
|
+
* nodeType: "form",
|
|
1936
|
+
* nodeLabel: "Client Information",
|
|
1937
|
+
* requiredParticipationId: "part_789"
|
|
1938
|
+
* },
|
|
1939
|
+
* startedBy: "user_001",
|
|
1940
|
+
* tenantId: "tenant_abc",
|
|
1941
|
+
* createdAt: new Date()
|
|
1942
|
+
* };
|
|
1943
|
+
* ```
|
|
1944
|
+
*/
|
|
1945
|
+
interface WorkflowInstance {
|
|
1946
|
+
/** Unique instance ID */
|
|
1947
|
+
id: Uuid;
|
|
1948
|
+
/** Reference to the workflow definition */
|
|
1949
|
+
workflowId: Uuid;
|
|
1950
|
+
/** Version of the workflow at creation time */
|
|
1951
|
+
workflowVersion: number;
|
|
1952
|
+
/** Complete snapshot of the workflow definition */
|
|
1953
|
+
workflowSnapshot: WorkflowDefinition;
|
|
1954
|
+
/** Current execution status */
|
|
1955
|
+
status: InstanceStatus;
|
|
1956
|
+
/** ID of the current node */
|
|
1957
|
+
currentNodeId: string;
|
|
1958
|
+
/** Accumulated execution context */
|
|
1959
|
+
context: WorkflowExecutionContext;
|
|
1960
|
+
/** History of node transitions */
|
|
1961
|
+
history: WorkflowTransition[];
|
|
1962
|
+
/** Current pending action (when status is "waiting") */
|
|
1963
|
+
pendingAction?: PendingAction;
|
|
1964
|
+
/** Error information (when status is "failed") */
|
|
1965
|
+
error?: WorkflowError;
|
|
1966
|
+
/** ID of the user who started the workflow */
|
|
1967
|
+
startedBy: string;
|
|
1968
|
+
/** Tenant ID for multi-tenant isolation */
|
|
1969
|
+
tenantId: string;
|
|
1970
|
+
/** When the instance expires */
|
|
1971
|
+
expiresAt?: Date;
|
|
1972
|
+
/** Timestamps */
|
|
1973
|
+
createdAt: Date;
|
|
1974
|
+
updatedAt: Date;
|
|
1975
|
+
completedAt?: Date;
|
|
1976
|
+
}
|
|
1977
|
+
/**
|
|
1978
|
+
* Check if an instance is in a terminal state
|
|
1979
|
+
*/
|
|
1980
|
+
declare function isInstanceTerminal(instance: WorkflowInstance): boolean;
|
|
1981
|
+
/**
|
|
1982
|
+
* Check if an instance is waiting for external action
|
|
1983
|
+
*/
|
|
1984
|
+
declare function isInstanceWaiting(instance: WorkflowInstance): boolean;
|
|
1985
|
+
/**
|
|
1986
|
+
* Check if an instance can be resumed
|
|
1987
|
+
*/
|
|
1988
|
+
declare function canResumeInstance(instance: WorkflowInstance): boolean;
|
|
1989
|
+
/**
|
|
1990
|
+
* Create initial transition record for workflow start
|
|
1991
|
+
*/
|
|
1992
|
+
declare function createStartTransition(startNodeId: string, startedBy: string): WorkflowTransition;
|
|
1993
|
+
|
|
1994
|
+
/**
|
|
1995
|
+
* Type of view - determines the config structure
|
|
1996
|
+
*/
|
|
1997
|
+
type ViewType = "detail" | "list" | "calendar" | "timeline" | "gallery";
|
|
1998
|
+
/**
|
|
1999
|
+
* Creation behavior when clicking the "+" button
|
|
2000
|
+
* - `redirect`: Create the record then navigate to its detail page
|
|
2001
|
+
* - `inline`: Insert an empty row in the table (no navigation)
|
|
2002
|
+
* - `modal`: Open a stacked modal for creation
|
|
2003
|
+
*/
|
|
2004
|
+
type CreateMode = "redirect" | "inline" | "modal";
|
|
2005
|
+
/**
|
|
2006
|
+
* Inline attribute group configuration
|
|
2007
|
+
* Groups multiple attributes into a single composite field with dropdown editing
|
|
2008
|
+
*/
|
|
2009
|
+
interface AttributeGroupField {
|
|
2010
|
+
/** Unique identifier for the group */
|
|
2011
|
+
id: string;
|
|
2012
|
+
/** Display label for the composite field */
|
|
2013
|
+
label: string;
|
|
2014
|
+
/** Description shown in the dropdown */
|
|
2015
|
+
description?: string;
|
|
2016
|
+
/** Attribute names to include in this group */
|
|
2017
|
+
attributes: string[];
|
|
2018
|
+
/**
|
|
2019
|
+
* Template for the display value
|
|
2020
|
+
* Uses {attributeName} syntax for interpolation
|
|
2021
|
+
* @example "{billing_street}, {billing_city} {billing_postal_code}"
|
|
2022
|
+
*/
|
|
2023
|
+
displayTemplate?: string;
|
|
2024
|
+
}
|
|
2025
|
+
/**
|
|
2026
|
+
* Field definition within a form group
|
|
2027
|
+
* Can be either a single attribute or an inline attribute group
|
|
2028
|
+
*/
|
|
2029
|
+
interface Field {
|
|
2030
|
+
/** Attribute name to display (for single attribute fields) */
|
|
2031
|
+
attribute?: string;
|
|
2032
|
+
/** Inline attribute group (groups multiple attributes into one composite field) */
|
|
2033
|
+
attributeGroup?: AttributeGroupField;
|
|
2034
|
+
/** Grid span (1-12 columns) */
|
|
2035
|
+
span?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
|
|
2036
|
+
/** Override label for this view (only for single attribute fields) */
|
|
2037
|
+
label?: string;
|
|
2038
|
+
/** Force read-only display */
|
|
2039
|
+
readOnly?: boolean;
|
|
2040
|
+
}
|
|
2041
|
+
/**
|
|
2042
|
+
* Base properties shared by all group types
|
|
2043
|
+
*/
|
|
2044
|
+
interface BaseGroup {
|
|
2045
|
+
id: string;
|
|
2046
|
+
label: string;
|
|
2047
|
+
description?: string;
|
|
2048
|
+
collapsible?: boolean;
|
|
2049
|
+
collapsed?: boolean;
|
|
2050
|
+
order?: number;
|
|
2051
|
+
}
|
|
2052
|
+
/**
|
|
2053
|
+
* Group of fields for organizing forms (default group type)
|
|
2054
|
+
*/
|
|
2055
|
+
interface FieldGroup extends BaseGroup {
|
|
2056
|
+
/** Discriminant — optional for backward compatibility with existing data */
|
|
2057
|
+
type?: "fields";
|
|
2058
|
+
fields: Field[];
|
|
2059
|
+
}
|
|
2060
|
+
/**
|
|
2061
|
+
* Group that displays related records for a relation attribute
|
|
2062
|
+
*/
|
|
2063
|
+
interface RelationGroup extends BaseGroup {
|
|
2064
|
+
type: "relation";
|
|
2065
|
+
/** Relation attribute name on the source object */
|
|
2066
|
+
attribute: string;
|
|
2067
|
+
/** Columns to display (auto-detected from target object if empty) */
|
|
2068
|
+
columns?: string[];
|
|
2069
|
+
/** Read-only mode */
|
|
2070
|
+
readOnly?: boolean;
|
|
2071
|
+
/** Allow creating new related records */
|
|
2072
|
+
allowCreate?: boolean;
|
|
2073
|
+
/**
|
|
2074
|
+
* Two-level traversal — display records from the target's relation.
|
|
2075
|
+
* When set, parent rows become grouping headers and the sub-rows
|
|
2076
|
+
* (from `through.attribute`) are the primary display.
|
|
2077
|
+
*
|
|
2078
|
+
* @example attribute = "members", through.attribute = "companies"
|
|
2079
|
+
* → displays companies of each member
|
|
2080
|
+
*/
|
|
2081
|
+
through?: {
|
|
2082
|
+
/** Relation attribute on the first-level target object */
|
|
2083
|
+
attribute: string;
|
|
2084
|
+
};
|
|
2085
|
+
}
|
|
2086
|
+
/**
|
|
2087
|
+
* Discriminated union of all group types
|
|
2088
|
+
*/
|
|
2089
|
+
type Group = FieldGroup | RelationGroup;
|
|
2090
|
+
type TabType = "form" | "table" | "custom" | "activity" | "richtext" | "flows" | "documents";
|
|
2091
|
+
/**
|
|
2092
|
+
* Base properties shared by all tab types
|
|
2093
|
+
*/
|
|
2094
|
+
interface BaseTab {
|
|
2095
|
+
id: string;
|
|
2096
|
+
name: string;
|
|
2097
|
+
label: string;
|
|
2098
|
+
icon?: IconName;
|
|
2099
|
+
order?: number;
|
|
2100
|
+
}
|
|
2101
|
+
/**
|
|
2102
|
+
* Form layout density
|
|
2103
|
+
*/
|
|
2104
|
+
type FormDensity = "compact" | "comfortable" | "spacious";
|
|
2105
|
+
/**
|
|
2106
|
+
* Form tab - displays attributes organized in groups
|
|
2107
|
+
*/
|
|
2108
|
+
interface FormTab extends BaseTab {
|
|
2109
|
+
type: "form";
|
|
2110
|
+
groups: Group[];
|
|
2111
|
+
/** Number of grid columns (1, 2, or 3). Default: 2 */
|
|
2112
|
+
formColumns?: 1 | 2 | 3;
|
|
2113
|
+
/** Layout density. Default: "comfortable" */
|
|
2114
|
+
density?: FormDensity;
|
|
2115
|
+
}
|
|
2116
|
+
/**
|
|
2117
|
+
* Direct relation on the current object
|
|
2118
|
+
*
|
|
2119
|
+
* @example Contact.companies → shows Companies linked via the "companies" relation
|
|
2120
|
+
*/
|
|
2121
|
+
interface RelationSource {
|
|
2122
|
+
type: "relation";
|
|
2123
|
+
/** Relation attribute name on the current object */
|
|
2124
|
+
attribute: string;
|
|
2125
|
+
}
|
|
2126
|
+
/**
|
|
2127
|
+
* Inverse lookup — records from another object that point to us
|
|
2128
|
+
*
|
|
2129
|
+
* @example On Company, show Contacts where Contact.company = this Company
|
|
2130
|
+
*/
|
|
2131
|
+
interface InverseSource {
|
|
2132
|
+
type: "inverse";
|
|
2133
|
+
/** Object name that has the relation to us */
|
|
2134
|
+
object: string;
|
|
2135
|
+
/** Relation attribute name on the source object that points to us */
|
|
2136
|
+
attribute: string;
|
|
2137
|
+
}
|
|
2138
|
+
/**
|
|
2139
|
+
* Where table data comes from — either a direct relation or an inverse lookup
|
|
2140
|
+
*/
|
|
2141
|
+
type TableSource = RelationSource | InverseSource;
|
|
2142
|
+
/**
|
|
2143
|
+
* Table tab - displays related records in a table
|
|
2144
|
+
*
|
|
2145
|
+
* The `source` field determines where data comes from.
|
|
2146
|
+
*
|
|
2147
|
+
* @example Direct: source = { type: "relation", attribute: "members" }
|
|
2148
|
+
* @example Inverse: source = { type: "inverse", object: "contacts", attribute: "company" }
|
|
2149
|
+
*/
|
|
2150
|
+
interface TableTab extends BaseTab {
|
|
2151
|
+
type: "table";
|
|
2152
|
+
/** Where the data comes from */
|
|
2153
|
+
source: TableSource;
|
|
2154
|
+
/** Columns to display (attribute names from the resolved target object) */
|
|
2155
|
+
columns: string[];
|
|
2156
|
+
/**
|
|
2157
|
+
* Traverse a 2nd-level relation to display nested data.
|
|
2158
|
+
* When active, `columns` stores the 2nd-level object's attribute names.
|
|
2159
|
+
*
|
|
2160
|
+
* @example source.attribute = "members", through.attribute = "companies"
|
|
2161
|
+
* → displays companies of each member
|
|
2162
|
+
*/
|
|
2163
|
+
through?: {
|
|
2164
|
+
/** Relation attribute on the first-level target object */
|
|
2165
|
+
attribute: string;
|
|
2166
|
+
/** Show _source and _target columns */
|
|
2167
|
+
showSourceTarget?: boolean;
|
|
2168
|
+
};
|
|
2169
|
+
/** Allow creating new records */
|
|
2170
|
+
allowCreate?: boolean;
|
|
2171
|
+
/** Creation behavior when allowCreate is true. Default: "redirect" */
|
|
2172
|
+
createMode?: CreateMode;
|
|
2173
|
+
/** Allow inline editing */
|
|
2174
|
+
allowEdit?: boolean;
|
|
2175
|
+
/** Allow deleting records */
|
|
2176
|
+
allowDelete?: boolean;
|
|
2177
|
+
/** Default filters applied to the table */
|
|
2178
|
+
filters?: FilterState;
|
|
2179
|
+
/** Default sort rules */
|
|
2180
|
+
sorts?: SortRule[];
|
|
2181
|
+
}
|
|
2182
|
+
/**
|
|
2183
|
+
* Custom tab - renders a developer-defined component
|
|
2184
|
+
*/
|
|
2185
|
+
interface CustomTab extends BaseTab {
|
|
2186
|
+
type: "custom";
|
|
2187
|
+
/** Component identifier to render */
|
|
2188
|
+
component: string;
|
|
2189
|
+
/** Props to pass to the component */
|
|
2190
|
+
props?: Record<string, unknown>;
|
|
2191
|
+
}
|
|
2192
|
+
/**
|
|
2193
|
+
* Activity tab - displays activity feed for the current record
|
|
2194
|
+
*/
|
|
2195
|
+
interface ActivityTab extends BaseTab {
|
|
2196
|
+
type: "activity";
|
|
2197
|
+
limit?: number;
|
|
2198
|
+
}
|
|
2199
|
+
/**
|
|
2200
|
+
* Richtext tab - displays a block editor for a richtext attribute
|
|
2201
|
+
*/
|
|
2202
|
+
interface RichtextTab extends BaseTab {
|
|
2203
|
+
type: "richtext";
|
|
2204
|
+
/** Richtext attribute to display in the BlockEditor */
|
|
2205
|
+
attribute: string;
|
|
2206
|
+
/** Optional text attribute for an editable title input above the editor */
|
|
2207
|
+
titleAttribute?: string;
|
|
2208
|
+
}
|
|
2209
|
+
/**
|
|
2210
|
+
* Flows tab - displays workflow instances linked to the current record
|
|
2211
|
+
*/
|
|
2212
|
+
interface FlowsTab extends BaseTab {
|
|
2213
|
+
type: "flows";
|
|
2214
|
+
allowStart?: boolean;
|
|
2215
|
+
allowCancel?: boolean;
|
|
2216
|
+
statusFilter?: InstanceStatus[];
|
|
2217
|
+
columns?: ("workflow" | "status" | "startedBy" | "createdAt" | "updatedAt")[];
|
|
2218
|
+
}
|
|
2219
|
+
/**
|
|
2220
|
+
* Documents tab - displays all documents attached to the record
|
|
2221
|
+
*/
|
|
2222
|
+
interface DocumentsTab extends BaseTab {
|
|
2223
|
+
type: "documents";
|
|
2224
|
+
allowUpload?: boolean;
|
|
2225
|
+
allowRemove?: boolean;
|
|
2226
|
+
showProcessing?: boolean;
|
|
2227
|
+
showRequiredWarnings?: boolean;
|
|
2228
|
+
hideAttachments?: boolean;
|
|
2229
|
+
}
|
|
2230
|
+
/**
|
|
2231
|
+
* Union of all tab types (for detail views)
|
|
2232
|
+
*/
|
|
2233
|
+
type Tab = FormTab | TableTab | CustomTab | ActivityTab | RichtextTab | FlowsTab | DocumentsTab;
|
|
2234
|
+
/**
|
|
2235
|
+
* Detail view layout mode
|
|
2236
|
+
* - `page`: Full view with multiple tabs
|
|
2237
|
+
* - `modal`: Simplified view for modals (single FormTab, no tabs UI)
|
|
2238
|
+
*/
|
|
2239
|
+
type DetailViewLayout = "page" | "modal";
|
|
2240
|
+
/**
|
|
2241
|
+
* List view layout mode
|
|
2242
|
+
* - `table`: Table/grid layout
|
|
2243
|
+
* - `kanban`: Kanban board layout (grouped by attribute)
|
|
2244
|
+
*/
|
|
2245
|
+
type ListViewLayout = "table" | "kanban";
|
|
2246
|
+
/**
|
|
2247
|
+
* Tab within a list view — each tab carries its own full display configuration.
|
|
2248
|
+
*
|
|
2249
|
+
* @example
|
|
2250
|
+
* ```typescript
|
|
2251
|
+
* const tabs: ListViewTab[] = [
|
|
2252
|
+
* { id: "all", label: "All Contacts", default: true, layout: "table", columns: ["name", "email", "status"] },
|
|
2253
|
+
* { id: "active", label: "Active", layout: "table", columns: ["name", "email"], filters: activeFilter },
|
|
2254
|
+
* { id: "pipeline", label: "Pipeline", layout: "kanban", columns: ["name", "amount"], groupByAttribute: "stage" },
|
|
2255
|
+
* ];
|
|
2256
|
+
* ```
|
|
2257
|
+
*/
|
|
2258
|
+
interface ListViewTab {
|
|
2259
|
+
/** Unique identifier */
|
|
2260
|
+
id: string;
|
|
2261
|
+
/** Display label */
|
|
2262
|
+
label: string;
|
|
2263
|
+
/** Icon */
|
|
2264
|
+
icon?: IconName;
|
|
2265
|
+
/** Default tab (shown on load) */
|
|
2266
|
+
default?: boolean;
|
|
2267
|
+
/** Layout mode */
|
|
2268
|
+
layout: ListViewLayout;
|
|
2269
|
+
/** Attribute names to display as columns */
|
|
2270
|
+
columns: string[];
|
|
2271
|
+
/** Column widths in pixels */
|
|
2272
|
+
columnSizing?: Record<string, number>;
|
|
2273
|
+
/** Filters applied to this tab */
|
|
2274
|
+
filters?: FilterGroup;
|
|
2275
|
+
/** Sort rules for this tab */
|
|
2276
|
+
sorts?: SortRule[];
|
|
2277
|
+
/** Attribute to group by (required when layout is "kanban") */
|
|
2278
|
+
groupByAttribute?: string;
|
|
2279
|
+
/** When true, the tab is read-only: no cell editing, no create, no delete */
|
|
2280
|
+
readOnly?: boolean;
|
|
2281
|
+
/** Creation behavior when clicking "+". Default: "redirect" */
|
|
2282
|
+
createMode?: CreateMode;
|
|
2283
|
+
/** User attribute to display on kanban cards (bottom-left) */
|
|
2284
|
+
cardUserAttribute?: string;
|
|
2285
|
+
/** Date attribute to display on kanban cards (bottom-right) */
|
|
2286
|
+
cardDateAttribute?: string;
|
|
2287
|
+
/** Order of kanban columns (by option value) - for kanban layout only */
|
|
2288
|
+
kanbanColumnOrder?: string[];
|
|
2289
|
+
/** Visibility of kanban columns (by option value) - for kanban layout only */
|
|
2290
|
+
kanbanColumnVisibility?: Record<string, boolean>;
|
|
2291
|
+
/** Pinned kanban columns (by option value) - for kanban layout only */
|
|
2292
|
+
kanbanPinnedColumns?: string[];
|
|
2293
|
+
}
|
|
2294
|
+
/**
|
|
2295
|
+
* Configuration for the side panel displayed alongside tab content.
|
|
2296
|
+
* When present, a right-side panel shows the configured attributes as flat fields.
|
|
2297
|
+
*/
|
|
2298
|
+
interface SidePanelConfig {
|
|
2299
|
+
/** Attribute names to display as flat fields in the panel */
|
|
2300
|
+
attributes: string[];
|
|
2301
|
+
/** Width in pixels. @default 320 */
|
|
2302
|
+
width?: number;
|
|
2303
|
+
}
|
|
2304
|
+
/**
|
|
2305
|
+
* Configuration for detail views (RecordEditView)
|
|
2306
|
+
*/
|
|
2307
|
+
interface DetailViewConfig {
|
|
2308
|
+
/** Layout mode */
|
|
2309
|
+
layout: DetailViewLayout;
|
|
2310
|
+
/** Tabs in this view */
|
|
2311
|
+
tabs: Tab[];
|
|
2312
|
+
/** Optional side panel with flat attribute fields (not available for modal layout) */
|
|
2313
|
+
sidePanel?: SidePanelConfig;
|
|
2314
|
+
}
|
|
2315
|
+
/**
|
|
2316
|
+
* Configuration for list views (RecordsView)
|
|
2317
|
+
*
|
|
2318
|
+
* Each tab carries its own full config (layout, columns, filters, sorts, groupBy).
|
|
2319
|
+
* The view only holds shared base filters applied to ALL tabs.
|
|
2320
|
+
*/
|
|
2321
|
+
interface ListViewConfig {
|
|
2322
|
+
/** Base filters applied to ALL tabs (scoping, tenant, etc.) */
|
|
2323
|
+
defaultFilters?: FilterGroup;
|
|
2324
|
+
/** Tabs — at least one required. Each carries its own full config. */
|
|
2325
|
+
tabs: ListViewTab[];
|
|
2326
|
+
}
|
|
2327
|
+
/**
|
|
2328
|
+
* Configuration for calendar views (future)
|
|
2329
|
+
*/
|
|
2330
|
+
interface CalendarViewConfig {
|
|
2331
|
+
/** Date attribute for positioning events */
|
|
2332
|
+
dateAttribute: string;
|
|
2333
|
+
/** End date attribute (for range events) */
|
|
2334
|
+
endDateAttribute?: string;
|
|
2335
|
+
/** Title attribute for event display */
|
|
2336
|
+
titleAttribute: string;
|
|
2337
|
+
/** Color attribute (status/select) */
|
|
2338
|
+
colorAttribute?: string;
|
|
2339
|
+
}
|
|
2340
|
+
/**
|
|
2341
|
+
* Configuration for timeline views (future)
|
|
2342
|
+
*/
|
|
2343
|
+
interface TimelineViewConfig {
|
|
2344
|
+
/** Date attribute for timeline positioning */
|
|
2345
|
+
dateAttribute: string;
|
|
2346
|
+
/** Group by attribute */
|
|
2347
|
+
groupByAttribute?: string;
|
|
2348
|
+
}
|
|
2349
|
+
/**
|
|
2350
|
+
* Configuration for gallery views (future)
|
|
2351
|
+
*/
|
|
2352
|
+
interface GalleryViewConfig {
|
|
2353
|
+
/** Image attribute to display */
|
|
2354
|
+
imageAttribute: string;
|
|
2355
|
+
/** Title attribute */
|
|
2356
|
+
titleAttribute?: string;
|
|
2357
|
+
/** Columns per row */
|
|
2358
|
+
columnsPerRow?: number;
|
|
2359
|
+
}
|
|
2360
|
+
/**
|
|
2361
|
+
* Union of all view configs
|
|
2362
|
+
*/
|
|
2363
|
+
type ViewConfig = DetailViewConfig | ListViewConfig | CalendarViewConfig | TimelineViewConfig | GalleryViewConfig;
|
|
2364
|
+
/**
|
|
2365
|
+
* Base view properties shared by all view types
|
|
2366
|
+
*/
|
|
2367
|
+
interface BaseViewDefinition {
|
|
2368
|
+
/** Unique identifier (UUID, assigned by database) */
|
|
2369
|
+
id?: string;
|
|
2370
|
+
/** Technical name (kebab-case) */
|
|
2371
|
+
name: string;
|
|
2372
|
+
/** Display label */
|
|
2373
|
+
label: string;
|
|
2374
|
+
/** Description */
|
|
2375
|
+
description?: string;
|
|
2376
|
+
/** Icon */
|
|
2377
|
+
icon?: IconName;
|
|
2378
|
+
/** Object this view belongs to (object name) */
|
|
2379
|
+
object: string;
|
|
2380
|
+
/** Default view for this object+type combination */
|
|
2381
|
+
default?: boolean;
|
|
2382
|
+
/** Extensible metadata */
|
|
2383
|
+
metadata?: Record<string, unknown>;
|
|
2384
|
+
/** Current schema version of this view definition */
|
|
2385
|
+
schema_version: number;
|
|
2386
|
+
}
|
|
2387
|
+
/**
|
|
2388
|
+
* Detail view definition
|
|
2389
|
+
*/
|
|
2390
|
+
interface DetailViewDefinition extends BaseViewDefinition {
|
|
2391
|
+
type: "detail";
|
|
2392
|
+
config: DetailViewConfig;
|
|
2393
|
+
}
|
|
2394
|
+
/**
|
|
2395
|
+
* List view definition
|
|
2396
|
+
*/
|
|
2397
|
+
interface ListViewDefinition extends BaseViewDefinition {
|
|
2398
|
+
type: "list";
|
|
2399
|
+
config: ListViewConfig;
|
|
2400
|
+
}
|
|
2401
|
+
/**
|
|
2402
|
+
* Calendar view definition (future)
|
|
2403
|
+
*/
|
|
2404
|
+
interface CalendarViewDefinition extends BaseViewDefinition {
|
|
2405
|
+
type: "calendar";
|
|
2406
|
+
config: CalendarViewConfig;
|
|
2407
|
+
}
|
|
2408
|
+
/**
|
|
2409
|
+
* Timeline view definition (future)
|
|
2410
|
+
*/
|
|
2411
|
+
interface TimelineViewDefinition extends BaseViewDefinition {
|
|
2412
|
+
type: "timeline";
|
|
2413
|
+
config: TimelineViewConfig;
|
|
2414
|
+
}
|
|
2415
|
+
/**
|
|
2416
|
+
* Gallery view definition (future)
|
|
2417
|
+
*/
|
|
2418
|
+
interface GalleryViewDefinition extends BaseViewDefinition {
|
|
2419
|
+
type: "gallery";
|
|
2420
|
+
config: GalleryViewConfig;
|
|
2421
|
+
}
|
|
2422
|
+
/**
|
|
2423
|
+
* Unified view definition - discriminated union by type
|
|
2424
|
+
*/
|
|
2425
|
+
type ViewDefinition = DetailViewDefinition | ListViewDefinition | CalendarViewDefinition | TimelineViewDefinition | GalleryViewDefinition;
|
|
2426
|
+
/**
|
|
2427
|
+
* Configuration overrides for user customizations
|
|
2428
|
+
* Only stores the delta from the source view
|
|
2429
|
+
*/
|
|
2430
|
+
interface ConfigOverrides {
|
|
2431
|
+
tabs?: ListViewTab[];
|
|
2432
|
+
hiddenTabIds?: string[];
|
|
2433
|
+
detailTabs?: Tab[];
|
|
2434
|
+
hiddenDetailTabIds?: string[];
|
|
2435
|
+
}
|
|
2436
|
+
/**
|
|
2437
|
+
* User customization overlay for a view
|
|
2438
|
+
* Stored per user, merged at runtime with the source view
|
|
2439
|
+
*/
|
|
2440
|
+
interface ViewOverlay {
|
|
2441
|
+
/** Unique identifier */
|
|
2442
|
+
id: string;
|
|
2443
|
+
/** View ID this overlay applies to (UUID or virtual ID) */
|
|
2444
|
+
viewId: string;
|
|
2445
|
+
/** User ID who owns this overlay */
|
|
2446
|
+
userId: string;
|
|
2447
|
+
/** Configuration overrides (delta only) */
|
|
2448
|
+
configOverrides: ConfigOverrides;
|
|
2449
|
+
/** User's default view for this object (stored in overlay) */
|
|
2450
|
+
isUserDefault?: boolean;
|
|
2451
|
+
/** Created timestamp */
|
|
2452
|
+
createdAt: Date;
|
|
2453
|
+
/** Updated timestamp */
|
|
2454
|
+
updatedAt: Date;
|
|
2455
|
+
}
|
|
2456
|
+
/**
|
|
2457
|
+
* Check if a view is a detail view
|
|
2458
|
+
*/
|
|
2459
|
+
declare function isDetailView(view: ViewDefinition): view is DetailViewDefinition;
|
|
2460
|
+
/**
|
|
2461
|
+
* Check if a view is a list view
|
|
2462
|
+
*/
|
|
2463
|
+
declare function isListView(view: ViewDefinition): view is ListViewDefinition;
|
|
2464
|
+
/**
|
|
2465
|
+
* Check if a view is a calendar view
|
|
2466
|
+
*/
|
|
2467
|
+
declare function isCalendarView(view: ViewDefinition): view is CalendarViewDefinition;
|
|
2468
|
+
/**
|
|
2469
|
+
* Check if a view is a timeline view
|
|
2470
|
+
*/
|
|
2471
|
+
declare function isTimelineView(view: ViewDefinition): view is TimelineViewDefinition;
|
|
2472
|
+
/**
|
|
2473
|
+
* Check if a view is a gallery view
|
|
2474
|
+
*/
|
|
2475
|
+
declare function isGalleryView(view: ViewDefinition): view is GalleryViewDefinition;
|
|
2476
|
+
/**
|
|
2477
|
+
* Check if a group is a field group (default type)
|
|
2478
|
+
*/
|
|
2479
|
+
declare function isFieldGroup(group: Group): group is FieldGroup;
|
|
2480
|
+
/**
|
|
2481
|
+
* Check if a group is a relation group
|
|
2482
|
+
*/
|
|
2483
|
+
declare function isRelationGroup(group: Group): group is RelationGroup;
|
|
2484
|
+
/**
|
|
2485
|
+
* Check if a tab is a form tab
|
|
2486
|
+
*/
|
|
2487
|
+
declare function isFormTab(tab: Tab): tab is FormTab;
|
|
2488
|
+
/**
|
|
2489
|
+
* Check if a tab is a table tab
|
|
2490
|
+
*/
|
|
2491
|
+
declare function isTableTab(tab: Tab): tab is TableTab;
|
|
2492
|
+
/**
|
|
2493
|
+
* Check if a table tab uses a direct relation source
|
|
2494
|
+
*/
|
|
2495
|
+
declare function isRelationSourceTab(tab: Tab): tab is TableTab & {
|
|
2496
|
+
source: RelationSource;
|
|
2497
|
+
};
|
|
2498
|
+
/**
|
|
2499
|
+
* Check if a table tab uses an inverse source
|
|
2500
|
+
*/
|
|
2501
|
+
declare function isInverseSourceTab(tab: Tab): tab is TableTab & {
|
|
2502
|
+
source: InverseSource;
|
|
2503
|
+
};
|
|
2504
|
+
/**
|
|
2505
|
+
* Check if a tab is a custom tab
|
|
2506
|
+
*/
|
|
2507
|
+
declare function isCustomTab(tab: Tab): tab is CustomTab;
|
|
2508
|
+
/**
|
|
2509
|
+
* Check if a tab is an activity tab
|
|
2510
|
+
*/
|
|
2511
|
+
declare function isActivityTab(tab: Tab): tab is ActivityTab;
|
|
2512
|
+
/**
|
|
2513
|
+
* Check if a tab is a richtext tab
|
|
2514
|
+
*/
|
|
2515
|
+
declare function isRichtextTab(tab: Tab): tab is RichtextTab;
|
|
2516
|
+
/**
|
|
2517
|
+
* Check if a tab is a flows tab
|
|
2518
|
+
*/
|
|
2519
|
+
declare function isFlowsTab(tab: Tab): tab is FlowsTab;
|
|
2520
|
+
/**
|
|
2521
|
+
* Check if a tab is a documents tab
|
|
2522
|
+
*/
|
|
2523
|
+
declare function isDocumentsTab(tab: Tab): tab is DocumentsTab;
|
|
2524
|
+
|
|
2525
|
+
type TransformSource = "system" | "runtime" | "rollback" | "seed";
|
|
2526
|
+
type BuiltInTransform = "toString" | "toNumber" | "toDate" | "toBoolean" | "toISOString";
|
|
2527
|
+
type SchemaOperation = {
|
|
2528
|
+
type: "add_attribute";
|
|
2529
|
+
attribute: Attribute;
|
|
2530
|
+
} | {
|
|
2531
|
+
type: "remove_attribute";
|
|
2532
|
+
name: string;
|
|
2533
|
+
backup_config: Attribute;
|
|
2534
|
+
} | {
|
|
2535
|
+
type: "rename_attribute";
|
|
2536
|
+
from: string;
|
|
2537
|
+
to: string;
|
|
2538
|
+
} | {
|
|
2539
|
+
type: "change_type";
|
|
2540
|
+
name: string;
|
|
2541
|
+
from: AttributeType;
|
|
2542
|
+
to: AttributeType;
|
|
2543
|
+
transform?: BuiltInTransform;
|
|
2544
|
+
} | {
|
|
2545
|
+
type: "update_config";
|
|
2546
|
+
name: string;
|
|
2547
|
+
from: Partial<Record<string, unknown>>;
|
|
2548
|
+
to: Partial<Record<string, unknown>>;
|
|
2549
|
+
} | {
|
|
2550
|
+
type: "remove_object";
|
|
2551
|
+
backup: Record<string, unknown>;
|
|
2552
|
+
} | {
|
|
2553
|
+
type: "rename_object";
|
|
2554
|
+
from: string;
|
|
2555
|
+
to: string;
|
|
2556
|
+
};
|
|
2557
|
+
type ViewOperation = {
|
|
2558
|
+
type: "update_config";
|
|
2559
|
+
from: ViewConfig;
|
|
2560
|
+
to: ViewConfig;
|
|
2561
|
+
} | {
|
|
2562
|
+
type: "update_tabs";
|
|
2563
|
+
from: (ListViewTab | Tab)[];
|
|
2564
|
+
to: (ListViewTab | Tab)[];
|
|
2565
|
+
} | {
|
|
2566
|
+
type: "force_reset";
|
|
2567
|
+
config: ViewConfig;
|
|
2568
|
+
} | {
|
|
2569
|
+
type: "remove_view";
|
|
2570
|
+
backup: Record<string, unknown>;
|
|
2571
|
+
};
|
|
2572
|
+
interface MigrationDefinition {
|
|
2573
|
+
version: number;
|
|
2574
|
+
operations: SchemaOperation[];
|
|
2575
|
+
reverse_operations: SchemaOperation[];
|
|
2576
|
+
}
|
|
2577
|
+
interface SchemaTransform {
|
|
2578
|
+
id: string;
|
|
2579
|
+
tenantId: string;
|
|
2580
|
+
objectId: string;
|
|
2581
|
+
fromVersion: number;
|
|
2582
|
+
toVersion: number;
|
|
2583
|
+
operations: SchemaOperation[];
|
|
2584
|
+
reverseOperations: SchemaOperation[];
|
|
2585
|
+
source: TransformSource;
|
|
2586
|
+
appliedAt: Date;
|
|
2587
|
+
fullyMigrated: boolean;
|
|
2588
|
+
}
|
|
2589
|
+
interface ViewTransform {
|
|
2590
|
+
id: string;
|
|
2591
|
+
tenantId: string;
|
|
2592
|
+
viewId: string;
|
|
2593
|
+
fromVersion: number;
|
|
2594
|
+
toVersion: number;
|
|
2595
|
+
operations: ViewOperation[];
|
|
2596
|
+
reverseOperations: ViewOperation[];
|
|
2597
|
+
source: TransformSource;
|
|
2598
|
+
appliedAt: Date;
|
|
2599
|
+
}
|
|
2600
|
+
interface MigrationError {
|
|
2601
|
+
id: string;
|
|
2602
|
+
tenantId: string;
|
|
2603
|
+
transformId: string;
|
|
2604
|
+
recordId: string;
|
|
2605
|
+
attributeName: string;
|
|
2606
|
+
originalValue: unknown;
|
|
2607
|
+
error: string;
|
|
2608
|
+
resolvedAt: Date | null;
|
|
2609
|
+
resolvedValue: unknown | null;
|
|
2610
|
+
}
|
|
2611
|
+
interface RetentionPolicy {
|
|
2612
|
+
attributeData: number;
|
|
2613
|
+
deletedObjects: number;
|
|
2614
|
+
transforms: number;
|
|
2615
|
+
migrationErrors: number;
|
|
2616
|
+
}
|
|
2617
|
+
declare const DEFAULT_RETENTION_POLICY: RetentionPolicy;
|
|
2618
|
+
interface MigrationPreview {
|
|
2619
|
+
affectedRecords: number;
|
|
2620
|
+
potentialErrors: number;
|
|
2621
|
+
reversible: boolean;
|
|
2622
|
+
estimatedDuration: string;
|
|
2623
|
+
sampleErrors: Array<{
|
|
2624
|
+
recordId: string;
|
|
2625
|
+
attribute: string;
|
|
2626
|
+
value: unknown;
|
|
2627
|
+
reason: string;
|
|
2628
|
+
}>;
|
|
2629
|
+
}
|
|
2630
|
+
|
|
2631
|
+
/**
|
|
2632
|
+
* Timestamps for tracking creation and updates
|
|
2633
|
+
*/
|
|
2634
|
+
interface Timestamps {
|
|
2635
|
+
createdAt: Date;
|
|
2636
|
+
updatedAt: Date;
|
|
2637
|
+
}
|
|
2638
|
+
/**
|
|
2639
|
+
* Object definition - Represents a database table/entity
|
|
2640
|
+
*/
|
|
2641
|
+
interface ObjectDefinition {
|
|
2642
|
+
id?: Uuid;
|
|
2643
|
+
name: string;
|
|
2644
|
+
label: string;
|
|
2645
|
+
pluralLabel?: string;
|
|
2646
|
+
description?: string;
|
|
2647
|
+
icon?: IconName;
|
|
2648
|
+
/**
|
|
2649
|
+
* Template expression used to compute the object's display label.
|
|
2650
|
+
* Supports variable interpolation and pipes for formatting.
|
|
2651
|
+
*
|
|
2652
|
+
* @example
|
|
2653
|
+
* ```typescript
|
|
2654
|
+
* // Simple attribute reference
|
|
2655
|
+
* labelExpression: "{{ name }}"
|
|
2656
|
+
*
|
|
2657
|
+
* // Multiple attributes
|
|
2658
|
+
* labelExpression: "{{ firstName }} {{ lastName }}"
|
|
2659
|
+
*
|
|
2660
|
+
* // With pipes for formatting
|
|
2661
|
+
* labelExpression: "{{ code | UPPER }} - {{ name | capitalize }}"
|
|
2662
|
+
* ```
|
|
2663
|
+
*
|
|
2664
|
+
* Available pipes: UPPER, LOWER, capitalize, trim
|
|
2665
|
+
*/
|
|
2666
|
+
labelExpression: string;
|
|
2667
|
+
attributes: Attribute[];
|
|
2668
|
+
system?: boolean;
|
|
2669
|
+
metadata?: Record<string, unknown>;
|
|
2670
|
+
/** Current schema version (incremented with each migration) */
|
|
2671
|
+
schema_version: number;
|
|
2672
|
+
/** Ordered list of migrations applied to this object's schema */
|
|
2673
|
+
migrations: MigrationDefinition[];
|
|
2674
|
+
}
|
|
2675
|
+
/**
|
|
2676
|
+
* Links an attribute to an object
|
|
2677
|
+
*/
|
|
2678
|
+
interface ObjectAttribute {
|
|
2679
|
+
objectId: Uuid;
|
|
2680
|
+
attributeId: Uuid;
|
|
2681
|
+
order?: number;
|
|
2682
|
+
required?: boolean;
|
|
2683
|
+
}
|
|
2684
|
+
/**
|
|
2685
|
+
* Completion status of a record based on data completeness.
|
|
2686
|
+
*
|
|
2687
|
+
* - `draft`: Record is missing one or more required attribute values.
|
|
2688
|
+
* Can be saved but is considered incomplete.
|
|
2689
|
+
* - `complete`: All required attribute values are present and valid.
|
|
2690
|
+
* Record is ready for use.
|
|
2691
|
+
*
|
|
2692
|
+
* This is different from workflow status (e.g., "pending", "approved").
|
|
2693
|
+
* Completion status is computed dynamically based on the object schema.
|
|
2694
|
+
*/
|
|
2695
|
+
type CompletionStatus = "draft" | "complete";
|
|
2696
|
+
/**
|
|
2697
|
+
* Record - Instance of an Object (a row in the database)
|
|
2698
|
+
*/
|
|
2699
|
+
interface ObjectRecord extends Timestamps {
|
|
2700
|
+
id: Uuid;
|
|
2701
|
+
objectId: Uuid;
|
|
2702
|
+
/**
|
|
2703
|
+
* Display label computed from the object's labelExpression.
|
|
2704
|
+
* Computed dynamically based on record values.
|
|
2705
|
+
*
|
|
2706
|
+
* @example "John Doe" (from "{{ firstName }} {{ lastName }}")
|
|
2707
|
+
*/
|
|
2708
|
+
label: string;
|
|
2709
|
+
/**
|
|
2710
|
+
* Completion status of the record.
|
|
2711
|
+
* - `draft`: Missing required values, record is incomplete
|
|
2712
|
+
* - `complete`: All required values present and valid
|
|
2713
|
+
*
|
|
2714
|
+
* Computed dynamically based on the object's schema.
|
|
2715
|
+
*/
|
|
2716
|
+
completionStatus: CompletionStatus;
|
|
2717
|
+
values: Record<string, unknown>;
|
|
2718
|
+
/**
|
|
2719
|
+
* Custom metadata for the record.
|
|
2720
|
+
* Use this for UI/UX state, feature flags, or any application-specific data.
|
|
2721
|
+
* Unlike system fields (id, createdAt, updatedAt), metadata can be updated.
|
|
2722
|
+
*/
|
|
2723
|
+
metadata?: Record<string, unknown>;
|
|
2724
|
+
/**
|
|
2725
|
+
* Soft delete timestamp.
|
|
2726
|
+
* If set, the record is considered deleted but can be restored.
|
|
2727
|
+
* Queries exclude soft-deleted records by default.
|
|
2728
|
+
*/
|
|
2729
|
+
deletedAt?: Date | null;
|
|
2730
|
+
/**
|
|
2731
|
+
* User ID who created this record.
|
|
2732
|
+
* Automatically set by RecordService when userId is configured.
|
|
2733
|
+
* Optional for backward compatibility with existing records.
|
|
2734
|
+
*/
|
|
2735
|
+
createdBy?: string;
|
|
2736
|
+
/**
|
|
2737
|
+
* User ID who last updated this record.
|
|
2738
|
+
* Automatically set by RecordService when userId is configured.
|
|
2739
|
+
* Optional for backward compatibility with existing records.
|
|
2740
|
+
*/
|
|
2741
|
+
lastUpdatedBy?: string;
|
|
2742
|
+
/** Schema version at the time this record was last migrated */
|
|
2743
|
+
schemaVersion: number;
|
|
2744
|
+
/**
|
|
2745
|
+
* Values archived during attribute removal or type changes.
|
|
2746
|
+
* Retained according to the retention policy before permanent deletion.
|
|
2747
|
+
*/
|
|
2748
|
+
archivedValues?: Record<string, unknown>;
|
|
2749
|
+
}
|
|
2750
|
+
/**
|
|
2751
|
+
* System-managed field names on ObjectRecord.
|
|
2752
|
+
* These are stored as SQL columns (not in JSONB `values`).
|
|
2753
|
+
*
|
|
2754
|
+
* Use this in adapters to determine if a filter/sort attribute is a table column
|
|
2755
|
+
* vs. a JSONB value field.
|
|
2756
|
+
*
|
|
2757
|
+
* @example
|
|
2758
|
+
* ```typescript
|
|
2759
|
+
* if (SYSTEM_FIELD_NAMES.includes(filter.attribute)) {
|
|
2760
|
+
* // Filter on SQL column (e.g., WHERE created_at > ...)
|
|
2761
|
+
* } else {
|
|
2762
|
+
* // Filter on JSONB field (e.g., WHERE values->>'name' = ...)
|
|
2763
|
+
* }
|
|
2764
|
+
* ```
|
|
2765
|
+
*/
|
|
2766
|
+
declare const SYSTEM_FIELD_NAMES: readonly ["id", "createdAt", "updatedAt", "createdBy", "lastUpdatedBy"];
|
|
2767
|
+
/**
|
|
2768
|
+
* Type for system field names
|
|
2769
|
+
*/
|
|
2770
|
+
type SystemFieldName = (typeof SYSTEM_FIELD_NAMES)[number];
|
|
2771
|
+
/**
|
|
2772
|
+
* Reserved attribute names that cannot be used for custom attributes.
|
|
2773
|
+
* These names conflict with ObjectRecord properties.
|
|
2774
|
+
*
|
|
2775
|
+
* Includes:
|
|
2776
|
+
* - System fields (id, createdAt, updatedAt, createdBy, lastUpdatedBy)
|
|
2777
|
+
* - Other ObjectRecord properties (objectId, label, completionStatus, values, metadata, deletedAt)
|
|
2778
|
+
*
|
|
2779
|
+
* @example
|
|
2780
|
+
* ```typescript
|
|
2781
|
+
* if (RESERVED_ATTRIBUTE_NAMES.includes(attributeName)) {
|
|
2782
|
+
* throw new Error(`"${attributeName}" is a reserved name`);
|
|
2783
|
+
* }
|
|
2784
|
+
* ```
|
|
2785
|
+
*/
|
|
2786
|
+
declare const RESERVED_ATTRIBUTE_NAMES: readonly ["id", "createdAt", "updatedAt", "createdBy", "lastUpdatedBy", "objectId", "label", "completionStatus", "values", "metadata", "deletedAt", "schemaVersion", "archivedValues"];
|
|
2787
|
+
/**
|
|
2788
|
+
* Type for reserved attribute names
|
|
2789
|
+
*/
|
|
2790
|
+
type ReservedAttributeName = (typeof RESERVED_ATTRIBUTE_NAMES)[number];
|
|
2791
|
+
|
|
2792
|
+
/**
|
|
2793
|
+
* Format Zod validation errors into a consistent structure.
|
|
2794
|
+
* This eliminates code duplication across multiple validation functions.
|
|
2795
|
+
*/
|
|
2796
|
+
declare function formatZodErrors(error: z.ZodError): Array<{
|
|
2797
|
+
path: string[];
|
|
2798
|
+
message: string;
|
|
2799
|
+
}>;
|
|
2800
|
+
/**
|
|
2801
|
+
* Validation messages for Zod validators.
|
|
2802
|
+
* All functions receive the full Attribute to access label, type, etc.
|
|
2803
|
+
* Can be customized for i18n support.
|
|
2804
|
+
*/
|
|
2805
|
+
interface ValidationMessages {
|
|
2806
|
+
required: (attr: Attribute) => string;
|
|
2807
|
+
invalidType: (attr: Attribute, expected: string) => string;
|
|
2808
|
+
minLength: (attr: Attribute, min: number) => string;
|
|
2809
|
+
maxLength: (attr: Attribute, max: number) => string;
|
|
2810
|
+
invalidPattern: (attr: Attribute) => string;
|
|
2811
|
+
minValue: (attr: Attribute, min: number) => string;
|
|
2812
|
+
maxValue: (attr: Attribute, max: number) => string;
|
|
2813
|
+
mustBeInteger: (attr: Attribute) => string;
|
|
2814
|
+
invalidDate: (attr: Attribute) => string;
|
|
2815
|
+
invalidOption: (attr: Attribute, options: string[]) => string;
|
|
2816
|
+
invalidId: (attr: Attribute) => string;
|
|
2817
|
+
minItems: (attr: Attribute, min: number) => string;
|
|
2818
|
+
maxItems: (attr: Attribute, max: number) => string;
|
|
2819
|
+
invalidRichtext: (attr: Attribute) => string;
|
|
2820
|
+
invalidPhone: (attr: Attribute) => string;
|
|
2821
|
+
invalidCurrency: (attr: Attribute) => string;
|
|
2822
|
+
invalidLocation: (attr: Attribute) => string;
|
|
2823
|
+
}
|
|
2824
|
+
declare const DEFAULT_VALIDATION_MESSAGES: ValidationMessages;
|
|
2825
|
+
/**
|
|
2826
|
+
* Text attribute config schema
|
|
2827
|
+
*/
|
|
2828
|
+
declare const textConfigSchema: z.ZodObject<{
|
|
2829
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
2830
|
+
placeholder: z.ZodOptional<z.ZodString>;
|
|
2831
|
+
description: z.ZodOptional<z.ZodString>;
|
|
2832
|
+
defaultValue: z.ZodOptional<z.ZodUnknown>;
|
|
2833
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
2834
|
+
order: z.ZodOptional<z.ZodNumber>;
|
|
2835
|
+
hidden: z.ZodOptional<z.ZodBoolean>;
|
|
2836
|
+
archived: z.ZodOptional<z.ZodBoolean>;
|
|
2837
|
+
deprecated: z.ZodOptional<z.ZodBoolean>;
|
|
2838
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
2839
|
+
minLength: z.ZodOptional<z.ZodNumber>;
|
|
2840
|
+
maxLength: z.ZodOptional<z.ZodNumber>;
|
|
2841
|
+
pattern: z.ZodOptional<z.ZodString>;
|
|
2842
|
+
}, z.core.$strip>;
|
|
2843
|
+
/**
|
|
2844
|
+
* Textarea attribute config schema
|
|
2845
|
+
*/
|
|
2846
|
+
declare const textareaConfigSchema: z.ZodObject<{
|
|
2847
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
2848
|
+
placeholder: z.ZodOptional<z.ZodString>;
|
|
2849
|
+
description: z.ZodOptional<z.ZodString>;
|
|
2850
|
+
defaultValue: z.ZodOptional<z.ZodUnknown>;
|
|
2851
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
2852
|
+
order: z.ZodOptional<z.ZodNumber>;
|
|
2853
|
+
hidden: z.ZodOptional<z.ZodBoolean>;
|
|
2854
|
+
archived: z.ZodOptional<z.ZodBoolean>;
|
|
2855
|
+
deprecated: z.ZodOptional<z.ZodBoolean>;
|
|
2856
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
2857
|
+
}, z.core.$strip>;
|
|
2858
|
+
/**
|
|
2859
|
+
* Richtext attribute config schema
|
|
2860
|
+
*/
|
|
2861
|
+
declare const richtextConfigSchema: z.ZodObject<{
|
|
2862
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
2863
|
+
placeholder: z.ZodOptional<z.ZodString>;
|
|
2864
|
+
description: z.ZodOptional<z.ZodString>;
|
|
2865
|
+
defaultValue: z.ZodOptional<z.ZodUnknown>;
|
|
2866
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
2867
|
+
order: z.ZodOptional<z.ZodNumber>;
|
|
2868
|
+
hidden: z.ZodOptional<z.ZodBoolean>;
|
|
2869
|
+
archived: z.ZodOptional<z.ZodBoolean>;
|
|
2870
|
+
deprecated: z.ZodOptional<z.ZodBoolean>;
|
|
2871
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
2872
|
+
features: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
2873
|
+
headings: "headings";
|
|
2874
|
+
bold: "bold";
|
|
2875
|
+
italic: "italic";
|
|
2876
|
+
lists: "lists";
|
|
2877
|
+
links: "links";
|
|
2878
|
+
images: "images";
|
|
2879
|
+
codeBlocks: "codeBlocks";
|
|
2880
|
+
tables: "tables";
|
|
2881
|
+
}>>>;
|
|
2882
|
+
}, z.core.$strip>;
|
|
2883
|
+
/**
|
|
2884
|
+
* Number attribute config schema
|
|
2885
|
+
*/
|
|
2886
|
+
declare const numberConfigSchema: z.ZodObject<{
|
|
2887
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
2888
|
+
placeholder: z.ZodOptional<z.ZodString>;
|
|
2889
|
+
description: z.ZodOptional<z.ZodString>;
|
|
2890
|
+
defaultValue: z.ZodOptional<z.ZodUnknown>;
|
|
2891
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
2892
|
+
order: z.ZodOptional<z.ZodNumber>;
|
|
2893
|
+
hidden: z.ZodOptional<z.ZodBoolean>;
|
|
2894
|
+
archived: z.ZodOptional<z.ZodBoolean>;
|
|
2895
|
+
deprecated: z.ZodOptional<z.ZodBoolean>;
|
|
2896
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
2897
|
+
min: z.ZodOptional<z.ZodNumber>;
|
|
2898
|
+
max: z.ZodOptional<z.ZodNumber>;
|
|
2899
|
+
unit: z.ZodOptional<z.ZodEnum<{
|
|
2900
|
+
percentage: "percentage";
|
|
2901
|
+
integer: "integer";
|
|
2902
|
+
decimal: "decimal";
|
|
2903
|
+
}>>;
|
|
2904
|
+
decimals: z.ZodOptional<z.ZodNumber>;
|
|
2905
|
+
}, z.core.$strip>;
|
|
2906
|
+
/**
|
|
2907
|
+
* Checkbox attribute config schema
|
|
2908
|
+
*/
|
|
2909
|
+
declare const checkboxConfigSchema: z.ZodObject<{
|
|
2910
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
2911
|
+
placeholder: z.ZodOptional<z.ZodString>;
|
|
2912
|
+
description: z.ZodOptional<z.ZodString>;
|
|
2913
|
+
defaultValue: z.ZodOptional<z.ZodUnknown>;
|
|
2914
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
2915
|
+
order: z.ZodOptional<z.ZodNumber>;
|
|
2916
|
+
hidden: z.ZodOptional<z.ZodBoolean>;
|
|
2917
|
+
archived: z.ZodOptional<z.ZodBoolean>;
|
|
2918
|
+
deprecated: z.ZodOptional<z.ZodBoolean>;
|
|
2919
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
2920
|
+
}, z.core.$strip>;
|
|
2921
|
+
/**
|
|
2922
|
+
* Date attribute config schema
|
|
2923
|
+
*/
|
|
2924
|
+
declare const dateConfigSchema: z.ZodObject<{
|
|
2925
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
2926
|
+
placeholder: z.ZodOptional<z.ZodString>;
|
|
2927
|
+
description: z.ZodOptional<z.ZodString>;
|
|
2928
|
+
defaultValue: z.ZodOptional<z.ZodUnknown>;
|
|
2929
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
2930
|
+
order: z.ZodOptional<z.ZodNumber>;
|
|
2931
|
+
hidden: z.ZodOptional<z.ZodBoolean>;
|
|
2932
|
+
archived: z.ZodOptional<z.ZodBoolean>;
|
|
2933
|
+
deprecated: z.ZodOptional<z.ZodBoolean>;
|
|
2934
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
2935
|
+
dateFormat: z.ZodOptional<z.ZodEnum<{
|
|
2936
|
+
short: "short";
|
|
2937
|
+
long: "long";
|
|
2938
|
+
full: "full";
|
|
2939
|
+
relative: "relative";
|
|
2940
|
+
}>>;
|
|
2941
|
+
minDate: z.ZodOptional<z.ZodString>;
|
|
2942
|
+
maxDate: z.ZodOptional<z.ZodString>;
|
|
2943
|
+
}, z.core.$strip>;
|
|
2944
|
+
/**
|
|
2945
|
+
* Phone attribute config schema
|
|
2946
|
+
*/
|
|
2947
|
+
declare const phoneConfigSchema: z.ZodObject<{
|
|
2948
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
2949
|
+
placeholder: z.ZodOptional<z.ZodString>;
|
|
2950
|
+
description: z.ZodOptional<z.ZodString>;
|
|
2951
|
+
defaultValue: z.ZodOptional<z.ZodUnknown>;
|
|
2952
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
2953
|
+
order: z.ZodOptional<z.ZodNumber>;
|
|
2954
|
+
hidden: z.ZodOptional<z.ZodBoolean>;
|
|
2955
|
+
archived: z.ZodOptional<z.ZodBoolean>;
|
|
2956
|
+
deprecated: z.ZodOptional<z.ZodBoolean>;
|
|
2957
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
2958
|
+
defaultCountryCode: z.ZodOptional<z.ZodString>;
|
|
2959
|
+
}, z.core.$strip>;
|
|
2960
|
+
/**
|
|
2961
|
+
* Currency attribute config schema
|
|
2962
|
+
*/
|
|
2963
|
+
declare const currencyConfigSchema: z.ZodObject<{
|
|
2964
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
2965
|
+
placeholder: z.ZodOptional<z.ZodString>;
|
|
2966
|
+
description: z.ZodOptional<z.ZodString>;
|
|
2967
|
+
defaultValue: z.ZodOptional<z.ZodUnknown>;
|
|
2968
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
2969
|
+
order: z.ZodOptional<z.ZodNumber>;
|
|
2970
|
+
hidden: z.ZodOptional<z.ZodBoolean>;
|
|
2971
|
+
archived: z.ZodOptional<z.ZodBoolean>;
|
|
2972
|
+
deprecated: z.ZodOptional<z.ZodBoolean>;
|
|
2973
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
2974
|
+
defaultCurrency: z.ZodOptional<z.ZodString>;
|
|
2975
|
+
allowedCurrencies: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
2976
|
+
}, z.core.$strip>;
|
|
2977
|
+
/**
|
|
2978
|
+
* Status attribute config schema
|
|
2979
|
+
*/
|
|
2980
|
+
declare const statusConfigSchema: z.ZodObject<{
|
|
2981
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
2982
|
+
placeholder: z.ZodOptional<z.ZodString>;
|
|
2983
|
+
description: z.ZodOptional<z.ZodString>;
|
|
2984
|
+
defaultValue: z.ZodOptional<z.ZodUnknown>;
|
|
2985
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
2986
|
+
order: z.ZodOptional<z.ZodNumber>;
|
|
2987
|
+
hidden: z.ZodOptional<z.ZodBoolean>;
|
|
2988
|
+
archived: z.ZodOptional<z.ZodBoolean>;
|
|
2989
|
+
deprecated: z.ZodOptional<z.ZodBoolean>;
|
|
2990
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
2991
|
+
options: z.ZodArray<z.ZodObject<{
|
|
2992
|
+
id: z.ZodString;
|
|
2993
|
+
label: z.ZodString;
|
|
2994
|
+
value: z.ZodString;
|
|
2995
|
+
color: z.ZodOptional<z.ZodString>;
|
|
2996
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
2997
|
+
description: z.ZodOptional<z.ZodString>;
|
|
2998
|
+
group: z.ZodOptional<z.ZodEnum<{
|
|
2999
|
+
idle: "idle";
|
|
3000
|
+
in_progress: "in_progress";
|
|
3001
|
+
finished: "finished";
|
|
3002
|
+
}>>;
|
|
3003
|
+
inverse: z.ZodOptional<z.ZodString>;
|
|
3004
|
+
}, z.core.$strip>>;
|
|
3005
|
+
}, z.core.$strip>;
|
|
3006
|
+
/**
|
|
3007
|
+
* Location attribute config schema
|
|
3008
|
+
*/
|
|
3009
|
+
declare const locationConfigSchema: z.ZodObject<{
|
|
3010
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
3011
|
+
placeholder: z.ZodOptional<z.ZodString>;
|
|
3012
|
+
description: z.ZodOptional<z.ZodString>;
|
|
3013
|
+
defaultValue: z.ZodOptional<z.ZodUnknown>;
|
|
3014
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
3015
|
+
order: z.ZodOptional<z.ZodNumber>;
|
|
3016
|
+
hidden: z.ZodOptional<z.ZodBoolean>;
|
|
3017
|
+
archived: z.ZodOptional<z.ZodBoolean>;
|
|
3018
|
+
deprecated: z.ZodOptional<z.ZodBoolean>;
|
|
3019
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
3020
|
+
granularity: z.ZodEnum<{
|
|
3021
|
+
full: "full";
|
|
3022
|
+
address: "address";
|
|
3023
|
+
city: "city";
|
|
3024
|
+
state: "state";
|
|
3025
|
+
country: "country";
|
|
3026
|
+
coordinates: "coordinates";
|
|
3027
|
+
}>;
|
|
3028
|
+
enableAutocomplete: z.ZodOptional<z.ZodBoolean>;
|
|
3029
|
+
enableMap: z.ZodOptional<z.ZodBoolean>;
|
|
3030
|
+
defaultCountry: z.ZodOptional<z.ZodString>;
|
|
3031
|
+
allowedCountries: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
3032
|
+
displayFormat: z.ZodOptional<z.ZodEnum<{
|
|
3033
|
+
single_line: "single_line";
|
|
3034
|
+
multi_line: "multi_line";
|
|
3035
|
+
compact: "compact";
|
|
3036
|
+
}>>;
|
|
3037
|
+
}, z.core.$strip>;
|
|
3038
|
+
/**
|
|
3039
|
+
* Select attribute config schema
|
|
3040
|
+
*/
|
|
3041
|
+
declare const selectConfigSchema: z.ZodObject<{
|
|
3042
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
3043
|
+
placeholder: z.ZodOptional<z.ZodString>;
|
|
3044
|
+
description: z.ZodOptional<z.ZodString>;
|
|
3045
|
+
defaultValue: z.ZodOptional<z.ZodUnknown>;
|
|
3046
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
3047
|
+
order: z.ZodOptional<z.ZodNumber>;
|
|
3048
|
+
hidden: z.ZodOptional<z.ZodBoolean>;
|
|
3049
|
+
archived: z.ZodOptional<z.ZodBoolean>;
|
|
3050
|
+
deprecated: z.ZodOptional<z.ZodBoolean>;
|
|
3051
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
3052
|
+
options: z.ZodArray<z.ZodObject<{
|
|
3053
|
+
id: z.ZodString;
|
|
3054
|
+
label: z.ZodString;
|
|
3055
|
+
value: z.ZodString;
|
|
3056
|
+
color: z.ZodOptional<z.ZodString>;
|
|
3057
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
3058
|
+
description: z.ZodOptional<z.ZodString>;
|
|
3059
|
+
group: z.ZodOptional<z.ZodEnum<{
|
|
3060
|
+
idle: "idle";
|
|
3061
|
+
in_progress: "in_progress";
|
|
3062
|
+
finished: "finished";
|
|
3063
|
+
}>>;
|
|
3064
|
+
inverse: z.ZodOptional<z.ZodString>;
|
|
3065
|
+
}, z.core.$strip>>;
|
|
3066
|
+
}, z.core.$strip>;
|
|
3067
|
+
/**
|
|
3068
|
+
* Multiselect attribute config schema
|
|
3069
|
+
*/
|
|
3070
|
+
declare const multiselectConfigSchema: z.ZodObject<{
|
|
3071
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
3072
|
+
placeholder: z.ZodOptional<z.ZodString>;
|
|
3073
|
+
description: z.ZodOptional<z.ZodString>;
|
|
3074
|
+
defaultValue: z.ZodOptional<z.ZodUnknown>;
|
|
3075
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
3076
|
+
order: z.ZodOptional<z.ZodNumber>;
|
|
3077
|
+
hidden: z.ZodOptional<z.ZodBoolean>;
|
|
3078
|
+
archived: z.ZodOptional<z.ZodBoolean>;
|
|
3079
|
+
deprecated: z.ZodOptional<z.ZodBoolean>;
|
|
3080
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
3081
|
+
options: z.ZodArray<z.ZodObject<{
|
|
3082
|
+
id: z.ZodString;
|
|
3083
|
+
label: z.ZodString;
|
|
3084
|
+
value: z.ZodString;
|
|
3085
|
+
color: z.ZodOptional<z.ZodString>;
|
|
3086
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
3087
|
+
description: z.ZodOptional<z.ZodString>;
|
|
3088
|
+
group: z.ZodOptional<z.ZodEnum<{
|
|
3089
|
+
idle: "idle";
|
|
3090
|
+
in_progress: "in_progress";
|
|
3091
|
+
finished: "finished";
|
|
3092
|
+
}>>;
|
|
3093
|
+
inverse: z.ZodOptional<z.ZodString>;
|
|
3094
|
+
}, z.core.$strip>>;
|
|
3095
|
+
}, z.core.$strip>;
|
|
3096
|
+
/**
|
|
3097
|
+
* File attribute config schema
|
|
3098
|
+
*/
|
|
3099
|
+
declare const fileConfigSchema: z.ZodObject<{
|
|
3100
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
3101
|
+
placeholder: z.ZodOptional<z.ZodString>;
|
|
3102
|
+
description: z.ZodOptional<z.ZodString>;
|
|
3103
|
+
defaultValue: z.ZodOptional<z.ZodUnknown>;
|
|
3104
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
3105
|
+
order: z.ZodOptional<z.ZodNumber>;
|
|
3106
|
+
hidden: z.ZodOptional<z.ZodBoolean>;
|
|
3107
|
+
archived: z.ZodOptional<z.ZodBoolean>;
|
|
3108
|
+
deprecated: z.ZodOptional<z.ZodBoolean>;
|
|
3109
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
3110
|
+
maxFiles: z.ZodOptional<z.ZodNumber>;
|
|
3111
|
+
maxSize: z.ZodOptional<z.ZodNumber>;
|
|
3112
|
+
allowedTypes: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
3113
|
+
multiple: z.ZodOptional<z.ZodBoolean>;
|
|
3114
|
+
}, z.core.$strip>;
|
|
3115
|
+
/**
|
|
3116
|
+
* User attribute config schema
|
|
3117
|
+
*/
|
|
3118
|
+
declare const userConfigSchema: z.ZodObject<{
|
|
3119
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
3120
|
+
placeholder: z.ZodOptional<z.ZodString>;
|
|
3121
|
+
description: z.ZodOptional<z.ZodString>;
|
|
3122
|
+
defaultValue: z.ZodOptional<z.ZodUnknown>;
|
|
3123
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
3124
|
+
order: z.ZodOptional<z.ZodNumber>;
|
|
3125
|
+
hidden: z.ZodOptional<z.ZodBoolean>;
|
|
3126
|
+
archived: z.ZodOptional<z.ZodBoolean>;
|
|
3127
|
+
deprecated: z.ZodOptional<z.ZodBoolean>;
|
|
3128
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
3129
|
+
allowedRoles: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
3130
|
+
multiple: z.ZodOptional<z.ZodBoolean>;
|
|
3131
|
+
}, z.core.$strip>;
|
|
3132
|
+
/**
|
|
3133
|
+
* Relation attribute config schema
|
|
3134
|
+
*/
|
|
3135
|
+
declare const relationConfigSchema: z.ZodObject<{
|
|
3136
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
3137
|
+
placeholder: z.ZodOptional<z.ZodString>;
|
|
3138
|
+
description: z.ZodOptional<z.ZodString>;
|
|
3139
|
+
defaultValue: z.ZodOptional<z.ZodUnknown>;
|
|
3140
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
3141
|
+
order: z.ZodOptional<z.ZodNumber>;
|
|
3142
|
+
hidden: z.ZodOptional<z.ZodBoolean>;
|
|
3143
|
+
archived: z.ZodOptional<z.ZodBoolean>;
|
|
3144
|
+
deprecated: z.ZodOptional<z.ZodBoolean>;
|
|
3145
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
3146
|
+
targets: z.ZodArray<z.ZodObject<{
|
|
3147
|
+
object: z.ZodString;
|
|
3148
|
+
displayTemplate: z.ZodOptional<z.ZodString>;
|
|
3149
|
+
filter: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
3150
|
+
}, z.core.$strip>>;
|
|
3151
|
+
cardinality: z.ZodEnum<{
|
|
3152
|
+
one: "one";
|
|
3153
|
+
many: "many";
|
|
3154
|
+
}>;
|
|
3155
|
+
minItems: z.ZodOptional<z.ZodNumber>;
|
|
3156
|
+
maxItems: z.ZodOptional<z.ZodNumber>;
|
|
3157
|
+
}, z.core.$strip>;
|
|
3158
|
+
/**
|
|
3159
|
+
* Rating attribute config schema
|
|
3160
|
+
*/
|
|
3161
|
+
declare const ratingConfigSchema: z.ZodObject<{
|
|
3162
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
3163
|
+
placeholder: z.ZodOptional<z.ZodString>;
|
|
3164
|
+
description: z.ZodOptional<z.ZodString>;
|
|
3165
|
+
defaultValue: z.ZodOptional<z.ZodUnknown>;
|
|
3166
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
3167
|
+
order: z.ZodOptional<z.ZodNumber>;
|
|
3168
|
+
hidden: z.ZodOptional<z.ZodBoolean>;
|
|
3169
|
+
archived: z.ZodOptional<z.ZodBoolean>;
|
|
3170
|
+
deprecated: z.ZodOptional<z.ZodBoolean>;
|
|
3171
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
3172
|
+
max: z.ZodOptional<z.ZodNumber>;
|
|
3173
|
+
iconType: z.ZodOptional<z.ZodEnum<{
|
|
3174
|
+
number: "number";
|
|
3175
|
+
heart: "heart";
|
|
3176
|
+
star: "star";
|
|
3177
|
+
thumbs: "thumbs";
|
|
3178
|
+
}>>;
|
|
3179
|
+
}, z.core.$strip>;
|
|
3180
|
+
/**
|
|
3181
|
+
* Formula attribute config schema
|
|
3182
|
+
*/
|
|
3183
|
+
declare const formulaConfigSchema: z.ZodObject<{
|
|
3184
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
3185
|
+
placeholder: z.ZodOptional<z.ZodString>;
|
|
3186
|
+
description: z.ZodOptional<z.ZodString>;
|
|
3187
|
+
defaultValue: z.ZodOptional<z.ZodUnknown>;
|
|
3188
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
3189
|
+
order: z.ZodOptional<z.ZodNumber>;
|
|
3190
|
+
hidden: z.ZodOptional<z.ZodBoolean>;
|
|
3191
|
+
archived: z.ZodOptional<z.ZodBoolean>;
|
|
3192
|
+
deprecated: z.ZodOptional<z.ZodBoolean>;
|
|
3193
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
3194
|
+
expression: z.ZodString;
|
|
3195
|
+
returnType: z.ZodEnum<{
|
|
3196
|
+
number: "number";
|
|
3197
|
+
boolean: "boolean";
|
|
3198
|
+
text: "text";
|
|
3199
|
+
date: "date";
|
|
3200
|
+
}>;
|
|
3201
|
+
decimals: z.ZodOptional<z.ZodNumber>;
|
|
3202
|
+
allowRelations: z.ZodOptional<z.ZodBoolean>;
|
|
3203
|
+
}, z.core.$strip>;
|
|
3204
|
+
/**
|
|
3205
|
+
* Rollup attribute config schema
|
|
3206
|
+
*/
|
|
3207
|
+
declare const rollupConfigSchema: z.ZodObject<{
|
|
3208
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
3209
|
+
placeholder: z.ZodOptional<z.ZodString>;
|
|
3210
|
+
description: z.ZodOptional<z.ZodString>;
|
|
3211
|
+
defaultValue: z.ZodOptional<z.ZodUnknown>;
|
|
3212
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
3213
|
+
order: z.ZodOptional<z.ZodNumber>;
|
|
3214
|
+
hidden: z.ZodOptional<z.ZodBoolean>;
|
|
3215
|
+
archived: z.ZodOptional<z.ZodBoolean>;
|
|
3216
|
+
deprecated: z.ZodOptional<z.ZodBoolean>;
|
|
3217
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
3218
|
+
relationAttribute: z.ZodOptional<z.ZodString>;
|
|
3219
|
+
relationPath: z.ZodOptional<z.ZodString>;
|
|
3220
|
+
targetAttribute: z.ZodString;
|
|
3221
|
+
function: z.ZodEnum<{
|
|
3222
|
+
sum: "sum";
|
|
3223
|
+
avg: "avg";
|
|
3224
|
+
earliest: "earliest";
|
|
3225
|
+
latest: "latest";
|
|
3226
|
+
count: "count";
|
|
3227
|
+
countValues: "countValues";
|
|
3228
|
+
countUniqueValues: "countUniqueValues";
|
|
3229
|
+
countEmpty: "countEmpty";
|
|
3230
|
+
percentEmpty: "percentEmpty";
|
|
3231
|
+
percentNotEmpty: "percentNotEmpty";
|
|
3232
|
+
original: "original";
|
|
3233
|
+
}>;
|
|
3234
|
+
decimals: z.ZodOptional<z.ZodNumber>;
|
|
3235
|
+
targetAttributeType: z.ZodOptional<z.ZodString>;
|
|
3236
|
+
targetAttributeOptions: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
3237
|
+
id: z.ZodString;
|
|
3238
|
+
label: z.ZodString;
|
|
3239
|
+
value: z.ZodString;
|
|
3240
|
+
color: z.ZodOptional<z.ZodString>;
|
|
3241
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
3242
|
+
description: z.ZodOptional<z.ZodString>;
|
|
3243
|
+
group: z.ZodOptional<z.ZodEnum<{
|
|
3244
|
+
idle: "idle";
|
|
3245
|
+
in_progress: "in_progress";
|
|
3246
|
+
finished: "finished";
|
|
3247
|
+
}>>;
|
|
3248
|
+
}, z.core.$strip>>>;
|
|
3249
|
+
}, z.core.$strip>;
|
|
3250
|
+
/**
|
|
3251
|
+
* Document attribute config schema
|
|
3252
|
+
*/
|
|
3253
|
+
declare const documentConfigSchema: z.ZodObject<{
|
|
3254
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
3255
|
+
placeholder: z.ZodOptional<z.ZodString>;
|
|
3256
|
+
description: z.ZodOptional<z.ZodString>;
|
|
3257
|
+
defaultValue: z.ZodOptional<z.ZodUnknown>;
|
|
3258
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
3259
|
+
order: z.ZodOptional<z.ZodNumber>;
|
|
3260
|
+
hidden: z.ZodOptional<z.ZodBoolean>;
|
|
3261
|
+
archived: z.ZodOptional<z.ZodBoolean>;
|
|
3262
|
+
deprecated: z.ZodOptional<z.ZodBoolean>;
|
|
3263
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
3264
|
+
multiple: z.ZodOptional<z.ZodBoolean>;
|
|
3265
|
+
maxDocuments: z.ZodOptional<z.ZodNumber>;
|
|
3266
|
+
autoProcess: z.ZodOptional<z.ZodBoolean>;
|
|
3267
|
+
}, z.core.$strip>;
|
|
3268
|
+
/**
|
|
3269
|
+
* Map of attribute type to config schema
|
|
3270
|
+
*/
|
|
3271
|
+
declare const attributeConfigSchemas: Record<AttributeType, z.ZodObject<z.ZodRawShape>>;
|
|
3272
|
+
/**
|
|
3273
|
+
* Get the config schema for a specific attribute type
|
|
3274
|
+
*/
|
|
3275
|
+
declare function getAttributeConfigSchema(type: AttributeType): z.ZodObject<z.ZodRawShape>;
|
|
3276
|
+
/**
|
|
3277
|
+
* Validate attribute config for a specific type
|
|
3278
|
+
* Returns the validated config with only allowed properties
|
|
3279
|
+
*/
|
|
3280
|
+
declare function validateAttributeConfig(type: AttributeType, config: Record<string, unknown>): {
|
|
3281
|
+
success: true;
|
|
3282
|
+
data: Record<string, unknown>;
|
|
3283
|
+
} | {
|
|
3284
|
+
success: false;
|
|
3285
|
+
errors: string[];
|
|
3286
|
+
};
|
|
3287
|
+
/**
|
|
3288
|
+
* Validate and strip unknown properties from attribute config
|
|
3289
|
+
* This ensures only allowed properties are stored in the database
|
|
3290
|
+
*/
|
|
3291
|
+
declare function parseAttributeConfig(type: AttributeType, config: Record<string, unknown>): Record<string, unknown>;
|
|
3292
|
+
/**
|
|
3293
|
+
* Safely parse attribute config, returning undefined for invalid configs
|
|
3294
|
+
*/
|
|
3295
|
+
declare function safeParseAttributeConfig(type: AttributeType, config: Record<string, unknown>): Record<string, unknown> | undefined;
|
|
3296
|
+
/**
|
|
3297
|
+
* Create a Zod schema for a text attribute
|
|
3298
|
+
*/
|
|
3299
|
+
declare function createTextValidator(attr: TextAttribute, messages?: ValidationMessages): z.ZodString;
|
|
3300
|
+
/**
|
|
3301
|
+
* Create a Zod schema for a number attribute
|
|
3302
|
+
*/
|
|
3303
|
+
declare function createNumberValidator(attr: NumberAttribute, messages?: ValidationMessages): z.ZodNumber;
|
|
3304
|
+
/**
|
|
3305
|
+
* Create a Zod schema for a checkbox attribute
|
|
3306
|
+
*/
|
|
3307
|
+
declare function createCheckboxValidator(_attr: CheckboxAttribute, _messages?: ValidationMessages): z.ZodBoolean;
|
|
3308
|
+
/**
|
|
3309
|
+
* Create a Zod schema for a date attribute
|
|
3310
|
+
*/
|
|
3311
|
+
declare function createDateValidator(attr: DateAttribute, messages?: ValidationMessages): z.ZodTypeAny;
|
|
3312
|
+
/**
|
|
3313
|
+
* Create a Zod schema for a phone attribute.
|
|
3314
|
+
*
|
|
3315
|
+
* Validates:
|
|
3316
|
+
* - countryCode is a valid ISO3 country code
|
|
3317
|
+
* - phoneNumber contains valid digits for the given country
|
|
3318
|
+
*
|
|
3319
|
+
* Transforms:
|
|
3320
|
+
* - Normalizes phoneNumber to national digits without trunk prefix
|
|
3321
|
+
*/
|
|
3322
|
+
declare function createPhoneValidator(attr: PhoneAttribute, messages?: ValidationMessages): z.ZodType<{
|
|
3323
|
+
countryCode: string;
|
|
3324
|
+
phoneNumber: string;
|
|
3325
|
+
}>;
|
|
3326
|
+
/**
|
|
3327
|
+
* Create a Zod schema for a currency attribute
|
|
3328
|
+
*/
|
|
3329
|
+
declare function createCurrencyValidator(attr: CurrencyAttribute, messages?: ValidationMessages): z.ZodType<{
|
|
3330
|
+
code: string;
|
|
3331
|
+
value: number;
|
|
3332
|
+
}>;
|
|
3333
|
+
/**
|
|
3334
|
+
* Create a Zod schema for a status attribute
|
|
3335
|
+
*/
|
|
3336
|
+
declare function createStatusValidator(attr: StatusAttribute, messages?: ValidationMessages): z.ZodEnum<Readonly<Record<string, string>>>;
|
|
3337
|
+
/**
|
|
3338
|
+
* Create a Zod schema for a select attribute
|
|
3339
|
+
*/
|
|
3340
|
+
declare function createSelectValidator(attr: SelectAttribute, messages?: ValidationMessages): z.ZodEnum<Readonly<Record<string, string>>>;
|
|
3341
|
+
/**
|
|
3342
|
+
* Create a Zod schema for a multiselect attribute
|
|
3343
|
+
*/
|
|
3344
|
+
declare function createMultiselectValidator(attr: MultiselectAttribute, messages?: ValidationMessages): z.ZodArray<z.ZodEnum<Readonly<Record<string, string>>>>;
|
|
3345
|
+
/**
|
|
3346
|
+
* Create a Zod schema for a location attribute
|
|
3347
|
+
*/
|
|
3348
|
+
type LocationShape = {
|
|
3349
|
+
address?: string;
|
|
3350
|
+
address2?: string;
|
|
3351
|
+
city?: string;
|
|
3352
|
+
state?: string;
|
|
3353
|
+
postalCode?: string;
|
|
3354
|
+
country?: string;
|
|
3355
|
+
latitude?: number;
|
|
3356
|
+
longitude?: number;
|
|
3357
|
+
};
|
|
3358
|
+
declare function createLocationValidator(attr: LocationAttribute, messages?: ValidationMessages): z.ZodType<LocationShape>;
|
|
3359
|
+
/**
|
|
3360
|
+
* Create a Zod schema for a file attribute
|
|
3361
|
+
* Supports both single file (UUID) and multiple files (array of UUIDs)
|
|
3362
|
+
*/
|
|
3363
|
+
declare function createFileValidator(attr: FileAttribute, messages?: ValidationMessages): z.ZodTypeAny;
|
|
3364
|
+
/**
|
|
3365
|
+
* Create a Zod schema for a user attribute
|
|
3366
|
+
* Supports both single user (UUID) and multiple users (array of UUIDs)
|
|
3367
|
+
*/
|
|
3368
|
+
declare function createUserValidator(attr: UserAttribute, messages?: ValidationMessages): z.ZodTypeAny;
|
|
3369
|
+
/**
|
|
3370
|
+
* Create a Zod schema for a single relation attribute (cardinality: "one")
|
|
3371
|
+
* Supports hybrid format `{ id, props }` from qualified relations.
|
|
3372
|
+
* IMPORTANT: Validates the ID but preserves the original format (keeps props).
|
|
3373
|
+
*/
|
|
3374
|
+
declare function createSingleRelationValidator(attr: SingleRelationAttribute, messages?: ValidationMessages): z.ZodTypeAny;
|
|
3375
|
+
/**
|
|
3376
|
+
* Create a Zod schema for a multi relation attribute (cardinality: "many")
|
|
3377
|
+
* Supports hybrid format arrays with `{ id, props }` items from qualified relations.
|
|
3378
|
+
* IMPORTANT: Validates the IDs but preserves the original format (keeps props).
|
|
3379
|
+
*/
|
|
3380
|
+
declare function createMultiRelationValidator(attr: MultiRelationAttribute, messages?: ValidationMessages): z.ZodTypeAny;
|
|
3381
|
+
/**
|
|
3382
|
+
* Create a Zod schema for a relation attribute
|
|
3383
|
+
* Dispatches to single or multi validator based on cardinality
|
|
3384
|
+
*/
|
|
3385
|
+
declare function createRelationValidator(attr: RelationAttribute, messages?: ValidationMessages): z.ZodTypeAny;
|
|
3386
|
+
/**
|
|
3387
|
+
* Create a Zod schema for a rating attribute
|
|
3388
|
+
*/
|
|
3389
|
+
declare function createRatingValidator(attr: RatingAttribute, messages?: ValidationMessages): z.ZodNumber;
|
|
3390
|
+
/**
|
|
3391
|
+
* Create a Zod schema for a formula attribute.
|
|
3392
|
+
* Formula attributes are read-only (computed at runtime).
|
|
3393
|
+
* They accept any value during validation but are ignored during record creation/update.
|
|
3394
|
+
*/
|
|
3395
|
+
declare function createFormulaValidator(_attr: FormulaAttribute, _messages?: ValidationMessages): z.ZodUnknown;
|
|
3396
|
+
/**
|
|
3397
|
+
* Create a Zod schema for a rollup attribute.
|
|
3398
|
+
* Rollup attributes are read-only (computed from related records).
|
|
3399
|
+
* They accept any value during validation but are ignored during record creation/update.
|
|
3400
|
+
*/
|
|
3401
|
+
declare function createRollupValidator(_attr: RollupAttribute, _messages?: ValidationMessages): z.ZodUnknown;
|
|
3402
|
+
/**
|
|
3403
|
+
* Create a Zod schema for a textarea attribute.
|
|
3404
|
+
* Validates that the value is a string.
|
|
3405
|
+
*/
|
|
3406
|
+
declare function createTextAreaValidator(_attr: TextAreaAttribute, _messages?: ValidationMessages): z.ZodString;
|
|
3407
|
+
/**
|
|
3408
|
+
* Create a Zod schema for a richtext attribute.
|
|
3409
|
+
* Validates semantic markdown content as a string.
|
|
3410
|
+
*
|
|
3411
|
+
* @example Valid richtext content (semantic markdown)
|
|
3412
|
+
* ```typescript
|
|
3413
|
+
* `# Heading
|
|
3414
|
+
*
|
|
3415
|
+
* Some paragraph text.
|
|
3416
|
+
*
|
|
3417
|
+
* :::callout{variant="info"}
|
|
3418
|
+
* This is a callout block
|
|
3419
|
+
* :::
|
|
3420
|
+
* `
|
|
3421
|
+
* ```
|
|
3422
|
+
*/
|
|
3423
|
+
declare function createRichtextValidator(attr: RichtextAttribute, messages?: ValidationMessages): z.ZodTypeAny;
|
|
3424
|
+
/**
|
|
3425
|
+
* Create a Zod schema for any attribute type.
|
|
3426
|
+
* Returns a strict validator that does NOT handle optional fields.
|
|
3427
|
+
* Use createFormAttributeValidator for form validation with optional support.
|
|
3428
|
+
*
|
|
3429
|
+
* @param attr - The attribute to create a validator for
|
|
3430
|
+
* @param messages - Custom validation messages for i18n support
|
|
3431
|
+
*/
|
|
3432
|
+
declare function createAttributeValidator(attr: Attribute, messages?: ValidationMessages): z.ZodTypeAny;
|
|
3433
|
+
/**
|
|
3434
|
+
* Create a Zod schema for form validation.
|
|
3435
|
+
* - Normalizes empty values (empty strings, empty objects) to null for optional fields
|
|
3436
|
+
* - Accepts custom messages for i18n support
|
|
3437
|
+
*
|
|
3438
|
+
* Use this in UI forms where optional fields may have null/undefined values.
|
|
3439
|
+
*
|
|
3440
|
+
* @param attr - The attribute to create a validator for
|
|
3441
|
+
* @param messages - Custom validation messages for i18n support
|
|
3442
|
+
*/
|
|
3443
|
+
declare function createFormAttributeValidator(attr: Attribute, messages?: ValidationMessages): z.ZodTypeAny;
|
|
3444
|
+
/**
|
|
3445
|
+
* Create a Zod schema for an entire object
|
|
3446
|
+
*
|
|
3447
|
+
* Uses passthrough mode to allow computed fields (formula, rollup) that may be
|
|
3448
|
+
* present in record data but are not part of the mutable schema.
|
|
3449
|
+
*/
|
|
3450
|
+
declare function createObjectValidator(objectDef: ObjectDefinition): z.ZodType<Record<string, unknown>>;
|
|
3451
|
+
/**
|
|
3452
|
+
* Validation result
|
|
3453
|
+
*/
|
|
3454
|
+
interface ValidationResult {
|
|
3455
|
+
success: boolean;
|
|
3456
|
+
data?: Record<string, unknown>;
|
|
3457
|
+
errors?: Array<{
|
|
3458
|
+
path: string[];
|
|
3459
|
+
message: string;
|
|
3460
|
+
}>;
|
|
3461
|
+
}
|
|
3462
|
+
/**
|
|
3463
|
+
* Validate data against an attribute schema
|
|
3464
|
+
*/
|
|
3465
|
+
declare function validateAttribute(attr: Attribute, value: unknown): ValidationResult;
|
|
3466
|
+
/**
|
|
3467
|
+
* Validate data against an object schema
|
|
3468
|
+
*/
|
|
3469
|
+
declare function validateObject(objectDef: ObjectDefinition, data: Record<string, unknown>): ValidationResult;
|
|
3470
|
+
/**
|
|
3471
|
+
* Validate and throw if invalid
|
|
3472
|
+
*/
|
|
3473
|
+
declare function validateObjectOrThrow(objectDef: ObjectDefinition, data: Record<string, unknown>): Record<string, unknown>;
|
|
3474
|
+
/**
|
|
3475
|
+
* Create a Zod schema for draft validation.
|
|
3476
|
+
* All attributes become optional, but provided values are still validated.
|
|
3477
|
+
*
|
|
3478
|
+
* Uses passthrough mode to allow computed fields (formula, rollup) that may be
|
|
3479
|
+
* present in record data but are not part of the mutable schema.
|
|
3480
|
+
*/
|
|
3481
|
+
declare function createDraftValidator(objectDef: ObjectDefinition): z.ZodType<Record<string, unknown>>;
|
|
3482
|
+
/**
|
|
3483
|
+
* Validate data in draft mode.
|
|
3484
|
+
* - All attributes are treated as optional (no required validation)
|
|
3485
|
+
* - Provided values are still validated for format/type correctness
|
|
3486
|
+
*
|
|
3487
|
+
* Use this when creating records that may be incomplete (drafts).
|
|
3488
|
+
*
|
|
3489
|
+
* @example
|
|
3490
|
+
* ```typescript
|
|
3491
|
+
* const result = validateDraft(PRODUCT, { name: "Draft" });
|
|
3492
|
+
* // → success even if "price" is required but missing
|
|
3493
|
+
*
|
|
3494
|
+
* const result2 = validateDraft(PRODUCT, { price: -10 });
|
|
3495
|
+
* // → fails because price must be >= 0 (format validation still applies)
|
|
3496
|
+
* ```
|
|
3497
|
+
*/
|
|
3498
|
+
declare function validateDraft(objectDef: ObjectDefinition, data: Record<string, unknown>): ValidationResult;
|
|
3499
|
+
/**
|
|
3500
|
+
* Validate draft data and throw if format validation fails.
|
|
3501
|
+
*/
|
|
3502
|
+
declare function validateDraftOrThrow(objectDef: ObjectDefinition, data: Record<string, unknown>): Record<string, unknown>;
|
|
3503
|
+
/**
|
|
3504
|
+
* Get the list of required attributes that are missing values.
|
|
3505
|
+
*
|
|
3506
|
+
* @example
|
|
3507
|
+
* ```typescript
|
|
3508
|
+
* const missing = getMissingRequiredAttributes(PRODUCT, { name: "Test" });
|
|
3509
|
+
* // → [priceAttribute, statusAttribute] if price and status are required but missing
|
|
3510
|
+
* ```
|
|
3511
|
+
*/
|
|
3512
|
+
declare function getMissingRequiredAttributes(objectDef: ObjectDefinition, data: Record<string, unknown>): Attribute[];
|
|
3513
|
+
/**
|
|
3514
|
+
* Check if a record is complete (all required attributes have valid values).
|
|
3515
|
+
*
|
|
3516
|
+
* @returns `true` if all required values are present and valid, `false` otherwise
|
|
3517
|
+
*/
|
|
3518
|
+
declare function isRecordComplete(objectDef: ObjectDefinition, data: Record<string, unknown>): boolean;
|
|
3519
|
+
/**
|
|
3520
|
+
* Compute the completion status of a record based on its data.
|
|
3521
|
+
*
|
|
3522
|
+
* - `"complete"`: All required values are present and valid
|
|
3523
|
+
* - `"draft"`: One or more required values are missing or invalid
|
|
3524
|
+
*
|
|
3525
|
+
* This function is used to dynamically determine the status when
|
|
3526
|
+
* creating or updating records.
|
|
3527
|
+
*
|
|
3528
|
+
* @example
|
|
3529
|
+
* ```typescript
|
|
3530
|
+
* const status = computeRecordStatus(PRODUCT, {
|
|
3531
|
+
* name: "Nike Air Max",
|
|
3532
|
+
* price: 129.99,
|
|
3533
|
+
* status: "active"
|
|
3534
|
+
* });
|
|
3535
|
+
* // → "complete"
|
|
3536
|
+
*
|
|
3537
|
+
* const status2 = computeRecordStatus(PRODUCT, { name: "Draft Product" });
|
|
3538
|
+
* // → "draft" (missing required fields)
|
|
3539
|
+
* ```
|
|
3540
|
+
*/
|
|
3541
|
+
declare function computeRecordStatus(objectDef: ObjectDefinition, data: Record<string, unknown>): CompletionStatus;
|
|
3542
|
+
|
|
3543
|
+
export { type RelationAttribute as $, type Attribute as A, type FeatureGate as B, type ConfigOverrides as C, type DateAttribute as D, type TextAttribute as E, type FilterState as F, type TextAreaAttribute as G, type RichtextAttribute as H, type InstanceStatus as I, type RichtextFeature as J, type CheckboxAttribute as K, type LocationGranularity as L, type MultiselectAttribute as M, type NumberAttribute as N, type ObjectRecord as O, type PendingAction as P, type PhoneAttribute as Q, type RelationFieldConfig as R, type SortRule as S, type Timestamps as T, type UserAttribute as U, type ViewType as V, type WorkflowNode as W, type CurrencyAttribute as X, type Option as Y, type LocationAttribute as Z, type FileAttribute as _, type FormNode as a, type DocumentGenerationAction as a$, type RatingAttribute as a0, type BilateralConfig as a1, type SingleRelationAttribute as a2, type MultiRelationAttribute as a3, type RelationTarget as a4, type FormulaReturnType as a5, type RollupFunction as a6, type MigrationDefinition as a7, type ObjectDefinition as a8, type DetailViewLayout as a9, type AINode as aA, type ActivityTab as aB, type AdvancedFilterState as aC, type AssignNode as aD, type AssignmentMapping as aE, type AssignmentSource as aF, type AttributeGroup as aG, type BaseAttribute as aH, type BufferedRecord as aI, type BuiltInTransform as aJ, type CalendarViewConfig as aK, type CalendarViewDefinition as aL, type CanvasViewport as aM, type CheckboxFilterOperator as aN, type CodeExecutionAction as aO, type ConditionNode as aP, type ConditionOperator as aQ, type CurrencyFilterValue as aR, type CustomTab as aS, DEFAULT_RETENTION_POLICY as aT, DEFAULT_THEME as aU, DEFAULT_VALIDATION_MESSAGES as aV, type DateFilterOperator as aW, type DateFormat as aX, type DateValue as aY, type DetailViewConfig as aZ, type DisplayRecord as a_, type SidePanelConfig as aa, type Field as ab, type AttributeGroupField as ac, type FieldGroup as ad, type RelationGroup as ae, type Group as af, type TableTab as ag, type CreateMode as ah, type DetailViewDefinition as ai, type Tab as aj, type ListViewDefinition as ak, type SlotMode as al, type FlowFieldsRow as am, type ConditionGroup as an, type ConditionRule as ao, type FlagValueType as ap, type FeatureFlagDefinition as aq, type FlagLevel as ar, type FeatureFlagsRepository as as, type StaticFlagDefault as at, type ResolvedFlag as au, type ViewDefinition as av, type ListViewConfig as aw, type ListViewTab as ax, type AIActionConfig as ay, type AIActionType as az, type WorkflowNodeType as b, type StatusGroup as b$, type DocumentsTab as b0, type EndNode as b1, type ExtendedFilterRule as b2, FORBIDDEN_PROPERTY_TYPES as b3, type FeatureFlagsConfig as b4, type FilterCombinator as b5, type FilterGroup as b6, type FilterOperator as b7, type FilterRule as b8, type FilterValue as b9, type NumberFilterOperator as bA, type NumberUnit as bB, OPERATORS_BY_TYPE as bC, type ObjectAttribute as bD, type OptionPropertyAttribute as bE, type PhoneFilterValue as bF, type PropertyAttribute as bG, type PropertySchema as bH, type PropertyType as bI, type QueryState as bJ, RELATION_TARGET_ANY as bK, RESERVED_ATTRIBUTE_NAMES as bL, type RecordPatch as bM, type RelationBuffer as bN, type RelationFilterOperator as bO, type RelationQualifierPatch as bP, type RelationSource as bQ, type RelativeDateValue as bR, type ReservedAttributeName as bS, type RetentionPolicy as bT, type RichtextTab as bU, SYSTEM_FIELD_NAMES as bV, type SchemaOperation as bW, type SchemaTransform as bX, type SelectFilterOperator as bY, type SortDirection as bZ, type StartNode as b_, type FlagOverride as ba, type FlowDefinition as bb, type FlowPage as bc, type FlowRelation as bd, type FlowRow as be, type FlowRowField as bf, type FlowRowType as bg, type FlowSlot as bh, type FlowStatus as bi, type FlowsTab as bj, type ForbiddenPropertyType as bk, type FormDensity as bl, type FormFieldRef as bm, type FormTab as bn, type GalleryViewConfig as bo, type GalleryViewDefinition as bp, type GeneratedDocument as bq, type InverseSource as br, type ListViewLayout as bs, type MigrationError as bt, type MigrationPreview as bu, type MultiselectFilterOperator as bv, NON_SORTABLE_TYPES as bw, NO_VALUE_OPERATORS as bx, type NoValueOperator as by, type NodePosition as bz, type FlowHeadingRow as c, isAINode as c$, type SystemFieldName as c0, type TabType as c1, type TableSource as c2, type TextFilterOperator as c3, type ThemeColors as c4, type ThemeLogo as c5, type ThemeTypography as c6, type TimelineViewConfig as c7, type TimelineViewDefinition as c8, type TransformSource as c9, createPhoneValidator as cA, createRatingValidator as cB, createRelationValidator as cC, createRichtextValidator as cD, createRollupValidator as cE, createSelectValidator as cF, createSingleRelationValidator as cG, createStartTransition as cH, createStatusValidator as cI, createTextAreaValidator as cJ, createTextValidator as cK, createUserValidator as cL, currencyConfigSchema as cM, dateConfigSchema as cN, documentConfigSchema as cO, eq as cP, fileConfigSchema as cQ, formatZodErrors as cR, formulaConfigSchema as cS, generateCssVariables as cT, getAttributeConfigSchema as cU, getContextValue as cV, getMissingRequiredAttributes as cW, getRollupFilterOperators as cX, hasOptions as cY, inValues as cZ, inferInverseCardinality as c_, type ValidationMessages as ca, type ValidationResult as cb, type ViewOperation as cc, type ViewOverlay as cd, type ViewTransform as ce, type WorkflowError as cf, type WorkflowInstance as cg, and as ch, attributeConfigSchemas as ci, canResumeInstance as cj, checkboxConfigSchema as ck, computeRecordStatus as cl, createAttributeValidator as cm, createCheckboxValidator as cn, createCurrencyValidator as co, createDateValidator as cp, createDraftValidator as cq, createEmptyContext as cr, createFileValidator as cs, createFormAttributeValidator as ct, createFormulaValidator as cu, createLocationValidator as cv, createMultiRelationValidator as cw, createMultiselectValidator as cx, createNumberValidator as cy, createObjectValidator as cz, type FlowSeparatorRow as d, validateDraft as d$, isActivityTab as d0, isAdvancedFormNode as d1, isAssignNode as d2, isAttributeSortable as d3, isBilateralRelation as d4, isCalendarView as d5, isConditionGroup as d6, isConditionNode as d7, isConditionRule as d8, isCustomTab as d9, isSystemWorkflow as dA, isTableTab as dB, isTimelineView as dC, isUniversalRelation as dD, isWorkflowDefinition as dE, isWorkflowPublished as dF, locationConfigSchema as dG, mergeWithDefaults as dH, multiselectConfigSchema as dI, neq as dJ, numberConfigSchema as dK, or as dL, parseAttributeConfig as dM, phoneConfigSchema as dN, ratingConfigSchema as dO, relationConfigSchema as dP, richtextConfigSchema as dQ, rollupConfigSchema as dR, safeParseAttributeConfig as dS, selectConfigSchema as dT, setContextValue as dU, statusConfigSchema as dV, textConfigSchema as dW, textareaConfigSchema as dX, userConfigSchema as dY, validateAttribute as dZ, validateAttributeConfig as d_, isDetailView as da, isDocumentsTab as db, isEndNode as dc, isFieldGroup as dd, isFlowDefinition as de, isFlowFieldsRow as df, isFlowPublished as dg, isFlowRelationListRow as dh, isFlowsTab as di, isFormNode as dj, isFormTab as dk, isGalleryView as dl, isInstanceTerminal as dm, isInstanceWaiting as dn, isInverseSourceTab as dp, isLayoutRow as dq, isListView as dr, isNoValueOperator as ds, isRecordComplete as dt, isRelationGroup as du, isRelationSourceTab as dv, isRichtextTab as dw, isSimpleFormNode as dx, isStartNode as dy, isSystemFlow as dz, type FlowTextRow as e, validateDraftOrThrow as e0, validateObject as e1, validateObjectOrThrow as e2, type FlowRelationListRow as f, type WorkflowSlot as g, type WorkflowTheme as h, type RelationBufferMap as i, type AttributeType as j, type ViewConfig as k, type WorkflowStatus as l, type WorkflowLayout as m, type WorkflowConfig as n, type WorkflowDefinition as o, type WorkflowExecutionContext as p, type WorkflowTransition as q, type Location as r, type FormulaAttribute as s, type RollupAttribute as t, type CompletionStatus as u, type StatusAttribute as v, type SelectAttribute as w, type Phone as x, type Currency as y, type DocumentAttribute as z };
|