@stndrds/schema 0.1.0-alpha.38 → 0.1.0-alpha.39

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.
@@ -1227,6 +1227,8 @@ declare function isNoValueOperator(operator: FilterOperator): operator is NoValu
1227
1227
  * Ex: "mr" for the first contact, "company" for the company
1228
1228
  *
1229
1229
  * Note: Named "Slot" to avoid confusion with DB entities
1230
+ *
1231
+ * @deprecated Use WorkflowSlot from types/workflows instead
1230
1232
  */
1231
1233
  interface FlowSlot {
1232
1234
  /** Unique identifier for the slot (ex: "mr", "mme", "company") */
@@ -1966,269 +1968,1365 @@ interface AssignRoleInput {
1966
1968
  }
1967
1969
 
1968
1970
  /**
1969
- * Inline attribute group configuration
1970
- * Groups multiple attributes into a single composite field with dropdown editing
1971
- */
1972
- interface AttributeGroupField {
1973
- /** Unique identifier for the group */
1974
- id: string;
1975
- /** Display label for the composite field */
1976
- label: string;
1977
- /** Description shown in the dropdown */
1978
- description?: string;
1979
- /** Attribute names to include in this group */
1980
- attributes: string[];
1981
- /**
1982
- * Template for the display value
1983
- * Uses {attributeName} syntax for interpolation
1984
- * @example "{billing_street}, {billing_city} {billing_postal_code}"
1985
- */
1986
- displayTemplate?: string;
1987
- }
1988
- /**
1989
- * Field definition within a form group
1990
- * Can be either a single attribute or an inline attribute group
1991
- */
1992
- interface Field {
1993
- /** Attribute name to display (for single attribute fields) */
1994
- attribute?: string;
1995
- /** Inline attribute group (groups multiple attributes into one composite field) */
1996
- attributeGroup?: AttributeGroupField;
1997
- /** Grid span (1-12 columns) */
1998
- span?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
1999
- /** Override label for this view (only for single attribute fields) */
2000
- label?: string;
2001
- /** Force read-only display */
2002
- readOnly?: boolean;
2003
- }
2004
- /**
2005
- * Group of fields for organizing forms
2006
- */
2007
- interface Group {
2008
- id: string;
2009
- label: string;
2010
- description?: string;
2011
- fields: Field[];
2012
- collapsible?: boolean;
2013
- collapsed?: boolean;
2014
- order?: number;
2015
- }
2016
- type TabType = "form" | "table" | "custom" | "activity" | "notes";
2017
- /**
2018
- * Base properties shared by all tab types
1971
+ * Document generated during workflow execution
2019
1972
  */
2020
- interface BaseTab {
1973
+ interface GeneratedDocument {
1974
+ /** Document ID */
2021
1975
  id: string;
2022
- name: string;
2023
- label: string;
2024
- icon?: IconName;
2025
- order?: number;
2026
- /** If true, tab is defined by developer (protected) */
2027
- system?: boolean;
1976
+ /** URL to access the document */
1977
+ url: string;
1978
+ /** Document filename */
1979
+ filename?: string;
1980
+ /** MIME type */
1981
+ mimeType?: string;
1982
+ /** File size in bytes */
1983
+ size?: number;
1984
+ /** Additional metadata */
1985
+ metadata?: Record<string, unknown>;
2028
1986
  }
2029
1987
  /**
2030
- * Form tab - displays attributes organized in groups
1988
+ * Accumulated context during workflow execution.
1989
+ *
1990
+ * This context is built up as nodes execute and is passed to each node.
1991
+ * It contains all the data collected and generated during the workflow.
1992
+ *
1993
+ * @example
1994
+ * ```typescript
1995
+ * const context: WorkflowExecutionContext = {
1996
+ * slots: {
1997
+ * client: {
1998
+ * id: "rec_123",
1999
+ * firstName: "John",
2000
+ * lastName: "Doe",
2001
+ * email: "john@example.com",
2002
+ * type: "vip"
2003
+ * }
2004
+ * },
2005
+ * forms: {
2006
+ * "client-form": {
2007
+ * firstName: "John",
2008
+ * lastName: "Doe"
2009
+ * }
2010
+ * },
2011
+ * documents: {},
2012
+ * variables: {
2013
+ * totalAmount: 15000
2014
+ * },
2015
+ * conditionResults: {
2016
+ * "check-vip": true
2017
+ * }
2018
+ * };
2019
+ * ```
2031
2020
  */
2032
- interface FormTab extends BaseTab {
2033
- type: "form";
2034
- groups: Group[];
2021
+ interface WorkflowExecutionContext {
2022
+ /**
2023
+ * Records created/modified during execution, indexed by slot ID.
2024
+ * Contains the full record data for each slot.
2025
+ */
2026
+ slots: Record<string, Record<string, unknown>>;
2027
+ /**
2028
+ * Form submissions indexed by node ID.
2029
+ * Contains the raw form data submitted at each form node.
2030
+ */
2031
+ forms: Record<string, Record<string, unknown>>;
2032
+ /**
2033
+ * Documents generated during execution, indexed by node ID.
2034
+ * Contains document metadata and URLs.
2035
+ */
2036
+ documents: Record<string, GeneratedDocument>;
2037
+ /**
2038
+ * Custom variables set during execution.
2039
+ * Can be used by action nodes to store computed values.
2040
+ */
2041
+ variables: Record<string, unknown>;
2042
+ /**
2043
+ * Results of condition evaluations for debugging.
2044
+ * Indexed by condition node ID.
2045
+ */
2046
+ conditionResults: Record<string, boolean>;
2047
+ /**
2048
+ * IDs of records created during workflow completion.
2049
+ * Used for idempotence (avoid creating duplicates on retry).
2050
+ * Indexed by slot ID.
2051
+ */
2052
+ createdRecordIds?: Record<string, string>;
2035
2053
  }
2036
2054
  /**
2037
- * Shared properties for table tabs
2055
+ * Create an empty execution context
2038
2056
  */
2039
- interface TableTabBase extends BaseTab {
2040
- type: "table";
2041
- /** Columns to display (attribute names from target object) */
2042
- columns: string[];
2043
- /** Allow creating new records */
2044
- allowCreate?: boolean;
2045
- /** Allow inline editing */
2046
- allowEdit?: boolean;
2047
- /** Allow deleting records */
2048
- allowDelete?: boolean;
2049
- /** Default filters applied to the table */
2050
- filters?: FilterState;
2051
- /** Default sort rules */
2052
- sorts?: SortRule[];
2053
- }
2057
+ declare function createEmptyContext(): WorkflowExecutionContext;
2054
2058
  /**
2055
- * Direct table tab - displays records from a relation attribute on the current object
2059
+ * Get a value from the context using dot notation path.
2056
2060
  *
2057
- * @example Project.members → shows Users linked via the "members" relation
2061
+ * Supports paths like:
2062
+ * - "slots.client.email"
2063
+ * - "forms.step1.amount"
2064
+ * - "variables.customVar"
2065
+ *
2066
+ * @param context - The execution context
2067
+ * @param path - Dot notation path to the value
2068
+ * @returns The value at the path, or undefined if not found
2069
+ *
2070
+ * @example
2058
2071
  * ```typescript
2059
- * {
2060
- * type: "table",
2061
- * relationMode: "direct",
2062
- * relationAttribute: "members",
2063
- * columns: ["name", "email"]
2064
- * }
2072
+ * const email = getContextValue(context, "slots.client.email");
2073
+ * const amount = getContextValue(context, "forms.quote.amount");
2065
2074
  * ```
2066
2075
  */
2067
- interface DirectTableTab extends TableTabBase {
2068
- relationMode: "direct";
2069
- /** Relation attribute name on the current object */
2070
- relationAttribute: string;
2071
- }
2076
+ declare function getContextValue(context: WorkflowExecutionContext, path: string): unknown;
2072
2077
  /**
2073
- * Inverse table tab - displays records from another object that have a relation to us
2078
+ * Set a value in the context using dot notation path.
2074
2079
  *
2075
- * @example Contact.company on Company, shows Contacts that point to this Company
2080
+ * @param context - The execution context (mutated in place)
2081
+ * @param path - Dot notation path to set
2082
+ * @param value - Value to set
2083
+ *
2084
+ * @example
2076
2085
  * ```typescript
2077
- * {
2078
- * type: "table",
2079
- * relationMode: "inverse",
2080
- * sourceObject: "contacts",
2081
- * relationAttribute: "company",
2082
- * columns: ["firstName", "lastName", "email"]
2083
- * }
2086
+ * setContextValue(context, "variables.computed", 42);
2087
+ * setContextValue(context, "slots.client.status", "active");
2084
2088
  * ```
2085
2089
  */
2086
- interface InverseTableTab extends TableTabBase {
2087
- relationMode: "inverse";
2088
- /** Object name that has the relation to us */
2089
- sourceObject: string;
2090
- /** Relation attribute name on the source object that points to us */
2091
- relationAttribute: string;
2092
- }
2093
- /**
2094
- * Table tab - displays related records in a table
2095
- * Discriminated union by relationMode for type-safe configuration
2096
- */
2097
- type TableTab = DirectTableTab | InverseTableTab;
2090
+ declare function setContextValue(context: WorkflowExecutionContext, path: string, value: unknown): void;
2098
2091
  /**
2099
- * Custom tab - renders a developer-defined component
2092
+ * Merge form data into slot record
2100
2093
  */
2101
- interface CustomTab extends BaseTab {
2102
- type: "custom";
2103
- /** Component identifier to render */
2104
- component: string;
2105
- /** Props to pass to the component */
2106
- props?: Record<string, unknown>;
2107
- }
2094
+ declare function mergeFormToSlot(context: WorkflowExecutionContext, nodeId: string, slotId: string): void;
2095
+
2108
2096
  /**
2109
- * Activity tab - displays activity feed for the current record
2097
+ * All supported comparison operators for condition rules
2110
2098
  */
2111
- interface ActivityTab extends BaseTab {
2112
- type: "activity";
2113
- /** Maximum number of activities to display (optional) */
2114
- limit?: number;
2115
- }
2099
+ type ConditionOperator = "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "contains" | "startsWith" | "endsWith" | "isEmpty" | "isNotEmpty" | "in" | "notIn";
2116
2100
  /**
2117
- * Notes tab - displays notes linked to the current record
2101
+ * A single condition rule that compares a field value against a target value.
2118
2102
  *
2119
- * Shows all notes where linked_object_name matches the current object
2120
- * and linked_record_id matches the current record ID.
2121
- * Respects visibility rules (private notes only visible to author).
2103
+ * Field paths support dot notation for nested access:
2104
+ * - `slots.client.type` - Access slot record attribute
2105
+ * - `forms.step1.amount` - Access form submission data
2106
+ * - `context.variables.customVar` - Access custom variables
2122
2107
  *
2123
2108
  * @example
2124
2109
  * ```typescript
2125
- * {
2126
- * type: "notes",
2127
- * id: "notes",
2128
- * name: "notes",
2129
- * label: "Notes",
2130
- * allowCreate: true
2131
- * }
2110
+ * const rule: ConditionRule = {
2111
+ * field: "slots.client.type",
2112
+ * operator: "eq",
2113
+ * value: "vip"
2114
+ * };
2132
2115
  * ```
2133
2116
  */
2134
- interface NotesTab extends BaseTab {
2135
- type: "notes";
2136
- /** Show only private notes of the current user */
2137
- privateOnly?: boolean;
2138
- /** Allow creating new notes from this tab */
2139
- allowCreate?: boolean;
2117
+ interface ConditionRule {
2118
+ /** Field path to evaluate (dot notation) */
2119
+ field: string;
2120
+ /** Comparison operator */
2121
+ operator: ConditionOperator;
2122
+ /** Value to compare against (type depends on operator) */
2123
+ value: unknown;
2140
2124
  }
2141
2125
  /**
2142
- * Union of all tab types
2143
- */
2144
- type Tab = FormTab | TableTab | CustomTab | ActivityTab | NotesTab;
2145
- /**
2146
- * View layout mode
2147
- * - `page`: Full view with multiple tabs (form, table, activity, notes, custom)
2148
- * - `modal`: Simplified view for modals, single FormTab without tabs UI
2149
- */
2150
- type ViewLayout = "page" | "modal";
2151
- /**
2152
- * View definition - organizes object attributes into tabs/pages
2126
+ * A group of conditions combined with AND/OR logic.
2127
+ * Groups can be nested for complex conditions.
2153
2128
  *
2154
- * @example
2129
+ * @example Simple AND condition
2155
2130
  * ```typescript
2156
- * const companyView: ViewDefinition = {
2157
- * name: "detail",
2158
- * label: "Company Detail",
2159
- * object: "companies",
2160
- * layout: "page",
2161
- * tabs: [
2162
- * { type: "form", name: "general", label: "Info", groups: [...] },
2163
- * { type: "table", relationMode: "inverse", sourceObject: "contacts", relationAttribute: "company", columns: [...] }
2164
- * ],
2165
- * default: true,
2166
- * system: true
2131
+ * const condition: ConditionGroup = {
2132
+ * operator: "and",
2133
+ * rules: [
2134
+ * { field: "slots.client.type", operator: "eq", value: "vip" },
2135
+ * { field: "slots.client.active", operator: "eq", value: true }
2136
+ * ]
2137
+ * };
2138
+ * ```
2139
+ *
2140
+ * @example Nested condition (VIP OR (Premium AND Active))
2141
+ * ```typescript
2142
+ * const condition: ConditionGroup = {
2143
+ * operator: "or",
2144
+ * rules: [
2145
+ * { field: "slots.client.type", operator: "eq", value: "vip" },
2146
+ * {
2147
+ * operator: "and",
2148
+ * rules: [
2149
+ * { field: "slots.client.type", operator: "eq", value: "premium" },
2150
+ * { field: "slots.client.active", operator: "eq", value: true }
2151
+ * ]
2152
+ * }
2153
+ * ]
2167
2154
  * };
2168
2155
  * ```
2169
2156
  */
2170
- interface ViewDefinition {
2171
- id?: Uuid;
2172
- /** Technical name (kebab-case) */
2173
- name: string;
2174
- /** Display label */
2175
- label: string;
2176
- /** Description */
2177
- description?: string;
2178
- /** Icon */
2179
- icon?: IconName;
2180
- /** Object this view belongs to (object name) */
2181
- object: string;
2182
- /**
2183
- * Layout mode for the view
2184
- * - `page`: Full view with multiple tabs
2185
- * - `modal`: Simplified view for modals (single FormTab, no tabs UI)
2186
- * @default "page"
2187
- */
2188
- layout?: ViewLayout;
2189
- /** Tabs in this view */
2190
- tabs: Tab[];
2191
- /** Default view for this object (per layout) */
2192
- default?: boolean;
2193
- /** System view (defined by developer, protected) */
2194
- system?: boolean;
2195
- /** Extensible metadata */
2196
- metadata?: Record<string, unknown>;
2157
+ interface ConditionGroup {
2158
+ /** Logical operator to combine rules */
2159
+ operator: "and" | "or";
2160
+ /** Array of rules or nested groups */
2161
+ rules: Array<ConditionRule | ConditionGroup>;
2197
2162
  }
2198
2163
  /**
2199
- * Check if a tab is a form tab
2164
+ * Check if an item is a ConditionRule (not a ConditionGroup)
2200
2165
  */
2201
- declare function isFormTab(tab: Tab): tab is FormTab;
2166
+ declare function isConditionRule(item: ConditionRule | ConditionGroup): item is ConditionRule;
2202
2167
  /**
2203
- * Check if a tab is a table tab
2168
+ * Check if an item is a ConditionGroup
2204
2169
  */
2205
- declare function isTableTab(tab: Tab): tab is TableTab;
2170
+ declare function isConditionGroup(item: ConditionRule | ConditionGroup): item is ConditionGroup;
2206
2171
  /**
2207
- * Check if a table tab is a direct relation tab
2172
+ * Create a simple equality condition
2208
2173
  */
2209
- declare function isDirectTableTab(tab: Tab): tab is DirectTableTab;
2174
+ declare function eq(field: string, value: unknown): ConditionRule;
2210
2175
  /**
2211
- * Check if a table tab is an inverse relation tab
2176
+ * Create a simple inequality condition
2212
2177
  */
2213
- declare function isInverseTableTab(tab: Tab): tab is InverseTableTab;
2178
+ declare function neq(field: string, value: unknown): ConditionRule;
2214
2179
  /**
2215
- * Check if a tab is a custom tab
2180
+ * Create an AND condition group
2216
2181
  */
2217
- declare function isCustomTab(tab: Tab): tab is CustomTab;
2182
+ declare function and(...rules: Array<ConditionRule | ConditionGroup>): ConditionGroup;
2218
2183
  /**
2219
- * Check if a tab is an activity tab
2184
+ * Create an OR condition group
2220
2185
  */
2221
- declare function isActivityTab(tab: Tab): tab is ActivityTab;
2186
+ declare function or(...rules: Array<ConditionRule | ConditionGroup>): ConditionGroup;
2222
2187
  /**
2223
- * Check if a tab is a notes tab
2188
+ * Create an "in" condition (value in array)
2224
2189
  */
2225
- declare function isNotesTab(tab: Tab): tab is NotesTab;
2190
+ declare function inValues(field: string, values: unknown[]): ConditionRule;
2191
+ /**
2192
+ * Create an isEmpty condition
2193
+ */
2194
+ declare function isEmpty(field: string): ConditionRule;
2195
+ /**
2196
+ * Create an isNotEmpty condition
2197
+ */
2198
+ declare function isNotEmpty(field: string): ConditionRule;
2226
2199
 
2227
2200
  /**
2228
- * Object as stored in database (metadata)
2201
+ * Base properties shared by all workflow nodes
2229
2202
  */
2230
- interface DBObject extends Timestamps {
2231
- id: Uuid;
2203
+ interface BaseNode {
2204
+ /** Unique node identifier */
2205
+ id: string;
2206
+ }
2207
+ /**
2208
+ * Entry point of the workflow. Each workflow has exactly one StartNode.
2209
+ */
2210
+ interface StartNode extends BaseNode {
2211
+ type: "start";
2212
+ /** ID of the next node to execute (optional for drafts) */
2213
+ next?: string | null;
2214
+ }
2215
+ /**
2216
+ * Form node for collecting user input.
2217
+ *
2218
+ * Each FormNode acts as a "step" or "page" in the workflow.
2219
+ * It can contain fields from multiple slots, allowing complex forms
2220
+ * that collect data for different objects.
2221
+ *
2222
+ * @example Simple mode (single slot, quick setup)
2223
+ * ```typescript
2224
+ * const node: FormNode = {
2225
+ * type: "form",
2226
+ * id: "client-info",
2227
+ * label: "Client Information",
2228
+ * fields: [
2229
+ * { slotId: "client", attribute: "firstName" },
2230
+ * { slotId: "client", attribute: "lastName" },
2231
+ * ],
2232
+ * next: "check-vip"
2233
+ * };
2234
+ * ```
2235
+ *
2236
+ * @example Advanced mode (multiple slots, custom layout)
2237
+ * ```typescript
2238
+ * const node: FormNode = {
2239
+ * type: "form",
2240
+ * id: "couple-info",
2241
+ * label: "Couple Information",
2242
+ * rows: [
2243
+ * { id: "row-1", order: 1, fields: [
2244
+ * { id: "f1", slotId: "mr", attribute: "firstName" },
2245
+ * { id: "f2", slotId: "mme", attribute: "firstName" },
2246
+ * ]},
2247
+ * { id: "row-2", order: 2, fields: [
2248
+ * { id: "f3", slotId: "company", attribute: "name" },
2249
+ * ]},
2250
+ * ],
2251
+ * next: "check-vip"
2252
+ * };
2253
+ * ```
2254
+ */
2255
+ interface FormNode extends BaseNode {
2256
+ type: "form";
2257
+ /** Display label for the form step */
2258
+ label: string;
2259
+ /** Optional description */
2260
+ description?: string;
2261
+ /**
2262
+ * Simple mode: list of field references.
2263
+ * Each field specifies the slot and attribute.
2264
+ * Creates one field per row with equal width.
2265
+ * Mutually exclusive with `rows`.
2266
+ */
2267
+ fields?: FormFieldRef[];
2268
+ /**
2269
+ * Advanced mode: full row/field structure for custom layouts.
2270
+ * Each row can contain multiple fields from different slots.
2271
+ * Mutually exclusive with `fields`.
2272
+ */
2273
+ rows?: FlowRow[];
2274
+ /**
2275
+ * ID of the participant template allowed to fill this form.
2276
+ * If set, only this participant can execute this node.
2277
+ */
2278
+ participantId?: string | null;
2279
+ /** ID of the next node to execute (optional for drafts) */
2280
+ next?: string | null;
2281
+ }
2282
+ /**
2283
+ * Simple field reference for FormNode simple mode
2284
+ */
2285
+ interface FormFieldRef {
2286
+ /** Reference to WorkflowSlot.id */
2287
+ slotId: string;
2288
+ /** Attribute name on the object */
2289
+ attribute: string;
2290
+ }
2291
+ /**
2292
+ * Check if a FormNode uses simple mode (fields array)
2293
+ */
2294
+ declare function isSimpleFormNode(node: FormNode): boolean;
2295
+ /**
2296
+ * Check if a FormNode uses advanced mode (rows array)
2297
+ */
2298
+ declare function isAdvancedFormNode(node: FormNode): boolean;
2299
+
2300
+ /**
2301
+ * Conditional branching node.
2302
+ * Evaluates a condition and routes to different nodes based on the result.
2303
+ *
2304
+ * @example
2305
+ * ```typescript
2306
+ * const node: ConditionNode = {
2307
+ * type: "condition",
2308
+ * id: "check-vip",
2309
+ * label: "Is VIP Customer?",
2310
+ * condition: {
2311
+ * operator: "or",
2312
+ * rules: [
2313
+ * { field: "slots.client.type", operator: "eq", value: "vip" },
2314
+ * { field: "slots.client.type", operator: "eq", value: "premium" }
2315
+ * ]
2316
+ * },
2317
+ * onTrue: "premium-flow",
2318
+ * onFalse: "standard-flow"
2319
+ * };
2320
+ * ```
2321
+ */
2322
+ interface ConditionNode extends BaseNode {
2323
+ type: "condition";
2324
+ /** Display label for the condition */
2325
+ label: string;
2326
+ /** Condition to evaluate */
2327
+ condition: ConditionGroup;
2328
+ /** ID of node to execute if condition is true (optional for drafts) */
2329
+ onTrue?: string | null;
2330
+ /** ID of node to execute if condition is false (optional for drafts) */
2331
+ onFalse?: string | null;
2332
+ }
2333
+ /**
2334
+ * Terminal node marking the end of a workflow path.
2335
+ * A workflow can have multiple EndNodes for different outcomes.
2336
+ *
2337
+ * @example
2338
+ * ```typescript
2339
+ * const successEnd: EndNode = {
2340
+ * type: "end",
2341
+ * id: "end-success",
2342
+ * label: "Completed Successfully",
2343
+ * status: "completed"
2344
+ * };
2345
+ *
2346
+ * const declinedEnd: EndNode = {
2347
+ * type: "end",
2348
+ * id: "end-declined",
2349
+ * label: "Customer Declined",
2350
+ * status: "declined"
2351
+ * };
2352
+ * ```
2353
+ */
2354
+ interface EndNode extends BaseNode {
2355
+ type: "end";
2356
+ /** Optional display label */
2357
+ label?: string;
2358
+ /**
2359
+ * Final status for the workflow instance.
2360
+ * Common values: "completed", "declined", "cancelled", "expired"
2361
+ */
2362
+ status?: string;
2363
+ }
2364
+ /**
2365
+ * Union of all workflow node types.
2366
+ * Use discriminated union on `type` field for type narrowing.
2367
+ */
2368
+ type WorkflowNode = StartNode | FormNode | ConditionNode | EndNode;
2369
+ /**
2370
+ * All possible node types
2371
+ */
2372
+ type WorkflowNodeType = WorkflowNode["type"];
2373
+ /**
2374
+ * Check if a node is a StartNode
2375
+ */
2376
+ declare function isStartNode(node: WorkflowNode): node is StartNode;
2377
+ /**
2378
+ * Check if a node is a FormNode
2379
+ */
2380
+ declare function isFormNode(node: WorkflowNode): node is FormNode;
2381
+ /**
2382
+ * Check if a node is a ConditionNode
2383
+ */
2384
+ declare function isConditionNode(node: WorkflowNode): node is ConditionNode;
2385
+ /**
2386
+ * Check if a node is an EndNode
2387
+ */
2388
+ declare function isEndNode(node: WorkflowNode): node is EndNode;
2389
+ /**
2390
+ * Get the output node IDs from a node (for graph traversal)
2391
+ */
2392
+ declare function getNodeOutputs(node: WorkflowNode): string[];
2393
+
2394
+ /**
2395
+ * Logo configuration for external-facing interface
2396
+ */
2397
+ interface ThemeLogo {
2398
+ /** URL to the logo image */
2399
+ url: string;
2400
+ /** Alt text for accessibility */
2401
+ alt?: string;
2402
+ /** Max height in pixels */
2403
+ maxHeight?: number;
2404
+ }
2405
+ /**
2406
+ * Color configuration for theming
2407
+ */
2408
+ interface ThemeColors {
2409
+ /** Primary brand color (hex) */
2410
+ primary?: string;
2411
+ /** Primary color for text on primary background */
2412
+ primaryForeground?: string;
2413
+ /** Background color */
2414
+ background?: string;
2415
+ /** Foreground/text color */
2416
+ foreground?: string;
2417
+ /** Muted/secondary color */
2418
+ muted?: string;
2419
+ /** Border color */
2420
+ border?: string;
2421
+ /** Accent color for highlights */
2422
+ accent?: string;
2423
+ }
2424
+ /**
2425
+ * Typography configuration
2426
+ */
2427
+ interface ThemeTypography {
2428
+ /** Font family for headings */
2429
+ headingFont?: string;
2430
+ /** Font family for body text */
2431
+ bodyFont?: string;
2432
+ /** Base font size in pixels */
2433
+ baseFontSize?: number;
2434
+ }
2435
+ /**
2436
+ * Complete theme configuration for external-facing workflow interface.
2437
+ *
2438
+ * Allows full branding customization for forms displayed to external users.
2439
+ *
2440
+ * @example
2441
+ * ```typescript
2442
+ * const theme: WorkflowTheme = {
2443
+ * logo: {
2444
+ * url: "https://example.com/logo.png",
2445
+ * alt: "Company Logo",
2446
+ * maxHeight: 48
2447
+ * },
2448
+ * colors: {
2449
+ * primary: "#3B82F6",
2450
+ * primaryForeground: "#FFFFFF",
2451
+ * background: "#F8FAFC"
2452
+ * },
2453
+ * typography: {
2454
+ * headingFont: "Inter, sans-serif",
2455
+ * bodyFont: "Inter, sans-serif"
2456
+ * },
2457
+ * borderRadius: 8
2458
+ * };
2459
+ * ```
2460
+ */
2461
+ interface WorkflowTheme {
2462
+ /** Logo configuration */
2463
+ logo?: ThemeLogo;
2464
+ /** Color palette */
2465
+ colors?: ThemeColors;
2466
+ /** Typography settings */
2467
+ typography?: ThemeTypography;
2468
+ /** Border radius for cards/buttons in pixels */
2469
+ borderRadius?: number;
2470
+ /** Show powered by badge */
2471
+ showPoweredBy?: boolean;
2472
+ /** Custom CSS (advanced) */
2473
+ customCss?: string;
2474
+ }
2475
+ /**
2476
+ * Default theme values
2477
+ */
2478
+ declare const DEFAULT_THEME: Required<Pick<WorkflowTheme, "borderRadius" | "showPoweredBy">>;
2479
+ /**
2480
+ * Merge a partial theme with defaults
2481
+ */
2482
+ declare function mergeWithDefaults(theme?: WorkflowTheme): WorkflowTheme;
2483
+ /**
2484
+ * Generate CSS variables from theme colors
2485
+ */
2486
+ declare function generateCssVariables(colors?: ThemeColors): Record<string, string>;
2487
+
2488
+ /**
2489
+ * Mode for slot initialization when starting a workflow
2490
+ */
2491
+ type SlotMode = "create" | "select" | "optional";
2492
+ /**
2493
+ * Represents a "slot" for an object in the workflow.
2494
+ * Slots define which objects are manipulated during workflow execution.
2495
+ *
2496
+ * @example
2497
+ * ```typescript
2498
+ * const clientSlot: WorkflowSlot = {
2499
+ * id: "client",
2500
+ * objectName: "contacts",
2501
+ * label: "Client",
2502
+ * mode: "optional",
2503
+ * color: "blue",
2504
+ * icon: "User"
2505
+ * };
2506
+ * ```
2507
+ */
2508
+ interface WorkflowSlot {
2509
+ /** Unique identifier for the slot */
2510
+ id: string;
2511
+ /** Name of the object definition (e.g., "contacts", "companies") */
2512
+ objectName: string;
2513
+ /** Display label */
2514
+ label: string;
2515
+ /** How the slot is initialized at workflow start */
2516
+ mode: SlotMode;
2517
+ /** Color for visual distinction in the builder */
2518
+ color?: ColorId;
2519
+ /** Optional icon */
2520
+ icon?: IconName;
2521
+ }
2522
+ /**
2523
+ * Position of a node in the visual builder
2524
+ */
2525
+ interface NodePosition {
2526
+ x: number;
2527
+ y: number;
2528
+ }
2529
+ /**
2530
+ * Viewport state for the canvas
2531
+ */
2532
+ interface CanvasViewport {
2533
+ x: number;
2534
+ y: number;
2535
+ zoom: number;
2536
+ }
2537
+ /**
2538
+ * Layout information for the workflow builder.
2539
+ * Separated from business data to allow different visualizations.
2540
+ */
2541
+ interface WorkflowLayout {
2542
+ /** Node positions by node ID */
2543
+ positions: Record<string, NodePosition>;
2544
+ /** Canvas viewport state */
2545
+ viewport?: CanvasViewport;
2546
+ }
2547
+ /**
2548
+ * Authentication method for external participants
2549
+ */
2550
+ type AuthMethod = "signed_link" | "pin_code";
2551
+ /**
2552
+ * Channel for sending authentication credentials
2553
+ */
2554
+ type AuthChannel = "email" | "sms";
2555
+ /**
2556
+ * Default authentication configuration for a participant
2557
+ */
2558
+ interface ParticipantAuthConfig {
2559
+ /** Authentication method */
2560
+ method: AuthMethod;
2561
+ /** Link/code expiration (e.g., "7d", "24h") */
2562
+ expiresIn?: string;
2563
+ /** Channel for sending credentials */
2564
+ channel?: AuthChannel;
2565
+ }
2566
+ /**
2567
+ * Template for a participant in the workflow.
2568
+ * Defines who can participate and how they authenticate.
2569
+ *
2570
+ * Note: This is a template defined in WorkflowDefinition.
2571
+ * At runtime, WorkflowParticipation instances are created from this.
2572
+ *
2573
+ * @example
2574
+ * ```typescript
2575
+ * const externalClient: ParticipantTemplate = {
2576
+ * id: "external-client",
2577
+ * label: "Client Externe",
2578
+ * type: "external",
2579
+ * emailSource: "slots.client.email",
2580
+ * defaultAuth: {
2581
+ * method: "signed_link",
2582
+ * expiresIn: "7d",
2583
+ * channel: "email"
2584
+ * },
2585
+ * allowedNodeIds: ["client-form", "signature-step"]
2586
+ * };
2587
+ * ```
2588
+ */
2589
+ interface ParticipantTemplate {
2590
+ /** Unique identifier */
2591
+ id: string;
2592
+ /** Display label */
2593
+ label: string;
2594
+ /** Type of participant */
2595
+ type: "internal" | "external";
2596
+ /**
2597
+ * Path to email in execution context (for external participants).
2598
+ * Supports dot notation: "slots.client.email"
2599
+ */
2600
+ emailSource?: string;
2601
+ /**
2602
+ * Path to phone in execution context (for SMS auth).
2603
+ * Supports dot notation: "slots.client.phone"
2604
+ */
2605
+ phoneSource?: string;
2606
+ /** Default authentication configuration */
2607
+ defaultAuth: ParticipantAuthConfig;
2608
+ /** IDs of nodes this participant can execute */
2609
+ allowedNodeIds: string[];
2610
+ }
2611
+ /**
2612
+ * Global configuration options for a workflow
2613
+ */
2614
+ interface WorkflowConfig {
2615
+ /** Time-to-live for workflow instances (e.g., "30d") */
2616
+ instanceTtl?: string;
2617
+ /** Time-to-live for external participation links (e.g., "7d") */
2618
+ externalLinkTtl?: string;
2619
+ /** Whether external participants are allowed */
2620
+ allowExternalParticipants?: boolean;
2621
+ }
2622
+ /**
2623
+ * Workflow lifecycle status
2624
+ */
2625
+ type WorkflowStatus = "draft" | "published" | "archived";
2626
+ /**
2627
+ * Complete workflow definition (the "blueprint").
2628
+ *
2629
+ * This is the design-time representation of a workflow.
2630
+ * When executed, a WorkflowInstance is created from this definition.
2631
+ *
2632
+ * @example
2633
+ * ```typescript
2634
+ * const workflow: WorkflowDefinition = {
2635
+ * name: "client-onboarding",
2636
+ * label: "Client Onboarding",
2637
+ * status: "draft",
2638
+ * version: 1,
2639
+ * slots: [{ id: "client", objectName: "contacts", label: "Client", mode: "create" }],
2640
+ * nodes: {
2641
+ * "start": { type: "start", id: "start", next: "form-1" },
2642
+ * "form-1": { type: "form", id: "form-1", label: "Info", slotId: "client", fields: ["name"], next: "end" },
2643
+ * "end": { type: "end", id: "end" }
2644
+ * },
2645
+ * startNodeId: "start",
2646
+ * layout: { positions: { "start": { x: 0, y: 0 }, "form-1": { x: 200, y: 0 }, "end": { x: 400, y: 0 } } }
2647
+ * };
2648
+ * ```
2649
+ */
2650
+ interface WorkflowDefinition {
2651
+ /** Database ID */
2652
+ id?: Uuid;
2653
+ /** Technical name (kebab-case, unique per tenant) */
2654
+ name: string;
2655
+ /** Display label */
2656
+ label: string;
2657
+ /** Optional description */
2658
+ description?: string;
2659
+ /** Optional icon */
2660
+ icon?: IconName;
2661
+ /** Workflow lifecycle status */
2662
+ status: WorkflowStatus;
2663
+ /** Version number (incremented on publish) */
2664
+ version: number;
2665
+ /** Slots (objects) manipulated in this workflow */
2666
+ slots: WorkflowSlot[];
2667
+ /** Nodes indexed by ID for O(1) access */
2668
+ nodes: Record<string, WorkflowNode>;
2669
+ /** ID of the start node */
2670
+ startNodeId: string;
2671
+ /** Layout information for the visual builder */
2672
+ layout: WorkflowLayout;
2673
+ /** Participant templates (for external users) */
2674
+ participants?: ParticipantTemplate[];
2675
+ /** Theming for external-facing interface */
2676
+ theme?: WorkflowTheme;
2677
+ /** Global configuration options */
2678
+ config?: WorkflowConfig;
2679
+ /** Tenant ID for multi-tenant isolation */
2680
+ tenantId?: string;
2681
+ /** If true, defined in code (protected from UI deletion) */
2682
+ system?: boolean;
2683
+ /** Extensible metadata */
2684
+ metadata?: Record<string, unknown>;
2685
+ /** Timestamps */
2686
+ createdAt?: Date;
2687
+ updatedAt?: Date;
2688
+ }
2689
+ /**
2690
+ * Check if an object is a WorkflowDefinition
2691
+ */
2692
+ declare function isWorkflowDefinition(obj: unknown): obj is WorkflowDefinition;
2693
+ /**
2694
+ * Check if a workflow is published
2695
+ */
2696
+ declare function isWorkflowPublished(workflow: WorkflowDefinition): boolean;
2697
+ /**
2698
+ * Check if a workflow is a system workflow
2699
+ */
2700
+ declare function isSystemWorkflow(workflow: WorkflowDefinition): boolean;
2701
+
2702
+ /**
2703
+ * Status of a workflow instance
2704
+ */
2705
+ type InstanceStatus = "running" | "waiting" | "completed" | "failed" | "cancelled";
2706
+ /**
2707
+ * Record of a transition between nodes
2708
+ */
2709
+ interface WorkflowTransition {
2710
+ /** Timestamp of the transition */
2711
+ timestamp: Date;
2712
+ /** ID of the source node */
2713
+ fromNodeId: string | null;
2714
+ /** ID of the target node */
2715
+ toNodeId: string;
2716
+ /** Type of the target node */
2717
+ nodeType: string;
2718
+ /** ID of the user/participant who triggered the transition */
2719
+ triggeredBy?: string;
2720
+ /** Duration of node execution in milliseconds */
2721
+ durationMs?: number;
2722
+ /** Metadata about the transition */
2723
+ metadata?: Record<string, unknown>;
2724
+ }
2725
+ /**
2726
+ * Error information when instance is in "failed" status
2727
+ */
2728
+ interface WorkflowError {
2729
+ /** Error code for programmatic handling */
2730
+ code: string;
2731
+ /** Human-readable error message */
2732
+ message: string;
2733
+ /** ID of the node where error occurred */
2734
+ nodeId?: string;
2735
+ /** Stack trace (if available) */
2736
+ stack?: string;
2737
+ /** Additional error details */
2738
+ details?: Record<string, unknown>;
2739
+ /** Timestamp when error occurred */
2740
+ timestamp: Date;
2741
+ }
2742
+ /**
2743
+ * Information about the action the workflow is waiting for.
2744
+ * Populated when status is "waiting".
2745
+ */
2746
+ interface PendingAction {
2747
+ /** ID of the node waiting for action */
2748
+ nodeId: string;
2749
+ /** Type of the waiting node */
2750
+ nodeType: "form" | "signature" | "approval";
2751
+ /** Display label for the action */
2752
+ nodeLabel: string;
2753
+ /** ID of the participation required to complete this action */
2754
+ requiredParticipationId?: string;
2755
+ /** When the pending action expires */
2756
+ expiresAt?: Date;
2757
+ }
2758
+ /**
2759
+ * A specific execution of a workflow.
2760
+ *
2761
+ * Each instance maintains its own state, context, and history.
2762
+ * The workflow definition is snapshotted at creation to ensure
2763
+ * consistent execution even if the definition is later modified.
2764
+ *
2765
+ * @example
2766
+ * ```typescript
2767
+ * const instance: WorkflowInstance = {
2768
+ * id: "inst_123",
2769
+ * workflowId: "wf_456",
2770
+ * workflowVersion: 3,
2771
+ * workflowSnapshot: { ... }, // Full definition at creation time
2772
+ * status: "waiting",
2773
+ * currentNodeId: "client-form",
2774
+ * context: { slots: {}, forms: {}, documents: {}, variables: {}, conditionResults: {} },
2775
+ * history: [{ timestamp: new Date(), fromNodeId: null, toNodeId: "start", nodeType: "start" }],
2776
+ * pendingAction: {
2777
+ * nodeId: "client-form",
2778
+ * nodeType: "form",
2779
+ * nodeLabel: "Client Information",
2780
+ * requiredParticipationId: "part_789"
2781
+ * },
2782
+ * startedBy: "user_001",
2783
+ * tenantId: "tenant_abc",
2784
+ * createdAt: new Date()
2785
+ * };
2786
+ * ```
2787
+ */
2788
+ interface WorkflowInstance {
2789
+ /** Unique instance ID */
2790
+ id: Uuid;
2791
+ /** Reference to the workflow definition */
2792
+ workflowId: Uuid;
2793
+ /** Version of the workflow at creation time */
2794
+ workflowVersion: number;
2795
+ /** Complete snapshot of the workflow definition */
2796
+ workflowSnapshot: WorkflowDefinition;
2797
+ /** Current execution status */
2798
+ status: InstanceStatus;
2799
+ /** ID of the current node */
2800
+ currentNodeId: string;
2801
+ /** Accumulated execution context */
2802
+ context: WorkflowExecutionContext;
2803
+ /** History of node transitions */
2804
+ history: WorkflowTransition[];
2805
+ /** Current pending action (when status is "waiting") */
2806
+ pendingAction?: PendingAction;
2807
+ /** Error information (when status is "failed") */
2808
+ error?: WorkflowError;
2809
+ /** ID of the user who started the workflow */
2810
+ startedBy: string;
2811
+ /** Tenant ID for multi-tenant isolation */
2812
+ tenantId: string;
2813
+ /** When the instance expires */
2814
+ expiresAt?: Date;
2815
+ /** Timestamps */
2816
+ createdAt: Date;
2817
+ updatedAt: Date;
2818
+ completedAt?: Date;
2819
+ }
2820
+ /**
2821
+ * Check if an instance is in a terminal state
2822
+ */
2823
+ declare function isInstanceTerminal(instance: WorkflowInstance): boolean;
2824
+ /**
2825
+ * Check if an instance is waiting for external action
2826
+ */
2827
+ declare function isInstanceWaiting(instance: WorkflowInstance): boolean;
2828
+ /**
2829
+ * Check if an instance can be resumed
2830
+ */
2831
+ declare function canResumeInstance(instance: WorkflowInstance): boolean;
2832
+ /**
2833
+ * Create initial transition record for workflow start
2834
+ */
2835
+ declare function createStartTransition(startNodeId: string, startedBy: string): WorkflowTransition;
2836
+
2837
+ /**
2838
+ * Inline attribute group configuration
2839
+ * Groups multiple attributes into a single composite field with dropdown editing
2840
+ */
2841
+ interface AttributeGroupField {
2842
+ /** Unique identifier for the group */
2843
+ id: string;
2844
+ /** Display label for the composite field */
2845
+ label: string;
2846
+ /** Description shown in the dropdown */
2847
+ description?: string;
2848
+ /** Attribute names to include in this group */
2849
+ attributes: string[];
2850
+ /**
2851
+ * Template for the display value
2852
+ * Uses {attributeName} syntax for interpolation
2853
+ * @example "{billing_street}, {billing_city} {billing_postal_code}"
2854
+ */
2855
+ displayTemplate?: string;
2856
+ }
2857
+ /**
2858
+ * Field definition within a form group
2859
+ * Can be either a single attribute or an inline attribute group
2860
+ */
2861
+ interface Field {
2862
+ /** Attribute name to display (for single attribute fields) */
2863
+ attribute?: string;
2864
+ /** Inline attribute group (groups multiple attributes into one composite field) */
2865
+ attributeGroup?: AttributeGroupField;
2866
+ /** Grid span (1-12 columns) */
2867
+ span?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
2868
+ /** Override label for this view (only for single attribute fields) */
2869
+ label?: string;
2870
+ /** Force read-only display */
2871
+ readOnly?: boolean;
2872
+ }
2873
+ /**
2874
+ * Group of fields for organizing forms
2875
+ */
2876
+ interface Group {
2877
+ id: string;
2878
+ label: string;
2879
+ description?: string;
2880
+ fields: Field[];
2881
+ collapsible?: boolean;
2882
+ collapsed?: boolean;
2883
+ order?: number;
2884
+ }
2885
+ type TabType = "form" | "table" | "custom" | "activity" | "notes" | "flows";
2886
+ /**
2887
+ * Base properties shared by all tab types
2888
+ */
2889
+ interface BaseTab {
2890
+ id: string;
2891
+ name: string;
2892
+ label: string;
2893
+ icon?: IconName;
2894
+ order?: number;
2895
+ /** If true, tab is defined by developer (protected) */
2896
+ system?: boolean;
2897
+ }
2898
+ /**
2899
+ * Form tab - displays attributes organized in groups
2900
+ */
2901
+ interface FormTab extends BaseTab {
2902
+ type: "form";
2903
+ groups: Group[];
2904
+ }
2905
+ /**
2906
+ * Shared properties for table tabs
2907
+ */
2908
+ interface TableTabBase extends BaseTab {
2909
+ type: "table";
2910
+ /** Columns to display (attribute names from target object) */
2911
+ columns: string[];
2912
+ /** Allow creating new records */
2913
+ allowCreate?: boolean;
2914
+ /** Allow inline editing */
2915
+ allowEdit?: boolean;
2916
+ /** Allow deleting records */
2917
+ allowDelete?: boolean;
2918
+ /** Default filters applied to the table */
2919
+ filters?: FilterState;
2920
+ /** Default sort rules */
2921
+ sorts?: SortRule[];
2922
+ }
2923
+ /**
2924
+ * Direct table tab - displays records from a relation attribute on the current object
2925
+ *
2926
+ * @example Project.members → shows Users linked via the "members" relation
2927
+ * ```typescript
2928
+ * {
2929
+ * type: "table",
2930
+ * relationMode: "direct",
2931
+ * relationAttribute: "members",
2932
+ * columns: ["name", "email"]
2933
+ * }
2934
+ * ```
2935
+ */
2936
+ interface DirectTableTab extends TableTabBase {
2937
+ relationMode: "direct";
2938
+ /** Relation attribute name on the current object */
2939
+ relationAttribute: string;
2940
+ }
2941
+ /**
2942
+ * Inverse table tab - displays records from another object that have a relation to us
2943
+ *
2944
+ * @example Contact.company → on Company, shows Contacts that point to this Company
2945
+ * ```typescript
2946
+ * {
2947
+ * type: "table",
2948
+ * relationMode: "inverse",
2949
+ * sourceObject: "contacts",
2950
+ * relationAttribute: "company",
2951
+ * columns: ["firstName", "lastName", "email"]
2952
+ * }
2953
+ * ```
2954
+ */
2955
+ interface InverseTableTab extends TableTabBase {
2956
+ relationMode: "inverse";
2957
+ /** Object name that has the relation to us */
2958
+ sourceObject: string;
2959
+ /** Relation attribute name on the source object that points to us */
2960
+ relationAttribute: string;
2961
+ }
2962
+ /**
2963
+ * Table tab - displays related records in a table
2964
+ * Discriminated union by relationMode for type-safe configuration
2965
+ */
2966
+ type TableTab = DirectTableTab | InverseTableTab;
2967
+ /**
2968
+ * Custom tab - renders a developer-defined component
2969
+ */
2970
+ interface CustomTab extends BaseTab {
2971
+ type: "custom";
2972
+ /** Component identifier to render */
2973
+ component: string;
2974
+ /** Props to pass to the component */
2975
+ props?: Record<string, unknown>;
2976
+ }
2977
+ /**
2978
+ * Activity tab - displays activity feed for the current record
2979
+ */
2980
+ interface ActivityTab extends BaseTab {
2981
+ type: "activity";
2982
+ /** Maximum number of activities to display (optional) */
2983
+ limit?: number;
2984
+ }
2985
+ /**
2986
+ * Notes tab - displays notes linked to the current record
2987
+ *
2988
+ * Shows all notes where linked_object_name matches the current object
2989
+ * and linked_record_id matches the current record ID.
2990
+ * Respects visibility rules (private notes only visible to author).
2991
+ *
2992
+ * @example
2993
+ * ```typescript
2994
+ * {
2995
+ * type: "notes",
2996
+ * id: "notes",
2997
+ * name: "notes",
2998
+ * label: "Notes",
2999
+ * allowCreate: true
3000
+ * }
3001
+ * ```
3002
+ */
3003
+ interface NotesTab extends BaseTab {
3004
+ type: "notes";
3005
+ /** Show only private notes of the current user */
3006
+ privateOnly?: boolean;
3007
+ /** Allow creating new notes from this tab */
3008
+ allowCreate?: boolean;
3009
+ }
3010
+ /**
3011
+ * Flows tab - displays workflow instances linked to the current record
3012
+ *
3013
+ * Uses record.metadata.createdByWorkflow to find linked instances.
3014
+ * Allows launching new instances from published workflows that have
3015
+ * a slot matching the current object.
3016
+ *
3017
+ * @example
3018
+ * ```typescript
3019
+ * {
3020
+ * type: "flows",
3021
+ * id: "workflows",
3022
+ * name: "workflows",
3023
+ * label: "Workflows",
3024
+ * allowStart: true,
3025
+ * allowCancel: true
3026
+ * }
3027
+ * ```
3028
+ */
3029
+ interface FlowsTab extends BaseTab {
3030
+ type: "flows";
3031
+ /** Show only instances with specific statuses */
3032
+ statusFilter?: InstanceStatus[];
3033
+ /** Allow starting new workflow instances */
3034
+ allowStart?: boolean;
3035
+ /** Allow canceling running instances */
3036
+ allowCancel?: boolean;
3037
+ /** Columns to display in the instances table */
3038
+ columns?: ("workflow" | "status" | "startedBy" | "createdAt" | "updatedAt")[];
3039
+ }
3040
+ /**
3041
+ * Union of all tab types
3042
+ */
3043
+ type Tab = FormTab | TableTab | CustomTab | ActivityTab | NotesTab | FlowsTab;
3044
+ /**
3045
+ * View layout mode
3046
+ * - `page`: Full view with multiple tabs (form, table, activity, notes, custom)
3047
+ * - `modal`: Simplified view for modals, single FormTab without tabs UI
3048
+ */
3049
+ type ViewLayout = "page" | "modal";
3050
+ /**
3051
+ * View definition - organizes object attributes into tabs/pages
3052
+ *
3053
+ * @example
3054
+ * ```typescript
3055
+ * const companyView: ViewDefinition = {
3056
+ * name: "detail",
3057
+ * label: "Company Detail",
3058
+ * object: "companies",
3059
+ * layout: "page",
3060
+ * tabs: [
3061
+ * { type: "form", name: "general", label: "Info", groups: [...] },
3062
+ * { type: "table", relationMode: "inverse", sourceObject: "contacts", relationAttribute: "company", columns: [...] }
3063
+ * ],
3064
+ * default: true,
3065
+ * system: true
3066
+ * };
3067
+ * ```
3068
+ */
3069
+ interface ViewDefinition {
3070
+ id?: Uuid;
3071
+ /** Technical name (kebab-case) */
3072
+ name: string;
3073
+ /** Display label */
3074
+ label: string;
3075
+ /** Description */
3076
+ description?: string;
3077
+ /** Icon */
3078
+ icon?: IconName;
3079
+ /** Object this view belongs to (object name) */
3080
+ object: string;
3081
+ /**
3082
+ * Layout mode for the view
3083
+ * - `page`: Full view with multiple tabs
3084
+ * - `modal`: Simplified view for modals (single FormTab, no tabs UI)
3085
+ * @default "page"
3086
+ */
3087
+ layout?: ViewLayout;
3088
+ /** Tabs in this view */
3089
+ tabs: Tab[];
3090
+ /** Default view for this object (per layout) */
3091
+ default?: boolean;
3092
+ /** System view (defined by developer, protected) */
3093
+ system?: boolean;
3094
+ /** Extensible metadata */
3095
+ metadata?: Record<string, unknown>;
3096
+ }
3097
+ /**
3098
+ * Check if a tab is a form tab
3099
+ */
3100
+ declare function isFormTab(tab: Tab): tab is FormTab;
3101
+ /**
3102
+ * Check if a tab is a table tab
3103
+ */
3104
+ declare function isTableTab(tab: Tab): tab is TableTab;
3105
+ /**
3106
+ * Check if a table tab is a direct relation tab
3107
+ */
3108
+ declare function isDirectTableTab(tab: Tab): tab is DirectTableTab;
3109
+ /**
3110
+ * Check if a table tab is an inverse relation tab
3111
+ */
3112
+ declare function isInverseTableTab(tab: Tab): tab is InverseTableTab;
3113
+ /**
3114
+ * Check if a tab is a custom tab
3115
+ */
3116
+ declare function isCustomTab(tab: Tab): tab is CustomTab;
3117
+ /**
3118
+ * Check if a tab is an activity tab
3119
+ */
3120
+ declare function isActivityTab(tab: Tab): tab is ActivityTab;
3121
+ /**
3122
+ * Check if a tab is a notes tab
3123
+ */
3124
+ declare function isNotesTab(tab: Tab): tab is NotesTab;
3125
+ /**
3126
+ * Check if a tab is a flows tab
3127
+ */
3128
+ declare function isFlowsTab(tab: Tab): tab is FlowsTab;
3129
+
3130
+ /**
3131
+ * Status of a workflow participation
3132
+ */
3133
+ type ParticipationStatus = "pending" | "active" | "completed" | "expired" | "revoked";
3134
+ /**
3135
+ * Signed link authentication (JWT-based)
3136
+ */
3137
+ interface SignedLinkAuth {
3138
+ type: "signed_link";
3139
+ /** JWT token for authentication */
3140
+ token: string;
3141
+ /** Token expiration date */
3142
+ expiresAt: Date;
3143
+ /** Whether the link has been used */
3144
+ used: boolean;
3145
+ /** IP address that used the link (for audit) */
3146
+ usedFromIp?: string;
3147
+ }
3148
+ /**
3149
+ * PIN code authentication
3150
+ */
3151
+ interface PinCodeAuth {
3152
+ type: "pin_code";
3153
+ /** Hashed PIN code */
3154
+ codeHash: string;
3155
+ /** Code expiration date */
3156
+ expiresAt: Date;
3157
+ /** Number of failed attempts */
3158
+ attempts: number;
3159
+ /** Max allowed attempts before lockout */
3160
+ maxAttempts: number;
3161
+ /** Whether currently locked out */
3162
+ lockedOut: boolean;
3163
+ /** When lockout expires */
3164
+ lockedUntil?: Date;
3165
+ }
3166
+ /**
3167
+ * Union of all authentication types
3168
+ */
3169
+ type ParticipationAuth = SignedLinkAuth | PinCodeAuth;
3170
+ /**
3171
+ * Represents an external or internal user's participation in a workflow instance.
3172
+ *
3173
+ * Created at runtime from ParticipantTemplate when the workflow reaches
3174
+ * a node that requires participation.
3175
+ *
3176
+ * @example
3177
+ * ```typescript
3178
+ * const participation: WorkflowParticipation = {
3179
+ * id: "part_123",
3180
+ * instanceId: "inst_456",
3181
+ * participantTemplateId: "external-client",
3182
+ * type: "external",
3183
+ * email: "client@example.com",
3184
+ * name: "John Doe",
3185
+ * auth: {
3186
+ * type: "signed_link",
3187
+ * token: "eyJ...",
3188
+ * expiresAt: new Date("2024-01-15"),
3189
+ * used: false
3190
+ * },
3191
+ * allowedNodeIds: ["client-form", "signature-step"],
3192
+ * status: "pending",
3193
+ * createdAt: new Date()
3194
+ * };
3195
+ * ```
3196
+ */
3197
+ interface WorkflowParticipation {
3198
+ /** Unique participation ID */
3199
+ id: Uuid;
3200
+ /** ID of the workflow instance */
3201
+ instanceId: Uuid;
3202
+ /** ID of the participant template this was created from */
3203
+ participantTemplateId: string;
3204
+ /** Type of participant */
3205
+ type: "internal" | "external";
3206
+ /** Participant's email */
3207
+ email: string;
3208
+ /** Participant's display name */
3209
+ name?: string;
3210
+ /** Participant's phone (for SMS auth) */
3211
+ phone?: string;
3212
+ /** Authentication credentials */
3213
+ auth: ParticipationAuth;
3214
+ /** IDs of nodes this participant can execute */
3215
+ allowedNodeIds: string[];
3216
+ /** Current participation status */
3217
+ status: ParticipationStatus;
3218
+ /** When the participant authenticated */
3219
+ authenticatedAt?: Date;
3220
+ /** Last activity timestamp */
3221
+ lastActivityAt?: Date;
3222
+ /** Completed node IDs */
3223
+ completedNodeIds: string[];
3224
+ /** Timestamps */
3225
+ createdAt: Date;
3226
+ updatedAt: Date;
3227
+ }
3228
+ /**
3229
+ * Check if auth is signed link type
3230
+ */
3231
+ declare function isSignedLinkAuth(auth: ParticipationAuth): auth is SignedLinkAuth;
3232
+ /**
3233
+ * Check if auth is PIN code type
3234
+ */
3235
+ declare function isPinCodeAuth(auth: ParticipationAuth): auth is PinCodeAuth;
3236
+ /**
3237
+ * Check if participation is active and can execute nodes
3238
+ */
3239
+ declare function canParticipate(participation: WorkflowParticipation): boolean;
3240
+ /**
3241
+ * Check if participation can be authenticated (pending and not expired)
3242
+ */
3243
+ declare function canAuthenticate(participation: WorkflowParticipation): boolean;
3244
+ /**
3245
+ * Check if a participation can execute a specific node
3246
+ */
3247
+ declare function canExecuteNode(participation: WorkflowParticipation, nodeId: string): boolean;
3248
+
3249
+ /**
3250
+ * Workflow access mode - determines how the user is authenticated
3251
+ * and what permissions they have.
3252
+ */
3253
+ type WorkflowAccessMode = {
3254
+ type: "internal";
3255
+ userId: string;
3256
+ } | {
3257
+ type: "external";
3258
+ token: string;
3259
+ participationId: string;
3260
+ };
3261
+ /**
3262
+ * Reason why a field is read-only
3263
+ */
3264
+ type ReadOnlyReason = "user_field" | "computed" | "system";
3265
+ /**
3266
+ * Context for a single form field.
3267
+ * Contains schema, current value, and access information.
3268
+ */
3269
+ interface FormFieldContext {
3270
+ /** Slot ID this field belongs to */
3271
+ slotId: string;
3272
+ /** Attribute name */
3273
+ attributeName: string;
3274
+ /** Full attribute schema */
3275
+ schema: Attribute;
3276
+ /** Current value (from slot) */
3277
+ value: unknown;
3278
+ /** Is this field read-only for the current access mode? */
3279
+ readOnly: boolean;
3280
+ /** Reason for read-only (if applicable) */
3281
+ readOnlyReason?: ReadOnlyReason;
3282
+ }
3283
+ /**
3284
+ * A row of form fields.
3285
+ * Preserves the row structure defined in the workflow form node.
3286
+ */
3287
+ interface FormFieldRow {
3288
+ /** Row ID from the workflow definition */
3289
+ id: string;
3290
+ /** Fields in this row */
3291
+ fields: FormFieldContext[];
3292
+ }
3293
+ /**
3294
+ * Form node information
3295
+ */
3296
+ interface FormNodeInfo {
3297
+ /** Node ID */
3298
+ id: string;
3299
+ /** Display label */
3300
+ label: string;
3301
+ /** Optional description */
3302
+ description?: string;
3303
+ }
3304
+ /**
3305
+ * Complete form context response.
3306
+ * Contains all information needed to render a workflow form.
3307
+ */
3308
+ interface FormContextResponse {
3309
+ /** Form node definition */
3310
+ node: FormNodeInfo;
3311
+ /** Structured rows with their fields (preserves layout from workflow) */
3312
+ rows: FormFieldRow[];
3313
+ /** Flat list of all fields (for backward compatibility) */
3314
+ fields: FormFieldContext[];
3315
+ /** Current slot values */
3316
+ slotValues: Record<string, Record<string, unknown>>;
3317
+ /** Slot definitions for displaying slot labels and colors */
3318
+ slots: WorkflowSlot[];
3319
+ /** Workflow theme for styling */
3320
+ theme?: WorkflowTheme;
3321
+ /** Access mode for the current user */
3322
+ accessMode: "internal" | "external";
3323
+ }
3324
+
3325
+ /**
3326
+ * Object as stored in database (metadata)
3327
+ */
3328
+ interface DBObject extends Timestamps {
3329
+ id: Uuid;
2232
3330
  tenantId: TenantId;
2233
3331
  name: string;
2234
3332
  label: string;
@@ -2482,51 +3580,175 @@ interface UpsertDBView {
2482
3580
  metadata?: Record<string, unknown>;
2483
3581
  }
2484
3582
  /**
2485
- * Flow as stored in database
3583
+ * Workflow definition as stored in database.
3584
+ * Uses snake_case to match database column names.
2486
3585
  */
2487
- interface DBFlow extends Timestamps {
2488
- id: Uuid;
2489
- tenantId: TenantId;
3586
+ interface DBWorkflow {
3587
+ id: string;
3588
+ tenant_id: string;
2490
3589
  name: string;
2491
3590
  label: string;
2492
- description?: string;
2493
- icon?: IconName;
2494
- status: FlowStatus;
3591
+ description: string | null;
3592
+ icon: string | null;
3593
+ status: WorkflowStatus;
2495
3594
  version: number;
2496
- slots: FlowSlot[];
2497
- pages: FlowPage[];
2498
- relations: FlowRelation[];
3595
+ slots: WorkflowSlot[];
3596
+ nodes: Record<string, WorkflowNode>;
3597
+ start_node_id: string;
3598
+ layout: WorkflowLayout;
3599
+ participants: ParticipantTemplate[] | null;
3600
+ theme: WorkflowTheme | null;
3601
+ config: WorkflowConfig | null;
2499
3602
  system: boolean;
2500
- metadata?: Record<string, unknown>;
3603
+ metadata: Record<string, unknown> | null;
3604
+ created_at: string;
3605
+ updated_at: string;
2501
3606
  }
2502
3607
  /**
2503
- * Data for creating a new flow.
3608
+ * Data for creating a new workflow.
2504
3609
  * Tenant ID is automatically set from the execution context.
2505
3610
  */
2506
- interface CreateDBFlow {
3611
+ interface CreateDBWorkflow {
2507
3612
  name: string;
2508
3613
  label: string;
2509
3614
  description?: string;
2510
3615
  icon?: IconName;
2511
- status?: FlowStatus;
3616
+ status?: WorkflowStatus;
2512
3617
  version?: number;
2513
- slots: FlowSlot[];
2514
- pages: FlowPage[];
2515
- relations: FlowRelation[];
3618
+ slots: WorkflowSlot[];
3619
+ nodes: Record<string, WorkflowNode>;
3620
+ startNodeId: string;
3621
+ layout: WorkflowLayout;
3622
+ participants?: ParticipantTemplate[];
3623
+ theme?: WorkflowTheme;
3624
+ config?: WorkflowConfig;
2516
3625
  system?: boolean;
2517
3626
  metadata?: Record<string, unknown>;
2518
3627
  }
2519
- interface UpdateDBFlow {
3628
+ /**
3629
+ * Data for updating a workflow.
3630
+ */
3631
+ interface UpdateDBWorkflow {
2520
3632
  label?: string;
2521
3633
  description?: string;
2522
3634
  icon?: IconName;
2523
- status?: FlowStatus;
3635
+ status?: WorkflowStatus;
2524
3636
  version?: number;
2525
- slots?: FlowSlot[];
2526
- pages?: FlowPage[];
2527
- relations?: FlowRelation[];
3637
+ slots?: WorkflowSlot[];
3638
+ nodes?: Record<string, WorkflowNode>;
3639
+ startNodeId?: string;
3640
+ layout?: WorkflowLayout;
3641
+ participants?: ParticipantTemplate[];
3642
+ theme?: WorkflowTheme;
3643
+ config?: WorkflowConfig;
2528
3644
  metadata?: Record<string, unknown>;
2529
3645
  }
3646
+ /**
3647
+ * Workflow instance as stored in database.
3648
+ * Uses snake_case to match database column names.
3649
+ */
3650
+ interface DBWorkflowInstance {
3651
+ id: string;
3652
+ tenant_id: string;
3653
+ workflow_id: string;
3654
+ workflow_version: number;
3655
+ workflow_snapshot: WorkflowDefinition;
3656
+ status: InstanceStatus;
3657
+ current_node_id: string;
3658
+ context: WorkflowExecutionContext;
3659
+ history: WorkflowTransition[];
3660
+ pending_action: PendingAction | null;
3661
+ error: {
3662
+ code: string;
3663
+ message: string;
3664
+ nodeId?: string;
3665
+ } | null;
3666
+ started_by: string;
3667
+ expires_at: string | null;
3668
+ created_at: string;
3669
+ updated_at: string;
3670
+ completed_at: string | null;
3671
+ }
3672
+ /**
3673
+ * Data for creating a workflow instance.
3674
+ * Tenant ID is automatically set from the execution context.
3675
+ */
3676
+ interface CreateDBWorkflowInstance {
3677
+ workflowId: string;
3678
+ workflowVersion: number;
3679
+ workflowSnapshot: WorkflowDefinition;
3680
+ status: InstanceStatus;
3681
+ currentNodeId: string;
3682
+ context: WorkflowExecutionContext;
3683
+ history: WorkflowTransition[];
3684
+ pendingAction?: PendingAction;
3685
+ startedBy: string;
3686
+ expiresAt?: Date;
3687
+ }
3688
+ /**
3689
+ * Data for updating a workflow instance.
3690
+ */
3691
+ interface UpdateDBWorkflowInstance {
3692
+ status?: InstanceStatus;
3693
+ currentNodeId?: string;
3694
+ context?: WorkflowExecutionContext;
3695
+ history?: WorkflowTransition[];
3696
+ pendingAction?: PendingAction | null;
3697
+ error?: {
3698
+ code: string;
3699
+ message: string;
3700
+ nodeId?: string;
3701
+ } | null;
3702
+ expiresAt?: Date | null;
3703
+ completedAt?: Date | null;
3704
+ }
3705
+ /**
3706
+ * Workflow participation as stored in database.
3707
+ * Uses snake_case to match database column names.
3708
+ */
3709
+ interface DBWorkflowParticipation {
3710
+ id: string;
3711
+ tenant_id: string;
3712
+ instance_id: string;
3713
+ participant_template_id: string;
3714
+ type: "internal" | "external";
3715
+ email: string;
3716
+ name: string | null;
3717
+ phone: string | null;
3718
+ auth: ParticipationAuth;
3719
+ allowed_node_ids: string[];
3720
+ status: ParticipationStatus;
3721
+ authenticated_at: string | null;
3722
+ last_activity_at: string | null;
3723
+ completed_node_ids: string[];
3724
+ created_at: string;
3725
+ updated_at: string;
3726
+ }
3727
+ /**
3728
+ * Data for creating a workflow participation.
3729
+ * Tenant ID is automatically set from the execution context.
3730
+ */
3731
+ interface CreateDBWorkflowParticipation {
3732
+ instanceId: string;
3733
+ participantTemplateId: string;
3734
+ type: "internal" | "external";
3735
+ email: string;
3736
+ name?: string;
3737
+ phone?: string;
3738
+ auth: ParticipationAuth;
3739
+ allowedNodeIds: string[];
3740
+ status?: ParticipationStatus;
3741
+ }
3742
+ /**
3743
+ * Data for updating a workflow participation.
3744
+ */
3745
+ interface UpdateDBWorkflowParticipation {
3746
+ status?: ParticipationStatus;
3747
+ auth?: ParticipationAuth;
3748
+ authenticatedAt?: Date | null;
3749
+ lastActivityAt?: Date | null;
3750
+ completedNodeIds?: string[];
3751
+ }
2530
3752
  /**
2531
3753
  * Result of an operation
2532
3754
  */
@@ -4166,18 +5388,27 @@ interface ObjectRecordsRepository {
4166
5388
  * Batch update labels for all records of an object.
4167
5389
  * Used after labelExpression changes to refresh all record labels.
4168
5390
  *
5391
+ * Supports both sync and async compute functions to allow for
5392
+ * relation resolution when the label expression references relations.
5393
+ *
4169
5394
  * @param objectId - Object UUID
4170
- * @param computeLabel - Function to compute label from record values
5395
+ * @param computeLabel - Function to compute label from record values (sync or async)
4171
5396
  * @returns Number of records that were updated
4172
5397
  *
4173
5398
  * @example
4174
5399
  * ```typescript
5400
+ * // Sync compute (simple labels)
4175
5401
  * const updated = await repo.batchRefreshLabels("obj-123", (values) => {
4176
5402
  * return `${values.sku} - ${values.name}`;
4177
5403
  * });
5404
+ *
5405
+ * // Async compute (with relation resolution)
5406
+ * const updated = await repo.batchRefreshLabels("obj-123", async (values) => {
5407
+ * return await computeLabelWithRelations(template, values, attributes, resolver);
5408
+ * });
4178
5409
  * ```
4179
5410
  */
4180
- batchRefreshLabels(objectId: Uuid, computeLabel: (values: Record<string, unknown>) => string): Promise<number>;
5411
+ batchRefreshLabels(objectId: Uuid, computeLabel: (values: Record<string, unknown>) => Promise<string> | string): Promise<number>;
4181
5412
  /**
4182
5413
  * Batch update completion status for all records of an object.
4183
5414
  * Used after required attribute changes to refresh status.
@@ -4276,55 +5507,186 @@ interface ViewsRepository {
4276
5507
  upsert(data: UpsertDBView): Promise<DBView>;
4277
5508
  }
4278
5509
  /**
4279
- * Repository for flow definitions.
5510
+ * Repository for workflow definitions.
4280
5511
  *
4281
5512
  * This repository is optional - if not provided in the DatabaseAdapter,
4282
- * flow features are disabled.
5513
+ * workflow features are disabled.
4283
5514
  *
4284
5515
  * All operations are automatically scoped to the current tenant
4285
5516
  * from the execution context (via AsyncLocalStorage).
4286
5517
  */
4287
- interface FlowsRepository {
5518
+ interface WorkflowsRepository {
4288
5519
  /**
4289
- * Find flow by ID.
5520
+ * Find workflow by ID.
4290
5521
  * Automatically filtered by current tenant context.
4291
5522
  */
4292
- findById(id: Uuid): Promise<DBFlow | null>;
5523
+ findById(id: Uuid): Promise<DBWorkflow | null>;
4293
5524
  /**
4294
- * Find flow by name.
5525
+ * Find workflow by name.
4295
5526
  * Automatically filtered by current tenant context.
4296
5527
  */
4297
- findByName(name: string): Promise<DBFlow | null>;
5528
+ findByName(name: string): Promise<DBWorkflow | null>;
4298
5529
  /**
4299
- * Find all flows for current tenant.
4300
- * Automatically filtered by current tenant context.
5530
+ * Find system workflow by name (for sync).
5531
+ * System workflows are shared across tenants.
4301
5532
  */
4302
- findAllForTenant(): Promise<DBFlow[]>;
5533
+ findSystemByName(name: string): Promise<DBWorkflow | null>;
4303
5534
  /**
4304
- * Find flows by status.
5535
+ * List all workflows for current tenant.
4305
5536
  * Automatically filtered by current tenant context.
4306
5537
  */
4307
- findByStatus(status: FlowStatus): Promise<DBFlow[]>;
5538
+ list(): Promise<DBWorkflow[]>;
4308
5539
  /**
4309
- * Find system flow by name (for sync).
4310
- * System flows are shared across tenants.
5540
+ * List workflows by status.
5541
+ * Automatically filtered by current tenant context.
4311
5542
  */
4312
- findSystemByName(name: string): Promise<DBFlow | null>;
5543
+ listByStatus(status: WorkflowStatus): Promise<DBWorkflow[]>;
4313
5544
  /**
4314
- * Create flow.
5545
+ * Create workflow.
4315
5546
  * Tenant ID is automatically set from context.
4316
5547
  */
4317
- create(data: CreateDBFlow): Promise<DBFlow>;
5548
+ create(data: CreateDBWorkflow): Promise<DBWorkflow>;
4318
5549
  /**
4319
- * Update flow.
5550
+ * Update workflow.
4320
5551
  * Automatically filtered by current tenant context.
4321
5552
  */
4322
- update(id: Uuid, data: Partial<UpdateDBFlow>): Promise<DBFlow>;
5553
+ update(id: Uuid, data: Partial<UpdateDBWorkflow>): Promise<DBWorkflow>;
4323
5554
  /**
4324
- * Delete flow.
5555
+ * Delete workflow.
4325
5556
  * Automatically filtered by current tenant context.
4326
5557
  */
4327
5558
  delete(id: Uuid): Promise<void>;
5559
+ /**
5560
+ * Upsert workflow (create or update based on name + system flag).
5561
+ * Tenant ID is automatically set from context.
5562
+ */
5563
+ upsert(data: CreateDBWorkflow): Promise<DBWorkflow>;
5564
+ }
5565
+ /**
5566
+ * Repository for workflow instances (running/completed workflows).
5567
+ *
5568
+ * This repository is optional - if not provided in the DatabaseAdapter,
5569
+ * workflow execution features are disabled.
5570
+ *
5571
+ * All operations are automatically scoped to the current tenant
5572
+ * from the execution context (via AsyncLocalStorage).
5573
+ */
5574
+ interface WorkflowInstancesRepository {
5575
+ /**
5576
+ * Find instance by ID.
5577
+ * Automatically filtered by current tenant context.
5578
+ */
5579
+ findById(id: Uuid): Promise<DBWorkflowInstance | null>;
5580
+ /**
5581
+ * Find instances by workflow ID.
5582
+ * Automatically filtered by current tenant context.
5583
+ */
5584
+ findByWorkflowId(workflowId: Uuid): Promise<DBWorkflowInstance[]>;
5585
+ /**
5586
+ * Find instances by workflow name.
5587
+ * Automatically filtered by current tenant context.
5588
+ */
5589
+ findByWorkflowName(workflowName: string): Promise<DBWorkflowInstance[]>;
5590
+ /**
5591
+ * List all instances for current tenant.
5592
+ * Automatically filtered by current tenant context.
5593
+ */
5594
+ list(options?: ListOptions): Promise<{
5595
+ instances: DBWorkflowInstance[];
5596
+ total: number;
5597
+ }>;
5598
+ /**
5599
+ * List instances by status.
5600
+ * Automatically filtered by current tenant context.
5601
+ */
5602
+ listByStatus(status: InstanceStatus): Promise<DBWorkflowInstance[]>;
5603
+ /**
5604
+ * Create instance.
5605
+ * Tenant ID is automatically set from context.
5606
+ */
5607
+ create(data: CreateDBWorkflowInstance): Promise<DBWorkflowInstance>;
5608
+ /**
5609
+ * Update instance.
5610
+ * Automatically filtered by current tenant context.
5611
+ */
5612
+ update(id: Uuid, data: Partial<UpdateDBWorkflowInstance>): Promise<DBWorkflowInstance>;
5613
+ /**
5614
+ * Upsert instance (create or update based on ID).
5615
+ * Tenant ID is automatically set from context.
5616
+ */
5617
+ upsert(data: CreateDBWorkflowInstance & {
5618
+ id: string;
5619
+ }): Promise<DBWorkflowInstance>;
5620
+ /**
5621
+ * Find instances that reference a specific record in their slot context.
5622
+ * Searches in context.slots for slots where objectName and id match.
5623
+ * Automatically filtered by current tenant context.
5624
+ *
5625
+ * This method is required and must be implemented by all adapters.
5626
+ * No fallback is provided for performance reasons - all implementations
5627
+ * must use database-level optimizations (e.g., JSONB queries in PostgreSQL).
5628
+ *
5629
+ * @param objectName - Object name to match in slot data
5630
+ * @param recordId - Record ID to match in slot data
5631
+ * @param options - Optional filtering options
5632
+ */
5633
+ findByRecordInSlots(objectName: string, recordId: string, options?: {
5634
+ status?: InstanceStatus;
5635
+ limit?: number;
5636
+ offset?: number;
5637
+ }): Promise<{
5638
+ instances: DBWorkflowInstance[];
5639
+ total: number;
5640
+ }>;
5641
+ }
5642
+ /**
5643
+ * Repository for workflow participations (external user access to workflows).
5644
+ *
5645
+ * This repository is optional - if not provided in the DatabaseAdapter,
5646
+ * external participation features are disabled.
5647
+ *
5648
+ * All operations are automatically scoped to the current tenant
5649
+ * from the execution context (via AsyncLocalStorage).
5650
+ */
5651
+ interface WorkflowParticipationsRepository {
5652
+ /**
5653
+ * Find participation by ID.
5654
+ * Automatically filtered by current tenant context.
5655
+ */
5656
+ findById(id: Uuid): Promise<DBWorkflowParticipation | null>;
5657
+ /**
5658
+ * Find participations by instance ID.
5659
+ * Automatically filtered by current tenant context.
5660
+ */
5661
+ findByInstanceId(instanceId: Uuid): Promise<DBWorkflowParticipation[]>;
5662
+ /**
5663
+ * Find participations by email.
5664
+ * Automatically filtered by current tenant context.
5665
+ */
5666
+ findByEmail(email: string): Promise<DBWorkflowParticipation[]>;
5667
+ /**
5668
+ * Create participation.
5669
+ * Tenant ID is automatically set from context.
5670
+ */
5671
+ create(data: CreateDBWorkflowParticipation): Promise<DBWorkflowParticipation>;
5672
+ /**
5673
+ * Update participation.
5674
+ * Automatically filtered by current tenant context.
5675
+ */
5676
+ update(id: Uuid, data: Partial<UpdateDBWorkflowParticipation>): Promise<DBWorkflowParticipation>;
5677
+ /**
5678
+ * Upsert participation (create or update based on ID).
5679
+ * Tenant ID is automatically set from context.
5680
+ */
5681
+ upsert(data: CreateDBWorkflowParticipation & {
5682
+ id: string;
5683
+ }): Promise<DBWorkflowParticipation>;
5684
+ /**
5685
+ * Update only the auth field of a participation.
5686
+ * Used for recording failed PIN attempts without touching other fields.
5687
+ * Automatically filtered by current tenant context.
5688
+ */
5689
+ updateAuth(id: Uuid, auth: ParticipationAuth): Promise<void>;
4328
5690
  }
4329
5691
  /**
4330
5692
  * Repository for audit logs.
@@ -4667,23 +6029,171 @@ interface UploadFileInput {
4667
6029
  * import { createPrismaAdapter } from "./adapters/prisma";
4668
6030
  * import { prisma } from "./db";
4669
6031
  *
4670
- * const adapter = createPrismaAdapter(prisma);
4671
- * ```
6032
+ * const adapter = createPrismaAdapter(prisma);
6033
+ * ```
6034
+ */
6035
+ interface DatabaseAdapter {
6036
+ objects: ObjectsRepository;
6037
+ attributes: AttributesRepository;
6038
+ views: ViewsRepository;
6039
+ workflows?: WorkflowsRepository;
6040
+ workflowInstances?: WorkflowInstancesRepository;
6041
+ workflowParticipations?: WorkflowParticipationsRepository;
6042
+ userProfiles: UserProfilesRepository;
6043
+ files: FilesRepository;
6044
+ objectRecords: ObjectRecordsRepository;
6045
+ permissions?: PermissionsRepository;
6046
+ audit?: AuditRepository;
6047
+ storage?: StorageAdapter;
6048
+ cache?: CacheAdapter;
6049
+ transaction<T>(callback: (adapter: DatabaseAdapter) => Promise<T>): Promise<T>;
6050
+ }
6051
+
6052
+ /**
6053
+ * Payload encoded in the participation token
6054
+ */
6055
+ interface ParticipationTokenPayload {
6056
+ /** Participation ID */
6057
+ participationId: string;
6058
+ /** Instance ID */
6059
+ instanceId: string;
6060
+ /** Tenant ID */
6061
+ tenantId: string;
6062
+ /** Expiration timestamp (unix ms) */
6063
+ exp: number;
6064
+ /** Issued at timestamp (unix ms) */
6065
+ iat: number;
6066
+ /** Token ID (for revocation) */
6067
+ jti: string;
6068
+ }
6069
+ /**
6070
+ * Options for token generation
6071
+ */
6072
+ interface TokenGenerationOptions {
6073
+ /** Expiration duration (e.g., "7d", "24h", "1h") */
6074
+ expiresIn?: string;
6075
+ }
6076
+ /**
6077
+ * Result of token verification
6078
+ */
6079
+ interface TokenVerificationResult {
6080
+ valid: boolean;
6081
+ payload?: ParticipationTokenPayload;
6082
+ error?: string;
6083
+ }
6084
+ /**
6085
+ * Service for generating and verifying participation tokens.
6086
+ *
6087
+ * This is a minimal implementation that encodes data in base64.
6088
+ * In production, this should use proper JWT with HMAC/RSA signing.
6089
+ *
6090
+ * The signing key should be injected from environment configuration.
6091
+ */
6092
+ declare class ParticipationTokenService {
6093
+ private secret;
6094
+ constructor(secret?: string);
6095
+ /**
6096
+ * Generate a participation token (signed link)
6097
+ */
6098
+ generateToken(participation: Pick<WorkflowParticipation, "id" | "instanceId"> & {
6099
+ tenantId: string;
6100
+ }, options?: TokenGenerationOptions): SignedLinkAuth;
6101
+ /**
6102
+ * Verify a participation token
6103
+ */
6104
+ verifyToken(token: string): TokenVerificationResult;
6105
+ /**
6106
+ * Generate a shareable link URL
6107
+ */
6108
+ generateLink(baseUrl: string, token: string): string;
6109
+ /**
6110
+ * Extract token from a participation link
6111
+ */
6112
+ extractTokenFromLink(url: string): string | null;
6113
+ private encodeToken;
6114
+ private decodeToken;
6115
+ private sign;
6116
+ private parseExpiration;
6117
+ private base64Encode;
6118
+ private base64Decode;
6119
+ }
6120
+ /**
6121
+ * Get the default token service instance
6122
+ */
6123
+ declare function getDefaultTokenService(): ParticipationTokenService;
6124
+ /**
6125
+ * Initialize the token service with a custom secret
6126
+ */
6127
+ declare function initializeTokenService(secret: string): ParticipationTokenService;
6128
+
6129
+ /**
6130
+ * Options for PIN code generation
6131
+ */
6132
+ interface PinCodeGenerationOptions {
6133
+ /** Length of the PIN code (default: 6) */
6134
+ length?: number;
6135
+ /** Expiration duration (e.g., "24h", "7d") */
6136
+ expiresIn?: string;
6137
+ /** Maximum attempts before lockout (default: 3) */
6138
+ maxAttempts?: number;
6139
+ }
6140
+ /**
6141
+ * Result of PIN code verification
6142
+ */
6143
+ interface PinCodeVerificationResult {
6144
+ valid: boolean;
6145
+ error?: string;
6146
+ attemptsRemaining?: number;
6147
+ lockedUntil?: Date;
6148
+ }
6149
+ /**
6150
+ * Service for generating and verifying PIN codes.
6151
+ *
6152
+ * PIN codes are hashed before storage for security.
6153
+ * This implementation uses a simple hash for demonstration.
6154
+ * In production, use bcrypt or argon2.
4672
6155
  */
4673
- interface DatabaseAdapter {
4674
- objects: ObjectsRepository;
4675
- attributes: AttributesRepository;
4676
- views: ViewsRepository;
4677
- flows?: FlowsRepository;
4678
- userProfiles: UserProfilesRepository;
4679
- files: FilesRepository;
4680
- objectRecords: ObjectRecordsRepository;
4681
- permissions?: PermissionsRepository;
4682
- audit?: AuditRepository;
4683
- storage?: StorageAdapter;
4684
- cache?: CacheAdapter;
4685
- transaction<T>(callback: (adapter: DatabaseAdapter) => Promise<T>): Promise<T>;
6156
+ declare class PinCodeService {
6157
+ private salt;
6158
+ constructor(salt?: string);
6159
+ /**
6160
+ * Generate a PIN code and its auth object
6161
+ */
6162
+ generate(options?: PinCodeGenerationOptions): {
6163
+ code: string;
6164
+ auth: PinCodeAuth;
6165
+ };
6166
+ /**
6167
+ * Verify a PIN code against stored auth
6168
+ */
6169
+ verify(inputCode: string, auth: PinCodeAuth): PinCodeVerificationResult;
6170
+ /**
6171
+ * Record a failed attempt and return updated auth
6172
+ */
6173
+ recordFailedAttempt(auth: PinCodeAuth): PinCodeAuth;
6174
+ /**
6175
+ * Reset attempts (after successful verification or admin reset)
6176
+ */
6177
+ resetAttempts(auth: PinCodeAuth): PinCodeAuth;
6178
+ /**
6179
+ * Generate a new PIN code (for resend functionality)
6180
+ */
6181
+ regenerate(auth: PinCodeAuth, options?: PinCodeGenerationOptions): {
6182
+ code: string;
6183
+ auth: PinCodeAuth;
6184
+ };
6185
+ private generateNumericCode;
6186
+ private hashCode;
6187
+ private parseExpiration;
4686
6188
  }
6189
+ /**
6190
+ * Get the default PIN code service instance
6191
+ */
6192
+ declare function getDefaultPinCodeService(): PinCodeService;
6193
+ /**
6194
+ * Initialize the PIN code service with a custom salt
6195
+ */
6196
+ declare function initializePinCodeService(salt: string): PinCodeService;
4687
6197
 
4688
6198
  /**
4689
6199
  * Formatted record with values flattened to root level.
@@ -6153,6 +7663,70 @@ interface QueryBuilderOptions {
6153
7663
  */
6154
7664
  declare function createQueryBuilder<T extends Record<string, unknown> = Record<string, unknown>>(recordService: RecordService, adapter: DatabaseAdapter, objectName: string, options?: QueryBuilderOptions): QueryBuilder<T>;
6155
7665
 
7666
+ /**
7667
+ * Result of a condition evaluation with debug information
7668
+ */
7669
+ interface EvaluationResult {
7670
+ /** The final result of the evaluation */
7671
+ result: boolean;
7672
+ /** Debug trace of the evaluation (for debugging UI) */
7673
+ trace?: EvaluationTrace;
7674
+ }
7675
+ /**
7676
+ * Trace of a single rule or group evaluation
7677
+ */
7678
+ interface EvaluationTrace {
7679
+ /** Type of evaluation */
7680
+ type: "rule" | "group";
7681
+ /** Result of this specific evaluation */
7682
+ result: boolean;
7683
+ /** For rules: the field path */
7684
+ field?: string;
7685
+ /** For rules: the operator used */
7686
+ operator?: ConditionOperator;
7687
+ /** For rules: the expected value */
7688
+ expectedValue?: unknown;
7689
+ /** For rules: the actual value found */
7690
+ actualValue?: unknown;
7691
+ /** For groups: the logical operator */
7692
+ groupOperator?: "and" | "or";
7693
+ /** For groups: child evaluations */
7694
+ children?: EvaluationTrace[];
7695
+ }
7696
+ /**
7697
+ * Evaluate a condition group against an execution context
7698
+ *
7699
+ * @param condition - The condition group to evaluate
7700
+ * @param context - The workflow execution context
7701
+ * @param trace - Whether to include debug trace
7702
+ * @returns The evaluation result
7703
+ *
7704
+ * @example
7705
+ * ```typescript
7706
+ * const condition: ConditionGroup = {
7707
+ * operator: "and",
7708
+ * rules: [
7709
+ * { field: "slots.client.type", operator: "eq", value: "vip" },
7710
+ * { field: "forms.quote.amount", operator: "gte", value: 10000 }
7711
+ * ]
7712
+ * };
7713
+ *
7714
+ * const result = evaluateCondition(condition, context);
7715
+ * if (result.result) {
7716
+ * // Condition is true
7717
+ * }
7718
+ * ```
7719
+ */
7720
+ declare function evaluateCondition(condition: ConditionGroup, context: WorkflowExecutionContext, trace?: boolean): EvaluationResult;
7721
+ /**
7722
+ * Quick evaluation without trace (for production use)
7723
+ */
7724
+ declare function evaluate(condition: ConditionGroup, context: WorkflowExecutionContext): boolean;
7725
+ /**
7726
+ * Evaluate with full debug trace
7727
+ */
7728
+ declare function evaluateWithTrace(condition: ConditionGroup, context: WorkflowExecutionContext): EvaluationResult;
7729
+
6156
7730
  /**
6157
7731
  * Context-related errors for tenant isolation
6158
7732
  */
@@ -6314,6 +7888,231 @@ declare function runWithContext<T>(context: TenantContext, fn: () => T): T;
6314
7888
  */
6315
7889
  declare function withTenantContext<T>(tenantId: TenantId, fn: () => Promise<T>, userId?: UserId): Promise<T>;
6316
7890
 
7891
+ /**
7892
+ * Result of a successful node execution
7893
+ */
7894
+ interface ExecutorSuccessResult {
7895
+ status: "success";
7896
+ /** ID of the next node to execute */
7897
+ nextNodeId: string;
7898
+ /** Updated context (will be merged with current context) */
7899
+ contextUpdates?: Partial<WorkflowExecutionContext>;
7900
+ }
7901
+ /**
7902
+ * Result indicating the workflow should wait for external action
7903
+ */
7904
+ interface ExecutorWaitResult {
7905
+ status: "wait";
7906
+ /** Reason for waiting */
7907
+ reason: string;
7908
+ /** Required participation ID (if any) */
7909
+ requiredParticipationId?: string;
7910
+ /** When the wait expires */
7911
+ expiresAt?: Date;
7912
+ }
7913
+ /**
7914
+ * Result indicating the workflow has completed
7915
+ */
7916
+ interface ExecutorCompleteResult {
7917
+ status: "complete";
7918
+ /** Final status from the end node */
7919
+ finalStatus?: string;
7920
+ }
7921
+ /**
7922
+ * Result indicating an error occurred
7923
+ */
7924
+ interface ExecutorErrorResult {
7925
+ status: "error";
7926
+ /** Error code */
7927
+ code: string;
7928
+ /** Error message */
7929
+ message: string;
7930
+ /** Whether to retry */
7931
+ retryable?: boolean;
7932
+ }
7933
+ /**
7934
+ * Union of all executor result types
7935
+ */
7936
+ type ExecutorResult = ExecutorSuccessResult | ExecutorWaitResult | ExecutorCompleteResult | ExecutorErrorResult;
7937
+ /**
7938
+ * Context passed to executors
7939
+ */
7940
+ interface ExecutorContext {
7941
+ /** The workflow instance being executed */
7942
+ instance: WorkflowInstance;
7943
+ /** The workflow definition (from snapshot) */
7944
+ definition: WorkflowDefinition;
7945
+ /** Current execution context */
7946
+ executionContext: WorkflowExecutionContext;
7947
+ /** Input data for the node (e.g., form submission) */
7948
+ input?: Record<string, unknown>;
7949
+ /** ID of the user/participant executing */
7950
+ executorId?: string;
7951
+ }
7952
+ /**
7953
+ * Interface for node executors.
7954
+ * Each node type has its own executor implementation.
7955
+ */
7956
+ interface NodeExecutor<T extends WorkflowNode = WorkflowNode> {
7957
+ /**
7958
+ * The node type this executor handles
7959
+ */
7960
+ readonly nodeType: WorkflowNodeType;
7961
+ /**
7962
+ * Execute the node
7963
+ *
7964
+ * @param node - The node to execute
7965
+ * @param context - Execution context
7966
+ * @returns The execution result (sync or async)
7967
+ */
7968
+ execute(node: T, context: ExecutorContext): ExecutorResult | Promise<ExecutorResult>;
7969
+ /**
7970
+ * Check if the node can be executed
7971
+ * (e.g., check if required input is available)
7972
+ *
7973
+ * @param node - The node to check
7974
+ * @param context - Execution context
7975
+ * @returns Whether the node can be executed
7976
+ */
7977
+ canExecute?(node: T, context: ExecutorContext): boolean;
7978
+ /**
7979
+ * Validate the node configuration
7980
+ *
7981
+ * @param node - The node to validate
7982
+ * @returns Validation errors, or empty array if valid
7983
+ */
7984
+ validate?(node: T): string[];
7985
+ }
7986
+ /**
7987
+ * Registry for node executors.
7988
+ * Maps node types to their executor implementations.
7989
+ */
7990
+ declare class ExecutorRegistry {
7991
+ private executors;
7992
+ /**
7993
+ * Register an executor for a node type
7994
+ */
7995
+ register<T extends WorkflowNode>(executor: NodeExecutor<T>): void;
7996
+ /**
7997
+ * Get the executor for a node type
7998
+ */
7999
+ get(nodeType: WorkflowNodeType): NodeExecutor | undefined;
8000
+ /**
8001
+ * Check if an executor is registered for a node type
8002
+ */
8003
+ has(nodeType: WorkflowNodeType): boolean;
8004
+ /**
8005
+ * Execute a node using the appropriate executor
8006
+ */
8007
+ execute(node: WorkflowNode, context: ExecutorContext): Promise<ExecutorResult>;
8008
+ /**
8009
+ * Get all registered node types
8010
+ */
8011
+ getRegisteredTypes(): WorkflowNodeType[];
8012
+ }
8013
+ /**
8014
+ * Create a success result
8015
+ */
8016
+ declare function success(nextNodeId: string, contextUpdates?: Partial<WorkflowExecutionContext>): ExecutorSuccessResult;
8017
+ /**
8018
+ * Create a wait result
8019
+ */
8020
+ declare function wait(reason: string, options?: {
8021
+ requiredParticipationId?: string;
8022
+ expiresAt?: Date;
8023
+ }): ExecutorWaitResult;
8024
+ /**
8025
+ * Create a complete result
8026
+ */
8027
+ declare function complete(finalStatus?: string): ExecutorCompleteResult;
8028
+ /**
8029
+ * Create an error result
8030
+ */
8031
+ declare function error(code: string, message: string, retryable?: boolean): ExecutorErrorResult;
8032
+
8033
+ /**
8034
+ * Executor for ConditionNode.
8035
+ * Evaluates the condition and routes to onTrue or onFalse.
8036
+ */
8037
+ declare class ConditionExecutor implements NodeExecutor<ConditionNode> {
8038
+ readonly nodeType: "condition";
8039
+ execute(node: ConditionNode, context: ExecutorContext): ExecutorResult;
8040
+ canExecute(_node: ConditionNode, _context: ExecutorContext): boolean;
8041
+ validate(node: ConditionNode): string[];
8042
+ }
8043
+
8044
+ /**
8045
+ * Executor for EndNode.
8046
+ * Marks the workflow as completed with an optional status.
8047
+ */
8048
+ declare class EndExecutor implements NodeExecutor<EndNode> {
8049
+ readonly nodeType: "end";
8050
+ execute(node: EndNode, _context: ExecutorContext): ExecutorResult;
8051
+ canExecute(_node: EndNode, _context: ExecutorContext): boolean;
8052
+ validate(_node: EndNode): string[];
8053
+ }
8054
+
8055
+ /**
8056
+ * Executor for FormNode.
8057
+ * Handles both simple and advanced form modes.
8058
+ *
8059
+ * In the new structure:
8060
+ * - Simple mode: Uses `fields: FormFieldRef[]`
8061
+ * - Advanced mode: Uses `rows: FlowRow[]`
8062
+ *
8063
+ * Behavior:
8064
+ * - If no input is provided: Returns "wait" status (waiting for form submission)
8065
+ * - If input is provided: Validates and stores the data, then proceeds to next node
8066
+ */
8067
+ declare class FormExecutor implements NodeExecutor<FormNode> {
8068
+ readonly nodeType: "form";
8069
+ execute(node: FormNode, context: ExecutorContext): ExecutorResult;
8070
+ canExecute(node: FormNode, context: ExecutorContext): boolean;
8071
+ validate(node: FormNode): string[];
8072
+ /**
8073
+ * Extract all slot IDs referenced in the form
8074
+ */
8075
+ private extractSlotIds;
8076
+ /**
8077
+ * Validate required fields based on slot mode.
8078
+ *
8079
+ * Logic:
8080
+ * - Slot mode "create" or "optional" → fields with required=true on the attribute must be filled
8081
+ * - Slot mode "select" → required validation is skipped (record already exists)
8082
+ *
8083
+ * @param node - The FormNode being validated
8084
+ * @param input - The form input data, structured as { [slotId]: { [attribute]: value } }
8085
+ * @param slots - All workflow slots for mode lookup
8086
+ * @param objects - All object definitions for attribute metadata
8087
+ * @returns Array of validation error messages
8088
+ */
8089
+ validateRequiredFields(node: FormNode, input: Record<string, Record<string, unknown>>, slots: WorkflowSlot[], objects: ObjectDefinition[]): string[];
8090
+ /**
8091
+ * Collect all field references from a FormNode
8092
+ */
8093
+ private collectFieldRefs;
8094
+ }
8095
+
8096
+ /**
8097
+ * Executor for StartNode.
8098
+ * Simply transitions to the next node.
8099
+ */
8100
+ declare class StartExecutor implements NodeExecutor<StartNode> {
8101
+ readonly nodeType: "start";
8102
+ execute(node: StartNode, _context: ExecutorContext): ExecutorResult;
8103
+ canExecute(_node: StartNode, _context: ExecutorContext): boolean;
8104
+ validate(node: StartNode): string[];
8105
+ }
8106
+
8107
+ /**
8108
+ * Create a default executor registry with all core executors registered
8109
+ */
8110
+ declare function createDefaultExecutorRegistry(): ExecutorRegistry;
8111
+ /**
8112
+ * Get the default executor registry (singleton)
8113
+ */
8114
+ declare function getDefaultExecutorRegistry(): ExecutorRegistry;
8115
+
6317
8116
  /**
6318
8117
  * Resolved relation values for a record
6319
8118
  * Maps relation attribute name to the resolved record's values
@@ -6713,6 +8512,9 @@ interface MockStores {
6713
8512
  roles: Map<Uuid, Role>;
6714
8513
  permissions: Map<Uuid, Permission>;
6715
8514
  userRoles: Map<Uuid, UserRoleAssignment>;
8515
+ workflows: Map<Uuid, DBWorkflow>;
8516
+ workflowInstances: Map<Uuid, DBWorkflowInstance>;
8517
+ workflowParticipations: Map<Uuid, DBWorkflowParticipation>;
6716
8518
  }
6717
8519
  /**
6718
8520
  * Create an in-memory mock adapter for testing and development
@@ -7017,94 +8819,6 @@ declare class FileService extends TenantAwareService {
7017
8819
  removeTags(fileId: string, tags: string[]): Promise<File>;
7018
8820
  }
7019
8821
 
7020
- /**
7021
- * Input for creating a flow
7022
- */
7023
- interface CreateFlowInput {
7024
- name: string;
7025
- label: string;
7026
- description?: string;
7027
- icon?: IconName;
7028
- slots: FlowSlot[];
7029
- pages: FlowPage[];
7030
- relations: FlowRelation[];
7031
- metadata?: Record<string, unknown>;
7032
- }
7033
- /**
7034
- * Input for updating a flow
7035
- */
7036
- interface UpdateFlowInput {
7037
- label?: string;
7038
- description?: string;
7039
- icon?: IconName;
7040
- slots?: FlowSlot[];
7041
- pages?: FlowPage[];
7042
- relations?: FlowRelation[];
7043
- metadata?: Record<string, unknown>;
7044
- }
7045
- /**
7046
- * Service for managing flow definitions.
7047
- * Handles fusion of system flows (from registry) and custom flows (from database).
7048
- * Automatically uses tenant context from AsyncLocalStorage.
7049
- */
7050
- declare class FlowService extends TenantAwareService {
7051
- private adapter;
7052
- private systemFlows;
7053
- constructor(adapter: DatabaseAdapter, systemFlows?: FlowDefinition[]);
7054
- /**
7055
- * Get all flows for current tenant (system + custom)
7056
- */
7057
- getAllFlows(): Promise<FlowDefinition[]>;
7058
- /**
7059
- * Get published flows only
7060
- */
7061
- getPublishedFlows(): Promise<FlowDefinition[]>;
7062
- /**
7063
- * Get a specific flow by name
7064
- */
7065
- getFlow(name: string): Promise<FlowDefinition | null>;
7066
- /**
7067
- * Get a flow by ID
7068
- */
7069
- getFlowById(flowId: string): Promise<FlowDefinition | null>;
7070
- /**
7071
- * Create a new custom flow (as draft)
7072
- */
7073
- createFlow(input: CreateFlowInput): Promise<FlowDefinition>;
7074
- /**
7075
- * Update a custom flow
7076
- */
7077
- updateFlow(flowId: string, input: UpdateFlowInput): Promise<FlowDefinition>;
7078
- /**
7079
- * Publish a flow
7080
- */
7081
- publishFlow(flowId: string): Promise<FlowDefinition>;
7082
- /**
7083
- * Archive a flow
7084
- */
7085
- archiveFlow(flowId: string): Promise<FlowDefinition>;
7086
- /**
7087
- * Delete a custom flow
7088
- */
7089
- deleteFlow(flowId: string): Promise<void>;
7090
- /**
7091
- * Validate flow name format (kebab-case)
7092
- */
7093
- private validateFlowName;
7094
- /**
7095
- * Validate flow structure (slots, pages, relations)
7096
- */
7097
- private validateFlowStructure;
7098
- private validateBasicFlowRequirements;
7099
- private validateSlotIds;
7100
- private validateFieldReferences;
7101
- private validateRelationReferences;
7102
- /**
7103
- * Convert database flow to FlowDefinition
7104
- */
7105
- private convertDBFlowToDefinition;
7106
- }
7107
-
7108
8822
  /**
7109
8823
  * Geocoding service for address autocomplete and geocoding operations
7110
8824
  *
@@ -7541,6 +9255,8 @@ interface GetRelationOptionsParams {
7541
9255
  pageSize?: number;
7542
9256
  /** Filter by specific target object */
7543
9257
  targetObject?: string;
9258
+ /** Additional filter to apply (e.g., workflow context filtering) */
9259
+ filter?: FilterState;
7544
9260
  }
7545
9261
  /**
7546
9262
  * Options for RelationService constructor
@@ -7637,11 +9353,77 @@ declare class RelationService extends TenantAwareService {
7637
9353
  * // [{ id: "rec-1", label: "Nike Air Max", objectName: "products", ... }]
7638
9354
  * ```
7639
9355
  */
7640
- resolveIds(ids: string[], attributeId: string): Promise<RelationOption[]>;
9356
+ resolveIds(ids: string[], attributeId: string): Promise<RelationOption[]>;
9357
+ /**
9358
+ * Find a relation attribute by ID
9359
+ */
9360
+ findAttributeById(attributeId: string): Promise<RelationAttribute | null>;
9361
+ }
9362
+
9363
+ /**
9364
+ * Options for the rollup scheduler
9365
+ */
9366
+ interface RollupSchedulerOptions {
9367
+ /** Debounce delay in milliseconds (default: 100) */
9368
+ debounceMs?: number;
9369
+ /** Maximum pending recalculations before forced flush (default: 100) */
9370
+ maxPending?: number;
9371
+ }
9372
+ /**
9373
+ * Scheduler for debouncing rollup recalculations
9374
+ *
9375
+ * When multiple child records are updated in quick succession (e.g., bulk import),
9376
+ * this scheduler batches the rollup recalculations to avoid N+1 updates.
9377
+ *
9378
+ * @example
9379
+ * ```typescript
9380
+ * const scheduler = new RollupScheduler(adapter, {
9381
+ * debounceMs: 100,
9382
+ * maxPending: 50,
9383
+ * });
9384
+ *
9385
+ * // Schedule recalculation (will be debounced)
9386
+ * scheduler.scheduleRecalculation("company-123", "companies-obj-id");
9387
+ * scheduler.scheduleRecalculation("company-123", "companies-obj-id"); // Ignored, already pending
9388
+ *
9389
+ * // Force immediate processing
9390
+ * await scheduler.flush();
9391
+ * ```
9392
+ */
9393
+ declare class RollupScheduler {
9394
+ private adapter;
9395
+ private getSchemaById;
9396
+ private pending;
9397
+ private rollupService;
9398
+ private debounceMs;
9399
+ private maxPending;
9400
+ constructor(adapter: DatabaseAdapter, getSchemaById: (id: string) => Promise<ObjectDefinition | null>, options?: RollupSchedulerOptions);
9401
+ /**
9402
+ * Schedule a rollup recalculation for a parent record.
9403
+ *
9404
+ * If the same record is already pending, the timer is reset.
9405
+ * If too many recalculations are pending, triggers an immediate flush.
9406
+ *
9407
+ * @param parentId - ID of the parent record to recalculate
9408
+ * @param parentObjectId - Object ID of the parent
9409
+ */
9410
+ scheduleRecalculation(parentId: string, parentObjectId: string): void;
9411
+ /**
9412
+ * Execute all pending recalculations immediately
9413
+ */
9414
+ flush(): Promise<void>;
9415
+ /**
9416
+ * Execute a single recalculation
9417
+ */
9418
+ private executeRecalculation;
9419
+ /**
9420
+ * Get number of pending recalculations
9421
+ */
9422
+ get pendingCount(): number;
7641
9423
  /**
7642
- * Find a relation attribute by ID
9424
+ * Clear all pending recalculations without executing them
7643
9425
  */
7644
- findAttributeById(attributeId: string): Promise<RelationAttribute | null>;
9426
+ clear(): void;
7645
9427
  }
7646
9428
 
7647
9429
  /**
@@ -7802,72 +9584,6 @@ declare class RollupService {
7802
9584
  findRecordsWithForwardRollup(changedRecord: ObjectRecord, changedSchema: ObjectDefinition): Promise<ObjectRecord[]>;
7803
9585
  }
7804
9586
 
7805
- /**
7806
- * Options for the rollup scheduler
7807
- */
7808
- interface RollupSchedulerOptions {
7809
- /** Debounce delay in milliseconds (default: 100) */
7810
- debounceMs?: number;
7811
- /** Maximum pending recalculations before forced flush (default: 100) */
7812
- maxPending?: number;
7813
- }
7814
- /**
7815
- * Scheduler for debouncing rollup recalculations
7816
- *
7817
- * When multiple child records are updated in quick succession (e.g., bulk import),
7818
- * this scheduler batches the rollup recalculations to avoid N+1 updates.
7819
- *
7820
- * @example
7821
- * ```typescript
7822
- * const scheduler = new RollupScheduler(adapter, {
7823
- * debounceMs: 100,
7824
- * maxPending: 50,
7825
- * });
7826
- *
7827
- * // Schedule recalculation (will be debounced)
7828
- * scheduler.scheduleRecalculation("company-123", "companies-obj-id");
7829
- * scheduler.scheduleRecalculation("company-123", "companies-obj-id"); // Ignored, already pending
7830
- *
7831
- * // Force immediate processing
7832
- * await scheduler.flush();
7833
- * ```
7834
- */
7835
- declare class RollupScheduler {
7836
- private adapter;
7837
- private getSchemaById;
7838
- private pending;
7839
- private rollupService;
7840
- private debounceMs;
7841
- private maxPending;
7842
- constructor(adapter: DatabaseAdapter, getSchemaById: (id: string) => Promise<ObjectDefinition | null>, options?: RollupSchedulerOptions);
7843
- /**
7844
- * Schedule a rollup recalculation for a parent record.
7845
- *
7846
- * If the same record is already pending, the timer is reset.
7847
- * If too many recalculations are pending, triggers an immediate flush.
7848
- *
7849
- * @param parentId - ID of the parent record to recalculate
7850
- * @param parentObjectId - Object ID of the parent
7851
- */
7852
- scheduleRecalculation(parentId: string, parentObjectId: string): void;
7853
- /**
7854
- * Execute all pending recalculations immediately
7855
- */
7856
- flush(): Promise<void>;
7857
- /**
7858
- * Execute a single recalculation
7859
- */
7860
- private executeRecalculation;
7861
- /**
7862
- * Get number of pending recalculations
7863
- */
7864
- get pendingCount(): number;
7865
- /**
7866
- * Clear all pending recalculations without executing them
7867
- */
7868
- clear(): void;
7869
- }
7870
-
7871
9587
  /**
7872
9588
  * Options for UserProfileService constructor
7873
9589
  */
@@ -8211,6 +9927,408 @@ declare class ViewService extends TenantAwareService {
8211
9927
  private convertDBViewToDefinition;
8212
9928
  }
8213
9929
 
9930
+ /**
9931
+ * Input for creating a workflow
9932
+ */
9933
+ interface CreateWorkflowInput {
9934
+ name: string;
9935
+ label: string;
9936
+ description?: string;
9937
+ icon?: IconName;
9938
+ slots: WorkflowSlot[];
9939
+ nodes: Record<string, WorkflowNode>;
9940
+ startNodeId: string;
9941
+ layout: WorkflowLayout;
9942
+ participants?: ParticipantTemplate[];
9943
+ theme?: WorkflowTheme;
9944
+ config?: WorkflowConfig;
9945
+ metadata?: Record<string, unknown>;
9946
+ }
9947
+ /**
9948
+ * Input for updating a workflow
9949
+ */
9950
+ interface UpdateWorkflowInput {
9951
+ label?: string;
9952
+ description?: string;
9953
+ icon?: IconName;
9954
+ slots?: WorkflowSlot[];
9955
+ nodes?: Record<string, WorkflowNode>;
9956
+ startNodeId?: string;
9957
+ layout?: WorkflowLayout;
9958
+ participants?: ParticipantTemplate[];
9959
+ theme?: WorkflowTheme;
9960
+ config?: WorkflowConfig;
9961
+ metadata?: Record<string, unknown>;
9962
+ }
9963
+ /**
9964
+ * Service for managing workflow definitions.
9965
+ * Handles fusion of system workflows (from registry) and custom workflows (from database).
9966
+ * Automatically uses tenant context from AsyncLocalStorage.
9967
+ */
9968
+ declare class WorkflowService extends TenantAwareService {
9969
+ private adapter;
9970
+ private systemWorkflows;
9971
+ constructor(adapter: DatabaseAdapter, systemWorkflows?: WorkflowDefinition[]);
9972
+ /**
9973
+ * Get all workflows for current tenant (system + custom)
9974
+ */
9975
+ getAllWorkflows(): Promise<WorkflowDefinition[]>;
9976
+ /**
9977
+ * Get published workflows only
9978
+ */
9979
+ getPublishedWorkflows(): Promise<WorkflowDefinition[]>;
9980
+ /**
9981
+ * Get a specific workflow by name
9982
+ */
9983
+ getWorkflow(name: string): Promise<WorkflowDefinition | null>;
9984
+ /**
9985
+ * Get a specific workflow by ID
9986
+ */
9987
+ getWorkflowById(id: string): Promise<WorkflowDefinition | null>;
9988
+ /**
9989
+ * Create a new workflow
9990
+ */
9991
+ createWorkflow(input: CreateWorkflowInput): Promise<WorkflowDefinition>;
9992
+ /**
9993
+ * Update an existing workflow
9994
+ */
9995
+ updateWorkflow(name: string, input: UpdateWorkflowInput): Promise<WorkflowDefinition>;
9996
+ /**
9997
+ * Publish a workflow (make it available for execution)
9998
+ */
9999
+ publishWorkflow(name: string): Promise<WorkflowDefinition>;
10000
+ /**
10001
+ * Archive a workflow (make it unavailable)
10002
+ */
10003
+ archiveWorkflow(name: string): Promise<WorkflowDefinition>;
10004
+ /**
10005
+ * Delete a workflow
10006
+ */
10007
+ deleteWorkflow(name: string): Promise<void>;
10008
+ /**
10009
+ * Duplicate a workflow
10010
+ */
10011
+ duplicateWorkflow(name: string, newName: string, newLabel?: string): Promise<WorkflowDefinition>;
10012
+ private convertDBWorkflowToDefinition;
10013
+ }
10014
+
10015
+ /**
10016
+ * Input for starting a workflow instance
10017
+ */
10018
+ interface StartWorkflowInput {
10019
+ /** Name of the workflow to start */
10020
+ workflowName: string;
10021
+ /** Initial slot data (for "select" mode slots) */
10022
+ initialSlots?: Record<string, Record<string, unknown>>;
10023
+ /** Custom variables to initialize */
10024
+ variables?: Record<string, unknown>;
10025
+ /** User ID who starts the workflow */
10026
+ startedBy: string;
10027
+ }
10028
+ /**
10029
+ * Input for resuming a waiting instance
10030
+ */
10031
+ interface ResumeWorkflowInput {
10032
+ /** Form/action data to submit */
10033
+ input: Record<string, unknown>;
10034
+ /** ID of the user/participant submitting */
10035
+ submittedBy?: string;
10036
+ }
10037
+ /**
10038
+ * Options for WorkflowInstanceService
10039
+ */
10040
+ interface WorkflowInstanceServiceOptions {
10041
+ /** Custom executor registry */
10042
+ executorRegistry?: ExecutorRegistry;
10043
+ /** Schema service for resolving object definitions */
10044
+ schemaService?: ObjectSchemaService;
10045
+ /** Record service for persisting slots at workflow completion */
10046
+ recordService?: RecordService;
10047
+ }
10048
+ /**
10049
+ * Service for executing and managing workflow instances.
10050
+ * Handles the state machine logic and node execution.
10051
+ */
10052
+ declare class WorkflowInstanceService extends TenantAwareService {
10053
+ private adapter;
10054
+ private workflowService;
10055
+ private executorRegistry;
10056
+ private schemaService?;
10057
+ private recordService?;
10058
+ constructor(adapter: DatabaseAdapter, workflowService: WorkflowService, options?: WorkflowInstanceServiceOptions);
10059
+ /**
10060
+ * Start a new workflow instance
10061
+ */
10062
+ startWorkflow(input: StartWorkflowInput): Promise<WorkflowInstance>;
10063
+ /**
10064
+ * Resume a waiting workflow instance
10065
+ */
10066
+ resumeWorkflow(instanceId: string, input: ResumeWorkflowInput): Promise<WorkflowInstance>;
10067
+ /**
10068
+ * Cancel a workflow instance
10069
+ */
10070
+ cancelWorkflow(instanceId: string, reason?: string): Promise<WorkflowInstance>;
10071
+ /**
10072
+ * Get an instance by ID
10073
+ */
10074
+ getInstance(id: string): Promise<WorkflowInstance | null>;
10075
+ /**
10076
+ * Get all instances for a workflow
10077
+ */
10078
+ getInstancesByWorkflow(workflowName: string): Promise<WorkflowInstance[]>;
10079
+ /**
10080
+ * List all workflow instances with optional filtering and pagination.
10081
+ *
10082
+ * @param options - Filtering and pagination options
10083
+ * @returns Paginated list of instances with total count
10084
+ */
10085
+ listInstances(options?: {
10086
+ workflowName?: string;
10087
+ status?: InstanceStatus;
10088
+ limit?: number;
10089
+ offset?: number;
10090
+ }): Promise<{
10091
+ instances: WorkflowInstance[];
10092
+ total: number;
10093
+ }>;
10094
+ /**
10095
+ * Get all instances linked to a specific record.
10096
+ * Finds instances where the record appears in any slot context.
10097
+ *
10098
+ * Uses database-optimized query (required implementation in all adapters).
10099
+ *
10100
+ * @param objectName - Object name of the record
10101
+ * @param recordId - Record ID
10102
+ * @param options - Optional filtering options
10103
+ */
10104
+ getInstancesByRecord(objectName: string, recordId: string, options?: {
10105
+ status?: string;
10106
+ limit?: number;
10107
+ offset?: number;
10108
+ }): Promise<{
10109
+ instances: WorkflowInstance[];
10110
+ total: number;
10111
+ }>;
10112
+ /**
10113
+ * Get pending action for an instance
10114
+ */
10115
+ getPendingAction(instanceId: string): Promise<PendingAction | null>;
10116
+ /**
10117
+ * Execute the current node and continue until wait/complete/error
10118
+ */
10119
+ private executeCurrentNode;
10120
+ private mergeContext;
10121
+ private getNodeLabel;
10122
+ /**
10123
+ * Persist all slots as records in the database.
10124
+ * - Slots with mode "create" create new records
10125
+ * - Slots with mode "select" or "optional" with existing ID update the record
10126
+ * - Slots with mode "optional" without ID create new records
10127
+ *
10128
+ * Returns updated context with createdRecordIds populated.
10129
+ */
10130
+ private persistSlots;
10131
+ /**
10132
+ * Clean slot data by removing undefined and null values.
10133
+ * This prevents form submissions from overwriting existing record values
10134
+ * with empty values when the form didn't actually provide a value.
10135
+ */
10136
+ private cleanSlotData;
10137
+ /**
10138
+ * Sort slots by dependencies.
10139
+ * Slots that reference other slots via "$slot:xxx" syntax must come after the referenced slot.
10140
+ */
10141
+ private sortSlotsByDependencies;
10142
+ /**
10143
+ * Find all "$slot:xxx" references in an object
10144
+ */
10145
+ private findSlotReferences;
10146
+ /**
10147
+ * Resolve "$slot:xxx" references to actual record IDs
10148
+ */
10149
+ private resolveSlotReferences;
10150
+ /**
10151
+ * Recursively resolve slot references in a value
10152
+ */
10153
+ private resolveValue;
10154
+ private saveInstance;
10155
+ private convertDBInstanceToInstance;
10156
+ }
10157
+
10158
+ /**
10159
+ * Input for creating a participation
10160
+ */
10161
+ interface CreateParticipationInput {
10162
+ /** Workflow instance ID */
10163
+ instanceId: string;
10164
+ /** Participant template ID */
10165
+ participantTemplateId: string;
10166
+ /** Override email (if not using emailSource) */
10167
+ email?: string;
10168
+ /** Override name */
10169
+ name?: string;
10170
+ /** Override phone */
10171
+ phone?: string;
10172
+ /** Override auth method */
10173
+ authMethod?: "signed_link" | "pin_code";
10174
+ }
10175
+ /**
10176
+ * Result of creating a participation
10177
+ */
10178
+ interface CreateParticipationResult {
10179
+ participation: WorkflowParticipation;
10180
+ /** For signed_link: the shareable URL */
10181
+ link?: string;
10182
+ /** For pin_code: the plain PIN (only returned once!) */
10183
+ pinCode?: string;
10184
+ }
10185
+ /**
10186
+ * Result of authentication
10187
+ */
10188
+ interface AuthenticationResult {
10189
+ success: boolean;
10190
+ participation?: WorkflowParticipation;
10191
+ error?: string;
10192
+ attemptsRemaining?: number;
10193
+ }
10194
+ /**
10195
+ * Service for managing external participant access to workflow instances.
10196
+ * Handles invitation, authentication, and participation tracking.
10197
+ */
10198
+ declare class WorkflowParticipationService extends TenantAwareService {
10199
+ private adapter;
10200
+ private instanceService;
10201
+ private tokenService;
10202
+ private pinCodeService;
10203
+ constructor(adapter: DatabaseAdapter, instanceService: WorkflowInstanceService, tokenService?: ParticipationTokenService, pinCodeService?: PinCodeService);
10204
+ /**
10205
+ * Create a participation for an external user
10206
+ */
10207
+ createParticipation(input: CreateParticipationInput, baseUrl: string): Promise<CreateParticipationResult>;
10208
+ /**
10209
+ * Authenticate using a signed link token
10210
+ */
10211
+ authenticateWithToken(token: string): Promise<AuthenticationResult>;
10212
+ /**
10213
+ * Authenticate using a PIN code
10214
+ */
10215
+ authenticateWithPin(participationId: string, pinCode: string): Promise<AuthenticationResult>;
10216
+ /**
10217
+ * Get a participation by ID
10218
+ */
10219
+ getParticipation(id: string): Promise<WorkflowParticipation | null>;
10220
+ /**
10221
+ * Get participations for an instance
10222
+ */
10223
+ getParticipationsForInstance(instanceId: string): Promise<WorkflowParticipation[]>;
10224
+ /**
10225
+ * Mark a node as completed by a participation
10226
+ */
10227
+ markNodeCompleted(participationId: string, nodeId: string): Promise<WorkflowParticipation>;
10228
+ /**
10229
+ * Revoke a participation
10230
+ */
10231
+ revokeParticipation(id: string): Promise<WorkflowParticipation>;
10232
+ private resolveEmailFromContext;
10233
+ private resolvePhoneFromContext;
10234
+ private markAuthenticated;
10235
+ private updateParticipationAuth;
10236
+ private saveParticipation;
10237
+ private convertDBToParticipation;
10238
+ }
10239
+
10240
+ /**
10241
+ * Result of checking if a field is read-only
10242
+ */
10243
+ interface FieldReadOnlyResult {
10244
+ /** Whether the field is read-only */
10245
+ readOnly: boolean;
10246
+ /** Reason for being read-only */
10247
+ reason?: "user_field" | "computed" | "system";
10248
+ }
10249
+ /**
10250
+ * Service for handling relation filtering in workflow context.
10251
+ *
10252
+ * This service is used by both internal (admin) and external (participant)
10253
+ * users when filling workflow forms. It computes contextual filters based on
10254
+ * the workflow's slot data.
10255
+ *
10256
+ * @example
10257
+ * ```typescript
10258
+ * const service = new WorkflowRelationService(adapter);
10259
+ *
10260
+ * // Compute filter for a relation based on workflow context
10261
+ * const filter = await service.computeContextualFilter(
10262
+ * relationAttribute,
10263
+ * instance.context,
10264
+ * definition.slots
10265
+ * );
10266
+ *
10267
+ * // Check if a field is read-only for external users
10268
+ * const { readOnly, reason } = service.isFieldReadOnly(
10269
+ * userAttribute,
10270
+ * { type: "external", token: "...", participationId: "..." }
10271
+ * );
10272
+ * ```
10273
+ */
10274
+ declare class WorkflowRelationService extends TenantAwareService {
10275
+ private adapter;
10276
+ private schemaService;
10277
+ constructor(adapter: DatabaseAdapter, nativeRegistry: typeof registry);
10278
+ /**
10279
+ * Compute contextual filter for a relation attribute based on workflow context.
10280
+ *
10281
+ * Logic: If the target object has a relation attribute that points to an object
10282
+ * type matching a filled slot, we filter by that slot's record ID.
10283
+ *
10284
+ * This ensures that when an external participant is filling a form, they only
10285
+ * see related records that are relevant to the workflow context.
10286
+ *
10287
+ * @example
10288
+ * ```typescript
10289
+ * // Workflow has a "company" slot filled with company ID "comp-123"
10290
+ * // User is selecting contacts, and Contact has a "company" relation
10291
+ * // -> Filter returns contacts where company = "comp-123"
10292
+ *
10293
+ * const filter = await service.computeContextualFilter(
10294
+ * contactsRelationAttr,
10295
+ * { slots: { company: { id: "comp-123" } } },
10296
+ * [{ id: "company", objectName: "companies", ... }]
10297
+ * );
10298
+ * // Result: { combinator: "and", rules: [{ attribute: "company", operator: "any_of", value: ["comp-123"] }] }
10299
+ * ```
10300
+ *
10301
+ * @param attribute - The relation attribute being queried for options
10302
+ * @param context - Current workflow execution context with slot values
10303
+ * @param slots - Slot definitions from the workflow
10304
+ * @returns Filter state to apply, or undefined if no filtering needed
10305
+ */
10306
+ computeContextualFilter(attribute: RelationAttribute, context: WorkflowExecutionContext, slots: WorkflowSlot[]): Promise<FilterState | undefined>;
10307
+ /**
10308
+ * Determine if a field is read-only based on the access mode.
10309
+ *
10310
+ * - User fields are read-only for external participants
10311
+ * - Formula fields are always read-only
10312
+ * - Other fields are editable
10313
+ *
10314
+ * @param attribute - The attribute to check
10315
+ * @param accessMode - The current access mode (internal or external)
10316
+ * @returns Whether the field is read-only and the reason
10317
+ */
10318
+ isFieldReadOnly(attribute: Attribute, accessMode: WorkflowAccessMode): FieldReadOnlyResult;
10319
+ /**
10320
+ * Check if a field should be hidden entirely for external users.
10321
+ *
10322
+ * Some fields may be marked as internal-only in the workflow definition.
10323
+ * This is a placeholder for future extension.
10324
+ *
10325
+ * @param _attributeName - The attribute name
10326
+ * @param _accessMode - The current access mode
10327
+ * @returns Whether the field should be hidden
10328
+ */
10329
+ isFieldHidden(_attributeName: string, _accessMode: WorkflowAccessMode): boolean;
10330
+ }
10331
+
8214
10332
  /**
8215
10333
  * Result of view sync operation
8216
10334
  */
@@ -8488,5 +10606,52 @@ declare function extractAttributeNames(template: string): string[];
8488
10606
  * ```
8489
10607
  */
8490
10608
  declare function enrichValuesWithSelectLabels(values: Record<string, unknown>, attributes: Attribute[]): Record<string, unknown>;
10609
+ /**
10610
+ * Extract relation IDs from a value (string or array)
10611
+ * For cardinality "many", only the first ID is extracted for label display
10612
+ *
10613
+ * @param val - Relation value (string ID or array of IDs)
10614
+ * @returns Array of IDs (max 1 element for display purposes)
10615
+ *
10616
+ * @example
10617
+ * ```typescript
10618
+ * extractRelationIds("rec-123") // → ["rec-123"]
10619
+ * extractRelationIds(["rec-1", "rec-2"]) // → ["rec-1"]
10620
+ * extractRelationIds(null) // → []
10621
+ * ```
10622
+ */
10623
+ declare function extractRelationIds(val: unknown): string[];
10624
+ /**
10625
+ * Resolver function type for fetching relation labels
10626
+ * Takes an array of record IDs and returns a map of ID → label
10627
+ */
10628
+ type RelationLabelResolver = (ids: string[]) => Promise<Map<string, string>>;
10629
+ /**
10630
+ * Compute a label from a template with full relation resolution (1 level deep)
10631
+ *
10632
+ * Uses pre-computed record.label for nested relations to avoid infinite recursion.
10633
+ * This function enriches select/multiselect values AND resolves relation IDs to their labels.
10634
+ *
10635
+ * @param template - Label expression template (e.g., "{{ company }} - {{ name }}")
10636
+ * @param values - Record values to interpolate
10637
+ * @param attributes - Attribute definitions for the object
10638
+ * @param resolveRelationIds - Function to resolve record IDs to their labels
10639
+ * @returns The rendered label string
10640
+ *
10641
+ * @example
10642
+ * ```typescript
10643
+ * const label = await computeLabelWithRelations(
10644
+ * "{{ company }} - {{ name }}",
10645
+ * { company: "rec-123", name: "Product A" },
10646
+ * objectSchema.attributes,
10647
+ * async (ids) => {
10648
+ * const records = await adapter.objectRecords.findByIds(ids);
10649
+ * return new Map(records.map(r => [r.id, r.label]));
10650
+ * }
10651
+ * );
10652
+ * // → "Acme Corp - Product A"
10653
+ * ```
10654
+ */
10655
+ declare function computeLabelWithRelations(template: string, values: Record<string, unknown>, attributes: Attribute[], resolveRelationIds: RelationLabelResolver): Promise<string>;
8491
10656
 
8492
- export { type Currency as $, type Attribute as A, type FilterState as B, type CheckboxAttribute as C, type DateAttribute as D, type SortRule as E, type FileAttribute as F, type Group as G, type DirectTableTab as H, type InferAttributeValue as I, type BlockNoteContent as J, type StatusGroup as K, type LocationAttribute as L, type MultiselectAttribute as M, type NumberAttribute as N, type ObjectAction as O, type PhoneAttribute as P, type AttributeGroup as Q, type RichtextAttribute as R, type SystemResource as S, type TextAttribute as T, type UserAttribute as U, type ViewLayout as V, type BaseAttribute as W, type NumberUnit as X, type DateFormat as Y, type DateValue as Z, type Phone as _, type SystemAction as a, type FlowRelation as a$, type Location as a0, type LocationGranularity as a1, RELATION_TARGET_ANY as a2, type RelationAttribute as a3, isUniversalRelation as a4, type BlockNoteBlock as a5, type BlockNoteCustomInlineContent as a6, type BlockNoteDefaultProps as a7, type BlockNoteInlineContent as a8, type BlockNoteLink as a9, type NumberFilterOperator as aA, type CheckboxFilterOperator as aB, type DateFilterOperator as aC, type SelectFilterOperator as aD, type MultiselectFilterOperator as aE, type RelationFilterOperator as aF, type FilterOperator as aG, type RelativeDateValue as aH, type CurrencyFilterValue as aI, type PhoneFilterValue as aJ, type FilterValue as aK, type FilterRule as aL, type ExtendedFilterRule as aM, type FilterCombinator as aN, type FilterGroup as aO, type AdvancedFilterState as aP, isAdvancedFilterState as aQ, toAdvancedFilterState as aR, toSimpleFilterState as aS, type SortDirection as aT, type QueryState as aU, OPERATORS_BY_TYPE as aV, type NoValueOperator as aW, NO_VALUE_OPERATORS as aX, isNoValueOperator as aY, type FlowSlot as aZ, type FlowRowField as a_, type BlockNoteStyledText as aa, type BlockNoteStyles as ab, type BlockNoteTableCell as ac, type BlockNoteTableCellProps as ad, type BlockNoteTableContent as ae, type PartialBlockNoteBlock as af, type PartialBlockNoteContent as ag, type PartialBlockNoteInlineContent as ah, type PartialBlockNoteLink as ai, type PartialBlockNoteStyledText as aj, type PartialBlockNoteTableCell as ak, type PartialBlockNoteTableContent as al, type AuditResourceType as am, type AuditAction as an, type AuditActorType as ao, type AuditChange as ap, type AuditLogEntry as aq, type CreateAuditLogInput as ar, type AuditListOptions as as, type AuditServiceOptions as at, type StorageProvider as au, type FileVisibility as av, type File as aw, type CreateFile as ax, type UpdateFile as ay, type TextFilterOperator as az, type TextAreaAttribute as b, isFormTab as b$, type FlowStatus as b0, isFlowDefinition as b1, isFlowPublished as b2, isSystemFlow as b3, type GeocodingSuggestion as b4, type GeocodingAutocompleteParams as b5, type ReverseGeocodingParams as b6, type GeocodingParams as b7, type GeocodingAdapter as b8, NoopGeocodingAdapter as b9, type CompletionStatus as bA, type ObjectRecord as bB, type PermissionScope as bC, type Role as bD, type Permission as bE, type UserRoleAssignment as bF, type EffectivePermissions as bG, type ObjectPermissions as bH, type SystemPermissions as bI, type CreateRoleInput as bJ, type UpdateRoleInput as bK, type CreatePermissionInput as bL, type AssignRoleInput as bM, type PolicyContext as bN, type RecordPolicy as bO, PolicyViolationError as bP, type UserRole as bQ, type UserStatus as bR, type UserProfile as bS, type CreateUserProfile as bT, type UpdateUserProfile as bU, type InviteUserInput as bV, type TabType as bW, type FormTab as bX, type CustomTab as bY, type ActivityTab as bZ, type NotesTab as b_, type AttributeSchema as ba, type InferRecordFromSchema as bb, type InferRecordWithRequirements as bc, type TypedAttribute as bd, type AttributeMap as be, type AddAttribute as bf, type InferRecord as bg, type InferRecordInput as bh, type InferRecordUpdate as bi, type CustomAttributeValue as bj, type WithCustomAttributes as bk, type RecordMetadata as bl, type SystemFields as bm, type ExtractRecord as bn, type ExtractRecordStrict as bo, type ExtractRecordInput as bp, type ExtractRecordInputStrict as bq, type ExtractRecordUpdate as br, type ExtractRecordUpdateStrict as bs, type ExtractAttributes as bt, RESERVED_ATTRIBUTE_NAMES as bu, SYSTEM_FIELD_NAMES as bv, type ReservedAttributeName as bw, type SystemFieldName as bx, type Timestamps as by, type ObjectAttribute as bz, type RichtextFeature as c, type ValidationResult as c$, isTableTab as c0, isDirectTableTab as c1, isInverseTableTab as c2, isCustomTab as c3, isActivityTab as c4, isNotesTab as c5, type Uuid as c6, type TenantId as c7, type UserId as c8, asTenantId as c9, getAttributeConfigSchema as cA, validateAttributeConfig as cB, parseAttributeConfig as cC, safeParseAttributeConfig as cD, createTextValidator as cE, createNumberValidator as cF, createCheckboxValidator as cG, createDateValidator as cH, createPhoneValidator as cI, createCurrencyValidator as cJ, createStatusValidator as cK, createSelectValidator as cL, createMultiselectValidator as cM, createLocationValidator as cN, createFileValidator as cO, createUserValidator as cP, createSingleRelationValidator as cQ, createMultiRelationValidator as cR, createRelationValidator as cS, createRatingValidator as cT, createFormulaValidator as cU, createRollupValidator as cV, createTextAreaValidator as cW, createRichtextValidator as cX, createAttributeValidator as cY, createFormAttributeValidator as cZ, createObjectValidator as c_, asUserId as ca, generateId as cb, generatePrefixedId as cc, registry as cd, viewRegistry as ce, type ValidationMessages as cf, DEFAULT_VALIDATION_MESSAGES as cg, textConfigSchema as ch, textareaConfigSchema as ci, richtextConfigSchema as cj, numberConfigSchema as ck, checkboxConfigSchema as cl, dateConfigSchema as cm, phoneConfigSchema as cn, currencyConfigSchema as co, statusConfigSchema as cp, locationConfigSchema as cq, selectConfigSchema as cr, multiselectConfigSchema as cs, fileConfigSchema as ct, userConfigSchema as cu, relationConfigSchema as cv, ratingConfigSchema as cw, formulaConfigSchema as cx, rollupConfigSchema as cy, attributeConfigSchemas as cz, type CurrencyAttribute as d, type PathSegment as d$, validateAttribute as d0, validateObject as d1, validateObjectOrThrow as d2, createDraftValidator as d3, validateDraft as d4, validateDraftOrThrow as d5, getMissingRequiredAttributes as d6, isRecordComplete as d7, computeRecordStatus as d8, type DatabaseAdapter as d9, getUserId as dA, hasContext as dB, runWithContext as dC, withTenantContext as dD, type TenantContext as dE, evaluateFormula as dF, evaluateFormulaAttribute as dG, evaluateFormulaAttributeWithRelations as dH, evaluateFormulaWithRelations as dI, evaluateFormulaWithResult as dJ, extractFormulaVariables as dK, extractRelationNames as dL, extractRelationReferences as dM, flattenRelationsForEval as dN, formatFormulaResult as dO, hasRelationReferences as dP, validateFormulaExpression as dQ, type FormulaResult as dR, getPathDepth as dS, getRelationPath as dT, getTargetAttributeName as dU, InvalidPathError as dV, MaxDepthExceededError as dW, parsePath as dX, pathHasManyCardinality as dY, validatePath as dZ, type PathCardinality as d_, type CacheAdapter as da, type CacheOptions as db, cacheKeys as dc, cacheTtl as dd, NoopCacheAdapter as de, type FetchResult as df, type FormattedRecord as dg, type GroupedFetchResult as dh, type InsertOptions as di, type QueryBuilderState as dj, type RegistryMap as dk, type RegistryObjectNames as dl, type ShortcutOperator as dm, createDefaultState as dn, formatRecord as dp, formatRecords as dq, QueryMultipleResultsError as dr, QueryNoResultError as ds, SHORTCUT_TO_FILTER_OPERATOR as dt, createQueryBuilder as du, QueryBuilder as dv, type QueryBuilderOptions as dw, TenantContextError as dx, getContext as dy, getTenantId as dz, type Option as e, type UserValidationResult as e$, type PathSegmentType as e0, type SchemaResolver as e1, resolveMultiplePaths as e2, resolveSingleValue as e3, traversePath as e4, type TraversalOptions as e5, type TraversalResult as e6, type AttributeChange as e7, type HookContext as e8, type HookDefinition as e9, GeocodingService as eA, GlobalSearchService as eB, type CreateCustomObjectInput as eC, type AddAttributeInput as eD, type UpdateObjectInput as eE, type ObjectSchemaServiceOptions as eF, ObjectSchemaService as eG, type PermissionServiceOptions as eH, PermissionService as eI, type RecordServiceOptions as eJ, RecordService as eK, type RelationValidationResult as eL, type RelationValidationError as eM, type RelationOption as eN, type RelationOptionsResponse as eO, type GetRelationOptionsParams as eP, type RelationServiceOptions as eQ, RelationService as eR, type ResolvedRelations as eS, RelationResolverService as eT, type RollupResult as eU, type RollupServiceOptions as eV, RollupService as eW, type RollupSchedulerOptions as eX, RollupScheduler as eY, type UserProfileServiceOptions as eZ, UserProfileService as e_, type HookHandler as ea, type HookType as eb, NoopHookRegistry as ec, type HookRegistry as ed, createMockAdapter as ee, defaultPolicyRegistry as ef, PolicyRegistry as eg, notesPolicy as eh, type ObjectsRepository as ei, type AttributesRepository as ej, type UserProfilesRepository as ek, type FilesRepository as el, type ObjectRecordsRepository as em, type ViewsRepository as en, type FlowsRepository as eo, type AuditRepository as ep, type PermissionsRepository as eq, buildAuditChanges as er, AuditService as es, TenantAwareService as et, TenantAwareRepository as eu, type FileServiceOptions as ev, FileService as ew, type CreateFlowInput as ex, type UpdateFlowInput as ey, FlowService as ez, type StatusAttribute as f, type UserValidationError as f0, UserService as f1, type CreateViewInput as f2, type UpdateViewInput as f3, ViewService as f4, type FileContent as f5, type StorageUploadInput as f6, type StorageUploadResult as f7, type SignedUrlOptions as f8, type StorageAdapter as f9, type GlobalSearchResultItem as fA, type FileListOptions as fB, type DBView as fC, type CreateDBView as fD, type UpdateDBView as fE, type UpsertDBView as fF, type DBFlow as fG, type CreateDBFlow as fH, type UpdateDBFlow as fI, type OperationResult as fJ, type ViewSyncResult as fK, type ViewSyncOptions as fL, syncNativeViews as fM, verifyNativeViewsSync as fN, getViewSyncPreview as fO, type UploadFileInput as fa, type SyncResult as fb, type SyncOptions as fc, syncNativeObjects as fd, verifyNativeObjectsSync as fe, getSyncPreview as ff, type FullSyncResult as fg, type FullSyncOptions as fh, syncAll as fi, DEFAULT_LABEL_FALLBACK as fj, renderLabelExpression as fk, isLabelExpression as fl, extractAttributeNames as fm, enrichValuesWithSelectLabels as fn, type DBObject as fo, type CreateDBObject as fp, type UpdateDBObject as fq, type UpsertDBObject as fr, type DBAttribute as fs, type CreateDBAttribute as ft, type UpdateDBAttribute as fu, type UpsertDBAttribute as fv, type CreateObjectRecord as fw, type ListOptions as fx, type SearchOptions as fy, type GlobalSearchOptions as fz, type SelectAttribute as g, type SingleRelationAttribute as h, type MultiRelationAttribute as i, type RelationTarget as j, type RatingAttribute as k, type FormulaAttribute as l, type FormulaReturnType as m, type RollupAttribute as n, type RollupFunction as o, type AttributeType as p, type FlowDefinition as q, type FlowPage as r, type FlowRow as s, type ObjectDefinition as t, type Field as u, type AttributeGroupField as v, type TableTab as w, type InverseTableTab as x, type ViewDefinition as y, type Tab as z };
10657
+ export { type FlowRow as $, type Attribute as A, type DirectTableTab as B, type CheckboxAttribute as C, type DateAttribute as D, type WorkflowConfig as E, type FileAttribute as F, type Group as G, type SlotMode as H, type InferAttributeValue as I, type AuthMethod as J, type AuthChannel as K, type LocationAttribute as L, type MultiselectAttribute as M, type NumberAttribute as N, type ObjectAction as O, type PhoneAttribute as P, type ParticipantTemplate as Q, type RichtextAttribute as R, type SystemResource as S, type TextAttribute as T, type UserAttribute as U, type ViewLayout as V, type WorkflowTheme as W, type ConditionGroup as X, type ConditionRule as Y, type WorkflowNode as Z, type WorkflowDefinition as _, type SystemAction as a, toSimpleFilterState as a$, type BlockNoteContent as a0, type StatusGroup as a1, type AttributeGroup as a2, type BaseAttribute as a3, type NumberUnit as a4, type DateFormat as a5, type DateValue as a6, type Phone as a7, type Currency as a8, type Location as a9, type CreateAuditLogInput as aA, type AuditListOptions as aB, type AuditServiceOptions as aC, type StorageProvider as aD, type FileVisibility as aE, type File as aF, type CreateFile as aG, type UpdateFile as aH, type TextFilterOperator as aI, type NumberFilterOperator as aJ, type CheckboxFilterOperator as aK, type DateFilterOperator as aL, type SelectFilterOperator as aM, type MultiselectFilterOperator as aN, type RelationFilterOperator as aO, type FilterOperator as aP, type RelativeDateValue as aQ, type CurrencyFilterValue as aR, type PhoneFilterValue as aS, type FilterValue as aT, type FilterRule as aU, type ExtendedFilterRule as aV, type FilterCombinator as aW, type FilterGroup as aX, type AdvancedFilterState as aY, isAdvancedFilterState as aZ, toAdvancedFilterState as a_, type LocationGranularity as aa, RELATION_TARGET_ANY as ab, type RelationAttribute as ac, isUniversalRelation as ad, type BlockNoteBlock as ae, type BlockNoteCustomInlineContent as af, type BlockNoteDefaultProps as ag, type BlockNoteInlineContent as ah, type BlockNoteLink as ai, type BlockNoteStyledText as aj, type BlockNoteStyles as ak, type BlockNoteTableCell as al, type BlockNoteTableCellProps as am, type BlockNoteTableContent as an, type PartialBlockNoteBlock as ao, type PartialBlockNoteContent as ap, type PartialBlockNoteInlineContent as aq, type PartialBlockNoteLink as ar, type PartialBlockNoteStyledText as as, type PartialBlockNoteTableCell as at, type PartialBlockNoteTableContent as au, type AuditResourceType as av, type AuditAction as aw, type AuditActorType as ax, type AuditChange as ay, type AuditLogEntry as az, type TextAreaAttribute as b, type UserRole as b$, type SortDirection as b0, type QueryState as b1, OPERATORS_BY_TYPE as b2, type NoValueOperator as b3, NO_VALUE_OPERATORS as b4, isNoValueOperator as b5, type FlowSlot as b6, type FlowRowField as b7, type FlowPage as b8, type FlowRelation as b9, type ExtractRecordInput as bA, type ExtractRecordInputStrict as bB, type ExtractRecordUpdate as bC, type ExtractRecordUpdateStrict as bD, type ExtractAttributes as bE, RESERVED_ATTRIBUTE_NAMES as bF, SYSTEM_FIELD_NAMES as bG, type ReservedAttributeName as bH, type SystemFieldName as bI, type Timestamps as bJ, type ObjectAttribute as bK, type CompletionStatus as bL, type ObjectRecord as bM, type PermissionScope as bN, type Role as bO, type Permission as bP, type UserRoleAssignment as bQ, type EffectivePermissions as bR, type ObjectPermissions as bS, type SystemPermissions as bT, type CreateRoleInput as bU, type UpdateRoleInput as bV, type CreatePermissionInput as bW, type AssignRoleInput as bX, type PolicyContext as bY, type RecordPolicy as bZ, PolicyViolationError as b_, type FlowStatus as ba, type FlowDefinition as bb, isFlowDefinition as bc, isFlowPublished as bd, isSystemFlow as be, type GeocodingSuggestion as bf, type GeocodingAutocompleteParams as bg, type ReverseGeocodingParams as bh, type GeocodingParams as bi, type GeocodingAdapter as bj, NoopGeocodingAdapter as bk, type AttributeSchema as bl, type InferRecordFromSchema as bm, type InferRecordWithRequirements as bn, type TypedAttribute as bo, type AttributeMap as bp, type AddAttribute as bq, type InferRecord as br, type InferRecordInput as bs, type InferRecordUpdate as bt, type CustomAttributeValue as bu, type WithCustomAttributes as bv, type RecordMetadata as bw, type SystemFields as bx, type ExtractRecord as by, type ExtractRecordStrict as bz, type RichtextFeature as c, type WorkflowParticipation as c$, type UserStatus as c0, type UserProfile as c1, type CreateUserProfile as c2, type UpdateUserProfile as c3, type InviteUserInput as c4, type TabType as c5, type FormTab as c6, type CustomTab as c7, type ActivityTab as c8, type NotesTab as c9, neq as cA, and as cB, or as cC, inValues as cD, isEmpty as cE, isNotEmpty as cF, type WorkflowSlot as cG, type NodePosition as cH, type CanvasViewport as cI, type WorkflowLayout as cJ, type ParticipantAuthConfig as cK, type WorkflowStatus as cL, isWorkflowDefinition as cM, isWorkflowPublished as cN, isSystemWorkflow as cO, type WorkflowTransition as cP, type WorkflowError as cQ, type PendingAction as cR, type WorkflowInstance as cS, isInstanceTerminal as cT, isInstanceWaiting as cU, canResumeInstance as cV, createStartTransition as cW, type ParticipationStatus as cX, type SignedLinkAuth as cY, type PinCodeAuth as cZ, type ParticipationAuth as c_, type FlowsTab as ca, isFormTab as cb, isTableTab as cc, isDirectTableTab as cd, isInverseTableTab as ce, isCustomTab as cf, isActivityTab as cg, isNotesTab as ch, isFlowsTab as ci, type StartNode as cj, type FormNode as ck, type FormFieldRef as cl, type ConditionNode as cm, type EndNode as cn, type WorkflowNodeType as co, isStartNode as cp, isFormNode as cq, isConditionNode as cr, isEndNode as cs, isSimpleFormNode as ct, isAdvancedFormNode as cu, getNodeOutputs as cv, type ConditionOperator as cw, isConditionRule as cx, isConditionGroup as cy, eq as cz, type CurrencyAttribute as d, createCurrencyValidator as d$, isSignedLinkAuth as d0, isPinCodeAuth as d1, canParticipate as d2, canAuthenticate as d3, canExecuteNode as d4, type GeneratedDocument as d5, type WorkflowExecutionContext as d6, createEmptyContext as d7, getContextValue as d8, setContextValue as d9, textareaConfigSchema as dA, richtextConfigSchema as dB, numberConfigSchema as dC, checkboxConfigSchema as dD, dateConfigSchema as dE, phoneConfigSchema as dF, currencyConfigSchema as dG, statusConfigSchema as dH, locationConfigSchema as dI, selectConfigSchema as dJ, multiselectConfigSchema as dK, fileConfigSchema as dL, userConfigSchema as dM, relationConfigSchema as dN, ratingConfigSchema as dO, formulaConfigSchema as dP, rollupConfigSchema as dQ, attributeConfigSchemas as dR, getAttributeConfigSchema as dS, validateAttributeConfig as dT, parseAttributeConfig as dU, safeParseAttributeConfig as dV, createTextValidator as dW, createNumberValidator as dX, createCheckboxValidator as dY, createDateValidator as dZ, createPhoneValidator as d_, mergeFormToSlot as da, type WorkflowAccessMode as db, type ReadOnlyReason as dc, type FormFieldContext as dd, type FormFieldRow as de, type FormNodeInfo as df, type FormContextResponse as dg, type ThemeLogo as dh, type ThemeColors as di, type ThemeTypography as dj, DEFAULT_THEME as dk, mergeWithDefaults as dl, generateCssVariables as dm, type Uuid as dn, type TenantId as dp, type UserId as dq, asTenantId as dr, asUserId as ds, generateId as dt, generatePrefixedId as du, registry as dv, viewRegistry as dw, type ValidationMessages as dx, DEFAULT_VALIDATION_MESSAGES as dy, textConfigSchema as dz, type Option as e, evaluateCondition as e$, createStatusValidator as e0, createSelectValidator as e1, createMultiselectValidator as e2, createLocationValidator as e3, createFileValidator as e4, createUserValidator as e5, createSingleRelationValidator as e6, createMultiRelationValidator as e7, createRelationValidator as e8, createRatingValidator as e9, initializePinCodeService as eA, type PinCodeGenerationOptions as eB, type PinCodeVerificationResult as eC, type CacheAdapter as eD, type CacheOptions as eE, cacheKeys as eF, cacheTtl as eG, NoopCacheAdapter as eH, type FetchResult as eI, type FormattedRecord as eJ, type GroupedFetchResult as eK, type InsertOptions as eL, type QueryBuilderState as eM, type RegistryMap as eN, type RegistryObjectNames as eO, type ShortcutOperator as eP, createDefaultState as eQ, formatRecord as eR, formatRecords as eS, QueryMultipleResultsError as eT, QueryNoResultError as eU, SHORTCUT_TO_FILTER_OPERATOR as eV, createQueryBuilder as eW, QueryBuilder as eX, type QueryBuilderOptions as eY, type EvaluationResult as eZ, type EvaluationTrace as e_, createFormulaValidator as ea, createRollupValidator as eb, createTextAreaValidator as ec, createRichtextValidator as ed, createAttributeValidator as ee, createFormAttributeValidator as ef, createObjectValidator as eg, type ValidationResult as eh, validateAttribute as ei, validateObject as ej, validateObjectOrThrow as ek, createDraftValidator as el, validateDraft as em, validateDraftOrThrow as en, getMissingRequiredAttributes as eo, isRecordComplete as ep, computeRecordStatus as eq, type DatabaseAdapter as er, ParticipationTokenService as es, getDefaultTokenService as et, initializeTokenService as eu, type ParticipationTokenPayload as ev, type TokenGenerationOptions as ew, type TokenVerificationResult as ex, PinCodeService as ey, getDefaultPinCodeService as ez, type StatusAttribute as f, NoopHookRegistry as f$, evaluate as f0, evaluateWithTrace as f1, TenantContextError as f2, getContext as f3, getTenantId as f4, getUserId as f5, hasContext as f6, runWithContext as f7, withTenantContext as f8, type TenantContext as f9, flattenRelationsForEval as fA, formatFormulaResult as fB, hasRelationReferences as fC, validateFormulaExpression as fD, type FormulaResult as fE, getPathDepth as fF, getRelationPath as fG, getTargetAttributeName as fH, InvalidPathError as fI, MaxDepthExceededError as fJ, parsePath as fK, pathHasManyCardinality as fL, validatePath as fM, type PathCardinality as fN, type PathSegment as fO, type PathSegmentType as fP, type SchemaResolver as fQ, resolveMultiplePaths as fR, resolveSingleValue as fS, traversePath as fT, type TraversalOptions as fU, type TraversalResult as fV, type AttributeChange as fW, type HookContext as fX, type HookDefinition as fY, type HookHandler as fZ, type HookType as f_, createDefaultExecutorRegistry as fa, getDefaultExecutorRegistry as fb, type ExecutorCompleteResult as fc, type ExecutorContext as fd, type ExecutorErrorResult as fe, type ExecutorResult as ff, type ExecutorSuccessResult as fg, type ExecutorWaitResult as fh, type NodeExecutor as fi, complete as fj, error as fk, ExecutorRegistry as fl, success as fm, wait as fn, ConditionExecutor as fo, EndExecutor as fp, FormExecutor as fq, StartExecutor as fr, evaluateFormula as fs, evaluateFormulaAttribute as ft, evaluateFormulaAttributeWithRelations as fu, evaluateFormulaWithRelations as fv, evaluateFormulaWithResult as fw, extractFormulaVariables as fx, extractRelationNames as fy, extractRelationReferences as fz, type SelectAttribute as g, type FieldReadOnlyResult as g$, type HookRegistry as g0, createMockAdapter as g1, defaultPolicyRegistry as g2, PolicyRegistry as g3, notesPolicy as g4, type ObjectsRepository as g5, type AttributesRepository as g6, type UserProfilesRepository as g7, type FilesRepository as g8, type ObjectRecordsRepository as g9, type RelationValidationError as gA, type RelationOption as gB, type RelationOptionsResponse as gC, type GetRelationOptionsParams as gD, type RelationServiceOptions as gE, RelationService as gF, type RollupSchedulerOptions as gG, RollupScheduler as gH, type RollupResult as gI, type RollupServiceOptions as gJ, RollupService as gK, type UserProfileServiceOptions as gL, UserProfileService as gM, type UserValidationResult as gN, type UserValidationError as gO, UserService as gP, type CreateViewInput as gQ, type UpdateViewInput as gR, ViewService as gS, type StartWorkflowInput as gT, type ResumeWorkflowInput as gU, type WorkflowInstanceServiceOptions as gV, WorkflowInstanceService as gW, type CreateParticipationInput as gX, type CreateParticipationResult as gY, type AuthenticationResult as gZ, WorkflowParticipationService as g_, type ViewsRepository as ga, type WorkflowsRepository as gb, type WorkflowInstancesRepository as gc, type WorkflowParticipationsRepository as gd, type AuditRepository as ge, type PermissionsRepository as gf, buildAuditChanges as gg, AuditService as gh, TenantAwareService as gi, TenantAwareRepository as gj, type FileServiceOptions as gk, FileService as gl, GeocodingService as gm, GlobalSearchService as gn, type CreateCustomObjectInput as go, type AddAttributeInput as gp, type UpdateObjectInput as gq, type ObjectSchemaServiceOptions as gr, ObjectSchemaService as gs, type PermissionServiceOptions as gt, PermissionService as gu, type RecordServiceOptions as gv, RecordService as gw, type ResolvedRelations as gx, RelationResolverService as gy, type RelationValidationResult as gz, type SingleRelationAttribute as h, WorkflowRelationService as h0, type CreateWorkflowInput as h1, type UpdateWorkflowInput as h2, WorkflowService as h3, type FileContent as h4, type StorageUploadInput as h5, type StorageUploadResult as h6, type SignedUrlOptions as h7, type StorageAdapter as h8, type UploadFileInput as h9, type SearchOptions as hA, type GlobalSearchOptions as hB, type GlobalSearchResultItem as hC, type FileListOptions as hD, type DBView as hE, type CreateDBView as hF, type UpdateDBView as hG, type UpsertDBView as hH, type DBWorkflow as hI, type CreateDBWorkflow as hJ, type UpdateDBWorkflow as hK, type DBWorkflowInstance as hL, type CreateDBWorkflowInstance as hM, type UpdateDBWorkflowInstance as hN, type DBWorkflowParticipation as hO, type CreateDBWorkflowParticipation as hP, type UpdateDBWorkflowParticipation as hQ, type OperationResult as hR, type ViewSyncResult as hS, type ViewSyncOptions as hT, syncNativeViews as hU, verifyNativeViewsSync as hV, getViewSyncPreview as hW, type SyncResult as ha, type SyncOptions as hb, syncNativeObjects as hc, verifyNativeObjectsSync as hd, getSyncPreview as he, type FullSyncResult as hf, type FullSyncOptions as hg, syncAll as hh, DEFAULT_LABEL_FALLBACK as hi, renderLabelExpression as hj, isLabelExpression as hk, extractAttributeNames as hl, enrichValuesWithSelectLabels as hm, extractRelationIds as hn, type RelationLabelResolver as ho, computeLabelWithRelations as hp, type DBObject as hq, type CreateDBObject as hr, type UpdateDBObject as hs, type UpsertDBObject as ht, type DBAttribute as hu, type CreateDBAttribute as hv, type UpdateDBAttribute as hw, type UpsertDBAttribute as hx, type CreateObjectRecord as hy, type ListOptions as hz, type MultiRelationAttribute as i, type RelationTarget as j, type RatingAttribute as k, type FormulaAttribute as l, type FormulaReturnType as m, type RollupAttribute as n, type RollupFunction as o, type AttributeType as p, type ObjectDefinition as q, type Field as r, type AttributeGroupField as s, type TableTab as t, type InverseTableTab as u, type ViewDefinition as v, type InstanceStatus as w, type Tab as x, type FilterState as y, type SortRule as z };