/* * The contents of this file were inserted manually and are not generated by Stainless. * * Shared helpers and enum types for the manifest builder. */ let _counter = 0; /** Generate a short unique ID string (e.g. "id_a3f1b2"). */ export function generateId(prefix = 'id'): string { const rand = Math.random().toString(36).slice(2, 8); return `${prefix}_${rand}${(_counter++).toString(36)}`; } // --------------------------------------------------------------------------- // Enum types for strongly-typed setters // --------------------------------------------------------------------------- /** Record-triggered flow trigger type. */ export type TriggerType = 'CREATE' | 'UPDATE' | 'CREATE_OR_UPDATE'; /** * Update-trigger condition type. Mirrors the backend * `FlowUpdateTriggerBehavior` enum (`constants.py`). Note the `OR_AFTER` * spelling — `BEFORE_AND_AFTER` is a common typo that /validate will reject. */ export type UpdateTriggerType = 'MEETS_CONDITION_AFTER_ONLY' | 'MEETS_CONDITION_BEFORE_OR_AFTER'; /** Validation rule state. */ export type ValidationState = 'ACTIVE' | 'INACTIVE'; /** Validation rule level. */ export type ValidationLevel = 'RECORD' | 'FIELD'; /** Sort direction for list views. */ export type SortOrder = 'ASC' | 'DESC'; /** Scope for list views. */ export type ObjectScope = 'all' | 'my_records'; /** * Supported `data_type.field_type` values for CUSTOM_OBJECT_FIELD and * CUSTOM_FIELD_V2. Note: lookup and parent-child relationships both use * `field_type: 'OG_REFERENCE_FIELD'` and are differentiated by `edge_type` * (see `EdgeType`). `'LOOKUP'` and `'PARENT_CHILD'` are NOT valid * `field_type` values — emitting them produces invalid manifests. */ export type FieldType = | 'TEXT' | 'LONG_TEXT' | 'EMAIL' | 'URL' | 'PHONE_NUMBER' | 'NUMBER' | 'CURRENCY' | 'PERCENTAGE' | 'DATE' | 'DATETIME' | 'TIME' | 'SELECT' | 'RADIO' | 'BOOLEAN' | 'FILE' | 'OG_REFERENCE_FIELD'; /** * Discriminator for `OG_REFERENCE_FIELD` data types — distinguishes a plain * lookup from a parent-child relationship. */ export type EdgeType = 'LOOKUP' | 'PARENT_CHILD'; /** * Allowed output `field_type` for Simple Formula Fields. Mirrors the UI * "Data type" dropdown in the formula field editor — backend `field_type` is * free-form `str`, but the product only validates these 7 variants end-to-end. */ export type FormulaFieldType = 'TEXT' | 'NUMBER' | 'BOOLEAN' | 'CURRENCY' | 'PERCENTAGE' | 'DATE' | 'URL'; /** * Page type emitted inside CUSTOM_APP pages. Apps authored through the manifest * SDK expose SDUI page tabs only; wrap custom-object records in an SDUI * ObjectListView when you need an object-backed page. */ export type PageType = 'sdui_page'; // --------------------------------------------------------------------------- // Summary-field constants (for Field.summary) // --------------------------------------------------------------------------- /** Backend supports exactly these four (`constants.py:1316`). */ export type SummaryAggregation = 'COUNT' | 'SUM' | 'MIN' | 'MAX'; /** * RQL operator for summary filters. Scalar-only, matching the admin * condition-builder dropdown. * * The backend's RQL engine accepts a wider set (WHERE_CLAUSE_OPERATORS * includes `LIKE`, `ILIKE`, `IN`, `CONTAINS`, …), but summary filters * authored by the UI are restricted to plain scalar comparisons. Emitting * anything else from the SDK produces a manifest that /validate accepts * but the admin UI cannot render or edit — a split-brain config. */ export type SummaryFilterOperator = | '=' | '!=' // equality (all scalar types) | '>' | '>=' | '<' | '<='; // ordered numeric / currency / date /** * Mirrors `DERIVED_AGGREGATION_FUNCTIONS_AND_SUPPORTED_TYPES` (constants.py:1316). * The output field_type of a summary must be in the aggregation function's * supported set. For non-COUNT, backend further requires the output to equal * the aggregated field's field_type (parent_child_util.py:217-220). */ export const ALLOWED_SUMMARY_OUTPUT: Record> = { COUNT: new Set(['NUMBER']), SUM: new Set(['NUMBER', 'PERCENTAGE', 'CURRENCY']), MIN: new Set(['NUMBER', 'PERCENTAGE', 'DATE', 'DATETIME', 'TIME', 'CURRENCY']), MAX: new Set(['NUMBER', 'PERCENTAGE', 'DATE', 'DATETIME', 'TIME', 'CURRENCY']), }; /** * Per-field-type allow-list for summary filter operators, mirroring the * admin condition-builder picker. * * This is also the single source of truth for "which field types can be * used as a summary filter at all": field types **absent from this map** * are rejected as filter fields entirely. The UI-hidden types are: * * SELECT — array-valued at the RQL layer; the * "is this option selected?" semantics are * ambiguous for aggregations. * RADIO — single-value choice fields are not supported * by the summary filter condition builder. * When a choice should drive an aggregate filter, * model a plain BOOLEAN on the child CO, update it * with a `Rule` action, and filter on that. * LONG_TEXT — backend hard-rejects (parent_child_util.py). * OG_REFERENCE_FIELD — lookup/parent-child: filter-on-what is * ambiguous (id vs. name vs. edge metadata). * * The backend additionally rejects formula and summary fields as filter * fields, and rejects the summary's own parent-child `lookup` field as * its filter field. Those are enforced at construction-time in * `SummaryField` (see `field.ts`) so the error surfaces before /validate. */ export const FILTER_OPERATORS_BY_TYPE: Partial>> = { TEXT: new Set(['=', '!=']), EMAIL: new Set(['=', '!=']), URL: new Set(['=', '!=']), PHONE_NUMBER: new Set(['=', '!=']), BOOLEAN: new Set(['=', '!=']), FILE: new Set(['=', '!=']), NUMBER: new Set(['=', '!=', '>', '>=', '<', '<=']), PERCENTAGE: new Set(['=', '!=', '>', '>=', '<', '<=']), CURRENCY: new Set(['=', '!=', '>', '>=', '<', '<=']), DATE: new Set(['=', '<', '>']), DATETIME: new Set(['=', '<', '>']), TIME: new Set(['=', '<', '>']), };