@stndrds/schema 1.0.0-alpha.166 → 1.0.0-alpha.169

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 (55) hide show
  1. package/dist/filters-DRXk4dLI.d.mts +1575 -0
  2. package/dist/filters-zzsF0GxK.d.ts +1575 -0
  3. package/dist/helpers-64gmAyw0.d.ts +61 -0
  4. package/dist/helpers-DOjqrfWE.d.mts +61 -0
  5. package/dist/index.d.mts +33 -101
  6. package/dist/index.d.ts +33 -101
  7. package/dist/index.js +118 -50
  8. package/dist/index.mjs +109 -52
  9. package/dist/{types-CUbVw7X2.d.ts → types-Bemfgle3.d.ts} +1 -1
  10. package/dist/{types-DT8dfR2I.d.mts → types-DxEobsMy.d.mts} +1 -1
  11. package/dist/validation/all.d.mts +3 -3
  12. package/dist/validation/all.d.ts +3 -3
  13. package/dist/validation/all.js +4 -0
  14. package/dist/validation/all.mjs +1 -1
  15. package/dist/validation/complex/currency.d.mts +2 -2
  16. package/dist/validation/complex/currency.d.ts +2 -2
  17. package/dist/validation/complex/file.d.mts +2 -2
  18. package/dist/validation/complex/file.d.ts +2 -2
  19. package/dist/validation/complex/location.d.mts +2 -2
  20. package/dist/validation/complex/location.d.ts +2 -2
  21. package/dist/validation/complex/phone.d.mts +2 -2
  22. package/dist/validation/complex/phone.d.ts +2 -2
  23. package/dist/validation/complex/relation.d.mts +2 -2
  24. package/dist/validation/complex/relation.d.ts +2 -2
  25. package/dist/validation/complex/richtext.d.mts +2 -2
  26. package/dist/validation/complex/richtext.d.ts +2 -2
  27. package/dist/validation/complex/select.d.mts +2 -2
  28. package/dist/validation/complex/select.d.ts +2 -2
  29. package/dist/validation/complex/user.d.mts +2 -2
  30. package/dist/validation/complex/user.d.ts +2 -2
  31. package/dist/validation/computed/formula.d.mts +2 -2
  32. package/dist/validation/computed/formula.d.ts +2 -2
  33. package/dist/validation/computed/rollup.d.mts +2 -2
  34. package/dist/validation/computed/rollup.d.ts +2 -2
  35. package/dist/validation/config/index.d.mts +1 -1
  36. package/dist/validation/config/index.d.ts +1 -1
  37. package/dist/validation/core/index.d.mts +3 -3
  38. package/dist/validation/core/index.d.ts +3 -3
  39. package/dist/validation/object/index.d.mts +3 -4
  40. package/dist/validation/object/index.d.ts +3 -4
  41. package/dist/validation/primitives/checkbox.d.mts +2 -2
  42. package/dist/validation/primitives/checkbox.d.ts +2 -2
  43. package/dist/validation/primitives/date.d.mts +2 -2
  44. package/dist/validation/primitives/date.d.ts +2 -2
  45. package/dist/validation/primitives/number.d.mts +2 -2
  46. package/dist/validation/primitives/number.d.ts +2 -2
  47. package/dist/validation/primitives/rating.d.mts +2 -2
  48. package/dist/validation/primitives/rating.d.ts +2 -2
  49. package/dist/validation/primitives/text.d.mts +2 -2
  50. package/dist/validation/primitives/text.d.ts +2 -2
  51. package/package.json +2 -2
  52. package/dist/attributes-CNpcbVbv.d.ts +0 -667
  53. package/dist/attributes-DcHM27jS.d.mts +0 -667
  54. package/dist/helpers-BDn1PUC2.d.mts +0 -860
  55. package/dist/helpers-oaW8DBAh.d.ts +0 -860
package/dist/index.js CHANGED
@@ -67,6 +67,9 @@ function isAttributeSortable(attr) {
67
67
  return !NON_SORTABLE_TYPES.has(attr.type);
68
68
  }
69
69
 
70
+ // src/types/documents.ts
71
+ var DEFAULT_DOCUMENT_SLOT = { name: "file" };
72
+
70
73
  // src/exceptions.ts
71
74
  var SchemaErrorCode = {
72
75
  // Generic
@@ -698,6 +701,53 @@ function isNotEmpty(obj) {
698
701
  function toUndefinedIfEmpty(obj) {
699
702
  return isNotEmpty(obj) ? obj : void 0;
700
703
  }
704
+
705
+ // src/lib/document-attribute.ts
706
+ var DOCUMENT_SYSTEM_ATTRIBUTES = {
707
+ ATTACHMENTS: "attachments"
708
+ };
709
+ function isDocumentAttribute(attr) {
710
+ return attr.type === "document";
711
+ }
712
+ function matchesMime(mime, accepted) {
713
+ if (!accepted || accepted.length === 0) return true;
714
+ return accepted.some((pattern) => {
715
+ if (pattern.endsWith("/*")) {
716
+ return mime.startsWith(pattern.slice(0, -1));
717
+ }
718
+ return mime === pattern;
719
+ });
720
+ }
721
+ function normaliseDocumentSlots(slots) {
722
+ if (!slots || slots.length === 0) return [DEFAULT_DOCUMENT_SLOT];
723
+ return slots;
724
+ }
725
+ var DocumentSlotValidationError = class extends Error {
726
+ constructor(code, message, context) {
727
+ super(`${code}: ${message}`);
728
+ this.code = code;
729
+ this.context = context;
730
+ this.name = "DocumentSlotValidationError";
731
+ }
732
+ };
733
+ function validateSlotAgainstConfig(slotName, mimeType, slots) {
734
+ const slot = slots.find((s) => s.name === slotName);
735
+ if (!slot) {
736
+ throw new DocumentSlotValidationError(
737
+ "SLOT_NOT_DECLARED",
738
+ `Slot "${slotName}" is not declared.`,
739
+ { availableSlots: slots.map((s) => s.name) }
740
+ );
741
+ }
742
+ if (!matchesMime(mimeType, slot.acceptedMimeTypes)) {
743
+ throw new DocumentSlotValidationError(
744
+ "MIME_NOT_ACCEPTED",
745
+ `MIME ${mimeType} not accepted for slot "${slotName}".`,
746
+ { acceptedMimeTypes: slot.acceptedMimeTypes }
747
+ );
748
+ }
749
+ return slot;
750
+ }
701
751
  var EMPTY_VALUE_PLACEHOLDER = "\u2014";
702
752
  function formatText(value) {
703
753
  return String(value);
@@ -2110,6 +2160,14 @@ var DocumentAttributeBuilder = class extends BaseAttributeBuilder {
2110
2160
  this.attr.autoProcess = true;
2111
2161
  return this;
2112
2162
  }
2163
+ /**
2164
+ * Define named upload slots for this document attribute.
2165
+ * An empty array falls back to a single default slot.
2166
+ */
2167
+ slots(configs) {
2168
+ this.attr.slots = configs.length === 0 ? [DEFAULT_DOCUMENT_SLOT] : configs;
2169
+ return this;
2170
+ }
2113
2171
  /**
2114
2172
  * Add a child attribute definition for per-document metadata.
2115
2173
  * Reuses existing attribute builders directly.
@@ -2948,6 +3006,35 @@ var RelationGroupBuilder = class {
2948
3006
  return this.data;
2949
3007
  }
2950
3008
  };
3009
+ function assertViewVersion(version) {
3010
+ if (version < 1) throw new Error("View version must be >= 1");
3011
+ }
3012
+ function assertUniqueBy(items, getKey, buildError) {
3013
+ const seen = /* @__PURE__ */ new Set();
3014
+ for (const item of items) {
3015
+ const key = getKey(item);
3016
+ if (seen.has(key)) {
3017
+ throw new Error(buildError(key));
3018
+ }
3019
+ seen.add(key);
3020
+ }
3021
+ }
3022
+ function validateViewName(name, builderName, examples) {
3023
+ const viewNameSchema = z3.z.string().min(1, "View name cannot be empty").max(63, "View name is too long (max 63 characters)").regex(/^[a-z][a-z0-9-]*$/, {
3024
+ message: `Invalid view name format.
3025
+ Name must be in kebab-case:
3026
+ \u2705 Valid: ${examples.valid}
3027
+ \u274C Invalid: ${examples.invalid}`
3028
+ });
3029
+ try {
3030
+ viewNameSchema.parse(name);
3031
+ } catch (error) {
3032
+ if (error instanceof z3.z.ZodError) {
3033
+ throw new Error(`[${builderName}] ${error.issues[0].message}`);
3034
+ }
3035
+ throw error;
3036
+ }
3037
+ }
2951
3038
  var TableTabConfig = class {
2952
3039
  /** @internal */
2953
3040
  constructor(view, tabData) {
@@ -3358,7 +3445,10 @@ var TabBuilder = class {
3358
3445
  var DetailViewBuilder = class {
3359
3446
  constructor(name, label) {
3360
3447
  this._version = 1;
3361
- this.validateName(name);
3448
+ validateViewName(name, "DetailViewBuilder", {
3449
+ valid: "'detail', 'list-view', 'company-detail'",
3450
+ invalid: "'Detail', 'listView', 'list_view'"
3451
+ });
3362
3452
  this.data = {
3363
3453
  name,
3364
3454
  label,
@@ -3426,7 +3516,7 @@ var DetailViewBuilder = class {
3426
3516
  * @default 1
3427
3517
  */
3428
3518
  version(v) {
3429
- if (v < 1) throw new Error("View version must be >= 1");
3519
+ assertViewVersion(v);
3430
3520
  this._version = v;
3431
3521
  return this;
3432
3522
  }
@@ -3470,13 +3560,11 @@ var DetailViewBuilder = class {
3470
3560
  if (this.data.tabs.length === 0) {
3471
3561
  throw new Error("[DetailViewBuilder] At least one tab is required");
3472
3562
  }
3473
- const tabNames = /* @__PURE__ */ new Set();
3474
- for (const tab of this.data.tabs) {
3475
- if (tabNames.has(tab.name)) {
3476
- throw new Error(`[DetailViewBuilder] Duplicate tab name "${tab.name}"`);
3477
- }
3478
- tabNames.add(tab.name);
3479
- }
3563
+ assertUniqueBy(
3564
+ this.data.tabs,
3565
+ (tab) => tab.name,
3566
+ (name) => `[DetailViewBuilder] Duplicate tab name "${name}"`
3567
+ );
3480
3568
  if (this.data.layout === "modal") {
3481
3569
  if (this.data.tabs.length !== 1) {
3482
3570
  throw new Error("[DetailViewBuilder] Modal views must have exactly one tab");
@@ -3506,22 +3594,6 @@ var DetailViewBuilder = class {
3506
3594
  schema_version: this._version
3507
3595
  };
3508
3596
  }
3509
- /**
3510
- * Validate view name format (kebab-case)
3511
- */
3512
- validateName(name) {
3513
- const viewNameSchema = z3.z.string().min(1, "View name cannot be empty").max(63, "View name is too long (max 63 characters)").regex(/^[a-z][a-z0-9-]*$/, {
3514
- message: "Invalid view name format.\nName must be in kebab-case:\n \u2705 Valid: 'detail', 'list-view', 'company-detail'\n \u274C Invalid: 'Detail', 'listView', 'list_view'"
3515
- });
3516
- try {
3517
- viewNameSchema.parse(name);
3518
- } catch (error) {
3519
- if (error instanceof z3.z.ZodError) {
3520
- throw new Error(`[DetailViewBuilder] ${error.issues[0].message}`);
3521
- }
3522
- throw error;
3523
- }
3524
- }
3525
3597
  };
3526
3598
  function detailView(name, label) {
3527
3599
  return new DetailViewBuilder(name, label);
@@ -3529,7 +3601,10 @@ function detailView(name, label) {
3529
3601
  var ListViewBuilder = class {
3530
3602
  constructor(name, label) {
3531
3603
  this._version = 1;
3532
- this.validateName(name);
3604
+ validateViewName(name, "ListViewBuilder", {
3605
+ valid: "'default', 'list-view', 'active-contacts'",
3606
+ invalid: "'Default', 'listView', 'list_view'"
3607
+ });
3533
3608
  this.data = {
3534
3609
  name,
3535
3610
  label,
@@ -3579,7 +3654,7 @@ var ListViewBuilder = class {
3579
3654
  * @default 1
3580
3655
  */
3581
3656
  version(v) {
3582
- if (v < 1) throw new Error("View version must be >= 1");
3657
+ assertViewVersion(v);
3583
3658
  this._version = v;
3584
3659
  return this;
3585
3660
  }
@@ -3621,13 +3696,11 @@ var ListViewBuilder = class {
3621
3696
  if (this.data.tabs.length === 0) {
3622
3697
  throw new Error("[ListViewBuilder] At least one tab is required");
3623
3698
  }
3624
- const tabIds = /* @__PURE__ */ new Set();
3625
- for (const tab of this.data.tabs) {
3626
- if (tabIds.has(tab.id)) {
3627
- throw new Error(`[ListViewBuilder] Duplicate tab id "${tab.id}"`);
3628
- }
3629
- tabIds.add(tab.id);
3630
- }
3699
+ assertUniqueBy(
3700
+ this.data.tabs,
3701
+ (tab) => tab.id,
3702
+ (id) => `[ListViewBuilder] Duplicate tab id "${id}"`
3703
+ );
3631
3704
  const defaultTabs = this.data.tabs.filter((t) => t.default);
3632
3705
  if (defaultTabs.length > 1) {
3633
3706
  throw new Error("[ListViewBuilder] Only one tab can be marked as default");
@@ -3682,22 +3755,6 @@ var ListViewBuilder = class {
3682
3755
  schema_version: this._version
3683
3756
  };
3684
3757
  }
3685
- /**
3686
- * Validate view name format (kebab-case)
3687
- */
3688
- validateName(name) {
3689
- const viewNameSchema = z3.z.string().min(1, "View name cannot be empty").max(63, "View name is too long (max 63 characters)").regex(/^[a-z][a-z0-9-]*$/, {
3690
- message: "Invalid view name format.\nName must be in kebab-case:\n \u2705 Valid: 'default', 'list-view', 'active-contacts'\n \u274C Invalid: 'Default', 'listView', 'list_view'"
3691
- });
3692
- try {
3693
- viewNameSchema.parse(name);
3694
- } catch (error) {
3695
- if (error instanceof z3.z.ZodError) {
3696
- throw new Error(`[ListViewBuilder] ${error.issues[0].message}`);
3697
- }
3698
- throw error;
3699
- }
3700
- }
3701
3758
  };
3702
3759
  var ListViewTabConfigBuilder = class _ListViewTabConfigBuilder {
3703
3760
  /** @internal */
@@ -5517,6 +5574,10 @@ Object.defineProperty(exports, "createFormAttributeValidator", {
5517
5574
  enumerable: true,
5518
5575
  get: function () { return chunk64R5X3DF_js.createFormAttributeValidator; }
5519
5576
  });
5577
+ Object.defineProperty(exports, "validateDraft", {
5578
+ enumerable: true,
5579
+ get: function () { return chunk64R5X3DF_js.validateDraft; }
5580
+ });
5520
5581
  Object.defineProperty(exports, "validateDraftOrThrow", {
5521
5582
  enumerable: true,
5522
5583
  get: function () { return chunk64R5X3DF_js.validateDraftOrThrow; }
@@ -5547,11 +5608,14 @@ exports.BEHAVIOR_PROPERTIES = BEHAVIOR_PROPERTIES;
5547
5608
  exports.ConcurrentModificationError = ConcurrentModificationError;
5548
5609
  exports.CustomTabConfig = CustomTabConfig;
5549
5610
  exports.DB_COLUMN_FIELDS = DB_COLUMN_FIELDS;
5611
+ exports.DEFAULT_DOCUMENT_SLOT = DEFAULT_DOCUMENT_SLOT;
5550
5612
  exports.DEFAULT_ROLES = DEFAULT_ROLES;
5551
5613
  exports.DEFAULT_ROLE_DESCRIPTIONS = DEFAULT_ROLE_DESCRIPTIONS;
5552
5614
  exports.DEFAULT_ROLE_LABELS = DEFAULT_ROLE_LABELS;
5553
5615
  exports.DEFAULT_ROLE_PERMISSIONS = DEFAULT_ROLE_PERMISSIONS;
5616
+ exports.DOCUMENT_SYSTEM_ATTRIBUTES = DOCUMENT_SYSTEM_ATTRIBUTES;
5554
5617
  exports.DetailViewBuilder = DetailViewBuilder;
5618
+ exports.DocumentSlotValidationError = DocumentSlotValidationError;
5555
5619
  exports.DocumentsTabConfig = DocumentsTabConfig;
5556
5620
  exports.DuplicateError = DuplicateError;
5557
5621
  exports.EMPTY_VALUE_PLACEHOLDER = EMPTY_VALUE_PLACEHOLDER;
@@ -5652,6 +5716,7 @@ exports.isAttributeSortable = isAttributeSortable;
5652
5716
  exports.isBilateralRelation = isBilateralRelation;
5653
5717
  exports.isDefaultRole = isDefaultRole;
5654
5718
  exports.isDetailView = isDetailView;
5719
+ exports.isDocumentAttribute = isDocumentAttribute;
5655
5720
  exports.isEmptyObject = isEmptyObject;
5656
5721
  exports.isFieldGroup = isFieldGroup;
5657
5722
  exports.isFormDefinition = isFormDefinition;
@@ -5677,7 +5742,9 @@ exports.isValidationError = isValidationError;
5677
5742
  exports.jsonFlag = jsonFlag;
5678
5743
  exports.listView = listView;
5679
5744
  exports.location = location;
5745
+ exports.matchesMime = matchesMime;
5680
5746
  exports.multiselect = multiselect;
5747
+ exports.normaliseDocumentSlots = normaliseDocumentSlots;
5681
5748
  exports.number = number;
5682
5749
  exports.numberFlag = numberFlag;
5683
5750
  exports.object = object;
@@ -5702,4 +5769,5 @@ exports.user = user;
5702
5769
  exports.validateAttributeName = validateAttributeName;
5703
5770
  exports.validateFormulaExpression = validateFormulaExpression;
5704
5771
  exports.validatePath = validatePath;
5772
+ exports.validateSlotAgainstConfig = validateSlotAgainstConfig;
5705
5773
  exports.viewRegistry = viewRegistry;
package/dist/index.mjs CHANGED
@@ -3,7 +3,7 @@ export { asTenantId, asUserId, deepEqual, generateId, indexBy } from './chunk-QY
3
3
  import './chunk-SP3PNHYF.mjs';
4
4
  export { parseAttributeConfig } from './chunk-SS2NR6DH.mjs';
5
5
  import { createObjectValidator, createAttributeValidator } from './chunk-6JEQE4IP.mjs';
6
- export { computeRecordStatus, createFormAttributeValidator, validateDraftOrThrow, validateObject, validateObjectOrThrow } from './chunk-6JEQE4IP.mjs';
6
+ export { computeRecordStatus, createFormAttributeValidator, validateDraft, validateDraftOrThrow, validateObject, validateObjectOrThrow } from './chunk-6JEQE4IP.mjs';
7
7
  import './chunk-TMYBEXBT.mjs';
8
8
  import './chunk-4KRLCWJM.mjs';
9
9
  import './chunk-KNYZH2WD.mjs';
@@ -63,6 +63,9 @@ function isAttributeSortable(attr) {
63
63
  return !NON_SORTABLE_TYPES.has(attr.type);
64
64
  }
65
65
 
66
+ // src/types/documents.ts
67
+ var DEFAULT_DOCUMENT_SLOT = { name: "file" };
68
+
66
69
  // src/exceptions.ts
67
70
  var SchemaErrorCode = {
68
71
  // Generic
@@ -694,6 +697,53 @@ function isNotEmpty(obj) {
694
697
  function toUndefinedIfEmpty(obj) {
695
698
  return isNotEmpty(obj) ? obj : void 0;
696
699
  }
700
+
701
+ // src/lib/document-attribute.ts
702
+ var DOCUMENT_SYSTEM_ATTRIBUTES = {
703
+ ATTACHMENTS: "attachments"
704
+ };
705
+ function isDocumentAttribute(attr) {
706
+ return attr.type === "document";
707
+ }
708
+ function matchesMime(mime, accepted) {
709
+ if (!accepted || accepted.length === 0) return true;
710
+ return accepted.some((pattern) => {
711
+ if (pattern.endsWith("/*")) {
712
+ return mime.startsWith(pattern.slice(0, -1));
713
+ }
714
+ return mime === pattern;
715
+ });
716
+ }
717
+ function normaliseDocumentSlots(slots) {
718
+ if (!slots || slots.length === 0) return [DEFAULT_DOCUMENT_SLOT];
719
+ return slots;
720
+ }
721
+ var DocumentSlotValidationError = class extends Error {
722
+ constructor(code, message, context) {
723
+ super(`${code}: ${message}`);
724
+ this.code = code;
725
+ this.context = context;
726
+ this.name = "DocumentSlotValidationError";
727
+ }
728
+ };
729
+ function validateSlotAgainstConfig(slotName, mimeType, slots) {
730
+ const slot = slots.find((s) => s.name === slotName);
731
+ if (!slot) {
732
+ throw new DocumentSlotValidationError(
733
+ "SLOT_NOT_DECLARED",
734
+ `Slot "${slotName}" is not declared.`,
735
+ { availableSlots: slots.map((s) => s.name) }
736
+ );
737
+ }
738
+ if (!matchesMime(mimeType, slot.acceptedMimeTypes)) {
739
+ throw new DocumentSlotValidationError(
740
+ "MIME_NOT_ACCEPTED",
741
+ `MIME ${mimeType} not accepted for slot "${slotName}".`,
742
+ { acceptedMimeTypes: slot.acceptedMimeTypes }
743
+ );
744
+ }
745
+ return slot;
746
+ }
697
747
  var EMPTY_VALUE_PLACEHOLDER = "\u2014";
698
748
  function formatText(value) {
699
749
  return String(value);
@@ -2106,6 +2156,14 @@ var DocumentAttributeBuilder = class extends BaseAttributeBuilder {
2106
2156
  this.attr.autoProcess = true;
2107
2157
  return this;
2108
2158
  }
2159
+ /**
2160
+ * Define named upload slots for this document attribute.
2161
+ * An empty array falls back to a single default slot.
2162
+ */
2163
+ slots(configs) {
2164
+ this.attr.slots = configs.length === 0 ? [DEFAULT_DOCUMENT_SLOT] : configs;
2165
+ return this;
2166
+ }
2109
2167
  /**
2110
2168
  * Add a child attribute definition for per-document metadata.
2111
2169
  * Reuses existing attribute builders directly.
@@ -2944,6 +3002,35 @@ var RelationGroupBuilder = class {
2944
3002
  return this.data;
2945
3003
  }
2946
3004
  };
3005
+ function assertViewVersion(version) {
3006
+ if (version < 1) throw new Error("View version must be >= 1");
3007
+ }
3008
+ function assertUniqueBy(items, getKey, buildError) {
3009
+ const seen = /* @__PURE__ */ new Set();
3010
+ for (const item of items) {
3011
+ const key = getKey(item);
3012
+ if (seen.has(key)) {
3013
+ throw new Error(buildError(key));
3014
+ }
3015
+ seen.add(key);
3016
+ }
3017
+ }
3018
+ function validateViewName(name, builderName, examples) {
3019
+ const viewNameSchema = z.string().min(1, "View name cannot be empty").max(63, "View name is too long (max 63 characters)").regex(/^[a-z][a-z0-9-]*$/, {
3020
+ message: `Invalid view name format.
3021
+ Name must be in kebab-case:
3022
+ \u2705 Valid: ${examples.valid}
3023
+ \u274C Invalid: ${examples.invalid}`
3024
+ });
3025
+ try {
3026
+ viewNameSchema.parse(name);
3027
+ } catch (error) {
3028
+ if (error instanceof z.ZodError) {
3029
+ throw new Error(`[${builderName}] ${error.issues[0].message}`);
3030
+ }
3031
+ throw error;
3032
+ }
3033
+ }
2947
3034
  var TableTabConfig = class {
2948
3035
  /** @internal */
2949
3036
  constructor(view, tabData) {
@@ -3354,7 +3441,10 @@ var TabBuilder = class {
3354
3441
  var DetailViewBuilder = class {
3355
3442
  constructor(name, label) {
3356
3443
  this._version = 1;
3357
- this.validateName(name);
3444
+ validateViewName(name, "DetailViewBuilder", {
3445
+ valid: "'detail', 'list-view', 'company-detail'",
3446
+ invalid: "'Detail', 'listView', 'list_view'"
3447
+ });
3358
3448
  this.data = {
3359
3449
  name,
3360
3450
  label,
@@ -3422,7 +3512,7 @@ var DetailViewBuilder = class {
3422
3512
  * @default 1
3423
3513
  */
3424
3514
  version(v) {
3425
- if (v < 1) throw new Error("View version must be >= 1");
3515
+ assertViewVersion(v);
3426
3516
  this._version = v;
3427
3517
  return this;
3428
3518
  }
@@ -3466,13 +3556,11 @@ var DetailViewBuilder = class {
3466
3556
  if (this.data.tabs.length === 0) {
3467
3557
  throw new Error("[DetailViewBuilder] At least one tab is required");
3468
3558
  }
3469
- const tabNames = /* @__PURE__ */ new Set();
3470
- for (const tab of this.data.tabs) {
3471
- if (tabNames.has(tab.name)) {
3472
- throw new Error(`[DetailViewBuilder] Duplicate tab name "${tab.name}"`);
3473
- }
3474
- tabNames.add(tab.name);
3475
- }
3559
+ assertUniqueBy(
3560
+ this.data.tabs,
3561
+ (tab) => tab.name,
3562
+ (name) => `[DetailViewBuilder] Duplicate tab name "${name}"`
3563
+ );
3476
3564
  if (this.data.layout === "modal") {
3477
3565
  if (this.data.tabs.length !== 1) {
3478
3566
  throw new Error("[DetailViewBuilder] Modal views must have exactly one tab");
@@ -3502,22 +3590,6 @@ var DetailViewBuilder = class {
3502
3590
  schema_version: this._version
3503
3591
  };
3504
3592
  }
3505
- /**
3506
- * Validate view name format (kebab-case)
3507
- */
3508
- validateName(name) {
3509
- const viewNameSchema = z.string().min(1, "View name cannot be empty").max(63, "View name is too long (max 63 characters)").regex(/^[a-z][a-z0-9-]*$/, {
3510
- message: "Invalid view name format.\nName must be in kebab-case:\n \u2705 Valid: 'detail', 'list-view', 'company-detail'\n \u274C Invalid: 'Detail', 'listView', 'list_view'"
3511
- });
3512
- try {
3513
- viewNameSchema.parse(name);
3514
- } catch (error) {
3515
- if (error instanceof z.ZodError) {
3516
- throw new Error(`[DetailViewBuilder] ${error.issues[0].message}`);
3517
- }
3518
- throw error;
3519
- }
3520
- }
3521
3593
  };
3522
3594
  function detailView(name, label) {
3523
3595
  return new DetailViewBuilder(name, label);
@@ -3525,7 +3597,10 @@ function detailView(name, label) {
3525
3597
  var ListViewBuilder = class {
3526
3598
  constructor(name, label) {
3527
3599
  this._version = 1;
3528
- this.validateName(name);
3600
+ validateViewName(name, "ListViewBuilder", {
3601
+ valid: "'default', 'list-view', 'active-contacts'",
3602
+ invalid: "'Default', 'listView', 'list_view'"
3603
+ });
3529
3604
  this.data = {
3530
3605
  name,
3531
3606
  label,
@@ -3575,7 +3650,7 @@ var ListViewBuilder = class {
3575
3650
  * @default 1
3576
3651
  */
3577
3652
  version(v) {
3578
- if (v < 1) throw new Error("View version must be >= 1");
3653
+ assertViewVersion(v);
3579
3654
  this._version = v;
3580
3655
  return this;
3581
3656
  }
@@ -3617,13 +3692,11 @@ var ListViewBuilder = class {
3617
3692
  if (this.data.tabs.length === 0) {
3618
3693
  throw new Error("[ListViewBuilder] At least one tab is required");
3619
3694
  }
3620
- const tabIds = /* @__PURE__ */ new Set();
3621
- for (const tab of this.data.tabs) {
3622
- if (tabIds.has(tab.id)) {
3623
- throw new Error(`[ListViewBuilder] Duplicate tab id "${tab.id}"`);
3624
- }
3625
- tabIds.add(tab.id);
3626
- }
3695
+ assertUniqueBy(
3696
+ this.data.tabs,
3697
+ (tab) => tab.id,
3698
+ (id) => `[ListViewBuilder] Duplicate tab id "${id}"`
3699
+ );
3627
3700
  const defaultTabs = this.data.tabs.filter((t) => t.default);
3628
3701
  if (defaultTabs.length > 1) {
3629
3702
  throw new Error("[ListViewBuilder] Only one tab can be marked as default");
@@ -3678,22 +3751,6 @@ var ListViewBuilder = class {
3678
3751
  schema_version: this._version
3679
3752
  };
3680
3753
  }
3681
- /**
3682
- * Validate view name format (kebab-case)
3683
- */
3684
- validateName(name) {
3685
- const viewNameSchema = z.string().min(1, "View name cannot be empty").max(63, "View name is too long (max 63 characters)").regex(/^[a-z][a-z0-9-]*$/, {
3686
- message: "Invalid view name format.\nName must be in kebab-case:\n \u2705 Valid: 'default', 'list-view', 'active-contacts'\n \u274C Invalid: 'Default', 'listView', 'list_view'"
3687
- });
3688
- try {
3689
- viewNameSchema.parse(name);
3690
- } catch (error) {
3691
- if (error instanceof z.ZodError) {
3692
- throw new Error(`[ListViewBuilder] ${error.issues[0].message}`);
3693
- }
3694
- throw error;
3695
- }
3696
- }
3697
3754
  };
3698
3755
  var ListViewTabConfigBuilder = class _ListViewTabConfigBuilder {
3699
3756
  /** @internal */
@@ -5481,4 +5538,4 @@ function evaluateRule(rule, values, attrByName) {
5481
5538
  return spec.evaluateInMemory(values[rule.attribute], rule.value, attr);
5482
5539
  }
5483
5540
 
5484
- export { ALL_ACTIONS, ALL_SYSTEM_RESOURCES, AccessDeniedError, ActivityTabConfig, AttributeInUseError, AttributeNotFoundError, BEHAVIOR_PROPERTIES, ConcurrentModificationError, CustomTabConfig, DB_COLUMN_FIELDS, DEFAULT_ROLES, DEFAULT_ROLE_DESCRIPTIONS, DEFAULT_ROLE_LABELS, DEFAULT_ROLE_PERMISSIONS, DetailViewBuilder, DocumentsTabConfig, DuplicateError, EMPTY_VALUE_PLACEHOLDER, FORM_FORBIDDEN_ATTRIBUTE_TYPES, FlagRegistry, FlagService, ForbiddenError, FormBuilder, FormRegistry, FormRowBuilder, FormStepBuilder, GroupBuilder, IDENTITY_PROPERTIES, InvalidPathError, ListViewBuilder, ListViewTabConfigBuilder, MaxDepthExceededError, MemoryNotFoundError, NO_VALUE_OPERATORS, NoopGeocodingAdapter, NotFoundError, NotImplementedError, OPERATORS_BY_TYPE, OPERATOR_SPECS, ObjectBuilder, ObjectNotFoundError, ObjectReferencedError, PRESENTATION_PROPERTIES, PolicyViolationError, ProtectedResourceError, ProtectedRoleError, RELATION_TARGET_ANY, RESERVED_ATTRIBUTE_NAMES, RecordNotFoundError, RecordReferencedError, RelationGroupBuilder, RepositoryError, RichtextTabConfig, RoleNotFoundError, STANDARD_SCHEMA_VENDOR, SYSTEM_ATTRIBUTES, SYSTEM_ATTRIBUTE_I18N_KEYS, SYSTEM_FIELD_NAMES, SYSTEM_RESOURCES, SYSTEM_RESOURCE_LABELS, SchemaError, SchemaErrorCode, StorageError, SyncError, TabBuilder, TableTabConfig, USER_STATUSES, ValidationError, accessLevelToActions, actionsToAccessLevel, applyPipes, booleanFlag, checkbox, createFlagRegistry, createFlagService, createStandardSchemaProps, currency, date, detailView, document, evaluateFilterState, evaluateFormula, evaluateFormulaAttribute, evaluateFormulaWithResult, extractAttributeNames, extractFormulaVariables, extractRelationNames, extractRelationReferences, file, flagRegistry, flattenRelationsForEval, form, formRegistry, formatAttributeValue, formatFormulaResult, formula, generateDefaultDetailView, generateDefaultListView, getActiveTab, getErrorMessage, getPathDepth, getRelationPath, getRollupFilterOperators, getSystemAttributeI18nKey, getSystemAttributeList, getTargetAttributeName, group, hasOptions, hasRelationReferences, inferInverseCardinality, isAttributeInUseError, isAttributeSortable, isBilateralRelation, isDefaultRole, isDetailView, isEmptyObject, isFieldGroup, isFormDefinition, isFormFieldsRow, isFormFreeFieldRef, isFormHeadingRow, isFormSeparatorRow, isFormSlotFieldRef, isFormTextRow, isLabelExpression, isListView, isNoValueOperator, isNotEmpty, isNotFoundError, isObjectReferencedError, isProtectedResourceError, isRecordReferencedError, isRelationGroup, isSchemaError, isStandardSchema, isUniversalRelation, isValidationError, jsonFlag, listView, location, multiselect, number, numberFlag, object, parsePath, pathHasManyCardinality, phone, rating, registry, relation, relationGroup, renderLabelExpression, resetViewToDefault, richtext, rollup, select, status, stringFlag, text, textarea, toUndefinedIfEmpty, user, validateAttributeName, validateFormulaExpression, validatePath, viewRegistry };
5541
+ export { ALL_ACTIONS, ALL_SYSTEM_RESOURCES, AccessDeniedError, ActivityTabConfig, AttributeInUseError, AttributeNotFoundError, BEHAVIOR_PROPERTIES, ConcurrentModificationError, CustomTabConfig, DB_COLUMN_FIELDS, DEFAULT_DOCUMENT_SLOT, DEFAULT_ROLES, DEFAULT_ROLE_DESCRIPTIONS, DEFAULT_ROLE_LABELS, DEFAULT_ROLE_PERMISSIONS, DOCUMENT_SYSTEM_ATTRIBUTES, DetailViewBuilder, DocumentSlotValidationError, DocumentsTabConfig, DuplicateError, EMPTY_VALUE_PLACEHOLDER, FORM_FORBIDDEN_ATTRIBUTE_TYPES, FlagRegistry, FlagService, ForbiddenError, FormBuilder, FormRegistry, FormRowBuilder, FormStepBuilder, GroupBuilder, IDENTITY_PROPERTIES, InvalidPathError, ListViewBuilder, ListViewTabConfigBuilder, MaxDepthExceededError, MemoryNotFoundError, NO_VALUE_OPERATORS, NoopGeocodingAdapter, NotFoundError, NotImplementedError, OPERATORS_BY_TYPE, OPERATOR_SPECS, ObjectBuilder, ObjectNotFoundError, ObjectReferencedError, PRESENTATION_PROPERTIES, PolicyViolationError, ProtectedResourceError, ProtectedRoleError, RELATION_TARGET_ANY, RESERVED_ATTRIBUTE_NAMES, RecordNotFoundError, RecordReferencedError, RelationGroupBuilder, RepositoryError, RichtextTabConfig, RoleNotFoundError, STANDARD_SCHEMA_VENDOR, SYSTEM_ATTRIBUTES, SYSTEM_ATTRIBUTE_I18N_KEYS, SYSTEM_FIELD_NAMES, SYSTEM_RESOURCES, SYSTEM_RESOURCE_LABELS, SchemaError, SchemaErrorCode, StorageError, SyncError, TabBuilder, TableTabConfig, USER_STATUSES, ValidationError, accessLevelToActions, actionsToAccessLevel, applyPipes, booleanFlag, checkbox, createFlagRegistry, createFlagService, createStandardSchemaProps, currency, date, detailView, document, evaluateFilterState, evaluateFormula, evaluateFormulaAttribute, evaluateFormulaWithResult, extractAttributeNames, extractFormulaVariables, extractRelationNames, extractRelationReferences, file, flagRegistry, flattenRelationsForEval, form, formRegistry, formatAttributeValue, formatFormulaResult, formula, generateDefaultDetailView, generateDefaultListView, getActiveTab, getErrorMessage, getPathDepth, getRelationPath, getRollupFilterOperators, getSystemAttributeI18nKey, getSystemAttributeList, getTargetAttributeName, group, hasOptions, hasRelationReferences, inferInverseCardinality, isAttributeInUseError, isAttributeSortable, isBilateralRelation, isDefaultRole, isDetailView, isDocumentAttribute, isEmptyObject, isFieldGroup, isFormDefinition, isFormFieldsRow, isFormFreeFieldRef, isFormHeadingRow, isFormSeparatorRow, isFormSlotFieldRef, isFormTextRow, isLabelExpression, isListView, isNoValueOperator, isNotEmpty, isNotFoundError, isObjectReferencedError, isProtectedResourceError, isRecordReferencedError, isRelationGroup, isSchemaError, isStandardSchema, isUniversalRelation, isValidationError, jsonFlag, listView, location, matchesMime, multiselect, normaliseDocumentSlots, number, numberFlag, object, parsePath, pathHasManyCardinality, phone, rating, registry, relation, relationGroup, renderLabelExpression, resetViewToDefault, richtext, rollup, select, status, stringFlag, text, textarea, toUndefinedIfEmpty, user, validateAttributeName, validateFormulaExpression, validatePath, validateSlotAgainstConfig, viewRegistry };
@@ -1,4 +1,4 @@
1
- import { A as Attribute } from './attributes-CNpcbVbv.js';
1
+ import { A as Attribute } from './filters-zzsF0GxK.js';
2
2
 
3
3
  /**
4
4
  * Validation messages for Zod validators.
@@ -1,4 +1,4 @@
1
- import { A as Attribute } from './attributes-DcHM27jS.mjs';
1
+ import { A as Attribute } from './filters-DRXk4dLI.mjs';
2
2
 
3
3
  /**
4
4
  * Validation messages for Zod validators.
@@ -1,8 +1,8 @@
1
- export { V as ValidationMessages } from '../types-DT8dfR2I.mjs';
1
+ export { V as ValidationMessages } from '../types-DxEobsMy.mjs';
2
2
  export { DEFAULT_VALIDATION_MESSAGES, formatZodErrors } from './core/index.mjs';
3
3
  export { parseAttributeConfig } from './config/index.mjs';
4
- export { c as computeRecordStatus, a as createFormAttributeValidator, v as validateDraftOrThrow, b as validateObject, d as validateObjectOrThrow } from '../helpers-BDn1PUC2.mjs';
5
- import '../attributes-DcHM27jS.mjs';
4
+ export { c as computeRecordStatus, a as createFormAttributeValidator, v as validateDraft, b as validateDraftOrThrow, d as validateObject, e as validateObjectOrThrow } from '../helpers-DOjqrfWE.mjs';
5
+ import '../filters-DRXk4dLI.mjs';
6
6
  import '@stndrds/constants';
7
7
  import '../utils.mjs';
8
8
  import 'zod';
@@ -1,8 +1,8 @@
1
- export { V as ValidationMessages } from '../types-CUbVw7X2.js';
1
+ export { V as ValidationMessages } from '../types-Bemfgle3.js';
2
2
  export { DEFAULT_VALIDATION_MESSAGES, formatZodErrors } from './core/index.js';
3
3
  export { parseAttributeConfig } from './config/index.js';
4
- export { c as computeRecordStatus, a as createFormAttributeValidator, v as validateDraftOrThrow, b as validateObject, d as validateObjectOrThrow } from '../helpers-oaW8DBAh.js';
5
- import '../attributes-CNpcbVbv.js';
4
+ export { c as computeRecordStatus, a as createFormAttributeValidator, v as validateDraft, b as validateDraftOrThrow, d as validateObject, e as validateObjectOrThrow } from '../helpers-64gmAyw0.js';
5
+ import '../filters-zzsF0GxK.js';
6
6
  import '@stndrds/constants';
7
7
  import '../utils.js';
8
8
  import 'zod';
@@ -34,6 +34,10 @@ Object.defineProperty(exports, "createFormAttributeValidator", {
34
34
  enumerable: true,
35
35
  get: function () { return chunk64R5X3DF_js.createFormAttributeValidator; }
36
36
  });
37
+ Object.defineProperty(exports, "validateDraft", {
38
+ enumerable: true,
39
+ get: function () { return chunk64R5X3DF_js.validateDraft; }
40
+ });
37
41
  Object.defineProperty(exports, "validateDraftOrThrow", {
38
42
  enumerable: true,
39
43
  get: function () { return chunk64R5X3DF_js.validateDraftOrThrow; }
@@ -1,6 +1,6 @@
1
1
  import '../chunk-SP3PNHYF.mjs';
2
2
  export { parseAttributeConfig } from '../chunk-SS2NR6DH.mjs';
3
- export { computeRecordStatus, createFormAttributeValidator, validateDraftOrThrow, validateObject, validateObjectOrThrow } from '../chunk-6JEQE4IP.mjs';
3
+ export { computeRecordStatus, createFormAttributeValidator, validateDraft, validateDraftOrThrow, validateObject, validateObjectOrThrow } from '../chunk-6JEQE4IP.mjs';
4
4
  import '../chunk-TMYBEXBT.mjs';
5
5
  import '../chunk-4KRLCWJM.mjs';
6
6
  import '../chunk-KNYZH2WD.mjs';
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
- import { C as CurrencyAttribute } from '../../attributes-DcHM27jS.mjs';
3
- import { V as ValidationMessages } from '../../types-DT8dfR2I.mjs';
2
+ import { C as CurrencyAttribute } from '../../filters-DRXk4dLI.mjs';
3
+ import { V as ValidationMessages } from '../../types-DxEobsMy.mjs';
4
4
  import '@stndrds/constants';
5
5
  import '../../utils.mjs';
6
6
 
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
- import { C as CurrencyAttribute } from '../../attributes-CNpcbVbv.js';
3
- import { V as ValidationMessages } from '../../types-CUbVw7X2.js';
2
+ import { C as CurrencyAttribute } from '../../filters-zzsF0GxK.js';
3
+ import { V as ValidationMessages } from '../../types-Bemfgle3.js';
4
4
  import '@stndrds/constants';
5
5
  import '../../utils.js';
6
6
 
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
- import { F as FileAttribute } from '../../attributes-DcHM27jS.mjs';
3
- import { V as ValidationMessages } from '../../types-DT8dfR2I.mjs';
2
+ import { F as FileAttribute } from '../../filters-DRXk4dLI.mjs';
3
+ import { V as ValidationMessages } from '../../types-DxEobsMy.mjs';
4
4
  import '@stndrds/constants';
5
5
  import '../../utils.mjs';
6
6
 
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
- import { F as FileAttribute } from '../../attributes-CNpcbVbv.js';
3
- import { V as ValidationMessages } from '../../types-CUbVw7X2.js';
2
+ import { F as FileAttribute } from '../../filters-zzsF0GxK.js';
3
+ import { V as ValidationMessages } from '../../types-Bemfgle3.js';
4
4
  import '@stndrds/constants';
5
5
  import '../../utils.js';
6
6
 
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
- import { L as LocationAttribute } from '../../attributes-DcHM27jS.mjs';
3
- import { V as ValidationMessages } from '../../types-DT8dfR2I.mjs';
2
+ import { L as LocationAttribute } from '../../filters-DRXk4dLI.mjs';
3
+ import { V as ValidationMessages } from '../../types-DxEobsMy.mjs';
4
4
  import '@stndrds/constants';
5
5
  import '../../utils.mjs';
6
6
 
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
- import { L as LocationAttribute } from '../../attributes-CNpcbVbv.js';
3
- import { V as ValidationMessages } from '../../types-CUbVw7X2.js';
2
+ import { L as LocationAttribute } from '../../filters-zzsF0GxK.js';
3
+ import { V as ValidationMessages } from '../../types-Bemfgle3.js';
4
4
  import '@stndrds/constants';
5
5
  import '../../utils.js';
6
6