@rippling/rippling-sdk 0.2.0-alpha.32 → 0.2.0-alpha.34

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.
Files changed (191) hide show
  1. package/client.d.mts +8 -2
  2. package/client.d.mts.map +1 -1
  3. package/client.d.ts +8 -2
  4. package/client.d.ts.map +1 -1
  5. package/client.js +17 -0
  6. package/client.js.map +1 -1
  7. package/client.mjs +17 -0
  8. package/client.mjs.map +1 -1
  9. package/internal/types.d.mts +6 -6
  10. package/internal/types.d.mts.map +1 -1
  11. package/internal/types.d.ts +6 -6
  12. package/internal/types.d.ts.map +1 -1
  13. package/lib/manifest/_helpers.d.mts +91 -0
  14. package/lib/manifest/_helpers.d.mts.map +1 -0
  15. package/lib/manifest/_helpers.d.ts +91 -0
  16. package/lib/manifest/_helpers.d.ts.map +1 -0
  17. package/lib/manifest/_helpers.js +65 -0
  18. package/lib/manifest/_helpers.js.map +1 -0
  19. package/lib/manifest/_helpers.mjs +61 -0
  20. package/lib/manifest/_helpers.mjs.map +1 -0
  21. package/lib/manifest/app.d.mts +45 -0
  22. package/lib/manifest/app.d.mts.map +1 -0
  23. package/lib/manifest/app.d.ts +45 -0
  24. package/lib/manifest/app.d.ts.map +1 -0
  25. package/lib/manifest/app.js +74 -0
  26. package/lib/manifest/app.js.map +1 -0
  27. package/lib/manifest/app.mjs +70 -0
  28. package/lib/manifest/app.mjs.map +1 -0
  29. package/lib/manifest/category.d.mts +23 -0
  30. package/lib/manifest/category.d.mts.map +1 -0
  31. package/lib/manifest/category.d.ts +23 -0
  32. package/lib/manifest/category.d.ts.map +1 -0
  33. package/lib/manifest/category.js +37 -0
  34. package/lib/manifest/category.js.map +1 -0
  35. package/lib/manifest/category.mjs +33 -0
  36. package/lib/manifest/category.mjs.map +1 -0
  37. package/lib/manifest/custom-object-field-section.d.mts +21 -0
  38. package/lib/manifest/custom-object-field-section.d.mts.map +1 -0
  39. package/lib/manifest/custom-object-field-section.d.ts +21 -0
  40. package/lib/manifest/custom-object-field-section.d.ts.map +1 -0
  41. package/lib/manifest/custom-object-field-section.js +42 -0
  42. package/lib/manifest/custom-object-field-section.js.map +1 -0
  43. package/lib/manifest/custom-object-field-section.mjs +38 -0
  44. package/lib/manifest/custom-object-field-section.mjs.map +1 -0
  45. package/lib/manifest/custom-object-page-layout.d.mts +158 -0
  46. package/lib/manifest/custom-object-page-layout.d.mts.map +1 -0
  47. package/lib/manifest/custom-object-page-layout.d.ts +158 -0
  48. package/lib/manifest/custom-object-page-layout.d.ts.map +1 -0
  49. package/lib/manifest/custom-object-page-layout.js +112 -0
  50. package/lib/manifest/custom-object-page-layout.js.map +1 -0
  51. package/lib/manifest/custom-object-page-layout.mjs +108 -0
  52. package/lib/manifest/custom-object-page-layout.mjs.map +1 -0
  53. package/lib/manifest/custom-object.d.mts +52 -0
  54. package/lib/manifest/custom-object.d.mts.map +1 -0
  55. package/lib/manifest/custom-object.d.ts +52 -0
  56. package/lib/manifest/custom-object.d.ts.map +1 -0
  57. package/lib/manifest/custom-object.js +219 -0
  58. package/lib/manifest/custom-object.js.map +1 -0
  59. package/lib/manifest/custom-object.mjs +215 -0
  60. package/lib/manifest/custom-object.mjs.map +1 -0
  61. package/lib/manifest/field.d.mts +276 -0
  62. package/lib/manifest/field.d.mts.map +1 -0
  63. package/lib/manifest/field.d.ts +276 -0
  64. package/lib/manifest/field.d.ts.map +1 -0
  65. package/lib/manifest/field.js +418 -0
  66. package/lib/manifest/field.js.map +1 -0
  67. package/lib/manifest/field.mjs +395 -0
  68. package/lib/manifest/field.mjs.map +1 -0
  69. package/lib/manifest/index.d.mts +15 -0
  70. package/lib/manifest/index.d.mts.map +1 -0
  71. package/lib/manifest/index.d.ts +15 -0
  72. package/lib/manifest/index.d.ts.map +1 -0
  73. package/lib/manifest/index.js +53 -0
  74. package/lib/manifest/index.js.map +1 -0
  75. package/lib/manifest/index.mjs +18 -0
  76. package/lib/manifest/index.mjs.map +1 -0
  77. package/lib/manifest/list-view.d.mts +47 -0
  78. package/lib/manifest/list-view.d.mts.map +1 -0
  79. package/lib/manifest/list-view.d.ts +47 -0
  80. package/lib/manifest/list-view.d.ts.map +1 -0
  81. package/lib/manifest/list-view.js +73 -0
  82. package/lib/manifest/list-view.js.map +1 -0
  83. package/lib/manifest/list-view.mjs +69 -0
  84. package/lib/manifest/list-view.mjs.map +1 -0
  85. package/lib/manifest/manifest-builder.d.mts +44 -0
  86. package/lib/manifest/manifest-builder.d.mts.map +1 -0
  87. package/lib/manifest/manifest-builder.d.ts +44 -0
  88. package/lib/manifest/manifest-builder.d.ts.map +1 -0
  89. package/lib/manifest/manifest-builder.js +69 -0
  90. package/lib/manifest/manifest-builder.js.map +1 -0
  91. package/lib/manifest/manifest-builder.mjs +65 -0
  92. package/lib/manifest/manifest-builder.mjs.map +1 -0
  93. package/lib/manifest/manifest-function.d.mts +39 -0
  94. package/lib/manifest/manifest-function.d.mts.map +1 -0
  95. package/lib/manifest/manifest-function.d.ts +39 -0
  96. package/lib/manifest/manifest-function.d.ts.map +1 -0
  97. package/lib/manifest/manifest-function.js +56 -0
  98. package/lib/manifest/manifest-function.js.map +1 -0
  99. package/lib/manifest/manifest-function.mjs +52 -0
  100. package/lib/manifest/manifest-function.mjs.map +1 -0
  101. package/lib/manifest/rule.d.mts +50 -0
  102. package/lib/manifest/rule.d.mts.map +1 -0
  103. package/lib/manifest/rule.d.ts +50 -0
  104. package/lib/manifest/rule.d.ts.map +1 -0
  105. package/lib/manifest/rule.js +84 -0
  106. package/lib/manifest/rule.js.map +1 -0
  107. package/lib/manifest/rule.mjs +80 -0
  108. package/lib/manifest/rule.mjs.map +1 -0
  109. package/lib/manifest/sdui-page.d.mts +33 -0
  110. package/lib/manifest/sdui-page.d.mts.map +1 -0
  111. package/lib/manifest/sdui-page.d.ts +33 -0
  112. package/lib/manifest/sdui-page.d.ts.map +1 -0
  113. package/lib/manifest/sdui-page.js +52 -0
  114. package/lib/manifest/sdui-page.js.map +1 -0
  115. package/lib/manifest/sdui-page.mjs +48 -0
  116. package/lib/manifest/sdui-page.mjs.map +1 -0
  117. package/lib/manifest/validation.d.mts +41 -0
  118. package/lib/manifest/validation.d.mts.map +1 -0
  119. package/lib/manifest/validation.d.ts +41 -0
  120. package/lib/manifest/validation.d.ts.map +1 -0
  121. package/lib/manifest/validation.js +57 -0
  122. package/lib/manifest/validation.js.map +1 -0
  123. package/lib/manifest/validation.mjs +53 -0
  124. package/lib/manifest/validation.mjs.map +1 -0
  125. package/package.json +11 -1
  126. package/resources/draft-hires.d.mts +22 -0
  127. package/resources/draft-hires.d.mts.map +1 -1
  128. package/resources/draft-hires.d.ts +22 -0
  129. package/resources/draft-hires.d.ts.map +1 -1
  130. package/resources/earnings-inputs.d.mts +104 -1
  131. package/resources/earnings-inputs.d.mts.map +1 -1
  132. package/resources/earnings-inputs.d.ts +104 -1
  133. package/resources/earnings-inputs.d.ts.map +1 -1
  134. package/resources/earnings-inputs.js +17 -0
  135. package/resources/earnings-inputs.js.map +1 -1
  136. package/resources/earnings-inputs.mjs +17 -0
  137. package/resources/earnings-inputs.mjs.map +1 -1
  138. package/resources/files.d.mts +149 -0
  139. package/resources/files.d.mts.map +1 -0
  140. package/resources/files.d.ts +149 -0
  141. package/resources/files.d.ts.map +1 -0
  142. package/resources/files.js +25 -0
  143. package/resources/files.js.map +1 -0
  144. package/resources/files.mjs +21 -0
  145. package/resources/files.mjs.map +1 -0
  146. package/resources/index.d.mts +2 -1
  147. package/resources/index.d.mts.map +1 -1
  148. package/resources/index.d.ts +2 -1
  149. package/resources/index.d.ts.map +1 -1
  150. package/resources/index.js +4 -2
  151. package/resources/index.js.map +1 -1
  152. package/resources/index.mjs +1 -0
  153. package/resources/index.mjs.map +1 -1
  154. package/resources/object-categories.d.mts +1 -1
  155. package/resources/object-categories.d.ts +1 -1
  156. package/resources/object-categories.js +1 -1
  157. package/resources/object-categories.mjs +1 -1
  158. package/resources/report-runs.d.mts +11 -11
  159. package/resources/report-runs.d.ts +11 -11
  160. package/resources/workflow-action-executions.d.mts +17 -2
  161. package/resources/workflow-action-executions.d.mts.map +1 -1
  162. package/resources/workflow-action-executions.d.ts +17 -2
  163. package/resources/workflow-action-executions.d.ts.map +1 -1
  164. package/src/client.ts +29 -0
  165. package/src/internal/types.ts +6 -8
  166. package/src/lib/manifest/_helpers.ts +164 -0
  167. package/src/lib/manifest/app.ts +108 -0
  168. package/src/lib/manifest/category.ts +51 -0
  169. package/src/lib/manifest/custom-object-field-section.ts +54 -0
  170. package/src/lib/manifest/custom-object-page-layout.ts +292 -0
  171. package/src/lib/manifest/custom-object.ts +269 -0
  172. package/src/lib/manifest/field.ts +632 -0
  173. package/src/lib/manifest/index.ts +114 -0
  174. package/src/lib/manifest/list-view.ts +103 -0
  175. package/src/lib/manifest/manifest-builder.ts +97 -0
  176. package/src/lib/manifest/manifest-function.ts +81 -0
  177. package/src/lib/manifest/rule.ts +125 -0
  178. package/src/lib/manifest/sdui-page.ts +72 -0
  179. package/src/lib/manifest/validation.ts +87 -0
  180. package/src/resources/draft-hires.ts +26 -0
  181. package/src/resources/earnings-inputs.ts +140 -0
  182. package/src/resources/files.ts +186 -0
  183. package/src/resources/index.ts +3 -0
  184. package/src/resources/object-categories.ts +1 -1
  185. package/src/resources/report-runs.ts +32 -32
  186. package/src/resources/workflow-action-executions.ts +22 -1
  187. package/src/version.ts +1 -1
  188. package/version.d.mts +1 -1
  189. package/version.d.ts +1 -1
  190. package/version.js +1 -1
  191. package/version.mjs +1 -1
@@ -0,0 +1,164 @@
1
+ /*
2
+ * The contents of this file were inserted manually and are not generated by Stainless.
3
+ *
4
+ * Shared helpers and enum types for the manifest builder.
5
+ */
6
+
7
+ let _counter = 0;
8
+
9
+ /** Generate a short unique ID string (e.g. "id_a3f1b2"). */
10
+ export function generateId(prefix = 'id'): string {
11
+ const rand = Math.random().toString(36).slice(2, 8);
12
+ return `${prefix}_${rand}${(_counter++).toString(36)}`;
13
+ }
14
+
15
+ // ---------------------------------------------------------------------------
16
+ // Enum types for strongly-typed setters
17
+ // ---------------------------------------------------------------------------
18
+
19
+ /** Record-triggered flow trigger type. */
20
+ export type TriggerType = 'CREATE' | 'UPDATE' | 'CREATE_OR_UPDATE';
21
+
22
+ /**
23
+ * Update-trigger condition type. Mirrors the backend
24
+ * `FlowUpdateTriggerBehavior` enum (`constants.py`). Note the `OR_AFTER`
25
+ * spelling — `BEFORE_AND_AFTER` is a common typo that /validate will reject.
26
+ */
27
+ export type UpdateTriggerType = 'MEETS_CONDITION_AFTER_ONLY' | 'MEETS_CONDITION_BEFORE_OR_AFTER';
28
+
29
+ /** Validation rule state. */
30
+ export type ValidationState = 'ACTIVE' | 'INACTIVE';
31
+
32
+ /** Validation rule level. */
33
+ export type ValidationLevel = 'RECORD' | 'FIELD';
34
+
35
+ /** Sort direction for list views. */
36
+ export type SortOrder = 'ASC' | 'DESC';
37
+
38
+ /** Scope for list views. */
39
+ export type ObjectScope = 'all' | 'my_records';
40
+
41
+ /**
42
+ * Supported `data_type.field_type` values for CUSTOM_OBJECT_FIELD and
43
+ * CUSTOM_FIELD_V2. Note: lookup and parent-child relationships both use
44
+ * `field_type: 'OG_REFERENCE_FIELD'` and are differentiated by `edge_type`
45
+ * (see `EdgeType`). `'LOOKUP'` and `'PARENT_CHILD'` are NOT valid
46
+ * `field_type` values — emitting them produces invalid manifests.
47
+ */
48
+ export type FieldType =
49
+ | 'TEXT'
50
+ | 'LONG_TEXT'
51
+ | 'EMAIL'
52
+ | 'URL'
53
+ | 'PHONE_NUMBER'
54
+ | 'NUMBER'
55
+ | 'CURRENCY'
56
+ | 'PERCENTAGE'
57
+ | 'DATE'
58
+ | 'DATETIME'
59
+ | 'TIME'
60
+ | 'SELECT'
61
+ | 'RADIO'
62
+ | 'BOOLEAN'
63
+ | 'FILE'
64
+ | 'OG_REFERENCE_FIELD';
65
+
66
+ /**
67
+ * Discriminator for `OG_REFERENCE_FIELD` data types — distinguishes a plain
68
+ * lookup from a parent-child relationship.
69
+ */
70
+ export type EdgeType = 'LOOKUP' | 'PARENT_CHILD';
71
+
72
+ /**
73
+ * Allowed output `field_type` for Simple Formula Fields. Mirrors the UI
74
+ * "Data type" dropdown in the formula field editor — backend `field_type` is
75
+ * free-form `str`, but the product only validates these 7 variants end-to-end.
76
+ */
77
+ export type FormulaFieldType = 'TEXT' | 'NUMBER' | 'BOOLEAN' | 'CURRENCY' | 'PERCENTAGE' | 'DATE' | 'URL';
78
+
79
+ /** Runtime for FUNCTION component. */
80
+ export type FunctionRuntime = 'cloudflare-js' | 'lambda-deno' | 'lambda-python';
81
+
82
+ /**
83
+ * Page type inside CUSTOM_APP. Mirrors the backend `PageType` enum
84
+ * (`pages.py`). The SDK currently models the two surfaces it supports —
85
+ * object pages and SDUI pages. `function_page` is NOT a valid backend token;
86
+ * wrap a function in an SDUI page instead.
87
+ */
88
+ export type PageType = 'object_page' | 'sdui_page';
89
+
90
+ // ---------------------------------------------------------------------------
91
+ // Summary-field constants (for Field.summary)
92
+ // ---------------------------------------------------------------------------
93
+
94
+ /** Backend supports exactly these four (`constants.py:1316`). */
95
+ export type SummaryAggregation = 'COUNT' | 'SUM' | 'MIN' | 'MAX';
96
+
97
+ /**
98
+ * RQL operator for summary filters. Scalar-only, matching the admin
99
+ * condition-builder dropdown.
100
+ *
101
+ * The backend's RQL engine accepts a wider set (WHERE_CLAUSE_OPERATORS
102
+ * includes `LIKE`, `ILIKE`, `IN`, `CONTAINS`, …), but summary filters
103
+ * authored by the UI are restricted to plain scalar comparisons. Emitting
104
+ * anything else from the SDK produces a manifest that /validate accepts
105
+ * but the admin UI cannot render or edit — a split-brain config.
106
+ */
107
+ export type SummaryFilterOperator =
108
+ | '='
109
+ | '!=' // equality (all scalar types)
110
+ | '>'
111
+ | '>='
112
+ | '<'
113
+ | '<='; // ordered numeric / currency / date
114
+
115
+ /**
116
+ * Mirrors `DERIVED_AGGREGATION_FUNCTIONS_AND_SUPPORTED_TYPES` (constants.py:1316).
117
+ * The output field_type of a summary must be in the aggregation function's
118
+ * supported set. For non-COUNT, backend further requires the output to equal
119
+ * the aggregated field's field_type (parent_child_util.py:217-220).
120
+ */
121
+ export const ALLOWED_SUMMARY_OUTPUT: Record<SummaryAggregation, ReadonlySet<FieldType>> = {
122
+ COUNT: new Set(['NUMBER']),
123
+ SUM: new Set(['NUMBER', 'PERCENTAGE', 'CURRENCY']),
124
+ MIN: new Set(['NUMBER', 'PERCENTAGE', 'DATE', 'DATETIME', 'TIME', 'CURRENCY']),
125
+ MAX: new Set(['NUMBER', 'PERCENTAGE', 'DATE', 'DATETIME', 'TIME', 'CURRENCY']),
126
+ };
127
+
128
+ /**
129
+ * Per-field-type allow-list for summary filter operators, mirroring the
130
+ * admin condition-builder picker.
131
+ *
132
+ * This is also the single source of truth for "which field types can be
133
+ * used as a summary filter at all": field types **absent from this map**
134
+ * are rejected as filter fields entirely. The UI-hidden types are:
135
+ *
136
+ * SELECT / RADIO — array-valued at the RQL layer; the
137
+ * "is this option selected?" semantics are
138
+ * ambiguous for aggregations. Users are
139
+ * expected to model a plain BOOLEAN on the
140
+ * child CO (updated via Rule) and filter
141
+ * on that.
142
+ * LONG_TEXT — backend hard-rejects (parent_child_util.py).
143
+ * OG_REFERENCE_FIELD — lookup/parent-child: filter-on-what is
144
+ * ambiguous (id vs. name vs. edge metadata).
145
+ *
146
+ * The backend additionally rejects formula and summary fields as filter
147
+ * fields, and rejects the summary's own parent-child `lookup` field as
148
+ * its filter field. Those are enforced at construction-time in
149
+ * `SummaryField` (see `field.ts`) so the error surfaces before /validate.
150
+ */
151
+ export const FILTER_OPERATORS_BY_TYPE: Partial<Record<FieldType, ReadonlySet<SummaryFilterOperator>>> = {
152
+ TEXT: new Set(['=', '!=']),
153
+ EMAIL: new Set(['=', '!=']),
154
+ URL: new Set(['=', '!=']),
155
+ PHONE_NUMBER: new Set(['=', '!=']),
156
+ BOOLEAN: new Set(['=', '!=']),
157
+ FILE: new Set(['=', '!=']),
158
+ NUMBER: new Set(['=', '!=', '>', '>=', '<', '<=']),
159
+ PERCENTAGE: new Set(['=', '!=', '>', '>=', '<', '<=']),
160
+ CURRENCY: new Set(['=', '!=', '>', '>=', '<', '<=']),
161
+ DATE: new Set(['=', '<', '>']),
162
+ DATETIME: new Set(['=', '<', '>']),
163
+ TIME: new Set(['=', '<', '>']),
164
+ };
@@ -0,0 +1,108 @@
1
+ /*
2
+ * The contents of this file were inserted manually and are not generated by Stainless.
3
+ *
4
+ * Unity App definitions that group pages for navigation.
5
+ * Backend schema: CUSTOM_APP (v2)
6
+ *
7
+ * Pages are declared at construction as a flat array of live refs — pass a
8
+ * `CustomObject` for an object-page tab, or an `SduiPage` for a custom SDUI
9
+ * surface. The tab `api_name` is derived from the ref's own identifier.
10
+ * External refs (e.g. native-model `employee`, or an externally-authored
11
+ * SDUI page) are not supported yet; add when a real case appears.
12
+ */
13
+
14
+ import { CustomObject } from './custom-object';
15
+ import type { ManifestScope } from './manifest-builder';
16
+ import { SduiPage } from './sdui-page';
17
+
18
+ /**
19
+ * A single page entry in an App:
20
+ * - `CustomObject` → object page, tab `api_name = co.getApiName()`
21
+ * - `SduiPage` → SDUI page, tab `api_name = page.getSduiPageId()`
22
+ */
23
+ export type AppPage = CustomObject | SduiPage;
24
+
25
+ export interface AppIcon {
26
+ s3Bucket: string;
27
+ s3Key: string;
28
+ }
29
+
30
+ export interface AppProps {
31
+ /** Required. App api_name. */
32
+ apiName: string;
33
+ /** Required. Display name. */
34
+ name: string;
35
+ /** Optional. App description. @default null */
36
+ description?: string;
37
+ /** Optional. App type. @default 'custom' */
38
+ appType?: string;
39
+ /** Optional. S3 icon reference. @default null */
40
+ icon?: AppIcon;
41
+ /** Optional. Pages shown as tabs in the App; order is preserved. @default [] */
42
+ pages?: AppPage[];
43
+ }
44
+
45
+ function resolvePage(entry: AppPage): Record<string, any> {
46
+ if (entry instanceof CustomObject) {
47
+ const apiName = entry.getApiName();
48
+ return {
49
+ api_name: apiName,
50
+ page_type: 'object_page',
51
+ object_rql_name: apiName,
52
+ };
53
+ } else {
54
+ const sduiPageId = entry.getSduiPageId();
55
+ return {
56
+ api_name: sduiPageId,
57
+ page_type: 'sdui_page',
58
+ sdui_page_id: sduiPageId,
59
+ };
60
+ }
61
+ }
62
+
63
+ export class App {
64
+ private readonly _apiName: string;
65
+ private readonly _name: string;
66
+ private readonly _description: string | undefined;
67
+ private readonly _appType: string | undefined;
68
+ private readonly _icon: AppIcon | undefined;
69
+ /** Wire-format pages, resolved eagerly at construction. */
70
+ private readonly _pages: Record<string, any>[];
71
+
72
+ /** Build a new app and auto-register with `scope`; resolves page refs eagerly. */
73
+ constructor(scope: ManifestScope, props: AppProps) {
74
+ this._apiName = props.apiName;
75
+ this._name = props.name;
76
+ this._description = props.description;
77
+ this._appType = props.appType;
78
+ this._icon = props.icon;
79
+ this._pages = (props.pages ?? []).map(resolvePage);
80
+ scope._register(this);
81
+ }
82
+
83
+ /** Backend api_name for this app. */
84
+ getApiName(): string {
85
+ return this._apiName;
86
+ }
87
+
88
+ /** Display name shown in the UI. */
89
+ getName(): string {
90
+ return this._name;
91
+ }
92
+
93
+ /** Serialize to the backend `CUSTOM_APP` wire shape; omits unset optional fields. */
94
+ toDict(): Record<string, any> {
95
+ const component: Record<string, any> = {
96
+ type: 'CUSTOM_APP',
97
+ api_name: this._apiName,
98
+ name: this._name,
99
+ };
100
+ if (this._description != null) component['description'] = this._description;
101
+ if (this._icon != null) {
102
+ component['icon'] = { s3_bucket: this._icon.s3Bucket, s3_key: this._icon.s3Key };
103
+ }
104
+ if (this._appType != null) component['app_type'] = this._appType;
105
+ if (this._pages.length > 0) component['pages'] = this._pages.map((p) => ({ ...p }));
106
+ return component;
107
+ }
108
+ }
@@ -0,0 +1,51 @@
1
+ /*
2
+ * The contents of this file were inserted manually and are not generated by Stainless.
3
+ *
4
+ * Rippling category definitions for grouping objects in navigation.
5
+ * Backend schema: CUSTOM_CATEGORY (v2)
6
+ */
7
+
8
+ import type { ManifestScope } from './manifest-builder';
9
+
10
+ export interface CategoryProps {
11
+ /** Required. Unique API name (e.g. `'finance__c'`). */
12
+ apiName: string;
13
+ /** Required. Display name shown in the UI. */
14
+ name: string;
15
+ /** Optional. Description. Pass `null` explicitly for "no description". @default null */
16
+ description?: string | null;
17
+ }
18
+
19
+ export class Category {
20
+ private readonly _apiName: string;
21
+ private readonly _name: string;
22
+ private readonly _description: string | null;
23
+
24
+ /** Build a new category and auto-register with `scope` (usually a `ManifestBuilder`). */
25
+ constructor(scope: ManifestScope, props: CategoryProps) {
26
+ this._apiName = props.apiName;
27
+ this._name = props.name;
28
+ this._description = props.description ?? null;
29
+ scope._register(this);
30
+ }
31
+
32
+ /** Backend api_name used as this category's identifier. */
33
+ getApiName(): string {
34
+ return this._apiName;
35
+ }
36
+
37
+ /** Display name shown in the UI. */
38
+ getName(): string {
39
+ return this._name;
40
+ }
41
+
42
+ /** Serialize to the backend `CUSTOM_CATEGORY` wire shape. */
43
+ toDict(): Record<string, any> {
44
+ return {
45
+ type: 'CUSTOM_CATEGORY',
46
+ api_name: this._apiName,
47
+ name: this._name,
48
+ description: this._description ?? null,
49
+ };
50
+ }
51
+ }
@@ -0,0 +1,54 @@
1
+ /*
2
+ * The contents of this file were inserted manually and are not generated by Stainless.
3
+ *
4
+ * Custom object field sections (UI grouping of fields on detail pages).
5
+ * Backend schema: CUSTOM_OBJECT_FIELD_SECTION (v2)
6
+ *
7
+ * Construction is CDK-style: `new CustomObjectFieldSection(customObject, props)`
8
+ * — the CO is the first positional arg, and the section auto-registers with
9
+ * the manifest via the CO's scope chain.
10
+ */
11
+
12
+ import { generateId } from './_helpers';
13
+ import type { CustomObject } from './custom-object';
14
+
15
+ export interface CustomObjectFieldSectionProps {
16
+ /** Required. Display name of the section. */
17
+ name: string;
18
+ /** Identity override. Override the section identifier. @default generateId('sec') */
19
+ sectionId?: string;
20
+ }
21
+
22
+ export class CustomObjectFieldSection {
23
+ private readonly _sectionId: string;
24
+ private readonly _name: string;
25
+ private readonly _model: CustomObject;
26
+
27
+ /** Build a new section and auto-register with the CO's scope. */
28
+ constructor(customObject: CustomObject, props: CustomObjectFieldSectionProps) {
29
+ this._sectionId = props.sectionId ?? generateId('sec');
30
+ this._name = props.name;
31
+ this._model = customObject;
32
+ customObject._register(this);
33
+ }
34
+
35
+ /** Backend section_id used as this section's identifier. */
36
+ getSectionId(): string {
37
+ return this._sectionId;
38
+ }
39
+
40
+ /** api_name of the parent custom object this section lives on. */
41
+ getModelApiName(): string {
42
+ return this._model.getApiName();
43
+ }
44
+
45
+ /** Serialize to the backend `CUSTOM_OBJECT_FIELD_SECTION` wire shape. */
46
+ toDict(): Record<string, any> {
47
+ return {
48
+ type: 'CUSTOM_OBJECT_FIELD_SECTION',
49
+ section_id: this._sectionId,
50
+ model_name: this._model.getApiName(),
51
+ name: this._name,
52
+ };
53
+ }
54
+ }
@@ -0,0 +1,292 @@
1
+ /*
2
+ * The contents of this file were inserted manually and are not generated by Stainless.
3
+ *
4
+ * Custom object page layouts (detail page structure).
5
+ * Backend schema: CUSTOM_OBJECT_PAGE_LAYOUT (v2)
6
+ *
7
+ * CDK-style: `new CustomObjectPageLayout(customObject, props)` auto-registers
8
+ * with the CO's scope. `blueprint_key` defaults to the CO's api_name.
9
+ * For the layout that drives **Add** and the default detail view, use
10
+ * `apiName: 'default'` (one per custom object). `CustomObjectPageLayout.basic`
11
+ * uses `default` automatically.
12
+ *
13
+ * TabEditsDTO / HeaderEditsDTO / VisibilityConditionsDTO are strict
14
+ * dataclasses on the backend. They expect camelCase keys on the wire
15
+ * (newTabs, systemTabEdits, fieldRqlName, newTitleField, ...). Snake_case
16
+ * keys are silently dropped and produce an empty layout on deploy. The
17
+ * interfaces below mirror the DTO field aliases exactly.
18
+ *
19
+ * TS catches misspellings on direct object literals but not on spreads,
20
+ * `as` casts, or loosely-typed variables — so be careful when constructing
21
+ * these objects dynamically.
22
+ *
23
+ * DTO references: types/edits.py, types/layout.py, types/sections.py.
24
+ */
25
+
26
+ import { generateId } from './_helpers';
27
+ import type { CustomObject } from './custom-object';
28
+ import type { Field } from './field';
29
+
30
+ // ---------------------------------------------------------------------------
31
+ // header_edits — HeaderEditsDTO
32
+ // ---------------------------------------------------------------------------
33
+
34
+ /** Edit to a built-in (system) header field. */
35
+ export interface SystemHeaderFieldEdit {
36
+ newRqlField?: string;
37
+ deleted?: boolean;
38
+ }
39
+
40
+ /** Custom header field added via newFields. `key` is required + non-empty. */
41
+ export interface NewHeaderField {
42
+ rqlName: string;
43
+ key: string;
44
+ canBeDeleted?: boolean;
45
+ canBeChanged?: boolean;
46
+ canBeMoved?: boolean;
47
+ }
48
+
49
+ /**
50
+ * Strict shape for header_edits. Only the keys listed here are accepted by
51
+ * HeaderEditsDTO — anything else is dropped on the wire. Pass `{}` for an
52
+ * empty header.
53
+ */
54
+ export interface HeaderEdits {
55
+ newTitleField?: string | null;
56
+ titleFieldDeleted?: boolean;
57
+ newDescriptionField?: string | null;
58
+ descriptionFieldDeleted?: boolean;
59
+ /** Map of system field key → edit. */
60
+ systemFieldEdits?: Record<string, SystemHeaderFieldEdit>;
61
+ newFields?: NewHeaderField[];
62
+ /** Sort order of header field `key` values (custom + system). */
63
+ headerFieldsOrder?: string[];
64
+ buttons?: string[];
65
+ }
66
+
67
+ // ---------------------------------------------------------------------------
68
+ // tab_edits — TabEditsDTO + section/tab DTOs
69
+ // ---------------------------------------------------------------------------
70
+
71
+ /** SectionFieldDTO — one field inside a fields_section. */
72
+ export interface SectionField {
73
+ fieldRqlName: string;
74
+ hidden?: boolean;
75
+ editable?: boolean;
76
+ movementOption?: 'tab' | 'free';
77
+ }
78
+
79
+ /** FieldsSectionDTO — standard field grid section. */
80
+ export interface FieldsSection {
81
+ type: 'fields_section';
82
+ key: string;
83
+ name: string;
84
+ fields: SectionField[];
85
+ }
86
+
87
+ /** Only `fields_section` is modeled today (most common). Add other section
88
+ * types (related_object_section, custom_section, …) explicitly as needed. */
89
+ export type PageLayoutSection = FieldsSection;
90
+
91
+ /** PageLayoutTabWithSectionsDTO. */
92
+ export interface TabWithSections {
93
+ type: 'tab_with_sections';
94
+ key: string;
95
+ name: string;
96
+ sections: PageLayoutSection[];
97
+ }
98
+
99
+ /** CustomTabDTO — host a custom component as a tab. */
100
+ export interface CustomTab {
101
+ type: 'custom_tab';
102
+ key: string;
103
+ name: string;
104
+ componentKey: string;
105
+ }
106
+
107
+ export type PageLayoutTab = TabWithSections | CustomTab;
108
+
109
+ /** Layout of fields inside a fields_section. */
110
+ export type SectionFieldsLayout = 'one_column' | 'two_column' | 'three_column' | 'responsive';
111
+
112
+ /** SystemSectionEditDTO — edits to a built-in section inside a system tab. */
113
+ export interface SystemSectionEdit {
114
+ newName?: string;
115
+ deleted?: boolean;
116
+ newLayout?: SectionFieldsLayout;
117
+ newFields?: SectionField[];
118
+ newHideName?: boolean;
119
+ }
120
+
121
+ /** SystemTabEditDTO — edits to a built-in tab (rename, delete, add sections, …). */
122
+ export interface SystemTabEdit {
123
+ newName?: string;
124
+ deleted?: boolean;
125
+ newSections?: PageLayoutSection[];
126
+ systemSectionEdits?: Record<string, SystemSectionEdit>;
127
+ sectionsOrder?: string[];
128
+ }
129
+
130
+ /**
131
+ * Strict shape for tab_edits. Only TabEditsDTO keys allowed.
132
+ *
133
+ * All fields are optional to match `TabEditsDTO`'s `default_factory` (empty
134
+ * list / empty dict). An omitted `tabEdits` defaults to `{}` in the
135
+ * constructor; partial objects rely on backend per-field defaults.
136
+ *
137
+ * - newTabs: tabs to create (each needs a `type` discriminator)
138
+ * - systemTabEdits: edits keyed by built-in tab key
139
+ * - tabsOrder: ordered list of tab `key` values (new + system)
140
+ * - newTabLayout: optional orientation
141
+ */
142
+ export interface TabEdits {
143
+ newTabs?: PageLayoutTab[];
144
+ systemTabEdits?: Record<string, SystemTabEdit>;
145
+ tabsOrder?: string[];
146
+ newTabLayout?: 'vertical' | 'horizontal';
147
+ }
148
+
149
+ // ---------------------------------------------------------------------------
150
+ // visibility_conditions — VisibilityConditionsDTO
151
+ // ---------------------------------------------------------------------------
152
+
153
+ /**
154
+ * VisibilityConditionDTO. Both fields are required on the Python type — pass
155
+ * empty string / empty object if you genuinely have no formula or AST.
156
+ */
157
+ export interface VisibilityCondition {
158
+ rqlFormula: string;
159
+ layeredConditionsTree: Record<string, any>;
160
+ }
161
+
162
+ /** Pass `{}` for "no conditions" — both maps default empty. */
163
+ export interface VisibilityConditions {
164
+ sections?: Record<string, VisibilityCondition>;
165
+ tabs?: Record<string, VisibilityCondition>;
166
+ }
167
+
168
+ // ---------------------------------------------------------------------------
169
+ // Public props
170
+ // ---------------------------------------------------------------------------
171
+
172
+ export interface CustomObjectPageLayoutProps {
173
+ /**
174
+ * Required. Stable `api_name` for the layout. Use `'default'` for the layout
175
+ * that drives **Add** and the default object detail view (per Custom Object
176
+ * — one `default` per object).
177
+ */
178
+ apiName: string;
179
+ /** Required. Display name of the layout. */
180
+ name: string;
181
+ /** Optional. Tab structure (TabEditsDTO). Defaults to empty. */
182
+ tabEdits?: TabEdits;
183
+ /** Optional. Header configuration (HeaderEditsDTO). Defaults to empty. */
184
+ headerEdits?: HeaderEdits;
185
+ /** Optional. Visibility conditions. Defaults to empty (no conditions). */
186
+ visibilityConditions?: VisibilityConditions;
187
+ /** Identity override. Override the layout identifier. @default generateId('layout') */
188
+ layoutId?: string;
189
+ /** Optional. Overwritten at install; defaults to object api_name. */
190
+ blueprintKey?: string;
191
+ }
192
+
193
+ // ---------------------------------------------------------------------------
194
+ // Class
195
+ // ---------------------------------------------------------------------------
196
+
197
+ export class CustomObjectPageLayout {
198
+ private readonly _layoutId: string;
199
+ private readonly _apiName: string;
200
+ private readonly _customObjectApiName: string;
201
+ private readonly _name: string;
202
+ private readonly _tabEdits: TabEdits;
203
+ private readonly _headerEdits: HeaderEdits;
204
+ private readonly _visibilityConditions: VisibilityConditions;
205
+ private readonly _blueprintKey: string | undefined;
206
+
207
+ /** Build a new layout and auto-register with the CO's scope. */
208
+ constructor(customObject: CustomObject, props: CustomObjectPageLayoutProps) {
209
+ if (!props.apiName) throw new Error('CustomObjectPageLayout: apiName cannot be empty');
210
+ if (!props.name) throw new Error('CustomObjectPageLayout: name cannot be empty');
211
+ this._layoutId = props.layoutId ?? generateId('layout');
212
+ this._apiName = props.apiName;
213
+ this._customObjectApiName = customObject.getApiName();
214
+ this._name = props.name;
215
+ this._tabEdits = props.tabEdits ?? {};
216
+ this._headerEdits = props.headerEdits ?? {};
217
+ this._visibilityConditions = props.visibilityConditions ?? {};
218
+ this._blueprintKey = props.blueprintKey;
219
+ customObject._register(this);
220
+ }
221
+
222
+ /** Backend layout_id used as this layout's identifier. */
223
+ getLayoutId(): string {
224
+ return this._layoutId;
225
+ }
226
+
227
+ /** Stable api_name for this layout. */
228
+ getApiName(): string {
229
+ return this._apiName;
230
+ }
231
+
232
+ /** api_name of the CustomObject this layout lives on. */
233
+ getCustomObjectApiName(): string {
234
+ return this._customObjectApiName;
235
+ }
236
+
237
+ /** Serialize to the backend `CUSTOM_OBJECT_PAGE_LAYOUT` wire shape. */
238
+ toDict(): Record<string, any> {
239
+ const d: Record<string, any> = {
240
+ type: 'CUSTOM_OBJECT_PAGE_LAYOUT',
241
+ layout_id: this._layoutId,
242
+ api_name: this._apiName,
243
+ object_rql_name: this._customObjectApiName,
244
+ name: this._name,
245
+ // Packaged layouts are never system-created (backend invariant).
246
+ system_created: false,
247
+ tab_edits: this._tabEdits,
248
+ header_edits: this._headerEdits,
249
+ visibility_conditions: this._visibilityConditions,
250
+ blueprint_key: this._blueprintKey ?? this._customObjectApiName,
251
+ };
252
+ return d;
253
+ }
254
+
255
+ /** Factory for a single-tab "Details" page listing the given fields. */
256
+ static basic(
257
+ customObject: CustomObject,
258
+ props: {
259
+ fields?: Field[];
260
+ } = {},
261
+ ): CustomObjectPageLayout {
262
+ const coApiName = customObject.getApiName();
263
+ const coName = customObject.getName();
264
+ return new CustomObjectPageLayout(customObject, {
265
+ apiName: 'default',
266
+ name: `${coName} Layout`,
267
+ tabEdits: {
268
+ newTabs: [
269
+ {
270
+ key: 'details',
271
+ name: 'Details',
272
+ type: 'tab_with_sections',
273
+ sections: [
274
+ {
275
+ key: 'general',
276
+ name: 'General',
277
+ type: 'fields_section',
278
+ fields: (props.fields ?? []).map((f: Field) => ({
279
+ fieldRqlName: f.getApiName(),
280
+ })),
281
+ },
282
+ ],
283
+ },
284
+ ],
285
+ systemTabEdits: {},
286
+ tabsOrder: ['details'],
287
+ },
288
+ headerEdits: {},
289
+ visibilityConditions: {},
290
+ });
291
+ }
292
+ }