@stndrds/schema 1.0.0-alpha.192 → 1.0.0-alpha.194

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 (125) hide show
  1. package/dist/attributes-DP08iPCh.d.mts +889 -0
  2. package/dist/attributes-Ddhps_AU.d.ts +889 -0
  3. package/dist/{chunk-MAKSIK3P.js → chunk-5WATIVCA.js} +2 -2
  4. package/dist/{chunk-4KRLCWJM.mjs → chunk-6I2R22CX.mjs} +1 -1
  5. package/dist/{chunk-DC7YYE3U.js → chunk-ACKMC6FL.js} +2 -2
  6. package/dist/{chunk-TEQNVO7W.mjs → chunk-AYVHMVKQ.mjs} +1 -1
  7. package/dist/{chunk-P2BE2A2G.js → chunk-BV3IUMMW.js} +4 -7
  8. package/dist/{chunk-CCB4OY2O.js → chunk-E6JUYGJX.js} +2 -2
  9. package/dist/{chunk-7A3Y6O32.js → chunk-EBGRZUIH.js} +2 -2
  10. package/dist/{chunk-QWZHR2OO.js → chunk-EW5XR2X3.js} +2 -2
  11. package/dist/{chunk-UQVW4KPP.mjs → chunk-HRQEZUAA.mjs} +0 -1
  12. package/dist/{chunk-OAQWRMTP.js → chunk-HTSTPTNZ.js} +2 -2
  13. package/dist/{chunk-U4JC7P6D.mjs → chunk-HXDDJLHD.mjs} +37 -52
  14. package/dist/{chunk-Z75P63VF.mjs → chunk-JUKLL5RJ.mjs} +1 -1
  15. package/dist/{chunk-YQROI4IE.js → chunk-M5QIBMIH.js} +37 -52
  16. package/dist/{chunk-FQ2ZYOVS.js → chunk-MZOEL7FN.js} +47 -41
  17. package/dist/{chunk-KWVCGQ7N.mjs → chunk-NOMHDOVE.mjs} +2 -5
  18. package/dist/{chunk-OLJLCVNY.mjs → chunk-NS63SPNN.mjs} +1 -1
  19. package/dist/{chunk-J5HRK3WD.js → chunk-O44XVGHE.js} +2 -2
  20. package/dist/{chunk-TMYBEXBT.mjs → chunk-OSSGN43B.mjs} +1 -1
  21. package/dist/{chunk-LTHSU4NF.mjs → chunk-PMKCDRRO.mjs} +26 -21
  22. package/dist/{chunk-4TC27SMF.mjs → chunk-QEZUDVTN.mjs} +1 -1
  23. package/dist/{chunk-BLXQGQLK.mjs → chunk-QVLQPW3O.mjs} +1 -1
  24. package/dist/{chunk-EZHMVZQ4.js → chunk-QWKLQRBX.js} +4 -4
  25. package/dist/{chunk-ROAZLZA2.js → chunk-ROLWVTU3.js} +2 -2
  26. package/dist/{chunk-3JINFUN3.js → chunk-SGSGREPG.js} +2 -6
  27. package/dist/{chunk-VXOTYFEW.js → chunk-T6L2MUG2.js} +2 -2
  28. package/dist/{chunk-KNYZH2WD.mjs → chunk-UANQJ2GH.mjs} +8 -1
  29. package/dist/{chunk-IRTRJH37.mjs → chunk-UXAHLSWC.mjs} +1 -1
  30. package/dist/{chunk-ACQ3TUFK.js → chunk-V2UA2D4E.js} +2 -2
  31. package/dist/{chunk-R4CJHCC4.mjs → chunk-XZ5RG2OG.mjs} +1 -4
  32. package/dist/{chunk-TKN73433.js → chunk-YIP5FJ5H.js} +9 -2
  33. package/dist/{chunk-T225DB55.js → chunk-YKWSHBT5.js} +0 -1
  34. package/dist/{chunk-TBYXYSGA.mjs → chunk-YUFTHPOE.mjs} +1 -1
  35. package/dist/{chunk-ITTQ4FGR.mjs → chunk-ZDMOXF3U.mjs} +1 -1
  36. package/dist/{chunk-SMOHDR6M.mjs → chunk-ZDQ5AP26.mjs} +1 -1
  37. package/dist/{helpers-Y9rNQ6sz.d.ts → helpers-Bph8AoY7.d.mts} +15 -3
  38. package/dist/{helpers-HrKmSkLi.d.mts → helpers-D9klos6x.d.ts} +15 -3
  39. package/dist/index.d.mts +1121 -235
  40. package/dist/index.d.ts +1121 -235
  41. package/dist/index.js +2369 -854
  42. package/dist/index.mjs +2264 -774
  43. package/dist/{types-Bdlhgrf7.d.ts → types-D38kriFw.d.mts} +1 -2
  44. package/dist/{types-C5DittlR.d.mts → types-iKvYBe6v.d.ts} +1 -2
  45. package/dist/validation/all.d.mts +3 -3
  46. package/dist/validation/all.d.ts +3 -3
  47. package/dist/validation/all.js +30 -27
  48. package/dist/validation/all.mjs +17 -18
  49. package/dist/validation/complex/currency.d.mts +2 -2
  50. package/dist/validation/complex/currency.d.ts +2 -2
  51. package/dist/validation/complex/currency.js +3 -3
  52. package/dist/validation/complex/currency.mjs +2 -2
  53. package/dist/validation/complex/file.d.mts +2 -2
  54. package/dist/validation/complex/file.d.ts +2 -2
  55. package/dist/validation/complex/file.js +3 -3
  56. package/dist/validation/complex/file.mjs +2 -2
  57. package/dist/validation/complex/location.d.mts +2 -2
  58. package/dist/validation/complex/location.d.ts +2 -2
  59. package/dist/validation/complex/location.js +3 -3
  60. package/dist/validation/complex/location.mjs +2 -2
  61. package/dist/validation/complex/phone.d.mts +2 -2
  62. package/dist/validation/complex/phone.d.ts +2 -2
  63. package/dist/validation/complex/phone.js +3 -3
  64. package/dist/validation/complex/phone.mjs +2 -2
  65. package/dist/validation/complex/relation.d.mts +2 -2
  66. package/dist/validation/complex/relation.d.ts +2 -2
  67. package/dist/validation/complex/relation.js +5 -5
  68. package/dist/validation/complex/relation.mjs +2 -2
  69. package/dist/validation/complex/richtext.d.mts +2 -2
  70. package/dist/validation/complex/richtext.d.ts +2 -2
  71. package/dist/validation/complex/richtext.js +3 -3
  72. package/dist/validation/complex/richtext.mjs +2 -2
  73. package/dist/validation/complex/select.d.mts +2 -2
  74. package/dist/validation/complex/select.d.ts +2 -2
  75. package/dist/validation/complex/select.js +5 -5
  76. package/dist/validation/complex/select.mjs +2 -2
  77. package/dist/validation/complex/user.d.mts +2 -2
  78. package/dist/validation/complex/user.d.ts +2 -2
  79. package/dist/validation/complex/user.js +3 -3
  80. package/dist/validation/complex/user.mjs +2 -2
  81. package/dist/validation/computed/formula.d.mts +2 -2
  82. package/dist/validation/computed/formula.d.ts +2 -2
  83. package/dist/validation/computed/formula.js +3 -3
  84. package/dist/validation/computed/formula.mjs +2 -2
  85. package/dist/validation/computed/rollup.d.mts +2 -2
  86. package/dist/validation/computed/rollup.d.ts +2 -2
  87. package/dist/validation/computed/rollup.js +3 -3
  88. package/dist/validation/computed/rollup.mjs +2 -2
  89. package/dist/validation/config/index.d.mts +1 -1
  90. package/dist/validation/config/index.d.ts +1 -1
  91. package/dist/validation/config/index.js +4 -4
  92. package/dist/validation/config/index.mjs +1 -1
  93. package/dist/validation/core/index.d.mts +3 -3
  94. package/dist/validation/core/index.d.ts +3 -3
  95. package/dist/validation/core/index.js +3 -3
  96. package/dist/validation/core/index.mjs +1 -1
  97. package/dist/validation/object/index.d.mts +3 -3
  98. package/dist/validation/object/index.d.ts +3 -3
  99. package/dist/validation/object/index.js +32 -29
  100. package/dist/validation/object/index.mjs +16 -17
  101. package/dist/validation/primitives/checkbox.d.mts +2 -2
  102. package/dist/validation/primitives/checkbox.d.ts +2 -2
  103. package/dist/validation/primitives/checkbox.js +3 -3
  104. package/dist/validation/primitives/checkbox.mjs +2 -2
  105. package/dist/validation/primitives/date.d.mts +2 -2
  106. package/dist/validation/primitives/date.d.ts +2 -2
  107. package/dist/validation/primitives/date.js +3 -3
  108. package/dist/validation/primitives/date.mjs +2 -2
  109. package/dist/validation/primitives/number.d.mts +2 -2
  110. package/dist/validation/primitives/number.d.ts +2 -2
  111. package/dist/validation/primitives/number.js +3 -3
  112. package/dist/validation/primitives/number.mjs +2 -2
  113. package/dist/validation/primitives/text.d.mts +3 -8
  114. package/dist/validation/primitives/text.d.ts +3 -8
  115. package/dist/validation/primitives/text.js +3 -7
  116. package/dist/validation/primitives/text.mjs +2 -2
  117. package/package.json +2 -13
  118. package/dist/chunk-D7WFIGXW.js +0 -14
  119. package/dist/chunk-RUYUFXNW.mjs +0 -12
  120. package/dist/filters-DVBn5tov.d.ts +0 -1630
  121. package/dist/filters-HDG4kLoo.d.mts +0 -1630
  122. package/dist/validation/primitives/rating.d.mts +0 -12
  123. package/dist/validation/primitives/rating.d.ts +0 -12
  124. package/dist/validation/primitives/rating.js +0 -11
  125. package/dist/validation/primitives/rating.mjs +0 -2
package/dist/index.js CHANGED
@@ -2,27 +2,25 @@
2
2
 
3
3
  var chunkFRCDMQER_js = require('./chunk-FRCDMQER.js');
4
4
  require('./chunk-PGERPYDR.js');
5
- var chunkYQROI4IE_js = require('./chunk-YQROI4IE.js');
6
- var chunkFQ2ZYOVS_js = require('./chunk-FQ2ZYOVS.js');
7
- require('./chunk-MAKSIK3P.js');
8
- require('./chunk-J5HRK3WD.js');
9
- require('./chunk-TKN73433.js');
10
- require('./chunk-D7WFIGXW.js');
11
- require('./chunk-3JINFUN3.js');
12
- require('./chunk-QWZHR2OO.js');
13
- require('./chunk-EZHMVZQ4.js');
14
- require('./chunk-VXOTYFEW.js');
15
- require('./chunk-OAQWRMTP.js');
16
- require('./chunk-ACQ3TUFK.js');
17
- require('./chunk-DC7YYE3U.js');
18
- require('./chunk-ROAZLZA2.js');
19
- require('./chunk-CCB4OY2O.js');
20
- var chunk7A3Y6O32_js = require('./chunk-7A3Y6O32.js');
21
- require('./chunk-P2BE2A2G.js');
22
- var chunkT225DB55_js = require('./chunk-T225DB55.js');
5
+ var chunkM5QIBMIH_js = require('./chunk-M5QIBMIH.js');
6
+ var chunkMZOEL7FN_js = require('./chunk-MZOEL7FN.js');
7
+ require('./chunk-5WATIVCA.js');
8
+ require('./chunk-O44XVGHE.js');
9
+ require('./chunk-YIP5FJ5H.js');
10
+ require('./chunk-SGSGREPG.js');
11
+ require('./chunk-EW5XR2X3.js');
12
+ require('./chunk-QWKLQRBX.js');
13
+ require('./chunk-T6L2MUG2.js');
14
+ require('./chunk-HTSTPTNZ.js');
15
+ require('./chunk-V2UA2D4E.js');
16
+ require('./chunk-ACKMC6FL.js');
17
+ require('./chunk-ROLWVTU3.js');
18
+ require('./chunk-E6JUYGJX.js');
19
+ var chunkEBGRZUIH_js = require('./chunk-EBGRZUIH.js');
20
+ require('./chunk-BV3IUMMW.js');
21
+ var chunkYKWSHBT5_js = require('./chunk-YKWSHBT5.js');
23
22
  var constants = require('@stndrds/constants');
24
23
  var z3 = require('zod');
25
- var exprEval = require('expr-eval');
26
24
 
27
25
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
28
26
 
@@ -32,7 +30,6 @@ var z3__default = /*#__PURE__*/_interopDefault(z3);
32
30
  var IDENTITY_PROPERTIES = ["name", "type"];
33
31
  var BEHAVIOR_PROPERTIES = [
34
32
  "required",
35
- "disabled",
36
33
  "hidden",
37
34
  "archived",
38
35
  "deprecated",
@@ -43,6 +40,318 @@ var BEHAVIOR_PROPERTIES = [
43
40
  ];
44
41
  var PRESENTATION_PROPERTIES = ["label", "description", "placeholder", "icon"];
45
42
 
43
+ // src/types/attribute-capabilities.ts
44
+ var TEXT_OPERATORS = [
45
+ "is",
46
+ "is_not",
47
+ "contains",
48
+ "not_contains",
49
+ "starts_with",
50
+ "ends_with",
51
+ "is_empty",
52
+ "is_not_empty"
53
+ ];
54
+ var NUMBER_OPERATORS = [
55
+ "eq",
56
+ "neq",
57
+ "lt",
58
+ "gt",
59
+ "lte",
60
+ "gte",
61
+ "is_empty",
62
+ "is_not_empty"
63
+ ];
64
+ var CHECKBOX_OPERATORS = [
65
+ "is_checked",
66
+ "is_not_checked"
67
+ ];
68
+ var DATE_OPERATORS = [
69
+ "is",
70
+ "is_not",
71
+ "before",
72
+ "after",
73
+ "on_or_before",
74
+ "on_or_after",
75
+ "is_within",
76
+ "day_month_eq",
77
+ "is_empty",
78
+ "is_not_empty"
79
+ ];
80
+ var SELECT_OPERATORS = [
81
+ "is",
82
+ "is_not",
83
+ "any_of",
84
+ "none_of",
85
+ "is_empty",
86
+ "is_not_empty"
87
+ ];
88
+ var MULTISELECT_OPERATORS = [
89
+ "contains",
90
+ "not_contains",
91
+ "is_empty",
92
+ "is_not_empty"
93
+ ];
94
+ var REFERENCE_OPERATORS = [
95
+ "is",
96
+ "is_not",
97
+ "any_of",
98
+ "none_of",
99
+ "contains",
100
+ "not_contains",
101
+ "is_empty",
102
+ "is_not_empty"
103
+ ];
104
+ var PRESENCE_OPERATORS = [
105
+ "is_empty",
106
+ "is_not_empty"
107
+ ];
108
+ var FORMULA_OPERATORS = [
109
+ "is",
110
+ "is_not",
111
+ "eq",
112
+ "neq",
113
+ "lt",
114
+ "gt",
115
+ "lte",
116
+ "gte",
117
+ "contains",
118
+ "not_contains",
119
+ "is_empty",
120
+ "is_not_empty"
121
+ ];
122
+ var ATTRIBUTE_FILTER_OPERATORS = {
123
+ text: TEXT_OPERATORS,
124
+ richtext: [],
125
+ number: NUMBER_OPERATORS,
126
+ checkbox: CHECKBOX_OPERATORS,
127
+ date: DATE_OPERATORS,
128
+ phone: ["is", "is_not", "contains", "not_contains", "is_empty", "is_not_empty"],
129
+ currency: NUMBER_OPERATORS,
130
+ status: SELECT_OPERATORS,
131
+ select: SELECT_OPERATORS,
132
+ multiselect: MULTISELECT_OPERATORS,
133
+ location: [],
134
+ file: PRESENCE_OPERATORS,
135
+ user: REFERENCE_OPERATORS,
136
+ relation: REFERENCE_OPERATORS,
137
+ formula: FORMULA_OPERATORS,
138
+ document: PRESENCE_OPERATORS
139
+ };
140
+ var COMPUTED_TYPES = /* @__PURE__ */ new Set(["formula", "rollup"]);
141
+ var EDGE_BACKED_TYPES = /* @__PURE__ */ new Set(["file", "user", "relation", "document"]);
142
+ var DIRECT_EDIT_TYPES = /* @__PURE__ */ new Set(["checkbox"]);
143
+ var STATIC_DEFAULT_TYPES = /* @__PURE__ */ new Set([
144
+ "text",
145
+ "richtext",
146
+ "number",
147
+ "select",
148
+ "multiselect",
149
+ "status",
150
+ "date",
151
+ "phone",
152
+ "currency",
153
+ "location",
154
+ "user",
155
+ "file",
156
+ "relation",
157
+ "document"
158
+ ]);
159
+ var PLACEHOLDER_TYPES = /* @__PURE__ */ new Set([
160
+ "text",
161
+ "number",
162
+ "date",
163
+ "phone",
164
+ "currency",
165
+ "select",
166
+ "multiselect"
167
+ ]);
168
+ var SEARCHABLE_TYPES = /* @__PURE__ */ new Set([
169
+ "text",
170
+ "phone",
171
+ "status",
172
+ "select",
173
+ "multiselect"
174
+ ]);
175
+ var SORTABLE_TYPES = /* @__PURE__ */ new Set([
176
+ "text",
177
+ "number",
178
+ "checkbox",
179
+ "date",
180
+ "phone",
181
+ "currency",
182
+ "status",
183
+ "select"
184
+ ]);
185
+ function getAttributeCapabilities(attribute) {
186
+ const suppressed = Boolean(attribute.hidden || attribute.archived);
187
+ const active = !attribute.archived;
188
+ const computed = COMPUTED_TYPES.has(attribute.type);
189
+ const document2 = attribute.type === "document";
190
+ const edgeBacked = EDGE_BACKED_TYPES.has(attribute.type);
191
+ const cardinality = getAttributeCardinality(attribute);
192
+ const operators = suppressed ? [] : getRawFilterOperators(attribute);
193
+ const filterable = operators.length > 0 && !suppressed;
194
+ const searchable = !suppressed && SEARCHABLE_TYPES.has(attribute.type);
195
+ const sortable = !suppressed && SORTABLE_TYPES.has(attribute.type);
196
+ const groupable = !suppressed && isGroupableType(attribute.type);
197
+ const kanbanGroupable = !suppressed && attribute.type === "status";
198
+ const readOnly = computed || document2;
199
+ const editable = !(suppressed || readOnly);
200
+ const required = isRequiredForbidden(attribute.type) ? "forbidden" : "allowed";
201
+ const defaultValue = getDefaultValueCapability(attribute.type);
202
+ const maxItems = supportsMaxItems(attribute);
203
+ const placeholder = PLACEHOLDER_TYPES.has(attribute.type);
204
+ const warningWhenDeprecated = Boolean(attribute.deprecated && !suppressed);
205
+ return {
206
+ lifecycle: {
207
+ active,
208
+ deprecated: Boolean(attribute.deprecated),
209
+ visibleInArchitect: true,
210
+ visibleInRuntime: !suppressed,
211
+ warningWhenDeprecated
212
+ },
213
+ storage: {
214
+ mode: computed ? "computed" : edgeBacked ? "edge" : "value",
215
+ cardinality,
216
+ edgeBacked,
217
+ preservesExistingValues: Boolean(attribute.archived),
218
+ qualifiedProperties: supportsQualifiedProperties(attribute.type),
219
+ polymorphic: getPolymorphicCapability(attribute),
220
+ maxItems
221
+ },
222
+ authoring: {
223
+ editable,
224
+ readOnly,
225
+ directEdit: editable && DIRECT_EDIT_TYPES.has(attribute.type),
226
+ required,
227
+ defaultValue,
228
+ placeholder,
229
+ maxItems
230
+ },
231
+ presentation: {
232
+ formField: !suppressed && isFormFieldType(attribute.type),
233
+ tableCell: !suppressed && isTableCellType(attribute.type),
234
+ defaultColumn: !suppressed && isDefaultColumnType(attribute.type),
235
+ compactDisplay: !suppressed,
236
+ popoverEditor: !suppressed && isPopoverEditorType(attribute.type),
237
+ placeholder,
238
+ warningWhenDeprecated
239
+ },
240
+ query: {
241
+ filterable,
242
+ searchable,
243
+ sortable,
244
+ groupable,
245
+ kanbanGroupable,
246
+ operators
247
+ },
248
+ agent: {
249
+ readable: !suppressed,
250
+ writable: editable && !document2,
251
+ compactReadable: !suppressed,
252
+ contentReadable: !suppressed && isContentReadableType(attribute.type),
253
+ requiresDedicatedTool: document2
254
+ },
255
+ exchange: {
256
+ importable: !suppressed,
257
+ exportable: !suppressed,
258
+ schemaExportable: true,
259
+ metadataExportable: false
260
+ }
261
+ };
262
+ }
263
+ function getAttributeFilterOperators(attribute) {
264
+ return getAttributeCapabilities(attribute).query.operators;
265
+ }
266
+ function isAttributeFilterable(attribute) {
267
+ return getAttributeCapabilities(attribute).query.filterable;
268
+ }
269
+ function isAttributeSearchable(attribute) {
270
+ return getAttributeCapabilities(attribute).query.searchable;
271
+ }
272
+ function isAttributeSortable(attribute) {
273
+ return getAttributeCapabilities(attribute).query.sortable;
274
+ }
275
+ function isAttributeGroupable(attribute) {
276
+ return getAttributeCapabilities(attribute).query.groupable;
277
+ }
278
+ function isAttributeKanbanGroupable(attribute) {
279
+ return getAttributeCapabilities(attribute).query.kanbanGroupable;
280
+ }
281
+ function getRollupFilterOperators(attr) {
282
+ const fn = attr.function;
283
+ if (fn === "earliest" || fn === "latest") {
284
+ return ATTRIBUTE_FILTER_OPERATORS.date;
285
+ }
286
+ if (fn === "original") {
287
+ const targetType = attr.targetAttributeType;
288
+ if (targetType && hasFilterOperatorEntry(targetType)) {
289
+ return ATTRIBUTE_FILTER_OPERATORS[targetType];
290
+ }
291
+ return ATTRIBUTE_FILTER_OPERATORS.number;
292
+ }
293
+ return ATTRIBUTE_FILTER_OPERATORS.number;
294
+ }
295
+ function getRawFilterOperators(attribute) {
296
+ if (attribute.type === "rollup") {
297
+ return getRollupFilterOperators(attribute);
298
+ }
299
+ return ATTRIBUTE_FILTER_OPERATORS[attribute.type] ?? [];
300
+ }
301
+ function getAttributeCardinality(attribute) {
302
+ if (attribute.type === "multiselect" || attribute.type === "document") return "many";
303
+ if (attribute.type === "file" && attribute.multiple === true) return "many";
304
+ if (attribute.type === "user" && attribute.multiple === true) return "many";
305
+ if (attribute.type === "relation") return attribute.cardinality === "many" ? "many" : "one";
306
+ return "one";
307
+ }
308
+ function getPolymorphicCapability(attribute) {
309
+ if (attribute.type !== "relation") return "none";
310
+ const relation2 = attribute;
311
+ const targets = relation2.targets ?? [];
312
+ if (targets.length === 1 && targets[0]?.object === "*") return "internal";
313
+ return targets.length > 1 ? "code-only" : "none";
314
+ }
315
+ function supportsMaxItems(attribute) {
316
+ if (attribute.type === "multiselect") return true;
317
+ if (attribute.type === "relation") return attribute.cardinality === "many";
318
+ if (attribute.type === "file") return attribute.multiple === true;
319
+ return false;
320
+ }
321
+ function supportsQualifiedProperties(type) {
322
+ return type === "relation" || type === "document";
323
+ }
324
+ function isRequiredForbidden(type) {
325
+ return type === "checkbox" || type === "formula" || type === "rollup";
326
+ }
327
+ function getDefaultValueCapability(type) {
328
+ if (type === "checkbox") return "automatic";
329
+ if (type === "formula" || type === "rollup") return "forbidden";
330
+ if (STATIC_DEFAULT_TYPES.has(type)) return "static";
331
+ return "forbidden";
332
+ }
333
+ function isDefaultColumnType(type) {
334
+ return isTableCellType(type);
335
+ }
336
+ function isTableCellType(type) {
337
+ return type !== "richtext" && type !== "file" && type !== "document";
338
+ }
339
+ function isFormFieldType(type) {
340
+ return type !== "richtext";
341
+ }
342
+ function isPopoverEditorType(type) {
343
+ return type === "select" || type === "status" || type === "multiselect" || type === "relation" || type === "user";
344
+ }
345
+ function isGroupableType(type) {
346
+ return type === "status" || type === "currency";
347
+ }
348
+ function isContentReadableType(type) {
349
+ return type === "richtext" || type === "document";
350
+ }
351
+ function hasFilterOperatorEntry(type) {
352
+ return Object.prototype.hasOwnProperty.call(ATTRIBUTE_FILTER_OPERATORS, type);
353
+ }
354
+
46
355
  // src/types/attributes.ts
47
356
  var RELATION_TARGET_ANY = "*";
48
357
  function isUniversalRelation(attr) {
@@ -54,17 +363,8 @@ function isBilateralRelation(attr) {
54
363
  function inferInverseCardinality(cardinality) {
55
364
  return cardinality === "one" ? "many" : "many";
56
365
  }
57
- var NON_SORTABLE_TYPES = /* @__PURE__ */ new Set([
58
- "richtext",
59
- "file",
60
- "document",
61
- "location",
62
- "user",
63
- "multiselect",
64
- "relation"
65
- ]);
66
- function isAttributeSortable(attr) {
67
- return !NON_SORTABLE_TYPES.has(attr.type);
366
+ function isAttributeSortable2(attr) {
367
+ return isAttributeSortable(attr);
68
368
  }
69
369
 
70
370
  // src/types/document-layout.ts
@@ -86,95 +386,7 @@ function getErrorMessage(error) {
86
386
  }
87
387
 
88
388
  // src/types/filters.ts
89
- var OPERATORS_BY_TYPE = {
90
- text: [
91
- "is",
92
- "is_not",
93
- "contains",
94
- "not_contains",
95
- "starts_with",
96
- "ends_with",
97
- "is_empty",
98
- "is_not_empty"
99
- ],
100
- textarea: [
101
- "is",
102
- "is_not",
103
- "contains",
104
- "not_contains",
105
- "starts_with",
106
- "ends_with",
107
- "is_empty",
108
- "is_not_empty"
109
- ],
110
- richtext: ["is_empty", "is_not_empty"],
111
- number: ["eq", "neq", "lt", "gt", "lte", "gte", "is_empty", "is_not_empty"],
112
- checkbox: ["is_checked", "is_not_checked"],
113
- date: [
114
- "is",
115
- "is_not",
116
- "before",
117
- "after",
118
- "on_or_before",
119
- "on_or_after",
120
- "is_within",
121
- "day_month_eq",
122
- "is_empty",
123
- "is_not_empty"
124
- ],
125
- phone: ["is", "is_not", "contains", "not_contains", "is_empty", "is_not_empty"],
126
- currency: ["eq", "neq", "lt", "gt", "lte", "gte", "is_empty", "is_not_empty"],
127
- status: ["is", "is_not", "any_of", "none_of", "is_empty", "is_not_empty"],
128
- select: ["is", "is_not", "any_of", "none_of", "is_empty", "is_not_empty"],
129
- multiselect: ["contains", "not_contains", "is_empty", "is_not_empty"],
130
- location: ["contains", "is_empty", "is_not_empty"],
131
- // Reference attribute types (user, relation) all route through the edge
132
- // filter resolver, which normalizes is/is_not/any_of/none_of/contains/
133
- // not_contains via `getOperatorPolarity` + `normalizeForEdgeRpc`. Keep the
134
- // operator lists symmetric so the schema validation matches what the runtime
135
- // actually supports.
136
- // File and document attributes only expose presence operators — qualified
137
- // filters (via `.qualifyWith()` on document) keep their own operator set
138
- // based on the property type.
139
- file: ["is_empty", "is_not_empty"],
140
- user: [
141
- "is",
142
- "is_not",
143
- "any_of",
144
- "none_of",
145
- "contains",
146
- "not_contains",
147
- "is_empty",
148
- "is_not_empty"
149
- ],
150
- relation: [
151
- "is",
152
- "is_not",
153
- "any_of",
154
- "none_of",
155
- "contains",
156
- "not_contains",
157
- "is_empty",
158
- "is_not_empty"
159
- ],
160
- rating: ["eq", "neq", "lt", "gt", "lte", "gte", "is_empty", "is_not_empty"],
161
- // Formula: operators depend on returnType, but we provide a general set
162
- formula: [
163
- "is",
164
- "is_not",
165
- "eq",
166
- "neq",
167
- "lt",
168
- "gt",
169
- "lte",
170
- "gte",
171
- "contains",
172
- "not_contains",
173
- "is_empty",
174
- "is_not_empty"
175
- ],
176
- document: ["is_empty", "is_not_empty"]
177
- };
389
+ var OPERATORS_BY_TYPE = ATTRIBUTE_FILTER_OPERATORS;
178
390
  var NO_VALUE_OPERATORS = [
179
391
  "is_empty",
180
392
  "is_not_empty",
@@ -184,19 +396,8 @@ var NO_VALUE_OPERATORS = [
184
396
  function isNoValueOperator(operator) {
185
397
  return NO_VALUE_OPERATORS.includes(operator);
186
398
  }
187
- function getRollupFilterOperators(attr) {
188
- const fn = attr.function;
189
- if (fn === "earliest" || fn === "latest") {
190
- return OPERATORS_BY_TYPE.date;
191
- }
192
- if (fn === "original") {
193
- const targetType = attr.targetAttributeType;
194
- if (targetType && Object.prototype.hasOwnProperty.call(OPERATORS_BY_TYPE, targetType)) {
195
- return OPERATORS_BY_TYPE[targetType];
196
- }
197
- return OPERATORS_BY_TYPE.number;
198
- }
199
- return OPERATORS_BY_TYPE.number;
399
+ function getRollupFilterOperators2(attr) {
400
+ return getRollupFilterOperators(attr);
200
401
  }
201
402
 
202
403
  // src/types/forms/definition.ts
@@ -314,7 +515,6 @@ var SYSTEM_ATTRIBUTES = {
314
515
  label: "Created time",
315
516
  type: "date",
316
517
  required: false,
317
- disabled: true,
318
518
  system: true,
319
519
  icon: "clock-circle",
320
520
  description: "When this record was created"
@@ -325,7 +525,6 @@ var SYSTEM_ATTRIBUTES = {
325
525
  label: "Last edited time",
326
526
  type: "date",
327
527
  required: false,
328
- disabled: true,
329
528
  system: true,
330
529
  icon: "clock-circle",
331
530
  description: "When this record was last modified"
@@ -336,7 +535,6 @@ var SYSTEM_ATTRIBUTES = {
336
535
  label: "Created by",
337
536
  type: "user",
338
537
  required: false,
339
- disabled: true,
340
538
  system: true,
341
539
  multiple: false,
342
540
  icon: "user",
@@ -348,7 +546,6 @@ var SYSTEM_ATTRIBUTES = {
348
546
  label: "Last edited by",
349
547
  type: "user",
350
548
  required: false,
351
- disabled: true,
352
549
  system: true,
353
550
  multiple: false,
354
551
  icon: "user",
@@ -365,8 +562,6 @@ var SYSTEM_ATTRIBUTES = {
365
562
  label: "Attachments",
366
563
  type: "document",
367
564
  required: false,
368
- disabled: false,
369
- // Editable via Documents tab
370
565
  system: true,
371
566
  hidden: true,
372
567
  // Hidden from regular form views
@@ -462,7 +657,6 @@ function validateSlotAgainstConfig(slotName, mimeType, slots) {
462
657
  // src/lib/qualify-with.ts
463
658
  var ALLOWED_PROPERTY_TYPES = Object.freeze([
464
659
  "text",
465
- "textarea",
466
660
  "number",
467
661
  "checkbox",
468
662
  "date",
@@ -471,7 +665,6 @@ var ALLOWED_PROPERTY_TYPES = Object.freeze([
471
665
  "status",
472
666
  "select",
473
667
  "multiselect",
474
- "rating",
475
668
  "location"
476
669
  ]);
477
670
  function buildPropertySchema(builders) {
@@ -511,6 +704,9 @@ function formatCheckbox(value) {
511
704
  }
512
705
  function formatNumber(value, attribute) {
513
706
  if (typeof value !== "number") return String(value);
707
+ if (attribute.renderAs === "rating") {
708
+ return `${value}/${attribute.max ?? 5}`;
709
+ }
514
710
  const decimals = attribute.decimals;
515
711
  if (attribute.unit === "integer") {
516
712
  return value.toLocaleString(void 0, {
@@ -558,7 +754,7 @@ function formatPhone(value) {
558
754
  if (!("phoneNumber" in phone2)) return String(value);
559
755
  if (!phone2.phoneNumber) return "";
560
756
  if (!phone2.countryCode) return phone2.phoneNumber;
561
- return chunk7A3Y6O32_js.formatPhoneForDisplay(phone2);
757
+ return chunkEBGRZUIH_js.formatPhoneForDisplay(phone2);
562
758
  }
563
759
  function formatLocation(value, attribute) {
564
760
  if (typeof value !== "object" || value === null) return String(value);
@@ -612,18 +808,12 @@ function formatMultiselect(value, attribute) {
612
808
  }
613
809
  return value.join(", ");
614
810
  }
615
- function formatRating(value, attribute) {
616
- if (typeof value !== "number") return String(value);
617
- const max = attribute.max ?? 5;
618
- return `${value}/${max}`;
619
- }
620
811
  function formatAttributeValue(value, attribute) {
621
812
  if (value === null || value === void 0 || value === "") {
622
813
  return EMPTY_VALUE_PLACEHOLDER;
623
814
  }
624
815
  switch (attribute.type) {
625
816
  case "text":
626
- case "textarea":
627
817
  return formatText(value);
628
818
  case "checkbox":
629
819
  return formatCheckbox(value);
@@ -642,8 +832,6 @@ function formatAttributeValue(value, attribute) {
642
832
  return formatSelect(value, attribute);
643
833
  case "multiselect":
644
834
  return formatMultiselect(value, attribute);
645
- case "rating":
646
- return formatRating(value, attribute);
647
835
  // Unsupported types - return value as-is or placeholder
648
836
  case "file":
649
837
  case "user":
@@ -987,41 +1175,25 @@ Icon must be one of the predefined icons from @stndrds/constants.`
987
1175
  );
988
1176
  }
989
1177
  }
990
- function validateOptions(options, attributeName) {
991
- if (options.length === 0) return;
992
- const ids = /* @__PURE__ */ new Set();
1178
+ function validateOptions(attributeName, options) {
993
1179
  const values = /* @__PURE__ */ new Set();
994
1180
  for (const option of options) {
995
- if (!option.id?.trim()) {
996
- throw new Error(
997
- `[AttributeBuilder] Option in "${attributeName}" has an empty or missing id.`
998
- );
999
- }
1000
1181
  if (!option.value?.trim()) {
1001
1182
  throw new Error(
1002
- `[AttributeBuilder] Option "${option.id}" in "${attributeName}" has an empty or missing value.`
1183
+ `[AttributeBuilder] Option in "${attributeName}" has an empty or missing value.`
1003
1184
  );
1004
1185
  }
1005
1186
  if (!option.label?.trim()) {
1006
1187
  throw new Error(
1007
- `[AttributeBuilder] Option "${option.id}" in "${attributeName}" has an empty or missing label.`
1188
+ `[AttributeBuilder] Option "${option.value}" in "${attributeName}" has an empty or missing label.`
1008
1189
  );
1009
1190
  }
1010
- if (ids.has(option.id)) {
1011
- throw new Error(
1012
- `[AttributeBuilder] Duplicate option id "${option.id}" in "${attributeName}".`
1013
- );
1014
- }
1015
- ids.add(option.id);
1016
1191
  if (values.has(option.value)) {
1017
1192
  throw new Error(
1018
1193
  `[AttributeBuilder] Duplicate option value "${option.value}" in "${attributeName}".`
1019
1194
  );
1020
1195
  }
1021
1196
  values.add(option.value);
1022
- if (option.icon) {
1023
- validateIconName(option.icon, `option "${option.id}" of "${attributeName}"`);
1024
- }
1025
1197
  }
1026
1198
  for (const option of options) {
1027
1199
  if (option.inverse === void 0) continue;
@@ -1053,7 +1225,7 @@ var BaseAttributeBuilder = class {
1053
1225
  * @see https://standardschema.dev/
1054
1226
  */
1055
1227
  get "~standard"() {
1056
- const zodSchema = chunkFQ2ZYOVS_js.createAttributeValidator(this.build());
1228
+ const zodSchema = chunkMZOEL7FN_js.createAttributeValidator(this.build());
1057
1229
  return createStandardSchemaProps(zodSchema);
1058
1230
  }
1059
1231
  constructor(type, name, label) {
@@ -1125,10 +1297,6 @@ var BaseAttributeBuilder = class {
1125
1297
  this.attr.system = false;
1126
1298
  return this;
1127
1299
  }
1128
- disabled() {
1129
- this.attr.disabled = true;
1130
- return this;
1131
- }
1132
1300
  hidden() {
1133
1301
  this.attr.hidden = true;
1134
1302
  return this;
@@ -1160,32 +1328,6 @@ var BaseAttributeBuilder = class {
1160
1328
  this.attr.metadata = value;
1161
1329
  return this;
1162
1330
  }
1163
- /**
1164
- * Add a feature gate to conditionally show/hide/disable this attribute.
1165
- *
1166
- * @param flagName - Name of the feature flag to check
1167
- * @param options - Optional configuration for expected value and fallback behavior
1168
- *
1169
- * @example Hide attribute when flag is disabled
1170
- * ```typescript
1171
- * text({ name: "aiSummary", label: "AI Summary" })
1172
- * .featureGate("ai-features")
1173
- * ```
1174
- *
1175
- * @example Disable attribute when tier is not enterprise
1176
- * ```typescript
1177
- * text({ name: "advancedField", label: "Advanced Field" })
1178
- * .featureGate("tier", { expectedValue: "enterprise", fallback: "disable" })
1179
- * ```
1180
- */
1181
- featureGate(flagName, options) {
1182
- this.attr.featureGate = {
1183
- flag: flagName,
1184
- expectedValue: options?.expectedValue,
1185
- fallback: options?.fallback
1186
- };
1187
- return this;
1188
- }
1189
1331
  build() {
1190
1332
  return this.attr;
1191
1333
  }
@@ -1206,6 +1348,10 @@ var TextAttributeBuilder = class extends BaseAttributeBuilder {
1206
1348
  this.attr.pattern = value;
1207
1349
  return this;
1208
1350
  }
1351
+ multiline(value = true) {
1352
+ this.attr.multiline = value;
1353
+ return this;
1354
+ }
1209
1355
  required() {
1210
1356
  this.setRequired(true);
1211
1357
  return this.asRequiredState();
@@ -1239,42 +1385,10 @@ var TextAttributeBuilder = class extends BaseAttributeBuilder {
1239
1385
  function text(config) {
1240
1386
  return new TextAttributeBuilder(config.name, config.label);
1241
1387
  }
1242
- var TextAreaAttributeBuilder = class extends BaseAttributeBuilder {
1243
- constructor(name, label) {
1244
- super("textarea", name, label);
1245
- }
1246
- required() {
1247
- this.setRequired(true);
1248
- return this.asRequiredState();
1249
- }
1250
- optional() {
1251
- this.setRequired(false);
1252
- return this.asRequiredState();
1253
- }
1254
- };
1255
- function textarea(config) {
1256
- return new TextAreaAttributeBuilder(config.name, config.label);
1257
- }
1258
1388
  var RichtextAttributeBuilder = class extends BaseAttributeBuilder {
1259
1389
  constructor(name, label) {
1260
1390
  super("richtext", name, label);
1261
1391
  }
1262
- /**
1263
- * Set enabled features for the richtext editor
1264
- * If not called, all features are enabled by default
1265
- *
1266
- * @param list - Array of features to enable
1267
- *
1268
- * @example
1269
- * ```typescript
1270
- * richtext({ name: "content", label: "Content" })
1271
- * .features(["headings", "bold", "italic", "lists", "links"])
1272
- * ```
1273
- */
1274
- features(list) {
1275
- this.attr.features = list;
1276
- return this;
1277
- }
1278
1392
  required() {
1279
1393
  this.setRequired(true);
1280
1394
  return this.asRequiredState();
@@ -1313,6 +1427,10 @@ var NumberAttributeBuilder = class extends BaseAttributeBuilder {
1313
1427
  this.attr.unit = "percentage";
1314
1428
  return this;
1315
1429
  }
1430
+ renderAs(value) {
1431
+ this.attr.renderAs = value;
1432
+ return this;
1433
+ }
1316
1434
  required() {
1317
1435
  this.setRequired(true);
1318
1436
  return this.asRequiredState();
@@ -1426,7 +1544,7 @@ var StatusAttributeBuilder = class extends BaseAttributeBuilder {
1426
1544
  */
1427
1545
  options(value) {
1428
1546
  const mutableOptions = asMutableArray(value);
1429
- validateOptions(mutableOptions, this.attr.name ?? "unknown");
1547
+ validateOptions(this.attr.name ?? "unknown", mutableOptions);
1430
1548
  this.attr.options = mutableOptions;
1431
1549
  return this.asPhantomState();
1432
1550
  }
@@ -1435,7 +1553,7 @@ var StatusAttributeBuilder = class extends BaseAttributeBuilder {
1435
1553
  this.attr.options = [];
1436
1554
  }
1437
1555
  const allOptions = [...this.attr.options, config];
1438
- validateOptions(allOptions, this.attr.name ?? "unknown");
1556
+ validateOptions(this.attr.name ?? "unknown", allOptions);
1439
1557
  this.attr.options.push(config);
1440
1558
  return this;
1441
1559
  }
@@ -1460,7 +1578,7 @@ var SelectAttributeBuilder = class extends BaseAttributeBuilder {
1460
1578
  */
1461
1579
  options(value) {
1462
1580
  const mutableOptions = asMutableArray(value);
1463
- validateOptions(mutableOptions, this.attr.name ?? "unknown");
1581
+ validateOptions(this.attr.name ?? "unknown", mutableOptions);
1464
1582
  this.attr.options = mutableOptions;
1465
1583
  return this.asPhantomState();
1466
1584
  }
@@ -1469,7 +1587,7 @@ var SelectAttributeBuilder = class extends BaseAttributeBuilder {
1469
1587
  this.attr.options = [];
1470
1588
  }
1471
1589
  const allOptions = [...this.attr.options, config];
1472
- validateOptions(allOptions, this.attr.name ?? "unknown");
1590
+ validateOptions(this.attr.name ?? "unknown", allOptions);
1473
1591
  this.attr.options.push(config);
1474
1592
  return this;
1475
1593
  }
@@ -1494,7 +1612,7 @@ var MultiselectAttributeBuilder = class extends BaseAttributeBuilder {
1494
1612
  */
1495
1613
  options(value) {
1496
1614
  const mutableOptions = asMutableArray(value);
1497
- validateOptions(mutableOptions, this.attr.name ?? "unknown");
1615
+ validateOptions(this.attr.name ?? "unknown", mutableOptions);
1498
1616
  this.attr.options = mutableOptions;
1499
1617
  return this.asPhantomState();
1500
1618
  }
@@ -1503,7 +1621,7 @@ var MultiselectAttributeBuilder = class extends BaseAttributeBuilder {
1503
1621
  this.attr.options = [];
1504
1622
  }
1505
1623
  const allOptions = [...this.attr.options, config];
1506
- validateOptions(allOptions, this.attr.name ?? "unknown");
1624
+ validateOptions(this.attr.name ?? "unknown", allOptions);
1507
1625
  this.attr.options.push(config);
1508
1626
  return this;
1509
1627
  }
@@ -1527,14 +1645,6 @@ var LocationAttributeBuilder = class extends BaseAttributeBuilder {
1527
1645
  this.attr.granularity = value;
1528
1646
  return this;
1529
1647
  }
1530
- enableAutocomplete() {
1531
- this.attr.enableAutocomplete = true;
1532
- return this;
1533
- }
1534
- enableMap() {
1535
- this.attr.enableMap = true;
1536
- return this;
1537
- }
1538
1648
  defaultCountry(value) {
1539
1649
  this.attr.defaultCountry = value;
1540
1650
  return this;
@@ -1543,10 +1653,6 @@ var LocationAttributeBuilder = class extends BaseAttributeBuilder {
1543
1653
  this.attr.allowedCountries = value;
1544
1654
  return this;
1545
1655
  }
1546
- displayFormat(value) {
1547
- this.attr.displayFormat = value;
1548
- return this;
1549
- }
1550
1656
  required() {
1551
1657
  this.setRequired(true);
1552
1658
  return this.asRequiredState();
@@ -1597,9 +1703,14 @@ function file(config) {
1597
1703
  var UserAttributeBuilder = class extends BaseAttributeBuilder {
1598
1704
  constructor(name, label) {
1599
1705
  super("user", name, label);
1706
+ this.attr.types = ["user", "agent"];
1600
1707
  }
1601
- allowedRoles(roles) {
1602
- this.attr.allowedRoles = roles;
1708
+ types(types) {
1709
+ const unique = [...new Set(types)];
1710
+ if (unique.length === 0) {
1711
+ throw new Error("[AttributeBuilder] user.types must contain at least one type.");
1712
+ }
1713
+ this.attr.types = unique;
1603
1714
  return this;
1604
1715
  }
1605
1716
  /**
@@ -1710,18 +1821,11 @@ var SingleRelationAttributeBuilder = class extends BaseRelationAttributeBuilder
1710
1821
  );
1711
1822
  if (this.attr.system === false) multiBuilder.runtime();
1712
1823
  if (this.attr.hidden) multiBuilder.hidden();
1713
- if (this.attr.disabled) multiBuilder.disabled();
1714
1824
  if (this.attr.placeholder) multiBuilder.placeholder(this.attr.placeholder);
1715
1825
  if (this.attr.description) multiBuilder.description(this.attr.description);
1716
1826
  if (this.attr.icon) multiBuilder.icon(this.attr.icon);
1717
1827
  if (this.attr.order !== void 0) multiBuilder.order(this.attr.order);
1718
1828
  if (this.attr.metadata) multiBuilder.metadata(this.attr.metadata);
1719
- if (this.attr.featureGate) {
1720
- multiBuilder.featureGate(this.attr.featureGate.flag, {
1721
- expectedValue: this.attr.featureGate.expectedValue,
1722
- fallback: this.attr.featureGate.fallback
1723
- });
1724
- }
1725
1829
  return multiBuilder;
1726
1830
  }
1727
1831
  required() {
@@ -1743,13 +1847,6 @@ var MultiRelationAttributeBuilder = class extends BaseRelationAttributeBuilder {
1743
1847
  this.setRequired(true);
1744
1848
  }
1745
1849
  }
1746
- /**
1747
- * Set minimum number of relations required
1748
- */
1749
- minItems(count) {
1750
- this.attr.minItems = count;
1751
- return this;
1752
- }
1753
1850
  /**
1754
1851
  * Set maximum number of relations allowed
1755
1852
  */
@@ -1769,30 +1866,6 @@ var MultiRelationAttributeBuilder = class extends BaseRelationAttributeBuilder {
1769
1866
  function relation(config) {
1770
1867
  return new SingleRelationAttributeBuilder(config.name, config.label);
1771
1868
  }
1772
- var RatingAttributeBuilder = class extends BaseAttributeBuilder {
1773
- constructor(name, label) {
1774
- super("rating", name, label);
1775
- }
1776
- max(value) {
1777
- this.attr.max = value;
1778
- return this;
1779
- }
1780
- iconType(value) {
1781
- this.attr.iconType = value;
1782
- return this;
1783
- }
1784
- required() {
1785
- this.setRequired(true);
1786
- return this.asRequiredState();
1787
- }
1788
- optional() {
1789
- this.setRequired(false);
1790
- return this.asRequiredState();
1791
- }
1792
- };
1793
- function rating(config) {
1794
- return new RatingAttributeBuilder(config.name, config.label);
1795
- }
1796
1869
  var FormulaAttributeBuilder = class extends BaseAttributeBuilder {
1797
1870
  constructor(name, label) {
1798
1871
  super("formula", name, label);
@@ -1916,20 +1989,6 @@ var DocumentAttributeBuilder = class extends BaseAttributeBuilder {
1916
1989
  constructor(name, label) {
1917
1990
  super("document", name, label);
1918
1991
  }
1919
- /**
1920
- * Maximum number of documents.
1921
- */
1922
- maxDocuments(count) {
1923
- this.attr.maxDocuments = count;
1924
- return this;
1925
- }
1926
- /**
1927
- * Automatically trigger agent-compatible processing on upload.
1928
- */
1929
- autoProcess() {
1930
- this.attr.autoProcess = true;
1931
- return this;
1932
- }
1933
1992
  /**
1934
1993
  * Define named upload slots for this document attribute.
1935
1994
  * An empty array falls back to a single default slot.
@@ -1938,38 +1997,6 @@ var DocumentAttributeBuilder = class extends BaseAttributeBuilder {
1938
1997
  this.attr.slots = configs.length === 0 ? [DEFAULT_DOCUMENT_SLOT] : configs;
1939
1998
  return this;
1940
1999
  }
1941
- /**
1942
- * Add a child attribute that qualifies the record→document edge.
1943
- *
1944
- * Equivalent to `.qualifyWith(builder)` for a single attribute, with the
1945
- * difference that the accepted type is broader (`Attribute`) and the
1946
- * accumulation is mutating rather than type-tracking. When the produced
1947
- * attribute is one of the `ALLOWED_PROPERTY_TYPES`, it is also pushed
1948
- * onto `attribute.properties.definitions`, so hydration and validation
1949
- * treat the document as qualified — same effect as `.qualifyWith()`.
1950
- *
1951
- * Both `attribute.attributes` and `attribute.properties` are populated to
1952
- * keep backwards compatibility with consumers that read either field.
1953
- *
1954
- * @example
1955
- * document({ name: "invoices" })
1956
- * .attribute(date({ name: "invoiceDate", label: "Date" }).required())
1957
- * .attribute(select({ name: "status", label: "Statut" }).options([...]))
1958
- */
1959
- attribute(builder) {
1960
- const built = builder.build();
1961
- if (!this.attr.attributes) this.attr.attributes = [];
1962
- this.attr.attributes = [...this.attr.attributes, built];
1963
- if (ALLOWED_PROPERTY_TYPES.includes(built.type)) {
1964
- const props = this.attr.properties ?? {
1965
- definitions: []
1966
- };
1967
- this.attr.properties = {
1968
- definitions: [...props.definitions, built]
1969
- };
1970
- }
1971
- return this;
1972
- }
1973
2000
  /**
1974
2001
  * Add properties to qualify each document using existing attribute builders.
1975
2002
  * Returns a new builder type that carries the inferred props shape for $infer.
@@ -2305,11 +2332,9 @@ function form(name, label) {
2305
2332
  function resolveBuiltInTransform(targetType) {
2306
2333
  const map = {
2307
2334
  text: "toString",
2308
- textarea: "toString",
2309
2335
  richtext: "toString",
2310
2336
  number: "toNumber",
2311
2337
  currency: "toNumber",
2312
- rating: "toNumber",
2313
2338
  date: "toDate",
2314
2339
  checkbox: "toBoolean"
2315
2340
  };
@@ -2414,6 +2439,8 @@ var MigrationBuilder = class {
2414
2439
  var ObjectBuilder = class {
2415
2440
  constructor(config) {
2416
2441
  this._migrations = [];
2442
+ this._sealed = false;
2443
+ this._toleratedAttributes = [];
2417
2444
  this.validateName(config.name);
2418
2445
  this.obj = {
2419
2446
  name: config.name,
@@ -2431,7 +2458,7 @@ var ObjectBuilder = class {
2431
2458
  * @see https://standardschema.dev/
2432
2459
  */
2433
2460
  get "~standard"() {
2434
- const zodSchema = chunkFQ2ZYOVS_js.createObjectValidator(this.build());
2461
+ const zodSchema = chunkMZOEL7FN_js.createObjectValidator(this.build());
2435
2462
  return createStandardSchemaProps(zodSchema);
2436
2463
  }
2437
2464
  /**
@@ -2474,6 +2501,43 @@ var ObjectBuilder = class {
2474
2501
  this.obj.system = false;
2475
2502
  return this;
2476
2503
  }
2504
+ /**
2505
+ * Marks this object as sealed — no custom (user-created) attributes allowed.
2506
+ *
2507
+ * When sealed, `standards diff` reports an error if any custom attribute
2508
+ * exists in the DB that is not listed in `.tolerate()`.
2509
+ *
2510
+ * @example
2511
+ * ```typescript
2512
+ * object({ name: "invoice", label: "Invoice" })
2513
+ * .sealed()
2514
+ * .attribute(number({ name: "amount", label: "Amount" }))
2515
+ * ```
2516
+ */
2517
+ sealed() {
2518
+ this._sealed = true;
2519
+ return this;
2520
+ }
2521
+ /**
2522
+ * Explicitly acknowledges custom attribute names on this object.
2523
+ *
2524
+ * On a sealed object: listed names will NOT trigger a CI failure in `standards diff`.
2525
+ * On an extensible object: purely documentary.
2526
+ *
2527
+ * @param names - Array of custom attribute names to tolerate
2528
+ *
2529
+ * @example
2530
+ * ```typescript
2531
+ * object({ name: "invoice", label: "Invoice" })
2532
+ * .sealed()
2533
+ * .tolerate(["legacy_ref", "old_status"])
2534
+ * .attribute(number({ name: "amount", label: "Amount" }))
2535
+ * ```
2536
+ */
2537
+ tolerate(names) {
2538
+ this._toleratedAttributes = [...this._toleratedAttributes, ...names];
2539
+ return this;
2540
+ }
2477
2541
  /**
2478
2542
  * Add an attribute to the object with type accumulation
2479
2543
  *
@@ -2598,17 +2662,17 @@ var ObjectBuilder = class {
2598
2662
  throw new Error("[ObjectBuilder] Missing required field: label");
2599
2663
  }
2600
2664
  if (!this._labelExpression) {
2601
- throw new chunkFQ2ZYOVS_js.SchemaError(
2665
+ throw new chunkMZOEL7FN_js.SchemaError(
2602
2666
  `Object "${this.obj.name}" must have a labelExpression. The labelExpression defines how records are displayed in lists and relations (e.g. "{{ name }}").`,
2603
- chunkFQ2ZYOVS_js.SchemaErrorCode.VALIDATION_FAILED
2667
+ chunkMZOEL7FN_js.SchemaErrorCode.VALIDATION_FAILED
2604
2668
  );
2605
2669
  }
2606
2670
  const labelResult = labelExpressionSchema.safeParse(this._labelExpression);
2607
2671
  if (!labelResult.success) {
2608
2672
  const errorMsg = labelResult.error.issues[0]?.message ?? "Invalid labelExpression";
2609
- throw new chunkFQ2ZYOVS_js.SchemaError(
2673
+ throw new chunkMZOEL7FN_js.SchemaError(
2610
2674
  `Invalid labelExpression for "${this.obj.name}": ${errorMsg}`,
2611
- chunkFQ2ZYOVS_js.SchemaErrorCode.VALIDATION_FAILED
2675
+ chunkMZOEL7FN_js.SchemaErrorCode.VALIDATION_FAILED
2612
2676
  );
2613
2677
  }
2614
2678
  const sortedVersions = [...this._migrations].sort((a, b) => a.version - b.version);
@@ -2626,7 +2690,9 @@ var ObjectBuilder = class {
2626
2690
  pluralLabel: this._pluralLabel,
2627
2691
  labelExpression: this._labelExpression,
2628
2692
  schema_version,
2629
- migrations: sortedVersions
2693
+ migrations: sortedVersions,
2694
+ sealed: this._sealed,
2695
+ toleratedAttributes: this._toleratedAttributes
2630
2696
  };
2631
2697
  }
2632
2698
  /**
@@ -2645,7 +2711,7 @@ var ObjectBuilder = class {
2645
2711
  objectNameSchema.parse(name);
2646
2712
  } catch (error) {
2647
2713
  if (error instanceof z3__default.default.ZodError) {
2648
- throw new chunkFQ2ZYOVS_js.SchemaError(error.issues[0].message, chunkFQ2ZYOVS_js.SchemaErrorCode.INVALID_OBJECT_NAME);
2714
+ throw new chunkMZOEL7FN_js.SchemaError(error.issues[0].message, chunkMZOEL7FN_js.SchemaErrorCode.INVALID_OBJECT_NAME);
2649
2715
  }
2650
2716
  throw error;
2651
2717
  }
@@ -4515,9 +4581,9 @@ Available views: ${availableNames}`
4515
4581
  var viewRegistry = new ViewRegistry();
4516
4582
 
4517
4583
  // src/views/auto-generator.ts
4518
- function getVisibleAttributes(attributes, excludeNames = []) {
4584
+ function getRuntimeAttributes(attributes, excludeNames = []) {
4519
4585
  return attributes.filter(
4520
- (attr) => !(attr.hidden || attr.archived || attr.system || excludeNames.includes(attr.name))
4586
+ (attr) => !(!getAttributeCapabilities(attr).lifecycle.visibleInRuntime || attr.system || excludeNames.includes(attr.name))
4521
4587
  );
4522
4588
  }
4523
4589
  function sortAttributes(attributes) {
@@ -4528,9 +4594,9 @@ function sortAttributes(attributes) {
4528
4594
  return a.name.localeCompare(b.name);
4529
4595
  });
4530
4596
  }
4531
- function getDefaultFieldSpan(type) {
4532
- switch (type) {
4533
- case "textarea":
4597
+ function getDefaultFieldSpan(attr) {
4598
+ if (attr.type === "text" && attr.multiline) return 12;
4599
+ switch (attr.type) {
4534
4600
  case "richtext":
4535
4601
  case "location":
4536
4602
  return 12;
@@ -4543,7 +4609,7 @@ function getDefaultFieldSpan(type) {
4543
4609
  function attributeToField(attr) {
4544
4610
  return {
4545
4611
  attribute: attr.name,
4546
- span: getDefaultFieldSpan(attr.type)
4612
+ span: getDefaultFieldSpan(attr)
4547
4613
  };
4548
4614
  }
4549
4615
  function generateDefaultDetailView(object2, options = {}) {
@@ -4553,8 +4619,10 @@ function generateDefaultDetailView(object2, options = {}) {
4553
4619
  excludeAttributes = [],
4554
4620
  layout = "page"
4555
4621
  } = options;
4556
- const visibleAttrs = getVisibleAttributes(object2.attributes, excludeAttributes);
4557
- const sortedAttrs = sortAttributes(visibleAttrs);
4622
+ const runtimeAttrs = getRuntimeAttributes(object2.attributes, excludeAttributes);
4623
+ const sortedAttrs = sortAttributes(
4624
+ runtimeAttrs.filter((attr) => getAttributeCapabilities(attr).presentation.formField)
4625
+ );
4558
4626
  const formTab = {
4559
4627
  id: "form",
4560
4628
  name: "form",
@@ -4609,8 +4677,10 @@ function generateDefaultDetailView(object2, options = {}) {
4609
4677
  }
4610
4678
  function generateDefaultListView(object2, options = {}) {
4611
4679
  const { excludeAttributes = [], maxListColumns = 5 } = options;
4612
- const visibleAttrs = getVisibleAttributes(object2.attributes, excludeAttributes);
4613
- const sortedAttrs = sortAttributes(visibleAttrs);
4680
+ const runtimeAttrs = getRuntimeAttributes(object2.attributes, excludeAttributes);
4681
+ const sortedAttrs = sortAttributes(
4682
+ runtimeAttrs.filter((attr) => getAttributeCapabilities(attr).presentation.defaultColumn)
4683
+ );
4614
4684
  const columns = sortedAttrs.slice(0, maxListColumns).map((attr) => attr.name);
4615
4685
  const config = {
4616
4686
  tabs: [
@@ -4652,289 +4722,1709 @@ function mergeDetailTabs(generatedTabs, preservedTabs) {
4652
4722
  if (preservedTabs.length === 0) {
4653
4723
  return generatedTabs;
4654
4724
  }
4655
- const formTab = generatedTabs.find((t) => t.type === "form");
4656
- const otherTabs = generatedTabs.filter((t) => t.type !== "form");
4657
- const result = [];
4658
- if (formTab) {
4659
- result.push(formTab);
4725
+ const formTab = generatedTabs.find((t) => t.type === "form");
4726
+ const otherTabs = generatedTabs.filter((t) => t.type !== "form");
4727
+ const result = [];
4728
+ if (formTab) {
4729
+ result.push(formTab);
4730
+ }
4731
+ let order = 1;
4732
+ for (const tab of preservedTabs) {
4733
+ result.push({ ...tab, order: order++ });
4734
+ }
4735
+ for (const tab of otherTabs) {
4736
+ result.push({ ...tab, order: order++ });
4737
+ }
4738
+ return result;
4739
+ }
4740
+ function resetDetailViewToDefault(view, object2, options) {
4741
+ const { preserveMetadata = true, ...generateOptions } = options;
4742
+ const defaultView = generateDefaultDetailView(object2, generateOptions);
4743
+ const preservedTabs = getPreservedDetailTabs(view, options);
4744
+ const mergedTabs = mergeDetailTabs(defaultView.config.tabs, preservedTabs);
4745
+ const config = {
4746
+ ...defaultView.config,
4747
+ tabs: mergedTabs
4748
+ };
4749
+ const resetView = {
4750
+ ...defaultView,
4751
+ config
4752
+ };
4753
+ if (preserveMetadata) {
4754
+ resetView.id = view.id;
4755
+ resetView.name = view.name;
4756
+ resetView.label = view.label;
4757
+ resetView.description = view.description;
4758
+ resetView.icon = view.icon;
4759
+ }
4760
+ return resetView;
4761
+ }
4762
+ function resetListViewToDefault(view, object2, options) {
4763
+ const { preserveMetadata = true, ...generateOptions } = options;
4764
+ const defaultView = generateDefaultListView(object2, generateOptions);
4765
+ const resetView = {
4766
+ ...defaultView
4767
+ };
4768
+ if (preserveMetadata) {
4769
+ resetView.id = view.id;
4770
+ resetView.name = view.name;
4771
+ resetView.label = view.label;
4772
+ resetView.description = view.description;
4773
+ resetView.icon = view.icon;
4774
+ }
4775
+ return resetView;
4776
+ }
4777
+ function resetViewToDefault(currentView, object2, options = {}) {
4778
+ if (isDetailView(currentView)) {
4779
+ return resetDetailViewToDefault(currentView, object2, options);
4780
+ }
4781
+ if (isListView(currentView)) {
4782
+ return resetListViewToDefault(currentView, object2, options);
4783
+ }
4784
+ throw new Error(`Reset not supported for view type: ${currentView.type}`);
4785
+ }
4786
+
4787
+ // src/views/index.ts
4788
+ function getActiveTab(config, tabId) {
4789
+ if (tabId) {
4790
+ const tab = config.tabs.find((t) => t.id === tabId);
4791
+ if (tab) return tab;
4792
+ }
4793
+ return config.tabs.find((t) => t.default) ?? config.tabs[0];
4794
+ }
4795
+
4796
+ // src/forms/registry.ts
4797
+ var FormRegistry = class {
4798
+ constructor() {
4799
+ this.forms = /* @__PURE__ */ new Map();
4800
+ }
4801
+ /**
4802
+ * Register a form definition (or array of definitions).
4803
+ * @throws Error if a form with the same name is already registered.
4804
+ */
4805
+ register(formOrForms) {
4806
+ const forms = Array.isArray(formOrForms) ? formOrForms : [formOrForms];
4807
+ for (const f of forms) {
4808
+ if (this.forms.has(f.name)) {
4809
+ throw new Error(`[FormRegistry] Duplicate form: "${f.name}"`);
4810
+ }
4811
+ this.forms.set(f.name, f);
4812
+ }
4813
+ return this;
4814
+ }
4815
+ /**
4816
+ * Get a form definition by name.
4817
+ */
4818
+ get(name) {
4819
+ return this.forms.get(name);
4820
+ }
4821
+ /**
4822
+ * Get all registered form definitions.
4823
+ */
4824
+ getAll() {
4825
+ return Array.from(this.forms.values());
4826
+ }
4827
+ /**
4828
+ * List all registered form names.
4829
+ */
4830
+ listNames() {
4831
+ return Array.from(this.forms.keys());
4832
+ }
4833
+ };
4834
+ var formRegistry = new FormRegistry();
4835
+
4836
+ // src/realtime/channels.ts
4837
+ function liveChannelKey(channel) {
4838
+ switch (channel.kind) {
4839
+ case "workspace":
4840
+ return `workspace:${encodeURIComponent(channel.workspaceId)}`;
4841
+ case "object":
4842
+ return `object:${encodeURIComponent(channel.objectId)}`;
4843
+ case "record":
4844
+ return `record:${encodeURIComponent(channel.objectId)}:${encodeURIComponent(channel.recordId)}`;
4845
+ case "view":
4846
+ return `view:${encodeURIComponent(channel.viewId)}`;
4847
+ case "agent":
4848
+ return `agent:${encodeURIComponent(channel.workspaceId)}`;
4849
+ case "user":
4850
+ return `user:${encodeURIComponent(channel.actorId)}`;
4851
+ case "conversation":
4852
+ return `conversation:${encodeURIComponent(channel.sessionId)}`;
4853
+ }
4854
+ }
4855
+ function decodeLiveChannelPart(part) {
4856
+ try {
4857
+ return decodeURIComponent(part);
4858
+ } catch {
4859
+ return null;
4860
+ }
4861
+ }
4862
+ function parseLiveChannelKey(key) {
4863
+ const parts = key.split(":");
4864
+ if (parts[0] === "workspace" && parts.length === 2 && parts[1]) {
4865
+ const workspaceId = decodeLiveChannelPart(parts[1]);
4866
+ return workspaceId ? { kind: "workspace", workspaceId } : null;
4867
+ }
4868
+ if (parts[0] === "object" && parts.length === 2 && parts[1]) {
4869
+ const objectId = decodeLiveChannelPart(parts[1]);
4870
+ return objectId ? { kind: "object", objectId } : null;
4871
+ }
4872
+ if (parts[0] === "record" && parts.length === 3 && parts[1] && parts[2]) {
4873
+ const objectId = decodeLiveChannelPart(parts[1]);
4874
+ const recordId = decodeLiveChannelPart(parts[2]);
4875
+ if (!(objectId && recordId)) return null;
4876
+ return {
4877
+ kind: "record",
4878
+ objectId,
4879
+ recordId
4880
+ };
4881
+ }
4882
+ if (parts[0] === "view" && parts.length === 2 && parts[1]) {
4883
+ const viewId = decodeLiveChannelPart(parts[1]);
4884
+ return viewId ? { kind: "view", viewId } : null;
4885
+ }
4886
+ if (parts[0] === "agent" && parts.length === 2 && parts[1]) {
4887
+ const workspaceId = decodeLiveChannelPart(parts[1]);
4888
+ return workspaceId ? { kind: "agent", workspaceId } : null;
4889
+ }
4890
+ if (parts[0] === "user" && parts.length === 2 && parts[1]) {
4891
+ const actorId = decodeLiveChannelPart(parts[1]);
4892
+ return actorId ? { kind: "user", actorId } : null;
4893
+ }
4894
+ if (parts[0] === "conversation" && parts.length === 2 && parts[1]) {
4895
+ const sessionId = decodeLiveChannelPart(parts[1]);
4896
+ return sessionId ? { kind: "conversation", sessionId } : null;
4897
+ }
4898
+ return null;
4899
+ }
4900
+
4901
+ // src/realtime/cursors.ts
4902
+ var LIVE_STREAM_START_CURSOR = "0-0";
4903
+ var LIVE_STREAM_CURSOR_PATTERN = /^(0|[1-9]\d*)-(0|[1-9]\d*)$/;
4904
+ function parseLiveStreamCursor(cursor) {
4905
+ if (!LIVE_STREAM_CURSOR_PATTERN.test(cursor)) {
4906
+ return null;
4907
+ }
4908
+ const [milliseconds = "0", sequence = "0"] = cursor.split("-");
4909
+ return [BigInt(milliseconds), BigInt(sequence)];
4910
+ }
4911
+ function isLiveStreamCursor(value) {
4912
+ return typeof value === "string" && parseLiveStreamCursor(value) !== null;
4913
+ }
4914
+ function assertLiveStreamCursor(cursor, label = "cursor") {
4915
+ if (cursor === null) {
4916
+ return;
4917
+ }
4918
+ if (!isLiveStreamCursor(cursor)) {
4919
+ throw new Error(`Invalid live stream cursor for ${label}: ${cursor}`);
4920
+ }
4921
+ }
4922
+ function compareLiveStreamCursors(left, right) {
4923
+ const leftCursor = parseLiveStreamCursor(left);
4924
+ if (!leftCursor) {
4925
+ throw new Error(`Invalid live stream cursor for left: ${left}`);
4926
+ }
4927
+ const rightCursor = parseLiveStreamCursor(right);
4928
+ if (!rightCursor) {
4929
+ throw new Error(`Invalid live stream cursor for right: ${right}`);
4930
+ }
4931
+ const [leftMilliseconds, leftSequence] = leftCursor;
4932
+ const [rightMilliseconds, rightSequence] = rightCursor;
4933
+ if (leftMilliseconds !== rightMilliseconds) {
4934
+ return leftMilliseconds < rightMilliseconds ? -1 : 1;
4935
+ }
4936
+ if (leftSequence !== rightSequence) {
4937
+ return leftSequence < rightSequence ? -1 : 1;
4938
+ }
4939
+ return 0;
4940
+ }
4941
+
4942
+ // src/realtime/events.ts
4943
+ var LIVE_EVENT_TYPE_REGISTRY = {
4944
+ "record.patch": true,
4945
+ "record.deleted": true,
4946
+ "view.projection.stale": true,
4947
+ "agent.session.patch": true,
4948
+ "agent.unread.patch": true,
4949
+ "conversation.renamed": true,
4950
+ "channel.revoked": true
4951
+ };
4952
+ var LIVE_EVENT_TYPES = Object.keys(LIVE_EVENT_TYPE_REGISTRY);
4953
+ var COMPLETION_STATUSES = ["draft", "complete"];
4954
+ var VIEW_PROJECTION_STALE_REASONS = [
4955
+ "membership-unknown",
4956
+ "sort-unknown",
4957
+ "permissions-changed"
4958
+ ];
4959
+ var CHANNEL_REVOKED_REASONS = [
4960
+ "permission-revoked",
4961
+ "workspace-left",
4962
+ "object-deleted"
4963
+ ];
4964
+ function isLiveEventType(value) {
4965
+ return typeof value === "string" && LIVE_EVENT_TYPES.includes(value);
4966
+ }
4967
+ function isLiveEventPayload(payload) {
4968
+ if (!(isRecord(payload) && isLiveEventType(payload.type))) {
4969
+ return false;
4970
+ }
4971
+ return isLiveEventPayloadForType(payload.type, payload);
4972
+ }
4973
+ function isLiveEventPayloadForType(type, payload) {
4974
+ if (!isRecord(payload)) {
4975
+ return false;
4976
+ }
4977
+ switch (type) {
4978
+ case "record.patch":
4979
+ return isRecordPatchPayload(payload);
4980
+ case "record.deleted":
4981
+ return isRecordDeletedPayload(payload);
4982
+ case "view.projection.stale":
4983
+ return isViewProjectionStalePayload(payload);
4984
+ case "agent.session.patch":
4985
+ return isAgentSessionPatchPayload(payload);
4986
+ case "agent.unread.patch":
4987
+ return isAgentUnreadPatchPayload(payload);
4988
+ case "conversation.renamed":
4989
+ return isConversationRenamedPayload(payload);
4990
+ case "channel.revoked":
4991
+ return isChannelRevokedPayload(payload);
4992
+ default:
4993
+ return false;
4994
+ }
4995
+ }
4996
+ function isRecord(value) {
4997
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4998
+ }
4999
+ function isString(value) {
5000
+ return typeof value === "string";
5001
+ }
5002
+ function isVersion(value) {
5003
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
5004
+ }
5005
+ function hasString(value, key) {
5006
+ return isString(value[key]);
5007
+ }
5008
+ function hasVersion(value, key) {
5009
+ return isVersion(value[key]);
5010
+ }
5011
+ function hasOptional(value, key, predicate) {
5012
+ return !Object.hasOwn(value, key) || predicate(value[key]);
5013
+ }
5014
+ function isOneOf(value, values) {
5015
+ return typeof value === "string" && values.includes(value);
5016
+ }
5017
+ function isCompletionStatus(value) {
5018
+ return isOneOf(value, COMPLETION_STATUSES);
5019
+ }
5020
+ function isRecordFieldPatch(value) {
5021
+ return isRecord(value) && hasString(value, "fieldKey") && Object.hasOwn(value, "value") && hasVersion(value, "version");
5022
+ }
5023
+ function isRecordPatchPayload(payload) {
5024
+ return payload.type === "record.patch" && hasString(payload, "objectId") && hasString(payload, "recordId") && hasVersion(payload, "recordVersion") && hasOptional(payload, "label", isString) && hasOptional(payload, "completionStatus", isCompletionStatus) && hasOptional(payload, "metadata", isRecord) && Array.isArray(payload.fieldPatches) && payload.fieldPatches.every(isRecordFieldPatch) && hasString(payload, "updatedAt");
5025
+ }
5026
+ function isRecordDeletedPayload(payload) {
5027
+ return payload.type === "record.deleted" && hasString(payload, "objectId") && hasString(payload, "recordId") && hasVersion(payload, "recordVersion") && hasString(payload, "deletedAt");
5028
+ }
5029
+ function isViewProjectionStalePayload(payload) {
5030
+ return payload.type === "view.projection.stale" && hasString(payload, "viewId") && isOneOf(payload.reason, VIEW_PROJECTION_STALE_REASONS);
5031
+ }
5032
+ function isAgentSessionPatchPayload(payload) {
5033
+ return payload.type === "agent.session.patch" && hasString(payload, "workspaceId") && hasString(payload, "sessionId") && isRecord(payload.patch) && hasVersion(payload, "version") && hasString(payload, "updatedAt");
5034
+ }
5035
+ function isAgentUnreadPatchPayload(payload) {
5036
+ return payload.type === "agent.unread.patch" && hasString(payload, "workspaceId") && hasString(payload, "targetActorId") && hasString(payload, "sessionId") && hasVersion(payload, "unreadCount") && hasVersion(payload, "version") && hasString(payload, "updatedAt") && (!Object.hasOwn(payload, "session") || isRecord(payload.session) && payload.session.id === payload.sessionId);
5037
+ }
5038
+ function isConversationRenamedPayload(payload) {
5039
+ return payload.type === "conversation.renamed" && hasString(payload, "workspaceId") && hasString(payload, "sessionId") && hasString(payload, "title") && hasVersion(payload, "version") && hasString(payload, "updatedAt");
5040
+ }
5041
+ function isChannelRevokedPayload(payload) {
5042
+ return payload.type === "channel.revoked" && hasString(payload, "channel") && isOneOf(payload.reason, CHANNEL_REVOKED_REASONS);
5043
+ }
5044
+
5045
+ // src/realtime/protocol.ts
5046
+ function isRecord2(value) {
5047
+ return typeof value === "object" && value !== null && !Array.isArray(value);
5048
+ }
5049
+ function payloadChannel(payload) {
5050
+ const { channel } = payload;
5051
+ return typeof channel === "string" && parseLiveChannelKey(channel) ? channel : null;
5052
+ }
5053
+ function getLiveProtocolPayloadChannel(payload) {
5054
+ return isRecord2(payload) ? payloadChannel(payload) : null;
5055
+ }
5056
+ function isLiveEventEnvelope(payload) {
5057
+ if (!isRecord2(payload)) return false;
5058
+ return typeof payload.id === "string" && isLiveStreamCursor(payload.id) && typeof payload.channel === "string" && typeof payload.type === "string" && typeof payload.occurredAt === "string" && isRecord2(payload.payload);
5059
+ }
5060
+ function parseLiveSubscribePayload(payload) {
5061
+ if (!isRecord2(payload)) return null;
5062
+ const channel = payloadChannel(payload);
5063
+ if (!channel) return null;
5064
+ const { cursor } = payload;
5065
+ if (cursor !== void 0 && cursor !== null) {
5066
+ if (typeof cursor !== "string" || !isLiveStreamCursor(cursor)) {
5067
+ return null;
5068
+ }
5069
+ }
5070
+ return { channel, cursor: cursor ?? null };
5071
+ }
5072
+ function parseLiveUnsubscribePayload(payload) {
5073
+ if (payload === void 0 || payload === null) return {};
5074
+ if (!isRecord2(payload)) return null;
5075
+ if (!Object.hasOwn(payload, "channel")) {
5076
+ return {};
5077
+ }
5078
+ const channel = payloadChannel(payload);
5079
+ return channel ? { channel } : null;
5080
+ }
5081
+ function isLiveReplayCompletePayload(payload) {
5082
+ if (!isRecord2(payload)) return false;
5083
+ const channel = payloadChannel(payload);
5084
+ if (!channel) return false;
5085
+ return payload.cursor === null || typeof payload.cursor === "string" && isLiveStreamCursor(payload.cursor);
5086
+ }
5087
+ function isLiveGapPayload(payload) {
5088
+ if (!isRecord2(payload)) return false;
5089
+ return payloadChannel(payload) !== null;
5090
+ }
5091
+ function isLiveErrorPayload(payload) {
5092
+ if (!isRecord2(payload)) return false;
5093
+ return payloadChannel(payload) !== null;
5094
+ }
5095
+
5096
+ // src/computed/functions.ts
5097
+ var COMPUTED_FUNCTION_NAMES = [
5098
+ "if",
5099
+ "concat",
5100
+ "sum",
5101
+ "avg",
5102
+ "count",
5103
+ "min",
5104
+ "max",
5105
+ "earliest",
5106
+ "latest",
5107
+ "unique",
5108
+ "first",
5109
+ "percent_empty",
5110
+ "percent_not_empty",
5111
+ "count_empty",
5112
+ "count_not_empty",
5113
+ "count_unique"
5114
+ ];
5115
+ var COMPUTED_FUNCTIONS = {
5116
+ if: { name: "if", returnType: "branch", minArgs: 3, maxArgs: 3 },
5117
+ concat: { name: "concat", returnType: { kind: "scalar", type: "text" }, minArgs: 1 },
5118
+ sum: { name: "sum", returnType: { kind: "scalar", type: "number" }, minArgs: 1, maxArgs: 1 },
5119
+ avg: { name: "avg", returnType: { kind: "scalar", type: "number" }, minArgs: 1, maxArgs: 1 },
5120
+ count: { name: "count", returnType: { kind: "scalar", type: "number" }, minArgs: 1, maxArgs: 1 },
5121
+ min: { name: "min", returnType: "source_item", minArgs: 1, maxArgs: 1 },
5122
+ max: { name: "max", returnType: "source_item", minArgs: 1, maxArgs: 1 },
5123
+ earliest: {
5124
+ name: "earliest",
5125
+ returnType: { kind: "scalar", type: "date" },
5126
+ minArgs: 1,
5127
+ maxArgs: 1
5128
+ },
5129
+ latest: { name: "latest", returnType: { kind: "scalar", type: "date" }, minArgs: 1, maxArgs: 1 },
5130
+ unique: { name: "unique", returnType: "argument", minArgs: 1, maxArgs: 1 },
5131
+ first: { name: "first", returnType: "source_item", minArgs: 1, maxArgs: 1 },
5132
+ percent_empty: {
5133
+ name: "percent_empty",
5134
+ returnType: { kind: "scalar", type: "number" },
5135
+ minArgs: 1,
5136
+ maxArgs: 1
5137
+ },
5138
+ percent_not_empty: {
5139
+ name: "percent_not_empty",
5140
+ returnType: { kind: "scalar", type: "number" },
5141
+ minArgs: 1,
5142
+ maxArgs: 1
5143
+ },
5144
+ count_empty: {
5145
+ name: "count_empty",
5146
+ returnType: { kind: "scalar", type: "number" },
5147
+ minArgs: 1,
5148
+ maxArgs: 1
5149
+ },
5150
+ count_not_empty: {
5151
+ name: "count_not_empty",
5152
+ returnType: { kind: "scalar", type: "number" },
5153
+ minArgs: 1,
5154
+ maxArgs: 1
5155
+ },
5156
+ count_unique: {
5157
+ name: "count_unique",
5158
+ returnType: { kind: "scalar", type: "number" },
5159
+ minArgs: 1,
5160
+ maxArgs: 1
5161
+ }
5162
+ };
5163
+ function isComputedFunctionName(name) {
5164
+ return Object.hasOwn(COMPUTED_FUNCTIONS, name);
5165
+ }
5166
+
5167
+ // src/computed/parser.ts
5168
+ var ComputedFormulaParseError = class extends Error {
5169
+ constructor(message) {
5170
+ super(message);
5171
+ this.name = "ComputedFormulaParseError";
5172
+ }
5173
+ };
5174
+ function parseComputedFormula(expression) {
5175
+ const parser = new Parser(tokenize(expression));
5176
+ const ast = parser.parseExpression();
5177
+ parser.expectEnd();
5178
+ return ast;
5179
+ }
5180
+ function tokenize(expression) {
5181
+ const tokens = [];
5182
+ let index = 0;
5183
+ while (index < expression.length) {
5184
+ const char = expression[index];
5185
+ if (char === " " || char === " " || char === "\n" || char === "\r") {
5186
+ index += 1;
5187
+ continue;
5188
+ }
5189
+ if (char === '"' || char === "'") {
5190
+ const result = scanString(expression, index, char);
5191
+ tokens.push({ kind: "string", value: result.value, position: index });
5192
+ index = result.nextIndex;
5193
+ continue;
5194
+ }
5195
+ if (isDigit(char)) {
5196
+ const result = scanNumber(expression, index);
5197
+ tokens.push({ kind: "number", value: result.value, position: index });
5198
+ index = result.nextIndex;
5199
+ continue;
5200
+ }
5201
+ if (isIdentifierStart(char)) {
5202
+ const result = scanIdentifier(expression, index);
5203
+ const canonical = result.value.toLowerCase();
5204
+ if (canonical === "true") {
5205
+ tokens.push({ kind: "boolean", value: true, position: index });
5206
+ } else if (canonical === "false") {
5207
+ tokens.push({ kind: "boolean", value: false, position: index });
5208
+ } else if (canonical === "null") {
5209
+ tokens.push({ kind: "null", position: index });
5210
+ } else {
5211
+ tokens.push({ kind: "identifier", value: result.value, position: index });
5212
+ }
5213
+ index = result.nextIndex;
5214
+ continue;
5215
+ }
5216
+ const twoChar = expression.slice(index, index + 2);
5217
+ if (twoChar === ">=" || twoChar === "<=" || twoChar === "==" || twoChar === "!=") {
5218
+ tokens.push({ kind: "operator", value: twoChar, position: index });
5219
+ index += 2;
5220
+ continue;
5221
+ }
5222
+ if (char === ">" || char === "<" || char === "+" || char === "-" || char === "*" || char === "/") {
5223
+ tokens.push({ kind: "operator", value: char, position: index });
5224
+ index += 1;
5225
+ continue;
5226
+ }
5227
+ if (char === "(" || char === ")" || char === "," || char === ".") {
5228
+ tokens.push({ kind: "punctuation", value: char, position: index });
5229
+ index += 1;
5230
+ continue;
5231
+ }
5232
+ throw new ComputedFormulaParseError(`Unexpected character "${char}" at position ${index}`);
5233
+ }
5234
+ return tokens;
5235
+ }
5236
+ function scanString(expression, startIndex, delimiter = '"') {
5237
+ let value = "";
5238
+ let index = startIndex + 1;
5239
+ while (index < expression.length) {
5240
+ const char = expression[index];
5241
+ if (char === delimiter) {
5242
+ return { value, nextIndex: index + 1 };
5243
+ }
5244
+ if (char === "\\") {
5245
+ const escaped = expression[index + 1];
5246
+ if (escaped === void 0) {
5247
+ throw new ComputedFormulaParseError(`Unterminated string literal at position ${index}`);
5248
+ }
5249
+ value += decodeEscape(escaped, index);
5250
+ index += 2;
5251
+ continue;
5252
+ }
5253
+ value += char;
5254
+ index += 1;
5255
+ }
5256
+ throw new ComputedFormulaParseError(`Unterminated string literal at position ${startIndex}`);
5257
+ }
5258
+ function decodeEscape(char, position) {
5259
+ switch (char) {
5260
+ case '"':
5261
+ case "\\":
5262
+ return char;
5263
+ case "n":
5264
+ return "\n";
5265
+ case "r":
5266
+ return "\r";
5267
+ case "t":
5268
+ return " ";
5269
+ default:
5270
+ throw new ComputedFormulaParseError(
5271
+ `Unknown escape sequence "\\${char}" at position ${position}`
5272
+ );
5273
+ }
5274
+ }
5275
+ function scanNumber(expression, startIndex) {
5276
+ let index = startIndex;
5277
+ while (index < expression.length && isDigit(expression[index])) {
5278
+ index += 1;
5279
+ }
5280
+ if (expression[index] === ".") {
5281
+ const decimalStart = index;
5282
+ index += 1;
5283
+ if (!isDigit(expression[index])) {
5284
+ throw new ComputedFormulaParseError(`Invalid number literal at position ${decimalStart}`);
5285
+ }
5286
+ while (index < expression.length && isDigit(expression[index])) {
5287
+ index += 1;
5288
+ }
5289
+ }
5290
+ const raw = expression.slice(startIndex, index);
5291
+ const value = Number(raw);
5292
+ if (!Number.isFinite(value)) {
5293
+ throw new ComputedFormulaParseError(`Invalid number literal "${raw}"`);
5294
+ }
5295
+ return { value, nextIndex: index };
5296
+ }
5297
+ function scanIdentifier(expression, startIndex) {
5298
+ let index = startIndex + 1;
5299
+ while (index < expression.length && isIdentifierPart(expression[index])) {
5300
+ index += 1;
5301
+ }
5302
+ return { value: expression.slice(startIndex, index), nextIndex: index };
5303
+ }
5304
+ function isDigit(char) {
5305
+ return char !== void 0 && char >= "0" && char <= "9";
5306
+ }
5307
+ function isIdentifierStart(char) {
5308
+ return char !== void 0 && /[A-Za-z_]/.test(char);
5309
+ }
5310
+ function isIdentifierPart(char) {
5311
+ return char !== void 0 && /[A-Za-z0-9_]/.test(char);
5312
+ }
5313
+ var Parser = class {
5314
+ constructor(tokens) {
5315
+ this.tokens = tokens;
5316
+ this.position = 0;
5317
+ }
5318
+ parseExpression() {
5319
+ return this.parseBinaryExpression(0);
5320
+ }
5321
+ expectEnd() {
5322
+ const token = this.peek();
5323
+ if (token !== void 0) {
5324
+ throw new ComputedFormulaParseError(
5325
+ `Unexpected token ${describeToken(token)} at position ${token.position}`
5326
+ );
5327
+ }
5328
+ }
5329
+ parseBinaryExpression(minPrecedence) {
5330
+ let left = this.parsePrimary();
5331
+ while (true) {
5332
+ const token = this.peek();
5333
+ if (token?.kind !== "operator") {
5334
+ return left;
5335
+ }
5336
+ const precedence = getOperatorPrecedence(token.value);
5337
+ if (precedence < minPrecedence) {
5338
+ return left;
5339
+ }
5340
+ const operator = token.value;
5341
+ this.consume();
5342
+ const right = this.parseBinaryExpression(precedence + 1);
5343
+ left = { kind: "binary", operator, left, right };
5344
+ }
5345
+ }
5346
+ parsePrimary() {
5347
+ const token = this.consume();
5348
+ if (token === void 0) {
5349
+ throw new ComputedFormulaParseError("Unexpected end of expression");
5350
+ }
5351
+ switch (token.kind) {
5352
+ case "string":
5353
+ case "number":
5354
+ case "boolean":
5355
+ return { kind: "literal", value: token.value };
5356
+ case "null":
5357
+ return { kind: "literal", value: null };
5358
+ case "identifier":
5359
+ return this.parseIdentifier(token.value);
5360
+ case "punctuation":
5361
+ if (token.value === "(") {
5362
+ const expression = this.parseExpression();
5363
+ this.expectPunctuation(")");
5364
+ return expression;
5365
+ }
5366
+ break;
5367
+ case "operator":
5368
+ if (token.value === "-") {
5369
+ const next = this.consume();
5370
+ if (next?.kind === "number") {
5371
+ return { kind: "literal", value: -next.value };
5372
+ }
5373
+ }
5374
+ break;
5375
+ }
5376
+ throw new ComputedFormulaParseError(
5377
+ `Expected literal, path, call, or parenthesized expression at position ${token.position}`
5378
+ );
5379
+ }
5380
+ parseIdentifier(identifier) {
5381
+ if (this.matchPunctuation("(")) {
5382
+ const args = [];
5383
+ if (!this.matchPunctuation(")")) {
5384
+ do {
5385
+ args.push(this.parseExpression());
5386
+ } while (this.matchPunctuation(","));
5387
+ this.expectPunctuation(")");
5388
+ }
5389
+ return { kind: "call", functionName: identifier.toLowerCase(), args };
5390
+ }
5391
+ const parts = [identifier];
5392
+ while (this.matchPunctuation(".")) {
5393
+ const next = this.consume();
5394
+ if (next?.kind !== "identifier") {
5395
+ const position = next?.position ?? this.previousPosition();
5396
+ throw new ComputedFormulaParseError(
5397
+ `Expected attribute name after path separator at position ${position}`
5398
+ );
5399
+ }
5400
+ parts.push(next.value);
5401
+ }
5402
+ return { kind: "path", parts };
5403
+ }
5404
+ expectPunctuation(value) {
5405
+ if (!this.matchPunctuation(value)) {
5406
+ const token = this.peek();
5407
+ const position = token?.position ?? this.previousPosition();
5408
+ throw new ComputedFormulaParseError(`Expected "${value}" at position ${position}`);
5409
+ }
5410
+ }
5411
+ matchPunctuation(value) {
5412
+ const token = this.peek();
5413
+ if (token?.kind === "punctuation" && token.value === value) {
5414
+ this.consume();
5415
+ return true;
5416
+ }
5417
+ return false;
5418
+ }
5419
+ peek() {
5420
+ return this.tokens[this.position];
5421
+ }
5422
+ consume() {
5423
+ const token = this.tokens[this.position];
5424
+ this.position += 1;
5425
+ return token;
5426
+ }
5427
+ previousPosition() {
5428
+ const previous = this.tokens[this.position - 1];
5429
+ return previous?.position ?? 0;
5430
+ }
5431
+ };
5432
+ function describeToken(token) {
5433
+ switch (token.kind) {
5434
+ case "identifier":
5435
+ case "number":
5436
+ case "string":
5437
+ case "boolean":
5438
+ case "operator":
5439
+ case "punctuation":
5440
+ return `"${String(token.value)}"`;
5441
+ case "null":
5442
+ return '"null"';
5443
+ default: {
5444
+ const exhaustive = token;
5445
+ return exhaustive;
5446
+ }
5447
+ }
5448
+ }
5449
+ function getOperatorPrecedence(operator) {
5450
+ switch (operator) {
5451
+ case "*":
5452
+ case "/":
5453
+ return 3;
5454
+ case "+":
5455
+ case "-":
5456
+ return 2;
5457
+ case ">":
5458
+ case "<":
5459
+ case ">=":
5460
+ case "<=":
5461
+ case "==":
5462
+ case "!=":
5463
+ return 1;
5464
+ default: {
5465
+ const exhaustive = operator;
5466
+ return exhaustive;
5467
+ }
5468
+ }
5469
+ }
5470
+
5471
+ // src/computed/compiler.ts
5472
+ var ComputedFormulaCompileError = class extends Error {
5473
+ constructor(message) {
5474
+ super(message);
5475
+ this.name = "ComputedFormulaCompileError";
5476
+ }
5477
+ };
5478
+ function compileComputedFormula(input) {
5479
+ const ast = parseCompileFormula(input.expression);
5480
+ const inferred = inferNode(ast, input.schema);
5481
+ const inferredReturnType = valueTypeToReturnType(inferred.valueType);
5482
+ if (inferredReturnType !== input.returnType) {
5483
+ throw new ComputedFormulaCompileError(
5484
+ `Computed formula "${input.attributeName}" returns "${inferredReturnType}", expected "${input.returnType}"`
5485
+ );
5486
+ }
5487
+ if (isSelectLikeReturnType(input.returnType) && inferred.optionsSource === void 0) {
5488
+ throw new ComputedFormulaCompileError(
5489
+ `Computed formula "${input.attributeName}" returns "${input.returnType}" without optionsSource`
5490
+ );
5491
+ }
5492
+ const optionsDependencies = inferred.optionsSource === void 0 ? [] : [{ kind: "options", source: inferred.optionsSource }];
5493
+ const dependencies = uniqueDependencies([...inferred.dependencies, ...optionsDependencies]);
5494
+ return {
5495
+ kind: "formula",
5496
+ attributeName: input.attributeName,
5497
+ expression: input.expression,
5498
+ returnType: input.returnType,
5499
+ valueType: inferred.valueType,
5500
+ dependencies,
5501
+ ...inferred.optionsSource ? { optionsSource: inferred.optionsSource } : {},
5502
+ ...inferred.targetAttributeType ? { targetAttributeType: inferred.targetAttributeType } : {},
5503
+ dependenciesHash: createDependenciesHash({
5504
+ expression: input.expression,
5505
+ returnType: input.returnType,
5506
+ dependencies
5507
+ })
5508
+ };
5509
+ }
5510
+ function assertAcyclicComputedDependencies(nodes) {
5511
+ const graph = new Map(nodes.map((node) => [node.attributeName, node]));
5512
+ const visited = /* @__PURE__ */ new Set();
5513
+ const visit = (attributeName, activePath) => {
5514
+ const cycleStart = activePath.indexOf(attributeName);
5515
+ if (cycleStart !== -1) {
5516
+ const cycle = [...activePath.slice(cycleStart), attributeName];
5517
+ throw new ComputedFormulaCompileError(`Computed field cycle detected: ${cycle.join(" -> ")}`);
5518
+ }
5519
+ if (visited.has(attributeName)) {
5520
+ return;
5521
+ }
5522
+ const node = graph.get(attributeName);
5523
+ if (node === void 0) {
5524
+ return;
5525
+ }
5526
+ const nextPath = [...activePath, attributeName];
5527
+ for (const dependency of node.dependencies) {
5528
+ if (dependency.kind === "computed") {
5529
+ visit(dependency.attributeName, nextPath);
5530
+ }
5531
+ }
5532
+ visited.add(attributeName);
5533
+ };
5534
+ for (const node of nodes) {
5535
+ visit(node.attributeName, []);
5536
+ }
5537
+ }
5538
+ function parseCompileFormula(expression) {
5539
+ try {
5540
+ return parseComputedFormula(expression);
5541
+ } catch (error) {
5542
+ if (error instanceof Error) {
5543
+ throw new ComputedFormulaCompileError(error.message);
5544
+ }
5545
+ throw error;
5546
+ }
5547
+ }
5548
+ function inferNode(node, schema) {
5549
+ switch (node.kind) {
5550
+ case "literal":
5551
+ return {
5552
+ valueType: literalToValueType(node.value),
5553
+ dependencies: [],
5554
+ ...typeof node.value === "string" ? { literalString: node.value } : {}
5555
+ };
5556
+ case "path":
5557
+ return inferPath(node.parts, schema);
5558
+ case "call":
5559
+ return inferCall(node.functionName, node.args, schema);
5560
+ case "binary":
5561
+ return inferBinary(
5562
+ node.operator,
5563
+ inferNode(node.left, schema),
5564
+ inferNode(node.right, schema)
5565
+ );
5566
+ default: {
5567
+ const exhaustive = node;
5568
+ return exhaustive;
5569
+ }
5570
+ }
5571
+ }
5572
+ function literalToValueType(value) {
5573
+ switch (typeof value) {
5574
+ case "string":
5575
+ return { kind: "scalar", type: "text" };
5576
+ case "number":
5577
+ return { kind: "scalar", type: "number" };
5578
+ case "boolean":
5579
+ return { kind: "scalar", type: "boolean" };
5580
+ case "object":
5581
+ return { kind: "scalar", type: "text" };
5582
+ default: {
5583
+ const exhaustive = value;
5584
+ return exhaustive;
5585
+ }
5586
+ }
5587
+ }
5588
+ function inferPath(parts, schema) {
5589
+ if (parts.length === 1) {
5590
+ const attributeName = parts[0];
5591
+ const attribute = findAttribute(schema, attributeName);
5592
+ if (attribute === void 0) {
5593
+ throw new ComputedFormulaCompileError(
5594
+ `Unknown attribute "${attributeName}" on object "${schema.objectName}"`
5595
+ );
5596
+ }
5597
+ if (attribute.type === "relation") {
5598
+ return {
5599
+ valueType: relationToValueType(),
5600
+ dependencies: [
5601
+ {
5602
+ kind: "relation",
5603
+ relationName: attribute.name,
5604
+ cardinality: relationCardinality(attribute)
5605
+ }
5606
+ ],
5607
+ targetAttributeType: attribute.type
5608
+ };
5609
+ }
5610
+ return {
5611
+ valueType: attributeToValueType(attribute),
5612
+ dependencies: [localDependencyFor(attribute)],
5613
+ optionsSource: optionsSourceForAttribute(schema.objectName, attribute),
5614
+ targetAttributeType: attribute.type
5615
+ };
5616
+ }
5617
+ if (parts.length === 2) {
5618
+ const [relationName, targetAttributeName] = parts;
5619
+ const relation2 = findAttribute(schema, relationName);
5620
+ if (relation2 === void 0) {
5621
+ throw new ComputedFormulaCompileError(
5622
+ `Unknown attribute "${relationName}" on object "${schema.objectName}"`
5623
+ );
5624
+ }
5625
+ if (relation2.type !== "relation") {
5626
+ throw new ComputedFormulaCompileError(
5627
+ `Attribute "${relationName}" on object "${schema.objectName}" is not a relation`
5628
+ );
5629
+ }
5630
+ const targetObjectName = getRelationTargetObjectName(relation2);
5631
+ if (targetObjectName === void 0) {
5632
+ throw new ComputedFormulaCompileError(
5633
+ `Relation "${relationName}" on object "${schema.objectName}" is missing targetObjectName`
5634
+ );
5635
+ }
5636
+ const targetObject = schema.relatedObjects?.[targetObjectName];
5637
+ if (targetObject === void 0) {
5638
+ throw new ComputedFormulaCompileError(`Unknown related object "${targetObjectName}"`);
5639
+ }
5640
+ const targetAttribute = findAttribute(targetObject, targetAttributeName);
5641
+ if (targetAttribute === void 0) {
5642
+ throw new ComputedFormulaCompileError(
5643
+ `Unknown attribute "${targetAttributeName}" on object "${targetObject.objectName}"`
5644
+ );
5645
+ }
5646
+ const targetValueType = attributeToValueType(targetAttribute);
5647
+ return {
5648
+ valueType: relation2.cardinality === "many" ? asCollectionValueType(targetValueType) : targetValueType,
5649
+ dependencies: [
5650
+ {
5651
+ kind: "relation",
5652
+ relationName,
5653
+ targetAttributeName,
5654
+ cardinality: relationCardinality(relation2)
5655
+ }
5656
+ ],
5657
+ optionsSource: optionsSourceForAttribute(targetObject.objectName, targetAttribute),
5658
+ targetAttributeType: targetAttribute.type
5659
+ };
5660
+ }
5661
+ throw new ComputedFormulaCompileError("Computed paths support at most one relation hop");
5662
+ }
5663
+ function findAttribute(object2, attributeName) {
5664
+ return object2.attributes.find((attribute) => attribute.name === attributeName);
5665
+ }
5666
+ function getRelationTargetObjectName(attribute) {
5667
+ if (attribute.targetObjectName !== void 0) {
5668
+ return attribute.targetObjectName;
5669
+ }
5670
+ if (attribute.targets?.length === 1) {
5671
+ const [target] = attribute.targets;
5672
+ return target?.object === "*" ? void 0 : target?.object;
5673
+ }
5674
+ return void 0;
5675
+ }
5676
+ function relationCardinality(attribute) {
5677
+ return attribute.cardinality ?? "one";
5678
+ }
5679
+ function localDependencyFor(attribute) {
5680
+ if (attribute.type === "formula" || attribute.type === "rollup") {
5681
+ return { kind: "computed", attributeName: attribute.name };
5682
+ }
5683
+ return { kind: "local", attributeName: attribute.name };
5684
+ }
5685
+ function attributeToValueType(attribute) {
5686
+ if (attribute.type === "formula" || attribute.type === "rollup") {
5687
+ if (attribute.returnType === void 0) {
5688
+ throw new ComputedFormulaCompileError(
5689
+ `Computed attribute "${attribute.name}" is missing returnType`
5690
+ );
5691
+ }
5692
+ return returnTypeToValueType(attribute.returnType);
5693
+ }
5694
+ switch (attribute.type) {
5695
+ case "number":
5696
+ case "currency":
5697
+ return { kind: "scalar", type: "number" };
5698
+ case "checkbox":
5699
+ return { kind: "scalar", type: "boolean" };
5700
+ case "date":
5701
+ return { kind: "scalar", type: "date" };
5702
+ case "select":
5703
+ case "status":
5704
+ return { kind: "scalar", type: "select" };
5705
+ case "multiselect":
5706
+ return { kind: "collection", itemType: "select" };
5707
+ case "text":
5708
+ case "richtext":
5709
+ case "phone":
5710
+ case "file":
5711
+ case "user":
5712
+ case "location":
5713
+ case "relation":
5714
+ case "document":
5715
+ return { kind: "scalar", type: "text" };
5716
+ default: {
5717
+ const exhaustive = attribute.type;
5718
+ return exhaustive;
5719
+ }
5720
+ }
5721
+ }
5722
+ function relationToValueType() {
5723
+ return { kind: "collection", itemType: "text" };
5724
+ }
5725
+ function returnTypeToValueType(returnType) {
5726
+ if (returnType === "multiselect") {
5727
+ return { kind: "collection", itemType: "select" };
5728
+ }
5729
+ return { kind: "scalar", type: returnType };
5730
+ }
5731
+ function asCollectionValueType(valueType) {
5732
+ if (valueType.kind === "collection") {
5733
+ return valueType;
5734
+ }
5735
+ return { kind: "collection", itemType: valueType.type };
5736
+ }
5737
+ function optionsSourceForAttribute(objectName, attribute) {
5738
+ if (attribute.type === "formula" || attribute.type === "rollup") {
5739
+ if (!isSelectLikeReturnType(attribute.returnType)) {
5740
+ return void 0;
5741
+ }
5742
+ return attribute.optionsSource;
5743
+ }
5744
+ if (attribute.type !== "select" && attribute.type !== "status" && attribute.type !== "multiselect") {
5745
+ return void 0;
5746
+ }
5747
+ return attribute.optionsSource ?? {
5748
+ objectName,
5749
+ attributeName: attribute.name,
5750
+ ...attribute.id ? { attributeId: attribute.id } : {}
5751
+ };
5752
+ }
5753
+ function inferCall(functionName, args, schema) {
5754
+ if (!isComputedFunctionName(functionName)) {
5755
+ throw new ComputedFormulaCompileError(`Unknown computed function "${functionName}"`);
5756
+ }
5757
+ const signature = COMPUTED_FUNCTIONS[functionName];
5758
+ if (args.length < signature.minArgs || signature.maxArgs !== void 0 && args.length > signature.maxArgs) {
5759
+ const expected = signature.maxArgs === void 0 || signature.maxArgs === signature.minArgs ? String(signature.minArgs) : `${signature.minArgs}-${signature.maxArgs}`;
5760
+ throw new ComputedFormulaCompileError(
5761
+ `Function "${functionName}" expects ${expected} arguments, received ${args.length}`
5762
+ );
5763
+ }
5764
+ const inferredArgs = args.map((arg) => inferNode(arg, schema));
5765
+ return inferFunctionReturn(functionName, inferredArgs);
5766
+ }
5767
+ function inferFunctionReturn(functionName, args) {
5768
+ const dependencies = uniqueDependencies(args.flatMap((arg) => arg.dependencies));
5769
+ switch (functionName) {
5770
+ case "if":
5771
+ return inferIfFunction(args, dependencies);
5772
+ case "concat":
5773
+ ensureNoCollections(args, `Function "${functionName}" does not accept collection values`);
5774
+ return { valueType: { kind: "scalar", type: "text" }, dependencies };
5775
+ case "sum":
5776
+ case "avg":
5777
+ ensureNumericCollectionOrScalar(functionName, args[0]);
5778
+ return { valueType: { kind: "scalar", type: "number" }, dependencies };
5779
+ case "count":
5780
+ case "count_empty":
5781
+ case "count_not_empty":
5782
+ case "count_unique":
5783
+ case "percent_empty":
5784
+ case "percent_not_empty":
5785
+ if (functionName === "count_unique") {
5786
+ ensureUniqueCountSource(args[0]);
5787
+ } else {
5788
+ ensureCollectionSource(functionName, args[0]);
5789
+ }
5790
+ return { valueType: { kind: "scalar", type: "number" }, dependencies };
5791
+ case "min":
5792
+ case "max":
5793
+ ensureMinMaxSource(functionName, args[0]);
5794
+ return {
5795
+ valueType: sourceItemValueType(args[0]),
5796
+ dependencies,
5797
+ optionsSource: args[0].optionsSource,
5798
+ targetAttributeType: args[0].targetAttributeType
5799
+ };
5800
+ case "earliest":
5801
+ case "latest":
5802
+ ensureDateCollectionOrScalar(functionName, args[0]);
5803
+ return {
5804
+ valueType: { kind: "scalar", type: "date" },
5805
+ dependencies,
5806
+ targetAttributeType: args[0].targetAttributeType
5807
+ };
5808
+ case "unique":
5809
+ return inferUniqueFunction(args[0], dependencies);
5810
+ case "first":
5811
+ return inferFirstFunction(args[0], dependencies);
5812
+ default: {
5813
+ const exhaustive = functionName;
5814
+ return exhaustive;
5815
+ }
5816
+ }
5817
+ }
5818
+ function inferIfFunction(args, dependencies) {
5819
+ ensureScalarType(args[0].valueType, "boolean", 'Function "if" condition must be boolean');
5820
+ const thenValue = args[1];
5821
+ const elseValue = args[2];
5822
+ const valueType = resolveIfBranchValueType(thenValue, elseValue);
5823
+ const optionsSource = resolveIfOptionsSource(thenValue, elseValue);
5824
+ if (valueType === void 0) {
5825
+ throw new ComputedFormulaCompileError('Function "if" branches must return the same type');
5826
+ }
5827
+ return {
5828
+ valueType,
5829
+ dependencies,
5830
+ ...optionsSource ? { optionsSource } : {},
5831
+ targetAttributeType: thenValue.targetAttributeType ?? elseValue.targetAttributeType
5832
+ };
5833
+ }
5834
+ function inferUniqueFunction(source, dependencies) {
5835
+ if (source.valueType.kind !== "collection" || source.valueType.itemType !== "select") {
5836
+ throw new ComputedFormulaCompileError('Function "unique" expects a select collection');
5837
+ }
5838
+ return {
5839
+ valueType: { kind: "collection", itemType: "select" },
5840
+ dependencies,
5841
+ optionsSource: source.optionsSource,
5842
+ targetAttributeType: source.targetAttributeType
5843
+ };
5844
+ }
5845
+ function inferFirstFunction(source, dependencies) {
5846
+ if (source.valueType.kind !== "collection") {
5847
+ throw new ComputedFormulaCompileError('Function "first" expects a collection');
5848
+ }
5849
+ return {
5850
+ valueType: { kind: "scalar", type: source.valueType.itemType },
5851
+ dependencies,
5852
+ optionsSource: source.optionsSource,
5853
+ targetAttributeType: source.targetAttributeType
5854
+ };
5855
+ }
5856
+ function inferBinary(operator, left, right) {
5857
+ const dependencies = uniqueDependencies([...left.dependencies, ...right.dependencies]);
5858
+ if (operator === "+" || operator === "-" || operator === "*" || operator === "/") {
5859
+ if (left.valueType.kind === "collection" || right.valueType.kind === "collection") {
5860
+ throw new ComputedFormulaCompileError(
5861
+ `Cannot use collection values with arithmetic operator "${operator}"`
5862
+ );
5863
+ }
5864
+ if (operator === "+" && (left.valueType.type === "text" || right.valueType.type === "text")) {
5865
+ return { valueType: { kind: "scalar", type: "text" }, dependencies };
5866
+ }
5867
+ ensureScalarType(left.valueType, "number", `Operator "${operator}" expects number operands`);
5868
+ ensureScalarType(right.valueType, "number", `Operator "${operator}" expects number operands`);
5869
+ return { valueType: { kind: "scalar", type: "number" }, dependencies };
5870
+ }
5871
+ if (left.valueType.kind === "collection" || right.valueType.kind === "collection") {
5872
+ throw new ComputedFormulaCompileError(
5873
+ `Cannot use collection values with comparison operator "${operator}"`
5874
+ );
5875
+ }
5876
+ if (operator === "==" || operator === "!=") {
5877
+ if (left.valueType.type !== right.valueType.type) {
5878
+ throw new ComputedFormulaCompileError(
5879
+ `Operator "${operator}" expects operands with the same scalar type`
5880
+ );
5881
+ }
5882
+ return { valueType: { kind: "scalar", type: "boolean" }, dependencies };
5883
+ }
5884
+ if ((left.valueType.type !== "number" || right.valueType.type !== "number") && (left.valueType.type !== "date" || right.valueType.type !== "date")) {
5885
+ throw new ComputedFormulaCompileError(
5886
+ `Operator "${operator}" expects number or date operands of the same type`
5887
+ );
5888
+ }
5889
+ return { valueType: { kind: "scalar", type: "boolean" }, dependencies };
5890
+ }
5891
+ function ensureNoCollections(args, message) {
5892
+ for (const arg of args) {
5893
+ if (arg.valueType.kind === "collection") {
5894
+ throw new ComputedFormulaCompileError(message);
5895
+ }
5896
+ }
5897
+ }
5898
+ function ensureNumericCollectionOrScalar(functionName, expression) {
5899
+ const type = expression.valueType.kind === "collection" ? expression.valueType.itemType : expression.valueType.type;
5900
+ if (type !== "number") {
5901
+ throw new ComputedFormulaCompileError(`Function "${functionName}" expects number values`);
5902
+ }
5903
+ }
5904
+ function ensureDateCollectionOrScalar(functionName, expression) {
5905
+ const type = expression.valueType.kind === "collection" ? expression.valueType.itemType : expression.valueType.type;
5906
+ if (type !== "date") {
5907
+ throw new ComputedFormulaCompileError(`Function "${functionName}" expects date values`);
5908
+ }
5909
+ }
5910
+ function ensureMinMaxSource(functionName, expression) {
5911
+ if (expression.valueType.kind !== "collection") {
5912
+ throw new ComputedFormulaCompileError(`Function "${functionName}" expects a collection`);
5913
+ }
5914
+ const type = expression.valueType.itemType;
5915
+ if (type !== "number" && type !== "date") {
5916
+ throw new ComputedFormulaCompileError(
5917
+ `Function "${functionName}" expects number or date values`
5918
+ );
5919
+ }
5920
+ }
5921
+ function ensureCollectionSource(functionName, expression) {
5922
+ if (expression.valueType.kind !== "collection") {
5923
+ throw new ComputedFormulaCompileError(`Function "${functionName}" expects a collection`);
5924
+ }
5925
+ }
5926
+ function ensureUniqueCountSource(expression) {
5927
+ if (expression.valueType.kind !== "collection") {
5928
+ throw new ComputedFormulaCompileError('Function "count_unique" expects a collection');
5929
+ }
5930
+ }
5931
+ function ensureScalarType(valueType, expectedType, message) {
5932
+ if (valueType.kind !== "scalar" || valueType.type !== expectedType) {
5933
+ throw new ComputedFormulaCompileError(message);
5934
+ }
5935
+ }
5936
+ function sourceItemValueType(source) {
5937
+ if (source.valueType.kind === "scalar") {
5938
+ return source.valueType;
5939
+ }
5940
+ return { kind: "scalar", type: source.valueType.itemType };
5941
+ }
5942
+ function sameValueType(left, right) {
5943
+ if (left.kind === "scalar") {
5944
+ return right.kind === "scalar" && left.type === right.type;
5945
+ }
5946
+ return right.kind === "collection" && left.itemType === right.itemType;
5947
+ }
5948
+ function resolveIfBranchValueType(thenValue, elseValue) {
5949
+ if (sameValueType(thenValue.valueType, elseValue.valueType)) {
5950
+ return thenValue.valueType;
5951
+ }
5952
+ if (isSelectScalarWithStringLiteral(thenValue, elseValue)) {
5953
+ return thenValue.valueType;
5954
+ }
5955
+ if (isSelectScalarWithStringLiteral(elseValue, thenValue)) {
5956
+ return elseValue.valueType;
5957
+ }
5958
+ return void 0;
5959
+ }
5960
+ function isSelectScalarWithStringLiteral(selectValue, literalValue) {
5961
+ return selectValue.valueType.kind === "scalar" && selectValue.valueType.type === "select" && literalValue.valueType.kind === "scalar" && literalValue.valueType.type === "text" && literalValue.literalString !== void 0;
5962
+ }
5963
+ function resolveIfOptionsSource(thenValue, elseValue) {
5964
+ const thenSource = thenValue.optionsSource;
5965
+ const elseSource = elseValue.optionsSource;
5966
+ if (thenSource !== void 0 && elseSource !== void 0 && !sameOptionsSource(thenSource, elseSource)) {
5967
+ throw new ComputedFormulaCompileError(
5968
+ 'Function "if" branches use incompatible options sources'
5969
+ );
5970
+ }
5971
+ return thenSource ?? elseSource;
5972
+ }
5973
+ function sameOptionsSource(left, right) {
5974
+ return left.objectName === right.objectName && left.attributeName === right.attributeName && left.attributeId === right.attributeId;
5975
+ }
5976
+ function isSelectLikeReturnType(returnType) {
5977
+ return returnType === "select" || returnType === "multiselect";
5978
+ }
5979
+ function valueTypeToReturnType(valueType) {
5980
+ if (valueType.kind === "scalar") {
5981
+ return valueType.type;
5982
+ }
5983
+ if (valueType.itemType === "select") {
5984
+ return "multiselect";
5985
+ }
5986
+ throw new ComputedFormulaCompileError(
5987
+ `Collection item type "${valueType.itemType}" cannot be used as a computed return type`
5988
+ );
5989
+ }
5990
+ function uniqueDependencies(dependencies) {
5991
+ const seen = /* @__PURE__ */ new Set();
5992
+ const unique = [];
5993
+ for (const dependency of dependencies) {
5994
+ const key = JSON.stringify(stableNormalize(dependency));
5995
+ if (!seen.has(key)) {
5996
+ seen.add(key);
5997
+ unique.push(dependency);
5998
+ }
5999
+ }
6000
+ return unique;
6001
+ }
6002
+ function createDependenciesHash(input) {
6003
+ const sortedDependencies = input.dependencies.map((dependency) => stableNormalize(dependency)).sort((left, right) => compareStrings(JSON.stringify(left), JSON.stringify(right)));
6004
+ return JSON.stringify(
6005
+ stableNormalize({
6006
+ expression: input.expression,
6007
+ returnType: input.returnType,
6008
+ dependencies: sortedDependencies
6009
+ })
6010
+ );
6011
+ }
6012
+ function stableNormalize(value) {
6013
+ if (Array.isArray(value)) {
6014
+ return value.map((item) => stableNormalize(item));
6015
+ }
6016
+ if (value !== null && typeof value === "object") {
6017
+ return Object.fromEntries(
6018
+ Object.entries(value).filter(([, item]) => item !== void 0).sort(([left], [right]) => compareStrings(left, right)).map(([key, item]) => [key, stableNormalize(item)])
6019
+ );
6020
+ }
6021
+ return value;
6022
+ }
6023
+ function compareStrings(left, right) {
6024
+ if (left < right) {
6025
+ return -1;
6026
+ }
6027
+ if (left > right) {
6028
+ return 1;
6029
+ }
6030
+ return 0;
6031
+ }
6032
+
6033
+ // src/computed/rollup-compiler.ts
6034
+ function rollupToFormulaExpression(attr) {
6035
+ if (attr.function === "count") {
6036
+ return `count(${attr.relationAttribute})`;
6037
+ }
6038
+ return `${rollupFunctionToFormulaFunction(attr.function)}(${attr.relationAttribute}.${attr.targetAttribute})`;
6039
+ }
6040
+ function inferRollupReturnType(attr, schema) {
6041
+ if (attr.function === "count") {
6042
+ return "number";
6043
+ }
6044
+ const targetAttribute = findRollupTargetAttribute(attr, schema);
6045
+ switch (attr.function) {
6046
+ case "countValues":
6047
+ case "countEmpty":
6048
+ case "percentEmpty":
6049
+ case "percentNotEmpty":
6050
+ case "countUniqueValues":
6051
+ return "number";
6052
+ case "sum":
6053
+ case "avg":
6054
+ return "number";
6055
+ case "earliest":
6056
+ case "latest":
6057
+ return "date";
6058
+ case "original":
6059
+ if (!isSelectLikeAttributeType(targetAttribute.type)) {
6060
+ throw new ComputedFormulaCompileError(
6061
+ `Rollup "original" requires a select, status, or multiselect target`
6062
+ );
6063
+ }
6064
+ return "multiselect";
6065
+ default: {
6066
+ const exhaustive = attr.function;
6067
+ return exhaustive;
6068
+ }
6069
+ }
6070
+ }
6071
+ function compileRollupAttribute(attr, schema) {
6072
+ const expression = rollupToFormulaExpression(attr);
6073
+ const returnType = inferRollupReturnType(attr, schema);
6074
+ const plan = compileComputedFormula({
6075
+ attributeName: attr.name,
6076
+ expression,
6077
+ returnType,
6078
+ schema: schemaWithRollupRelationAsMany(attr, schema)
6079
+ });
6080
+ return {
6081
+ ...plan,
6082
+ kind: "rollup"
6083
+ };
6084
+ }
6085
+ function schemaWithRollupRelationAsMany(attr, schema) {
6086
+ return {
6087
+ ...schema,
6088
+ attributes: schema.attributes.map(
6089
+ (attribute) => attribute.name === attr.relationAttribute && attribute.type === "relation" ? { ...attribute, cardinality: "many" } : attribute
6090
+ )
6091
+ };
6092
+ }
6093
+ function rollupFunctionToFormulaFunction(functionName) {
6094
+ switch (functionName) {
6095
+ case "sum":
6096
+ case "avg":
6097
+ case "earliest":
6098
+ case "latest":
6099
+ return functionName;
6100
+ case "original":
6101
+ return "unique";
6102
+ case "countValues":
6103
+ return "count_not_empty";
6104
+ case "countEmpty":
6105
+ return "count_empty";
6106
+ case "percentEmpty":
6107
+ return "percent_empty";
6108
+ case "percentNotEmpty":
6109
+ return "percent_not_empty";
6110
+ case "countUniqueValues":
6111
+ return "count_unique";
6112
+ default: {
6113
+ const exhaustive = functionName;
6114
+ return exhaustive;
6115
+ }
6116
+ }
6117
+ }
6118
+ function findRollupTargetAttribute(attr, schema) {
6119
+ const relation2 = findAttribute2(schema, attr.relationAttribute);
6120
+ if (relation2 === void 0) {
6121
+ throw new ComputedFormulaCompileError(
6122
+ `Unknown relation attribute "${attr.relationAttribute}" on object "${schema.objectName}"`
6123
+ );
6124
+ }
6125
+ if (relation2.type !== "relation") {
6126
+ throw new ComputedFormulaCompileError(
6127
+ `Attribute "${attr.relationAttribute}" on object "${schema.objectName}" is not a relation`
6128
+ );
6129
+ }
6130
+ const targetObjectName = getRelationTargetObjectName2(relation2);
6131
+ if (targetObjectName === void 0) {
6132
+ throw new ComputedFormulaCompileError(
6133
+ `Relation "${attr.relationAttribute}" on object "${schema.objectName}" is missing targetObjectName`
6134
+ );
6135
+ }
6136
+ const targetObject = schema.relatedObjects?.[targetObjectName];
6137
+ if (targetObject === void 0) {
6138
+ throw new ComputedFormulaCompileError(`Unknown related object "${targetObjectName}"`);
6139
+ }
6140
+ const targetAttribute = findAttribute2(targetObject, attr.targetAttribute);
6141
+ if (targetAttribute === void 0) {
6142
+ throw new ComputedFormulaCompileError(
6143
+ `Unknown attribute "${attr.targetAttribute}" on object "${targetObject.objectName}"`
6144
+ );
6145
+ }
6146
+ return targetAttribute;
6147
+ }
6148
+ function findAttribute2(object2, attributeName) {
6149
+ return object2.attributes.find((attribute) => attribute.name === attributeName);
6150
+ }
6151
+ function getRelationTargetObjectName2(attribute) {
6152
+ if (attribute.targetObjectName !== void 0) {
6153
+ return attribute.targetObjectName;
6154
+ }
6155
+ if (attribute.targets?.length === 1) {
6156
+ const [target] = attribute.targets;
6157
+ return target?.object === "*" ? void 0 : target?.object;
6158
+ }
6159
+ return void 0;
6160
+ }
6161
+ function isSelectLikeAttributeType(type) {
6162
+ return type === "select" || type === "status" || type === "multiselect";
6163
+ }
6164
+
6165
+ // src/computed/evaluator.ts
6166
+ function evaluateAst(node, input) {
6167
+ switch (node.kind) {
6168
+ case "literal":
6169
+ return node.value;
6170
+ case "path":
6171
+ return resolvePath(input, node.parts);
6172
+ case "binary":
6173
+ return evaluateBinary(
6174
+ node.operator,
6175
+ evaluateAst(node.left, input),
6176
+ evaluateAst(node.right, input)
6177
+ );
6178
+ case "call":
6179
+ return evaluateCallNode(node.functionName, node.args, input);
6180
+ default:
6181
+ return unreachable(node);
6182
+ }
6183
+ }
6184
+ function evaluateCallNode(functionName, args, input) {
6185
+ assertComputedFunctionName(functionName);
6186
+ validateArity(functionName, args.length);
6187
+ if (functionName === "if") {
6188
+ return evaluateAst(args[0], input) ? evaluateAst(args[1], input) : evaluateAst(args[2], input);
6189
+ }
6190
+ return evaluateCall(
6191
+ functionName,
6192
+ args.map((arg) => evaluateAst(arg, input))
6193
+ );
6194
+ }
6195
+ function resolvePath(input, parts) {
6196
+ return parts.reduce((value, part) => resolvePathPart(value, part), input);
6197
+ }
6198
+ function resolvePathPart(value, part) {
6199
+ if (Array.isArray(value)) {
6200
+ return value.map((item) => resolvePathPart(item, part));
6201
+ }
6202
+ if (!isPlainRecord(value)) {
6203
+ return null;
6204
+ }
6205
+ if (Object.hasOwn(value, part)) {
6206
+ return value[part] ?? null;
4660
6207
  }
4661
- let order = 1;
4662
- for (const tab of preservedTabs) {
4663
- result.push({ ...tab, order: order++ });
6208
+ const nestedValues = value.values;
6209
+ if (isPlainRecord(nestedValues) && Object.hasOwn(nestedValues, part)) {
6210
+ return nestedValues[part] ?? null;
4664
6211
  }
4665
- for (const tab of otherTabs) {
4666
- result.push({ ...tab, order: order++ });
6212
+ return null;
6213
+ }
6214
+ function evaluateBinary(operator, left, right) {
6215
+ switch (operator) {
6216
+ case "+":
6217
+ return add(left, right);
6218
+ case "-":
6219
+ return numericBinary(left, right, (leftNumber, rightNumber) => leftNumber - rightNumber);
6220
+ case "*":
6221
+ return numericBinary(left, right, (leftNumber, rightNumber) => leftNumber * rightNumber);
6222
+ case "/":
6223
+ return numericBinary(left, right, (leftNumber, rightNumber) => leftNumber / rightNumber);
6224
+ case ">":
6225
+ return compareWith(left, right, (result) => result > 0);
6226
+ case "<":
6227
+ return compareWith(left, right, (result) => result < 0);
6228
+ case ">=":
6229
+ return compareWith(left, right, (result) => result >= 0);
6230
+ case "<=":
6231
+ return compareWith(left, right, (result) => result <= 0);
6232
+ case "==":
6233
+ return equalScalar(left, right);
6234
+ case "!=":
6235
+ return !equalScalar(left, right);
6236
+ default:
6237
+ return unreachable(operator);
4667
6238
  }
4668
- return result;
4669
6239
  }
4670
- function resetDetailViewToDefault(view, object2, options) {
4671
- const { preserveMetadata = true, ...generateOptions } = options;
4672
- const defaultView = generateDefaultDetailView(object2, generateOptions);
4673
- const preservedTabs = getPreservedDetailTabs(view, options);
4674
- const mergedTabs = mergeDetailTabs(defaultView.config.tabs, preservedTabs);
4675
- const config = {
4676
- ...defaultView.config,
4677
- tabs: mergedTabs
4678
- };
4679
- const resetView = {
4680
- ...defaultView,
4681
- config
4682
- };
4683
- if (preserveMetadata) {
4684
- resetView.id = view.id;
4685
- resetView.name = view.name;
4686
- resetView.label = view.label;
4687
- resetView.description = view.description;
4688
- resetView.icon = view.icon;
6240
+ function add(left, right) {
6241
+ if (typeof left === "string" || typeof right === "string") {
6242
+ return `${left ?? ""}${right ?? ""}`;
4689
6243
  }
4690
- return resetView;
6244
+ return numericBinary(left, right, (leftNumber, rightNumber) => leftNumber + rightNumber);
4691
6245
  }
4692
- function resetListViewToDefault(view, object2, options) {
4693
- const { preserveMetadata = true, ...generateOptions } = options;
4694
- const defaultView = generateDefaultListView(object2, generateOptions);
4695
- const resetView = {
4696
- ...defaultView
4697
- };
4698
- if (preserveMetadata) {
4699
- resetView.id = view.id;
4700
- resetView.name = view.name;
4701
- resetView.label = view.label;
4702
- resetView.description = view.description;
4703
- resetView.icon = view.icon;
6246
+ function compareWith(left, right, predicate) {
6247
+ const result = compare(left, right);
6248
+ return result === null ? null : predicate(result);
6249
+ }
6250
+ function compare(left, right) {
6251
+ const leftNumber = toFiniteNumber(left);
6252
+ const rightNumber = toFiniteNumber(right);
6253
+ if (leftNumber !== null && rightNumber !== null) {
6254
+ return leftNumber - rightNumber;
4704
6255
  }
4705
- return resetView;
6256
+ const leftDate = toDate(left);
6257
+ const rightDate = toDate(right);
6258
+ return leftDate && rightDate ? leftDate.getTime() - rightDate.getTime() : null;
4706
6259
  }
4707
- function resetViewToDefault(currentView, object2, options = {}) {
4708
- if (isDetailView(currentView)) {
4709
- return resetDetailViewToDefault(currentView, object2, options);
6260
+ function equalScalar(left, right) {
6261
+ if (left === right) {
6262
+ return true;
4710
6263
  }
4711
- if (isListView(currentView)) {
4712
- return resetListViewToDefault(currentView, object2, options);
6264
+ if (left === null || left === void 0 || right === null || right === void 0) {
6265
+ return false;
4713
6266
  }
4714
- throw new Error(`Reset not supported for view type: ${currentView.type}`);
6267
+ return compare(left, right) === 0;
4715
6268
  }
4716
-
4717
- // src/views/index.ts
4718
- function getActiveTab(config, tabId) {
4719
- if (tabId) {
4720
- const tab = config.tabs.find((t) => t.id === tabId);
4721
- if (tab) return tab;
6269
+ function assertComputedFunctionName(name) {
6270
+ if (!isComputedFunctionName(name)) {
6271
+ throw new Error(`Unknown computed function "${name}"`);
4722
6272
  }
4723
- return config.tabs.find((t) => t.default) ?? config.tabs[0];
4724
6273
  }
4725
-
4726
- // src/forms/registry.ts
4727
- var FormRegistry = class {
4728
- constructor() {
4729
- this.forms = /* @__PURE__ */ new Map();
4730
- }
4731
- /**
4732
- * Register a form definition (or array of definitions).
4733
- * @throws Error if a form with the same name is already registered.
4734
- */
4735
- register(formOrForms) {
4736
- const forms = Array.isArray(formOrForms) ? formOrForms : [formOrForms];
4737
- for (const f of forms) {
4738
- if (this.forms.has(f.name)) {
4739
- throw new Error(`[FormRegistry] Duplicate form: "${f.name}"`);
4740
- }
4741
- this.forms.set(f.name, f);
4742
- }
4743
- return this;
4744
- }
4745
- /**
4746
- * Get a form definition by name.
4747
- */
4748
- get(name) {
4749
- return this.forms.get(name);
6274
+ function validateArity(functionName, actual) {
6275
+ const { minArgs, maxArgs } = COMPUTED_FUNCTIONS[functionName];
6276
+ if (actual >= minArgs && actual <= (maxArgs ?? Number.POSITIVE_INFINITY)) {
6277
+ return;
4750
6278
  }
4751
- /**
4752
- * Get all registered form definitions.
4753
- */
4754
- getAll() {
4755
- return Array.from(this.forms.values());
6279
+ const range = maxArgs === void 0 ? `at least ${minArgs}` : `between ${minArgs} and ${maxArgs}`;
6280
+ throw new Error(`Function "${functionName}" expects ${range} arguments, received ${actual}`);
6281
+ }
6282
+ function evaluateCall(functionName, args) {
6283
+ switch (functionName) {
6284
+ case "concat":
6285
+ return args.filter((arg) => arg !== null && arg !== void 0).map(String).join("");
6286
+ case "sum":
6287
+ return numericValues(args).reduce((total, value) => total + value, 0);
6288
+ case "avg": {
6289
+ const values = numericValues(args);
6290
+ return values.length > 0 ? values.reduce((total, value) => total + value, 0) / values.length : null;
6291
+ }
6292
+ case "count":
6293
+ return collectionItems(args[0]).length;
6294
+ case "min":
6295
+ return minMax(args, "min");
6296
+ case "max":
6297
+ return minMax(args, "max");
6298
+ case "earliest":
6299
+ return dateMinMax(args, "min");
6300
+ case "latest":
6301
+ return dateMinMax(args, "max");
6302
+ case "unique":
6303
+ return uniqueNonEmpty(collectionItems(args[0]));
6304
+ case "first":
6305
+ return collectionItems(args[0]).find((item) => item !== null && item !== void 0) ?? null;
6306
+ case "percent_empty":
6307
+ return percentByEmptyState(args[0], true);
6308
+ case "percent_not_empty":
6309
+ return percentByEmptyState(args[0], false);
6310
+ case "count_empty":
6311
+ return collectionItems(args[0]).filter(isEmptyValue).length;
6312
+ case "count_not_empty":
6313
+ return collectionItems(args[0]).filter((item) => !isEmptyValue(item)).length;
6314
+ case "count_unique":
6315
+ return uniqueNonEmpty(collectionItems(args[0])).length;
6316
+ default:
6317
+ return unreachable(functionName);
4756
6318
  }
4757
- /**
4758
- * List all registered form names.
4759
- */
4760
- listNames() {
4761
- return Array.from(this.forms.keys());
6319
+ }
6320
+ function unreachable(value) {
6321
+ return value;
6322
+ }
6323
+ function numericValues(values) {
6324
+ return flatten(values).map(toFiniteNumber).filter((value) => value !== null);
6325
+ }
6326
+ function numericBinary(left, right, operation) {
6327
+ const leftNumber = toFiniteNumber(left);
6328
+ const rightNumber = toFiniteNumber(right);
6329
+ if (leftNumber === null || rightNumber === null) {
6330
+ return null;
4762
6331
  }
4763
- };
4764
- var formRegistry = new FormRegistry();
4765
- var DOS_PROTECTION_LIMITS = {
4766
- MAX_EXPRESSION_LENGTH: 1e4,
4767
- MAX_TOKEN_COUNT: 1e3,
4768
- MAX_NESTING_DEPTH: 50
4769
- };
4770
- function createFormulaParser() {
4771
- const parser = new exprEval.Parser();
4772
- parser.functions.IF = (condition, thenValue, elseValue) => condition ? thenValue : elseValue;
4773
- parser.functions.AND = (...args) => args.every(Boolean);
4774
- parser.functions.OR = (...args) => args.some(Boolean);
4775
- parser.functions.NOT = (value) => !value;
4776
- parser.functions.EMPTY = (value) => value === null || value === void 0 || value === "";
4777
- parser.functions.COALESCE = (...args) => args.find((a) => a != null) ?? null;
4778
- parser.functions.DEFAULT = (value, defaultValue) => value == null || value === "" ? defaultValue : value;
4779
- parser.functions.CONCAT = (...args) => args.filter((a) => a != null).map(String).join("");
4780
- parser.functions.UPPER = (value) => String(value ?? "").toUpperCase();
4781
- parser.functions.LOWER = (value) => String(value ?? "").toLowerCase();
4782
- parser.functions.TRIM = (value) => String(value ?? "").trim();
4783
- parser.functions.LENGTH = (value) => String(value ?? "").length;
4784
- parser.functions.LEFT = (value, count) => String(value ?? "").slice(0, count);
4785
- parser.functions.RIGHT = (value, count) => String(value ?? "").slice(-count);
4786
- parser.functions.REPLACE = (value, search, replacement) => String(value ?? "").split(String(search)).join(replacement);
4787
- parser.functions.CONTAINS = (value, search) => String(value ?? "").toLowerCase().includes(String(search).toLowerCase());
4788
- parser.functions.ROUND = (value, decimals = 0) => {
4789
- if (typeof value !== "number" || Number.isNaN(value)) return null;
4790
- const factor = 10 ** decimals;
4791
- return Math.round(value * factor) / factor;
4792
- };
4793
- parser.functions.FLOOR = (value) => {
4794
- if (typeof value !== "number" || Number.isNaN(value)) return null;
4795
- return Math.floor(value);
4796
- };
4797
- parser.functions.CEIL = (value) => {
4798
- if (typeof value !== "number" || Number.isNaN(value)) return null;
4799
- return Math.ceil(value);
4800
- };
4801
- parser.functions.ABS = (value) => {
4802
- if (typeof value !== "number" || Number.isNaN(value)) return null;
4803
- return Math.abs(value);
4804
- };
4805
- parser.functions.MIN = (...args) => {
4806
- const nums = args.filter((n) => typeof n === "number" && !Number.isNaN(n));
4807
- return nums.length > 0 ? Math.min(...nums) : null;
4808
- };
4809
- parser.functions.MAX = (...args) => {
4810
- const nums = args.filter((n) => typeof n === "number" && !Number.isNaN(n));
4811
- return nums.length > 0 ? Math.max(...nums) : null;
4812
- };
4813
- parser.functions.POW = (base, exponent) => {
4814
- if (typeof base !== "number" || typeof exponent !== "number") return null;
4815
- if (exponent > 1e3 || exponent < -1e3) return null;
4816
- return base ** exponent;
4817
- };
4818
- parser.functions.MOD = (a, b) => {
4819
- if (typeof a !== "number" || typeof b !== "number" || b === 0) return null;
4820
- return a % b;
4821
- };
4822
- parser.functions.NOW = () => (/* @__PURE__ */ new Date()).toISOString();
4823
- parser.functions.TODAY = () => (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
4824
- parser.functions.YEAR = (value) => {
4825
- const date2 = parseDate(value);
4826
- return date2 ? date2.getFullYear() : null;
4827
- };
4828
- parser.functions.MONTH = (value) => {
4829
- const date2 = parseDate(value);
4830
- return date2 ? date2.getMonth() + 1 : null;
4831
- };
4832
- parser.functions.DAY = (value) => {
4833
- const date2 = parseDate(value);
4834
- return date2 ? date2.getDate() : null;
4835
- };
4836
- parser.functions.DATE_DIFF = (date1, date2, unit = "days") => {
4837
- const d1 = parseDate(date1);
4838
- const d2 = parseDate(date2);
4839
- if (d1 === null || d2 === null) return null;
4840
- const diffMs = d1.getTime() - d2.getTime();
4841
- const MS_PER_DAY = 1e3 * 60 * 60 * 24;
4842
- const conversions = {
4843
- years: MS_PER_DAY * 365,
4844
- months: MS_PER_DAY * 30,
4845
- weeks: MS_PER_DAY * 7,
4846
- days: MS_PER_DAY,
4847
- hours: 1e3 * 60 * 60,
4848
- minutes: 1e3 * 60
4849
- };
4850
- const divisor = conversions[unit] ?? MS_PER_DAY;
4851
- return diffMs / divisor;
4852
- };
4853
- return parser;
6332
+ const result = operation(leftNumber, rightNumber);
6333
+ return Number.isFinite(result) ? result : null;
4854
6334
  }
4855
- function parseDate(value) {
4856
- if (!value) return null;
4857
- if (value instanceof Date) return value;
4858
- if (typeof value === "string" || typeof value === "number") {
4859
- const date2 = new Date(value);
4860
- return Number.isNaN(date2.getTime()) ? null : date2;
6335
+ function minMax(values, mode) {
6336
+ const numbers = numericValues(values);
6337
+ if (numbers.length > 0) {
6338
+ return mode === "min" ? Math.min(...numbers) : Math.max(...numbers);
4861
6339
  }
4862
- return null;
6340
+ return dateMinMax(values, mode);
4863
6341
  }
4864
- var formulaParser = createFormulaParser();
4865
- function validateFormulaComplexity(expression) {
4866
- if (expression.length > DOS_PROTECTION_LIMITS.MAX_EXPRESSION_LENGTH) {
4867
- return {
4868
- valid: false,
4869
- error: `Expression too long (${expression.length} chars, max ${DOS_PROTECTION_LIMITS.MAX_EXPRESSION_LENGTH})`
4870
- };
6342
+ function dateMinMax(values, mode) {
6343
+ const dates = flatten(values).map(toDate).filter((date2) => date2 !== null);
6344
+ if (dates.length === 0) {
6345
+ return null;
4871
6346
  }
4872
- const nestingDepth = calculateNestingDepth(expression);
4873
- if (nestingDepth > DOS_PROTECTION_LIMITS.MAX_NESTING_DEPTH) {
4874
- return {
4875
- valid: false,
4876
- error: `Expression too deeply nested (${nestingDepth} levels, max ${DOS_PROTECTION_LIMITS.MAX_NESTING_DEPTH})`
4877
- };
6347
+ const timestamps = dates.map((date2) => date2.getTime());
6348
+ const timestamp = mode === "min" ? Math.min(...timestamps) : Math.max(...timestamps);
6349
+ return new Date(timestamp).toISOString();
6350
+ }
6351
+ function percentByEmptyState(value, countEmpty) {
6352
+ const items = collectionItems(value);
6353
+ if (items.length === 0) {
6354
+ return 0;
4878
6355
  }
4879
- try {
4880
- formulaParser.parse(expression);
4881
- const tokenCountApprox = estimateTokenCount(expression);
4882
- if (tokenCountApprox > DOS_PROTECTION_LIMITS.MAX_TOKEN_COUNT) {
4883
- return {
4884
- valid: false,
4885
- error: `Expression too complex (approx ${tokenCountApprox} tokens, max ${DOS_PROTECTION_LIMITS.MAX_TOKEN_COUNT})`
4886
- };
6356
+ const count = items.filter((item) => isEmptyValue(item) === countEmpty).length;
6357
+ return count / items.length;
6358
+ }
6359
+ function uniqueNonEmpty(values) {
6360
+ const seen = /* @__PURE__ */ new Set();
6361
+ const result = [];
6362
+ for (const value of values) {
6363
+ if (isEmptyValue(value)) {
6364
+ continue;
4887
6365
  }
4888
- return { valid: true };
4889
- } catch {
4890
- return { valid: true };
6366
+ const key = uniqueKey(value);
6367
+ if (seen.has(key)) {
6368
+ continue;
6369
+ }
6370
+ seen.add(key);
6371
+ result.push(value);
6372
+ }
6373
+ return result;
6374
+ }
6375
+ function collectionItems(value) {
6376
+ if (value === null || value === void 0) {
6377
+ return [];
4891
6378
  }
6379
+ return Array.isArray(value) ? flatten(value) : [value];
4892
6380
  }
4893
- function estimateTokenCount(expression) {
4894
- const tokens = expression.match(/-?\d+\.?\d*|[a-zA-Z_][a-zA-Z0-9_]*|[+\-*/(),.><=!&|]+|'(?:[^'\\]|\\.)*'/g) ?? [];
4895
- return tokens.length;
6381
+ function flatten(values) {
6382
+ return values.flat(Number.POSITIVE_INFINITY);
4896
6383
  }
4897
- function calculateNestingDepth(expression) {
4898
- let maxDepth = 0;
4899
- let currentDepth = 0;
4900
- for (const char of expression) {
4901
- if (char === "(") {
4902
- currentDepth++;
4903
- if (currentDepth > maxDepth) maxDepth = currentDepth;
4904
- } else if (char === ")") {
4905
- currentDepth--;
4906
- }
6384
+ function isEmptyValue(value) {
6385
+ return value === null || value === void 0 || value === "";
6386
+ }
6387
+ function toFiniteNumber(value) {
6388
+ if (typeof value === "number") {
6389
+ return Number.isFinite(value) ? value : null;
4907
6390
  }
4908
- return maxDepth;
6391
+ if (typeof value === "string" && value.trim() !== "") {
6392
+ const parsed = Number(value);
6393
+ return Number.isFinite(parsed) ? parsed : null;
6394
+ }
6395
+ return null;
4909
6396
  }
4910
- function evaluateFormula(expression, values) {
4911
- try {
4912
- const complexityCheck = validateFormulaComplexity(expression);
4913
- if (!complexityCheck.valid) {
4914
- console.warn(`[formula] Complexity limit violated: ${complexityCheck.error}`);
4915
- return null;
4916
- }
4917
- const parsed = formulaParser.parse(expression);
4918
- return parsed.evaluate(values);
4919
- } catch {
6397
+ function toDate(value) {
6398
+ if (value instanceof Date) {
6399
+ return Number.isNaN(value.getTime()) ? null : value;
6400
+ }
6401
+ if (typeof value !== "string") {
4920
6402
  return null;
4921
6403
  }
6404
+ const date2 = new Date(value);
6405
+ return Number.isNaN(date2.getTime()) ? null : date2;
4922
6406
  }
4923
- function evaluateFormulaWithResult(expression, values) {
4924
- try {
4925
- const complexityCheck = validateFormulaComplexity(expression);
4926
- if (!complexityCheck.valid) {
4927
- return { value: null, error: complexityCheck.error };
4928
- }
4929
- const parsed = formulaParser.parse(expression);
4930
- const value = parsed.evaluate(values);
4931
- return { value };
4932
- } catch (error) {
4933
- return { value: null, error: getErrorMessage(error) };
6407
+ function uniqueKey(value) {
6408
+ const numberValue = toFiniteNumber(value);
6409
+ if (numberValue !== null) {
6410
+ return `number:${numberValue}`;
4934
6411
  }
6412
+ if (value instanceof Date) {
6413
+ return `date:${value.toISOString()}`;
6414
+ }
6415
+ return `${typeof value}:${JSON.stringify(value)}`;
4935
6416
  }
4936
- function formatFormulaResult(value, returnType, decimals) {
6417
+ function isPlainRecord(value) {
6418
+ return typeof value === "object" && value !== null && !Array.isArray(value);
6419
+ }
6420
+ function formatComputedResult(value, returnType, decimals) {
4937
6421
  if (value === null || value === void 0) return null;
6422
+ const stringifyScalar = (input) => {
6423
+ if (typeof input === "string" || typeof input === "number" || typeof input === "boolean" || input instanceof Date) {
6424
+ return String(input);
6425
+ }
6426
+ return null;
6427
+ };
4938
6428
  switch (returnType) {
4939
6429
  case "number": {
4940
6430
  const num = typeof value === "number" ? value : Number(value);
@@ -4949,152 +6439,163 @@ function formatFormulaResult(value, returnType, decimals) {
4949
6439
  return null;
4950
6440
  case "text":
4951
6441
  return String(value);
4952
- }
4953
- }
4954
- function evaluateFormulaAttribute(attr, values) {
4955
- const raw = evaluateFormula(attr.expression, values);
4956
- return formatFormulaResult(raw, attr.returnType, attr.decimals);
4957
- }
4958
- function validateFormulaExpression(expression) {
4959
- try {
4960
- const complexityCheck = validateFormulaComplexity(expression);
4961
- if (!complexityCheck.valid) return complexityCheck;
4962
- formulaParser.parse(expression);
4963
- return { valid: true };
4964
- } catch (error) {
4965
- return { valid: false, error: getErrorMessage(error) };
4966
- }
4967
- }
4968
- function extractFormulaVariables(expression) {
4969
- try {
4970
- const parsed = formulaParser.parse(expression);
4971
- return parsed.variables();
4972
- } catch {
4973
- return [];
4974
- }
4975
- }
4976
- var RELATION_REF_PATTERN = /\b([a-zA-Z_][a-zA-Z0-9_]*)\.([a-zA-Z_][a-zA-Z0-9_]*)\b/g;
4977
- function extractRelationReferences(expression) {
4978
- const regex = new RegExp(RELATION_REF_PATTERN.source, "g");
4979
- const matches = expression.matchAll(regex);
4980
- return [...matches].map((m) => m[0]);
4981
- }
4982
- function extractRelationNames(expression) {
4983
- const refs = extractRelationReferences(expression);
4984
- const names = refs.map((ref) => ref.split(".")[0]);
4985
- return [...new Set(names)];
4986
- }
4987
- function hasRelationReferences(expression) {
4988
- const regex = new RegExp(RELATION_REF_PATTERN.source);
4989
- return regex.test(expression);
4990
- }
4991
- function flattenRelationsForEval(resolvedRelations) {
4992
- const result = {};
4993
- for (const [relationName, values] of Object.entries(resolvedRelations)) {
4994
- result[relationName] = { ...values };
4995
- }
4996
- return result;
4997
- }
4998
-
4999
- // src/formula/path-parser.ts
5000
- var InvalidPathError = class extends Error {
5001
- constructor(path, segment, reason) {
5002
- super(`Invalid path "${path}" at "${segment}": ${reason}`);
5003
- this.path = path;
5004
- this.segment = segment;
5005
- this.reason = reason;
5006
- this.name = "InvalidPathError";
5007
- }
5008
- };
5009
- var MaxDepthExceededError = class extends Error {
5010
- constructor(path, maxDepth) {
5011
- super(`Path "${path}" exceeds maximum depth of ${maxDepth}`);
5012
- this.path = path;
5013
- this.maxDepth = maxDepth;
5014
- this.name = "MaxDepthExceededError";
5015
- }
5016
- };
5017
- async function parsePath(path, startSchema, getSchema, maxDepth = 5) {
5018
- const segments = path.split(".");
5019
- if (segments.length === 0 || segments.length === 1 && segments[0] === "") {
5020
- throw new InvalidPathError(path, path, "Path cannot be empty");
5021
- }
5022
- if (segments.length > maxDepth) {
5023
- throw new MaxDepthExceededError(path, maxDepth);
5024
- }
5025
- const result = [];
5026
- let currentSchema = startSchema;
5027
- for (let i = 0; i < segments.length; i++) {
5028
- const segmentName = segments[i];
5029
- const isLastSegment = i === segments.length - 1;
5030
- const attr = currentSchema.attributes.find((a) => a.name === segmentName);
5031
- if (!attr) {
5032
- throw new InvalidPathError(
5033
- path,
5034
- segmentName,
5035
- `Attribute "${segmentName}" not found in object "${currentSchema.name}"`
5036
- );
5037
- }
5038
- if (attr.type === "relation") {
5039
- const relationAttr = attr;
5040
- const targetObject = relationAttr.targets[0]?.object;
5041
- if (!targetObject) {
5042
- throw new InvalidPathError(path, segmentName, "Relation has no target object");
5043
- }
5044
- result.push({
5045
- name: segmentName,
5046
- type: "relation",
5047
- cardinality: relationAttr.cardinality,
5048
- targetObject
5049
- });
5050
- if (!isLastSegment) {
5051
- const nextSchema = await getSchema(targetObject);
5052
- if (!nextSchema) {
5053
- throw new InvalidPathError(
5054
- path,
5055
- segmentName,
5056
- `Target object "${targetObject}" schema not found`
5057
- );
6442
+ case "select":
6443
+ if (Array.isArray(value)) {
6444
+ for (const item of value) {
6445
+ if (item === null || item === void 0) continue;
6446
+ const formatted = stringifyScalar(item);
6447
+ if (formatted !== null) return formatted;
5058
6448
  }
5059
- currentSchema = nextSchema;
6449
+ return null;
5060
6450
  }
5061
- } else {
5062
- if (!isLastSegment) {
5063
- throw new InvalidPathError(
5064
- path,
5065
- segmentName,
5066
- `"${segmentName}" is not a relation but has segments after it`
5067
- );
6451
+ return stringifyScalar(value);
6452
+ case "multiselect":
6453
+ if (Array.isArray(value)) {
6454
+ return value.flatMap((item) => {
6455
+ if (item === null || item === void 0) return [];
6456
+ const formatted = stringifyScalar(item);
6457
+ return formatted === null ? [] : [formatted];
6458
+ });
5068
6459
  }
5069
- result.push({ name: segmentName, type: "attribute" });
6460
+ return stringifyScalar(value) === null ? [] : [String(value)];
6461
+ default: {
6462
+ const _exhaustive = returnType;
6463
+ throw new Error(`Unsupported computed return type: ${_exhaustive}`);
5070
6464
  }
5071
6465
  }
5072
- return result;
5073
- }
5074
- async function validatePath(path, startSchema, getSchema, maxDepth = 5) {
5075
- try {
5076
- await parsePath(path, startSchema, getSchema, maxDepth);
5077
- return true;
5078
- } catch {
5079
- return false;
5080
- }
5081
6466
  }
5082
- function pathHasManyCardinality(segments) {
5083
- return segments.some((s) => s.type === "relation" && s.cardinality === "many");
6467
+ function evaluateComputedAst(node, input) {
6468
+ return evaluateAst(node, input);
5084
6469
  }
5085
- function getPathDepth(segments) {
5086
- return segments.filter((s) => s.type === "relation").length;
6470
+ function evaluateComputedFormula(expression, input) {
6471
+ return evaluateAst(parseComputedFormula(expression), input);
5087
6472
  }
5088
- function getTargetAttributeName(path) {
5089
- const parts = path.split(".");
5090
- return parts[parts.length - 1];
5091
- }
5092
- function getRelationPath(path) {
5093
- const parts = path.split(".");
5094
- if (parts.length <= 1) return null;
5095
- return parts.slice(0, -1).join(".");
6473
+ function evaluateComputedFormulaWithResult(expression, input, returnType, decimals) {
6474
+ try {
6475
+ const raw = evaluateAst(parseComputedFormula(expression), input);
6476
+ const value = returnType ? formatComputedResult(raw, returnType, decimals) : raw;
6477
+ return { value };
6478
+ } catch (error) {
6479
+ return { value: null, error: error instanceof Error ? error.message : String(error) };
6480
+ }
5096
6481
  }
5097
6482
 
6483
+ // src/computed/function-metadata.ts
6484
+ var COMPUTED_FUNCTION_METADATA = [
6485
+ {
6486
+ name: "if",
6487
+ signature: "if(condition, then, else)",
6488
+ description: "Conditional value",
6489
+ category: "logic",
6490
+ example: "if(amount > 100, 'big', 'small')"
6491
+ },
6492
+ {
6493
+ name: "concat",
6494
+ signature: "concat(a, b, ...)",
6495
+ description: "Join values into text",
6496
+ category: "text",
6497
+ example: "concat(firstName, ' ', lastName)"
6498
+ },
6499
+ {
6500
+ name: "sum",
6501
+ signature: "sum(collection)",
6502
+ description: "Total of values",
6503
+ category: "number",
6504
+ example: "sum(orders.amount)"
6505
+ },
6506
+ {
6507
+ name: "avg",
6508
+ signature: "avg(collection)",
6509
+ description: "Average of values",
6510
+ category: "number",
6511
+ example: "avg(orders.amount)"
6512
+ },
6513
+ {
6514
+ name: "min",
6515
+ signature: "min(collection)",
6516
+ description: "Smallest value",
6517
+ category: "number",
6518
+ example: "min(orders.amount)"
6519
+ },
6520
+ {
6521
+ name: "max",
6522
+ signature: "max(collection)",
6523
+ description: "Largest value",
6524
+ category: "number",
6525
+ example: "max(orders.amount)"
6526
+ },
6527
+ {
6528
+ name: "count",
6529
+ signature: "count(collection)",
6530
+ description: "Number of items",
6531
+ category: "collection",
6532
+ example: "count(orders)"
6533
+ },
6534
+ {
6535
+ name: "count_empty",
6536
+ signature: "count_empty(collection)",
6537
+ description: "Items with no value",
6538
+ category: "collection",
6539
+ example: "count_empty(orders.note)"
6540
+ },
6541
+ {
6542
+ name: "count_not_empty",
6543
+ signature: "count_not_empty(collection)",
6544
+ description: "Items with a value",
6545
+ category: "collection",
6546
+ example: "count_not_empty(orders.note)"
6547
+ },
6548
+ {
6549
+ name: "count_unique",
6550
+ signature: "count_unique(collection)",
6551
+ description: "Distinct values",
6552
+ category: "collection",
6553
+ example: "count_unique(orders.status)"
6554
+ },
6555
+ {
6556
+ name: "percent_empty",
6557
+ signature: "percent_empty(collection)",
6558
+ description: "Fraction with no value",
6559
+ category: "collection",
6560
+ example: "percent_empty(orders.note)"
6561
+ },
6562
+ {
6563
+ name: "percent_not_empty",
6564
+ signature: "percent_not_empty(collection)",
6565
+ description: "Fraction with a value",
6566
+ category: "collection",
6567
+ example: "percent_not_empty(orders.note)"
6568
+ },
6569
+ {
6570
+ name: "unique",
6571
+ signature: "unique(collection)",
6572
+ description: "Distinct values as a list",
6573
+ category: "collection",
6574
+ example: "unique(orders.status)"
6575
+ },
6576
+ {
6577
+ name: "first",
6578
+ signature: "first(collection)",
6579
+ description: "First non-empty value",
6580
+ category: "collection",
6581
+ example: "first(orders.status)"
6582
+ },
6583
+ {
6584
+ name: "earliest",
6585
+ signature: "earliest(collection)",
6586
+ description: "Earliest date",
6587
+ category: "date",
6588
+ example: "earliest(orders.closeDate)"
6589
+ },
6590
+ {
6591
+ name: "latest",
6592
+ signature: "latest(collection)",
6593
+ description: "Latest date",
6594
+ category: "date",
6595
+ example: "latest(orders.closeDate)"
6596
+ }
6597
+ ];
6598
+
5098
6599
  // src/filters/operators.ts
5099
6600
  var isEmpty = (v) => v === null || v === void 0 || v === "" || Array.isArray(v) && v.length === 0;
5100
6601
  var toStr = (v) => v == null ? "" : String(v);
@@ -5103,7 +6604,7 @@ var toNum = (v) => {
5103
6604
  const n = typeof v === "number" ? v : Number(v);
5104
6605
  return Number.isFinite(n) ? n : null;
5105
6606
  };
5106
- var toDate = (v) => {
6607
+ var toDate2 = (v) => {
5107
6608
  if (v == null) return null;
5108
6609
  const d = v instanceof Date ? v : new Date(String(v));
5109
6610
  return Number.isNaN(d.getTime()) ? null : d;
@@ -5122,48 +6623,38 @@ function relativeDateBoundary(rel) {
5122
6623
  var OPERATOR_SPECS = {
5123
6624
  // ---- text-style ----
5124
6625
  is: {
5125
- appliesTo: ["text", "textarea", "phone", "status", "select", "date", "formula"],
6626
+ appliesTo: ["text", "phone", "status", "select", "date", "formula"],
5126
6627
  evaluateInMemory: (v, rv) => toStr(v) === toStr(rv)
5127
6628
  },
5128
6629
  is_not: {
5129
- appliesTo: ["text", "textarea", "phone", "status", "select", "date", "formula"],
6630
+ appliesTo: ["text", "phone", "status", "select", "date", "formula"],
5130
6631
  evaluateInMemory: (v, rv) => toStr(v) !== toStr(rv)
5131
6632
  },
5132
6633
  contains: {
5133
- appliesTo: [
5134
- "text",
5135
- "textarea",
5136
- "phone",
5137
- "location",
5138
- "user",
5139
- "multiselect",
5140
- "relation",
5141
- "formula"
5142
- ],
6634
+ appliesTo: ["text", "phone", "location", "user", "multiselect", "relation", "formula"],
5143
6635
  evaluateInMemory: (v, rv) => {
5144
6636
  if (Array.isArray(v)) return v.map(toStr).includes(toStr(rv));
5145
6637
  return toStr(v).toLowerCase().includes(toStr(rv).toLowerCase());
5146
6638
  }
5147
6639
  },
5148
6640
  not_contains: {
5149
- appliesTo: ["text", "textarea", "phone", "user", "multiselect", "relation", "formula"],
6641
+ appliesTo: ["text", "phone", "user", "multiselect", "relation", "formula"],
5150
6642
  evaluateInMemory: (v, rv) => {
5151
6643
  if (Array.isArray(v)) return !v.map(toStr).includes(toStr(rv));
5152
6644
  return !toStr(v).toLowerCase().includes(toStr(rv).toLowerCase());
5153
6645
  }
5154
6646
  },
5155
6647
  starts_with: {
5156
- appliesTo: ["text", "textarea", "formula"],
6648
+ appliesTo: ["text", "formula"],
5157
6649
  evaluateInMemory: (v, rv) => toStr(v).toLowerCase().startsWith(toStr(rv).toLowerCase())
5158
6650
  },
5159
6651
  ends_with: {
5160
- appliesTo: ["text", "textarea", "formula"],
6652
+ appliesTo: ["text", "formula"],
5161
6653
  evaluateInMemory: (v, rv) => toStr(v).toLowerCase().endsWith(toStr(rv).toLowerCase())
5162
6654
  },
5163
6655
  is_empty: {
5164
6656
  appliesTo: [
5165
6657
  "text",
5166
- "textarea",
5167
6658
  "richtext",
5168
6659
  "number",
5169
6660
  "phone",
@@ -5176,7 +6667,6 @@ var OPERATOR_SPECS = {
5176
6667
  "file",
5177
6668
  "user",
5178
6669
  "relation",
5179
- "rating",
5180
6670
  "formula",
5181
6671
  "document"
5182
6672
  ],
@@ -5185,7 +6675,6 @@ var OPERATOR_SPECS = {
5185
6675
  is_not_empty: {
5186
6676
  appliesTo: [
5187
6677
  "text",
5188
- "textarea",
5189
6678
  "richtext",
5190
6679
  "number",
5191
6680
  "phone",
@@ -5198,7 +6687,6 @@ var OPERATOR_SPECS = {
5198
6687
  "file",
5199
6688
  "user",
5200
6689
  "relation",
5201
- "rating",
5202
6690
  "formula",
5203
6691
  "document"
5204
6692
  ],
@@ -5206,15 +6694,15 @@ var OPERATOR_SPECS = {
5206
6694
  },
5207
6695
  // ---- numeric ----
5208
6696
  eq: {
5209
- appliesTo: ["number", "currency", "rating", "formula"],
6697
+ appliesTo: ["number", "currency", "formula"],
5210
6698
  evaluateInMemory: (v, rv) => toNum(v) === toNum(rv)
5211
6699
  },
5212
6700
  neq: {
5213
- appliesTo: ["number", "currency", "rating", "formula"],
6701
+ appliesTo: ["number", "currency", "formula"],
5214
6702
  evaluateInMemory: (v, rv) => toNum(v) !== toNum(rv)
5215
6703
  },
5216
6704
  lt: {
5217
- appliesTo: ["number", "currency", "rating", "formula"],
6705
+ appliesTo: ["number", "currency", "formula"],
5218
6706
  evaluateInMemory: (v, rv) => {
5219
6707
  const a = toNum(v);
5220
6708
  const b = toNum(rv);
@@ -5222,7 +6710,7 @@ var OPERATOR_SPECS = {
5222
6710
  }
5223
6711
  },
5224
6712
  gt: {
5225
- appliesTo: ["number", "currency", "rating", "formula"],
6713
+ appliesTo: ["number", "currency", "formula"],
5226
6714
  evaluateInMemory: (v, rv) => {
5227
6715
  const a = toNum(v);
5228
6716
  const b = toNum(rv);
@@ -5230,7 +6718,7 @@ var OPERATOR_SPECS = {
5230
6718
  }
5231
6719
  },
5232
6720
  lte: {
5233
- appliesTo: ["number", "currency", "rating", "formula"],
6721
+ appliesTo: ["number", "currency", "formula"],
5234
6722
  evaluateInMemory: (v, rv) => {
5235
6723
  const a = toNum(v);
5236
6724
  const b = toNum(rv);
@@ -5238,7 +6726,7 @@ var OPERATOR_SPECS = {
5238
6726
  }
5239
6727
  },
5240
6728
  gte: {
5241
- appliesTo: ["number", "currency", "rating", "formula"],
6729
+ appliesTo: ["number", "currency", "formula"],
5242
6730
  evaluateInMemory: (v, rv) => {
5243
6731
  const a = toNum(v);
5244
6732
  const b = toNum(rv);
@@ -5258,39 +6746,39 @@ var OPERATOR_SPECS = {
5258
6746
  before: {
5259
6747
  appliesTo: ["date"],
5260
6748
  evaluateInMemory: (v, rv) => {
5261
- const a = toDate(v);
5262
- const b = toDate(rv);
6749
+ const a = toDate2(v);
6750
+ const b = toDate2(rv);
5263
6751
  return a !== null && b !== null && a < b;
5264
6752
  }
5265
6753
  },
5266
6754
  after: {
5267
6755
  appliesTo: ["date"],
5268
6756
  evaluateInMemory: (v, rv) => {
5269
- const a = toDate(v);
5270
- const b = toDate(rv);
6757
+ const a = toDate2(v);
6758
+ const b = toDate2(rv);
5271
6759
  return a !== null && b !== null && a > b;
5272
6760
  }
5273
6761
  },
5274
6762
  on_or_before: {
5275
6763
  appliesTo: ["date"],
5276
6764
  evaluateInMemory: (v, rv) => {
5277
- const a = toDate(v);
5278
- const b = toDate(rv);
6765
+ const a = toDate2(v);
6766
+ const b = toDate2(rv);
5279
6767
  return a !== null && b !== null && a <= b;
5280
6768
  }
5281
6769
  },
5282
6770
  on_or_after: {
5283
6771
  appliesTo: ["date"],
5284
6772
  evaluateInMemory: (v, rv) => {
5285
- const a = toDate(v);
5286
- const b = toDate(rv);
6773
+ const a = toDate2(v);
6774
+ const b = toDate2(rv);
5287
6775
  return a !== null && b !== null && a >= b;
5288
6776
  }
5289
6777
  },
5290
6778
  is_within: {
5291
6779
  appliesTo: ["date"],
5292
6780
  evaluateInMemory: (v, rv) => {
5293
- const d = toDate(v);
6781
+ const d = toDate2(v);
5294
6782
  if (!d) return false;
5295
6783
  const rel = rv;
5296
6784
  const boundary = relativeDateBoundary(rel);
@@ -5300,7 +6788,7 @@ var OPERATOR_SPECS = {
5300
6788
  day_month_eq: {
5301
6789
  appliesTo: ["date"],
5302
6790
  evaluateInMemory: (v, rv) => {
5303
- const d = toDate(v);
6791
+ const d = toDate2(v);
5304
6792
  if (!d) return false;
5305
6793
  const rule = rv;
5306
6794
  return d.getMonth() + 1 === rule.month && d.getDate() === rule.day;
@@ -5398,7 +6886,7 @@ function assertOperatorForType(operator, type, context) {
5398
6886
  if (!ops?.includes(operator)) {
5399
6887
  const validList = ops?.length ? ops.join(", ") : "(no operators registered for this type)";
5400
6888
  const summary = `Operator "${operator}" is not valid for ${context} type "${type}". Valid operators: ${validList}.`;
5401
- throw new chunkFQ2ZYOVS_js.ValidationError(summary, [
6889
+ throw new chunkMZOEL7FN_js.ValidationError(summary, [
5402
6890
  {
5403
6891
  path: ["operator"],
5404
6892
  message: summary
@@ -5410,43 +6898,45 @@ function validateQualifiedRule(rule, context) {
5410
6898
  const rootAttr = context.attributes.find((a) => a.name === rule.attribute);
5411
6899
  const systemOps = SYSTEM_FILTER_OPERATORS[rule.attribute];
5412
6900
  if (!(rootAttr || systemOps)) {
5413
- throw new chunkFQ2ZYOVS_js.ValidationError(`Unknown attribute: ${rule.attribute}`, [
6901
+ throw new chunkMZOEL7FN_js.ValidationError(`Unknown attribute: ${rule.attribute}`, [
5414
6902
  { path: ["attribute"], message: `Unknown attribute: ${rule.attribute}` }
5415
6903
  ]);
5416
6904
  }
5417
6905
  if (!rootAttr) {
5418
6906
  if (rule.property) {
5419
- throw new chunkFQ2ZYOVS_js.ValidationError(`Cannot qualify system attribute "${rule.attribute}"`, [
6907
+ throw new chunkMZOEL7FN_js.ValidationError(`Cannot qualify system attribute "${rule.attribute}"`, [
5420
6908
  { path: ["property"], message: `"${rule.attribute}" is a system column, not a reference` }
5421
6909
  ]);
5422
6910
  }
5423
6911
  if (!systemOps.includes(rule.operator)) {
5424
6912
  const summary = `Operator "${rule.operator}" is not valid for system attribute "${rule.attribute}". Valid operators: ${systemOps.join(", ")}.`;
5425
- throw new chunkFQ2ZYOVS_js.ValidationError(summary, [{ path: ["operator"], message: summary }]);
6913
+ throw new chunkMZOEL7FN_js.ValidationError(summary, [{ path: ["operator"], message: summary }]);
5426
6914
  }
5427
6915
  return;
5428
6916
  }
5429
6917
  if (!rule.property) {
5430
- if (rootAttr.type === "rollup") {
5431
- return;
6918
+ const ops = getAttributeFilterOperators(rootAttr);
6919
+ if (!ops.includes(rule.operator)) {
6920
+ const validList = ops.length ? ops.join(", ") : "(not filterable)";
6921
+ const summary = `Operator "${rule.operator}" is not valid for attribute "${rootAttr.name}". Valid operators: ${validList}.`;
6922
+ throw new chunkMZOEL7FN_js.ValidationError(summary, [{ path: ["operator"], message: summary }]);
5432
6923
  }
5433
- assertOperatorForType(rule.operator, rootAttr.type, "attribute");
5434
6924
  return;
5435
6925
  }
5436
6926
  if (!REFERENCE_TYPES.has(rootAttr.type)) {
5437
- throw new chunkFQ2ZYOVS_js.ValidationError(`Cannot qualify ${rootAttr.type} attribute "${rule.attribute}"`, [
6927
+ throw new chunkMZOEL7FN_js.ValidationError(`Cannot qualify ${rootAttr.type} attribute "${rule.attribute}"`, [
5438
6928
  { path: ["property"], message: `Attribute "${rule.attribute}" is not a reference type` }
5439
6929
  ]);
5440
6930
  }
5441
6931
  const propSchema = rootAttr.properties;
5442
6932
  if (!propSchema) {
5443
- throw new chunkFQ2ZYOVS_js.ValidationError(`Attribute "${rule.attribute}" has no qualifyWith schema`, [
6933
+ throw new chunkMZOEL7FN_js.ValidationError(`Attribute "${rule.attribute}" has no qualifyWith schema`, [
5444
6934
  { path: ["property"], message: `"${rule.attribute}" has no qualifyWith` }
5445
6935
  ]);
5446
6936
  }
5447
6937
  const propDef = propSchema.definitions.find((p) => p.name === rule.property);
5448
6938
  if (!propDef) {
5449
- throw new chunkFQ2ZYOVS_js.ValidationError(
6939
+ throw new chunkMZOEL7FN_js.ValidationError(
5450
6940
  `Property "${rule.property}" not defined on "${rule.attribute}".qualifyWith()`,
5451
6941
  [{ path: ["property"], message: `Unknown property: ${rule.property}` }]
5452
6942
  );
@@ -5476,189 +6966,199 @@ Object.defineProperty(exports, "indexBy", {
5476
6966
  });
5477
6967
  Object.defineProperty(exports, "parseAttributeConfig", {
5478
6968
  enumerable: true,
5479
- get: function () { return chunkYQROI4IE_js.parseAttributeConfig; }
6969
+ get: function () { return chunkM5QIBMIH_js.parseAttributeConfig; }
5480
6970
  });
5481
6971
  Object.defineProperty(exports, "AccessDeniedError", {
5482
6972
  enumerable: true,
5483
- get: function () { return chunkFQ2ZYOVS_js.AccessDeniedError; }
6973
+ get: function () { return chunkMZOEL7FN_js.AccessDeniedError; }
5484
6974
  });
5485
6975
  Object.defineProperty(exports, "AttributeInUseError", {
5486
6976
  enumerable: true,
5487
- get: function () { return chunkFQ2ZYOVS_js.AttributeInUseError; }
6977
+ get: function () { return chunkMZOEL7FN_js.AttributeInUseError; }
5488
6978
  });
5489
6979
  Object.defineProperty(exports, "AttributeNotFoundError", {
5490
6980
  enumerable: true,
5491
- get: function () { return chunkFQ2ZYOVS_js.AttributeNotFoundError; }
6981
+ get: function () { return chunkMZOEL7FN_js.AttributeNotFoundError; }
5492
6982
  });
5493
6983
  Object.defineProperty(exports, "ChangeTypeNotSupportedError", {
5494
6984
  enumerable: true,
5495
- get: function () { return chunkFQ2ZYOVS_js.ChangeTypeNotSupportedError; }
6985
+ get: function () { return chunkMZOEL7FN_js.ChangeTypeNotSupportedError; }
5496
6986
  });
5497
6987
  Object.defineProperty(exports, "ConcurrentModificationError", {
5498
6988
  enumerable: true,
5499
- get: function () { return chunkFQ2ZYOVS_js.ConcurrentModificationError; }
6989
+ get: function () { return chunkMZOEL7FN_js.ConcurrentModificationError; }
5500
6990
  });
5501
6991
  Object.defineProperty(exports, "DestructiveSyncNotAllowedError", {
5502
6992
  enumerable: true,
5503
- get: function () { return chunkFQ2ZYOVS_js.DestructiveSyncNotAllowedError; }
6993
+ get: function () { return chunkMZOEL7FN_js.DestructiveSyncNotAllowedError; }
5504
6994
  });
5505
6995
  Object.defineProperty(exports, "DuplicateError", {
5506
6996
  enumerable: true,
5507
- get: function () { return chunkFQ2ZYOVS_js.DuplicateError; }
6997
+ get: function () { return chunkMZOEL7FN_js.DuplicateError; }
5508
6998
  });
5509
6999
  Object.defineProperty(exports, "ForbiddenError", {
5510
7000
  enumerable: true,
5511
- get: function () { return chunkFQ2ZYOVS_js.ForbiddenError; }
7001
+ get: function () { return chunkMZOEL7FN_js.ForbiddenError; }
5512
7002
  });
5513
7003
  Object.defineProperty(exports, "MemoryNotFoundError", {
5514
7004
  enumerable: true,
5515
- get: function () { return chunkFQ2ZYOVS_js.MemoryNotFoundError; }
7005
+ get: function () { return chunkMZOEL7FN_js.MemoryNotFoundError; }
5516
7006
  });
5517
7007
  Object.defineProperty(exports, "MigrationTimeoutError", {
5518
7008
  enumerable: true,
5519
- get: function () { return chunkFQ2ZYOVS_js.MigrationTimeoutError; }
7009
+ get: function () { return chunkMZOEL7FN_js.MigrationTimeoutError; }
5520
7010
  });
5521
7011
  Object.defineProperty(exports, "NotFoundError", {
5522
7012
  enumerable: true,
5523
- get: function () { return chunkFQ2ZYOVS_js.NotFoundError; }
7013
+ get: function () { return chunkMZOEL7FN_js.NotFoundError; }
5524
7014
  });
5525
7015
  Object.defineProperty(exports, "NotImplementedError", {
5526
7016
  enumerable: true,
5527
- get: function () { return chunkFQ2ZYOVS_js.NotImplementedError; }
7017
+ get: function () { return chunkMZOEL7FN_js.NotImplementedError; }
5528
7018
  });
5529
7019
  Object.defineProperty(exports, "ObjectNotFoundError", {
5530
7020
  enumerable: true,
5531
- get: function () { return chunkFQ2ZYOVS_js.ObjectNotFoundError; }
7021
+ get: function () { return chunkMZOEL7FN_js.ObjectNotFoundError; }
5532
7022
  });
5533
7023
  Object.defineProperty(exports, "ObjectReferencedError", {
5534
7024
  enumerable: true,
5535
- get: function () { return chunkFQ2ZYOVS_js.ObjectReferencedError; }
7025
+ get: function () { return chunkMZOEL7FN_js.ObjectReferencedError; }
5536
7026
  });
5537
7027
  Object.defineProperty(exports, "OrphanSystemAttributeError", {
5538
7028
  enumerable: true,
5539
- get: function () { return chunkFQ2ZYOVS_js.OrphanSystemAttributeError; }
7029
+ get: function () { return chunkMZOEL7FN_js.OrphanSystemAttributeError; }
5540
7030
  });
5541
7031
  Object.defineProperty(exports, "ProtectedResourceError", {
5542
7032
  enumerable: true,
5543
- get: function () { return chunkFQ2ZYOVS_js.ProtectedResourceError; }
7033
+ get: function () { return chunkMZOEL7FN_js.ProtectedResourceError; }
5544
7034
  });
5545
7035
  Object.defineProperty(exports, "ProtectedRoleError", {
5546
7036
  enumerable: true,
5547
- get: function () { return chunkFQ2ZYOVS_js.ProtectedRoleError; }
7037
+ get: function () { return chunkMZOEL7FN_js.ProtectedRoleError; }
5548
7038
  });
5549
7039
  Object.defineProperty(exports, "RecordNotFoundError", {
5550
7040
  enumerable: true,
5551
- get: function () { return chunkFQ2ZYOVS_js.RecordNotFoundError; }
7041
+ get: function () { return chunkMZOEL7FN_js.RecordNotFoundError; }
5552
7042
  });
5553
7043
  Object.defineProperty(exports, "RecordReferencedError", {
5554
7044
  enumerable: true,
5555
- get: function () { return chunkFQ2ZYOVS_js.RecordReferencedError; }
7045
+ get: function () { return chunkMZOEL7FN_js.RecordReferencedError; }
5556
7046
  });
5557
7047
  Object.defineProperty(exports, "RepositoryError", {
5558
7048
  enumerable: true,
5559
- get: function () { return chunkFQ2ZYOVS_js.RepositoryError; }
7049
+ get: function () { return chunkMZOEL7FN_js.RepositoryError; }
5560
7050
  });
5561
7051
  Object.defineProperty(exports, "RoleNotFoundError", {
5562
7052
  enumerable: true,
5563
- get: function () { return chunkFQ2ZYOVS_js.RoleNotFoundError; }
7053
+ get: function () { return chunkMZOEL7FN_js.RoleNotFoundError; }
5564
7054
  });
5565
7055
  Object.defineProperty(exports, "SchemaError", {
5566
7056
  enumerable: true,
5567
- get: function () { return chunkFQ2ZYOVS_js.SchemaError; }
7057
+ get: function () { return chunkMZOEL7FN_js.SchemaError; }
5568
7058
  });
5569
7059
  Object.defineProperty(exports, "SchemaErrorCode", {
5570
7060
  enumerable: true,
5571
- get: function () { return chunkFQ2ZYOVS_js.SchemaErrorCode; }
7061
+ get: function () { return chunkMZOEL7FN_js.SchemaErrorCode; }
5572
7062
  });
5573
7063
  Object.defineProperty(exports, "StorageError", {
5574
7064
  enumerable: true,
5575
- get: function () { return chunkFQ2ZYOVS_js.StorageError; }
7065
+ get: function () { return chunkMZOEL7FN_js.StorageError; }
5576
7066
  });
5577
7067
  Object.defineProperty(exports, "SyncCascadeError", {
5578
7068
  enumerable: true,
5579
- get: function () { return chunkFQ2ZYOVS_js.SyncCascadeError; }
7069
+ get: function () { return chunkMZOEL7FN_js.SyncCascadeError; }
5580
7070
  });
5581
7071
  Object.defineProperty(exports, "SyncConflictError", {
5582
7072
  enumerable: true,
5583
- get: function () { return chunkFQ2ZYOVS_js.SyncConflictError; }
7073
+ get: function () { return chunkMZOEL7FN_js.SyncConflictError; }
5584
7074
  });
5585
7075
  Object.defineProperty(exports, "SyncError", {
5586
7076
  enumerable: true,
5587
- get: function () { return chunkFQ2ZYOVS_js.SyncError; }
7077
+ get: function () { return chunkMZOEL7FN_js.SyncError; }
5588
7078
  });
5589
7079
  Object.defineProperty(exports, "SystemEntityImmutableError", {
5590
7080
  enumerable: true,
5591
- get: function () { return chunkFQ2ZYOVS_js.SystemEntityImmutableError; }
7081
+ get: function () { return chunkMZOEL7FN_js.SystemEntityImmutableError; }
5592
7082
  });
5593
7083
  Object.defineProperty(exports, "ValidationError", {
5594
7084
  enumerable: true,
5595
- get: function () { return chunkFQ2ZYOVS_js.ValidationError; }
7085
+ get: function () { return chunkMZOEL7FN_js.ValidationError; }
5596
7086
  });
5597
7087
  Object.defineProperty(exports, "computeRecordStatus", {
5598
7088
  enumerable: true,
5599
- get: function () { return chunkFQ2ZYOVS_js.computeRecordStatus; }
7089
+ get: function () { return chunkMZOEL7FN_js.computeRecordStatus; }
5600
7090
  });
5601
7091
  Object.defineProperty(exports, "createFormAttributeValidator", {
5602
7092
  enumerable: true,
5603
- get: function () { return chunkFQ2ZYOVS_js.createFormAttributeValidator; }
7093
+ get: function () { return chunkMZOEL7FN_js.createFormAttributeValidator; }
5604
7094
  });
5605
7095
  Object.defineProperty(exports, "isAttributeInUseError", {
5606
7096
  enumerable: true,
5607
- get: function () { return chunkFQ2ZYOVS_js.isAttributeInUseError; }
7097
+ get: function () { return chunkMZOEL7FN_js.isAttributeInUseError; }
5608
7098
  });
5609
7099
  Object.defineProperty(exports, "isNotFoundError", {
5610
7100
  enumerable: true,
5611
- get: function () { return chunkFQ2ZYOVS_js.isNotFoundError; }
7101
+ get: function () { return chunkMZOEL7FN_js.isNotFoundError; }
5612
7102
  });
5613
7103
  Object.defineProperty(exports, "isObjectReferencedError", {
5614
7104
  enumerable: true,
5615
- get: function () { return chunkFQ2ZYOVS_js.isObjectReferencedError; }
7105
+ get: function () { return chunkMZOEL7FN_js.isObjectReferencedError; }
5616
7106
  });
5617
7107
  Object.defineProperty(exports, "isProtectedResourceError", {
5618
7108
  enumerable: true,
5619
- get: function () { return chunkFQ2ZYOVS_js.isProtectedResourceError; }
7109
+ get: function () { return chunkMZOEL7FN_js.isProtectedResourceError; }
5620
7110
  });
5621
7111
  Object.defineProperty(exports, "isRecordReferencedError", {
5622
7112
  enumerable: true,
5623
- get: function () { return chunkFQ2ZYOVS_js.isRecordReferencedError; }
7113
+ get: function () { return chunkMZOEL7FN_js.isRecordReferencedError; }
5624
7114
  });
5625
7115
  Object.defineProperty(exports, "isSchemaError", {
5626
7116
  enumerable: true,
5627
- get: function () { return chunkFQ2ZYOVS_js.isSchemaError; }
7117
+ get: function () { return chunkMZOEL7FN_js.isSchemaError; }
5628
7118
  });
5629
7119
  Object.defineProperty(exports, "isValidationError", {
5630
7120
  enumerable: true,
5631
- get: function () { return chunkFQ2ZYOVS_js.isValidationError; }
7121
+ get: function () { return chunkMZOEL7FN_js.isValidationError; }
7122
+ });
7123
+ Object.defineProperty(exports, "rejectUnknownAttributesOrThrow", {
7124
+ enumerable: true,
7125
+ get: function () { return chunkMZOEL7FN_js.rejectUnknownAttributesOrThrow; }
5632
7126
  });
5633
7127
  Object.defineProperty(exports, "validateDraft", {
5634
7128
  enumerable: true,
5635
- get: function () { return chunkFQ2ZYOVS_js.validateDraft; }
7129
+ get: function () { return chunkMZOEL7FN_js.validateDraft; }
5636
7130
  });
5637
7131
  Object.defineProperty(exports, "validateDraftOrThrow", {
5638
7132
  enumerable: true,
5639
- get: function () { return chunkFQ2ZYOVS_js.validateDraftOrThrow; }
7133
+ get: function () { return chunkMZOEL7FN_js.validateDraftOrThrow; }
5640
7134
  });
5641
7135
  Object.defineProperty(exports, "validateObject", {
5642
7136
  enumerable: true,
5643
- get: function () { return chunkFQ2ZYOVS_js.validateObject; }
7137
+ get: function () { return chunkMZOEL7FN_js.validateObject; }
5644
7138
  });
5645
7139
  Object.defineProperty(exports, "validateObjectOrThrow", {
5646
7140
  enumerable: true,
5647
- get: function () { return chunkFQ2ZYOVS_js.validateObjectOrThrow; }
7141
+ get: function () { return chunkMZOEL7FN_js.validateObjectOrThrow; }
5648
7142
  });
5649
7143
  Object.defineProperty(exports, "DEFAULT_VALIDATION_MESSAGES", {
5650
7144
  enumerable: true,
5651
- get: function () { return chunkT225DB55_js.DEFAULT_VALIDATION_MESSAGES; }
7145
+ get: function () { return chunkYKWSHBT5_js.DEFAULT_VALIDATION_MESSAGES; }
5652
7146
  });
5653
7147
  Object.defineProperty(exports, "formatZodErrors", {
5654
7148
  enumerable: true,
5655
- get: function () { return chunkT225DB55_js.formatZodErrors; }
7149
+ get: function () { return chunkYKWSHBT5_js.formatZodErrors; }
5656
7150
  });
5657
7151
  exports.ALLOWED_PROPERTY_TYPES = ALLOWED_PROPERTY_TYPES;
5658
7152
  exports.ALL_ACTIONS = ALL_ACTIONS;
5659
7153
  exports.ALL_SYSTEM_RESOURCES = ALL_SYSTEM_RESOURCES;
7154
+ exports.ATTRIBUTE_FILTER_OPERATORS = ATTRIBUTE_FILTER_OPERATORS;
5660
7155
  exports.ActivityTabConfig = ActivityTabConfig;
5661
7156
  exports.BEHAVIOR_PROPERTIES = BEHAVIOR_PROPERTIES;
7157
+ exports.COMPUTED_FUNCTIONS = COMPUTED_FUNCTIONS;
7158
+ exports.COMPUTED_FUNCTION_METADATA = COMPUTED_FUNCTION_METADATA;
7159
+ exports.COMPUTED_FUNCTION_NAMES = COMPUTED_FUNCTION_NAMES;
7160
+ exports.ComputedFormulaCompileError = ComputedFormulaCompileError;
7161
+ exports.ComputedFormulaParseError = ComputedFormulaParseError;
5662
7162
  exports.CustomTabConfig = CustomTabConfig;
5663
7163
  exports.DB_COLUMN_FIELDS = DB_COLUMN_FIELDS;
5664
7164
  exports.DEFAULT_DOCUMENT_SLOT = DEFAULT_DOCUMENT_SLOT;
@@ -5680,11 +7180,11 @@ exports.FormRowBuilder = FormRowBuilder;
5680
7180
  exports.FormStepBuilder = FormStepBuilder;
5681
7181
  exports.GroupBuilder = GroupBuilder;
5682
7182
  exports.IDENTITY_PROPERTIES = IDENTITY_PROPERTIES;
5683
- exports.InvalidPathError = InvalidPathError;
7183
+ exports.LIVE_EVENT_TYPES = LIVE_EVENT_TYPES;
7184
+ exports.LIVE_STREAM_START_CURSOR = LIVE_STREAM_START_CURSOR;
5684
7185
  exports.ListViewBuilder = ListViewBuilder;
5685
7186
  exports.ListViewTabConfigBuilder = ListViewTabConfigBuilder;
5686
7187
  exports.MAX_PRESET_DEPTH = MAX_PRESET_DEPTH;
5687
- exports.MaxDepthExceededError = MaxDepthExceededError;
5688
7188
  exports.NO_VALUE_OPERATORS = NO_VALUE_OPERATORS;
5689
7189
  exports.NoopGeocodingAdapter = NoopGeocodingAdapter;
5690
7190
  exports.OPERATORS_BY_TYPE = OPERATORS_BY_TYPE;
@@ -5708,10 +7208,15 @@ exports.USER_STATUSES = USER_STATUSES;
5708
7208
  exports.accessLevelToActions = accessLevelToActions;
5709
7209
  exports.actionsToAccessLevel = actionsToAccessLevel;
5710
7210
  exports.applyPipes = applyPipes;
7211
+ exports.assertAcyclicComputedDependencies = assertAcyclicComputedDependencies;
7212
+ exports.assertLiveStreamCursor = assertLiveStreamCursor;
5711
7213
  exports.booleanFlag = booleanFlag;
5712
7214
  exports.buildPropertySchema = buildPropertySchema;
5713
7215
  exports.buildQualifiedAttribute = buildQualifiedAttribute;
5714
7216
  exports.checkbox = checkbox;
7217
+ exports.compareLiveStreamCursors = compareLiveStreamCursors;
7218
+ exports.compileComputedFormula = compileComputedFormula;
7219
+ exports.compileRollupAttribute = compileRollupAttribute;
5715
7220
  exports.createFlagRegistry = createFlagRegistry;
5716
7221
  exports.createFlagService = createFlagService;
5717
7222
  exports.createStandardSchemaProps = createStandardSchemaProps;
@@ -5719,39 +7224,40 @@ exports.currency = currency;
5719
7224
  exports.date = date;
5720
7225
  exports.detailView = detailView;
5721
7226
  exports.document = document;
7227
+ exports.evaluateComputedAst = evaluateComputedAst;
7228
+ exports.evaluateComputedFormula = evaluateComputedFormula;
7229
+ exports.evaluateComputedFormulaWithResult = evaluateComputedFormulaWithResult;
5722
7230
  exports.evaluateFilterState = evaluateFilterState;
5723
- exports.evaluateFormula = evaluateFormula;
5724
- exports.evaluateFormulaAttribute = evaluateFormulaAttribute;
5725
- exports.evaluateFormulaWithResult = evaluateFormulaWithResult;
5726
7231
  exports.extractAttributeNames = extractAttributeNames;
5727
- exports.extractFormulaVariables = extractFormulaVariables;
5728
- exports.extractRelationNames = extractRelationNames;
5729
- exports.extractRelationReferences = extractRelationReferences;
5730
7232
  exports.file = file;
5731
7233
  exports.flagRegistry = flagRegistry;
5732
- exports.flattenRelationsForEval = flattenRelationsForEval;
5733
7234
  exports.form = form;
5734
7235
  exports.formRegistry = formRegistry;
5735
7236
  exports.formatAttributeValue = formatAttributeValue;
5736
- exports.formatFormulaResult = formatFormulaResult;
7237
+ exports.formatComputedResult = formatComputedResult;
5737
7238
  exports.formula = formula;
5738
7239
  exports.generateDefaultDetailView = generateDefaultDetailView;
5739
7240
  exports.generateDefaultListView = generateDefaultListView;
5740
7241
  exports.getActiveTab = getActiveTab;
7242
+ exports.getAttributeCapabilities = getAttributeCapabilities;
7243
+ exports.getAttributeFilterOperators = getAttributeFilterOperators;
5741
7244
  exports.getErrorMessage = getErrorMessage;
7245
+ exports.getLiveProtocolPayloadChannel = getLiveProtocolPayloadChannel;
5742
7246
  exports.getOperatorPolarity = getOperatorPolarity;
5743
- exports.getPathDepth = getPathDepth;
5744
- exports.getRelationPath = getRelationPath;
5745
- exports.getRollupFilterOperators = getRollupFilterOperators;
7247
+ exports.getRollupFilterOperators = getRollupFilterOperators2;
5746
7248
  exports.getSystemAttributeI18nKey = getSystemAttributeI18nKey;
5747
7249
  exports.getSystemAttributeList = getSystemAttributeList;
5748
- exports.getTargetAttributeName = getTargetAttributeName;
5749
7250
  exports.group = group;
5750
7251
  exports.hasOptions = hasOptions;
5751
- exports.hasRelationReferences = hasRelationReferences;
5752
7252
  exports.inferInverseCardinality = inferInverseCardinality;
5753
- exports.isAttributeSortable = isAttributeSortable;
7253
+ exports.inferRollupReturnType = inferRollupReturnType;
7254
+ exports.isAttributeFilterable = isAttributeFilterable;
7255
+ exports.isAttributeGroupable = isAttributeGroupable;
7256
+ exports.isAttributeKanbanGroupable = isAttributeKanbanGroupable;
7257
+ exports.isAttributeSearchable = isAttributeSearchable;
7258
+ exports.isAttributeSortable = isAttributeSortable2;
5754
7259
  exports.isBilateralRelation = isBilateralRelation;
7260
+ exports.isComputedFunctionName = isComputedFunctionName;
5755
7261
  exports.isDefaultRole = isDefaultRole;
5756
7262
  exports.isDetailView = isDetailView;
5757
7263
  exports.isDocumentAttribute = isDocumentAttribute;
@@ -5766,13 +7272,23 @@ exports.isFormSlotFieldRef = isFormSlotFieldRef;
5766
7272
  exports.isFormTextRow = isFormTextRow;
5767
7273
  exports.isLabelExpression = isLabelExpression;
5768
7274
  exports.isListView = isListView;
7275
+ exports.isLiveErrorPayload = isLiveErrorPayload;
7276
+ exports.isLiveEventEnvelope = isLiveEventEnvelope;
7277
+ exports.isLiveEventPayload = isLiveEventPayload;
7278
+ exports.isLiveEventPayloadForType = isLiveEventPayloadForType;
7279
+ exports.isLiveEventType = isLiveEventType;
7280
+ exports.isLiveGapPayload = isLiveGapPayload;
7281
+ exports.isLiveReplayCompletePayload = isLiveReplayCompletePayload;
7282
+ exports.isLiveStreamCursor = isLiveStreamCursor;
5769
7283
  exports.isNoValueOperator = isNoValueOperator;
5770
7284
  exports.isNotEmpty = isNotEmpty;
7285
+ exports.isPlainRecord = isPlainRecord;
5771
7286
  exports.isRelationGroup = isRelationGroup;
5772
7287
  exports.isStandardSchema = isStandardSchema;
5773
7288
  exports.isUniversalRelation = isUniversalRelation;
5774
7289
  exports.jsonFlag = jsonFlag;
5775
7290
  exports.listView = listView;
7291
+ exports.liveChannelKey = liveChannelKey;
5776
7292
  exports.location = location;
5777
7293
  exports.matchesMime = matchesMime;
5778
7294
  exports.multiselect = multiselect;
@@ -5781,11 +7297,12 @@ exports.normalizeForEdgeRpc = normalizeForEdgeRpc;
5781
7297
  exports.number = number;
5782
7298
  exports.numberFlag = numberFlag;
5783
7299
  exports.object = object;
5784
- exports.parsePath = parsePath;
7300
+ exports.parseComputedFormula = parseComputedFormula;
7301
+ exports.parseLiveChannelKey = parseLiveChannelKey;
7302
+ exports.parseLiveSubscribePayload = parseLiveSubscribePayload;
7303
+ exports.parseLiveUnsubscribePayload = parseLiveUnsubscribePayload;
5785
7304
  exports.parseQualifiedAttribute = parseQualifiedAttribute;
5786
- exports.pathHasManyCardinality = pathHasManyCardinality;
5787
7305
  exports.phone = phone;
5788
- exports.rating = rating;
5789
7306
  exports.registry = registry;
5790
7307
  exports.relation = relation;
5791
7308
  exports.relationGroup = relationGroup;
@@ -5793,16 +7310,14 @@ exports.renderLabelExpression = renderLabelExpression;
5793
7310
  exports.resetViewToDefault = resetViewToDefault;
5794
7311
  exports.richtext = richtext;
5795
7312
  exports.rollup = rollup;
7313
+ exports.rollupToFormulaExpression = rollupToFormulaExpression;
5796
7314
  exports.select = select;
5797
7315
  exports.status = status;
5798
7316
  exports.stringFlag = stringFlag;
5799
7317
  exports.text = text;
5800
- exports.textarea = textarea;
5801
7318
  exports.toUndefinedIfEmpty = toUndefinedIfEmpty;
5802
7319
  exports.user = user;
5803
7320
  exports.validateAttributeName = validateAttributeName;
5804
- exports.validateFormulaExpression = validateFormulaExpression;
5805
- exports.validatePath = validatePath;
5806
7321
  exports.validateQualifiedRule = validateQualifiedRule;
5807
7322
  exports.validateSlotAgainstConfig = validateSlotAgainstConfig;
5808
7323
  exports.viewRegistry = viewRegistry;