@valbuild/core 0.124.0 → 0.126.0

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 (37) hide show
  1. package/CHANGELOG.md +196 -0
  2. package/dist/declarations/src/getSourcePathFromRoute.d.ts +12 -3
  3. package/dist/declarations/src/index.d.ts +7 -3
  4. package/dist/declarations/src/initSchema.d.ts +46 -15
  5. package/dist/declarations/src/initVal.d.ts +108 -0
  6. package/dist/declarations/src/render.d.ts +5 -4
  7. package/dist/declarations/src/router.d.ts +45 -0
  8. package/dist/declarations/src/schema/array.d.ts +65 -0
  9. package/dist/declarations/src/schema/boolean.d.ts +44 -0
  10. package/dist/declarations/src/schema/code.d.ts +63 -0
  11. package/dist/declarations/src/schema/color.d.ts +54 -0
  12. package/dist/declarations/src/schema/date.d.ts +64 -2
  13. package/dist/declarations/src/schema/datetime.d.ts +87 -2
  14. package/dist/declarations/src/schema/discriminatedUnion.d.ts +166 -0
  15. package/dist/declarations/src/schema/enum.d.ts +122 -0
  16. package/dist/declarations/src/schema/file.d.ts +77 -0
  17. package/dist/declarations/src/schema/image.d.ts +102 -0
  18. package/dist/declarations/src/schema/index.d.ts +42 -2
  19. package/dist/declarations/src/schema/keyOf.d.ts +50 -0
  20. package/dist/declarations/src/schema/literal.d.ts +46 -0
  21. package/dist/declarations/src/schema/number.d.ts +58 -0
  22. package/dist/declarations/src/schema/object.d.ts +63 -0
  23. package/dist/declarations/src/schema/record.d.ts +136 -0
  24. package/dist/declarations/src/schema/richtext.d.ts +78 -0
  25. package/dist/declarations/src/schema/route.d.ts +44 -0
  26. package/dist/declarations/src/schema/string.d.ts +99 -0
  27. package/dist/declarations/src/schema/union.d.ts +54 -91
  28. package/dist/{index-22a40d42.cjs.prod.js → index-6db78f3c.cjs.prod.js} +2161 -423
  29. package/dist/{index-fcd087bd.cjs.dev.js → index-b41b638f.cjs.dev.js} +2161 -423
  30. package/dist/{index-9c14df37.esm.js → index-cd25c2dc.esm.js} +2155 -423
  31. package/dist/valbuild-core.cjs.dev.js +8 -2
  32. package/dist/valbuild-core.cjs.prod.js +8 -2
  33. package/dist/valbuild-core.esm.js +1 -1
  34. package/package.json +1 -1
  35. package/patch/dist/valbuild-core-patch.cjs.dev.js +1 -1
  36. package/patch/dist/valbuild-core-patch.cjs.prod.js +1 -1
  37. package/patch/dist/valbuild-core-patch.esm.js +2 -2
@@ -462,6 +462,23 @@ var StringSchema = /*#__PURE__*/function (_Schema) {
462
462
  _this.isMultiline = isMultiline;
463
463
  return _this;
464
464
  }
465
+
466
+ /**
467
+ * Describe this field.
468
+ *
469
+ * The description is shown next to the field's label in the Val editor, so
470
+ * it is where you say what an editor needs to know but the field name cannot
471
+ * carry. It also travels in the serialized schema, which is what the AI
472
+ * assistant and the MCP tools read.
473
+ *
474
+ * Pass `null` to clear a description set earlier.
475
+ *
476
+ * @example
477
+ * const schema = s
478
+ * .string()
479
+ * .describe("Shown in the browser tab and in search results");
480
+ * export default c.define("/example.val.ts", schema, "Hello");
481
+ */
465
482
  _inherits(StringSchema, _Schema);
466
483
  return _createClass(StringSchema, [{
467
484
  key: "describe",
@@ -471,12 +488,24 @@ var StringSchema = /*#__PURE__*/function (_Schema) {
471
488
 
472
489
  /**
473
490
  * @deprecated Use `minLength` instead
491
+ *
492
+ * @example
493
+ * const schema = s.string().minLength(2);
494
+ * export default c.define("/example.val.ts", schema, "Hi");
474
495
  */
475
496
  }, {
476
497
  key: "min",
477
498
  value: function min(minLength) {
478
499
  return this.minLength(minLength);
479
500
  }
501
+
502
+ /**
503
+ * Validate that the string is at least `minLength` characters long.
504
+ *
505
+ * @example
506
+ * const schema = s.string().minLength(2);
507
+ * export default c.define("/example.val.ts", schema, "Hi");
508
+ */
480
509
  }, {
481
510
  key: "minLength",
482
511
  value: function minLength(_minLength) {
@@ -487,12 +516,24 @@ var StringSchema = /*#__PURE__*/function (_Schema) {
487
516
 
488
517
  /**
489
518
  * @deprecated Use `maxLength` instead
519
+ *
520
+ * @example
521
+ * const schema = s.string().maxLength(60);
522
+ * export default c.define("/example.val.ts", schema, "A title that fits");
490
523
  */
491
524
  }, {
492
525
  key: "max",
493
526
  value: function max(maxLength) {
494
527
  return this.maxLength(maxLength);
495
528
  }
529
+
530
+ /**
531
+ * Validate that the string is at most `maxLength` characters long.
532
+ *
533
+ * @example
534
+ * const schema = s.string().maxLength(60);
535
+ * export default c.define("/example.val.ts", schema, "A title that fits");
536
+ */
496
537
  }, {
497
538
  key: "maxLength",
498
539
  value: function maxLength(_maxLength) {
@@ -500,6 +541,19 @@ var StringSchema = /*#__PURE__*/function (_Schema) {
500
541
  maxLength: _maxLength
501
542
  }), this.opt, this.isRaw, this.customValidateFunctions, this.renderInput, this.isReadonly, this.isHidden, this.description, this.previewInput, this.isMultiline);
502
543
  }
544
+
545
+ /**
546
+ * Validate that the string matches `regexp`.
547
+ *
548
+ * `message` is what the editor is shown when it does not match. Without one
549
+ * the error names the pattern, which is rarely what a non-developer needs.
550
+ *
551
+ * @example
552
+ * const schema = s
553
+ * .string()
554
+ * .regexp(/^[a-z0-9-]+$/, "Lower case letters, digits and dashes only");
555
+ * export default c.define("/example.val.ts", schema, "my-slug");
556
+ */
503
557
  }, {
504
558
  key: "regexp",
505
559
  value: function regexp(_regexp, message) {
@@ -508,6 +562,27 @@ var StringSchema = /*#__PURE__*/function (_Schema) {
508
562
  regExpMessage: message
509
563
  }), this.opt, this.isRaw, this.customValidateFunctions, this.renderInput, this.isReadonly, this.isHidden, this.description, this.previewInput, this.isMultiline);
510
564
  }
565
+
566
+ /**
567
+ * Add a custom validation rule to this field.
568
+ *
569
+ * The function is called with the field's value and returns `false` when the
570
+ * value is fine, or a STRING with the message to show when it is not. Call it
571
+ * more than once to add more rules — they all run, and every message is
572
+ * reported.
573
+ *
574
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
575
+ * when the value is fine, and `true` is not one of the two answers.
576
+ *
577
+ * Validation runs in the Studio as you type, in `npx val validate` and
578
+ * before a publish.
579
+ *
580
+ * @example
581
+ * const schema = s.string().validate((val) =>
582
+ * val.trim() === val ? false : "Must not start or end with a space",
583
+ * );
584
+ * export default c.define("/example.val.ts", schema, "Hello");
585
+ */
511
586
  }, {
512
587
  key: "validate",
513
588
  value: function validate(validationFunction) {
@@ -598,6 +673,26 @@ var StringSchema = /*#__PURE__*/function (_Schema) {
598
673
  var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
599
674
  return new StringSchema(this.options, this.opt, this.isRaw, this.customValidateFunctions, this.renderInput, this.isReadonly, isHidden, this.description, this.previewInput, this.isMultiline);
600
675
  }
676
+
677
+ /**
678
+ * Do not stega encode this string.
679
+ *
680
+ * Val normally encodes an invisible pointer back to the source into every
681
+ * string it hands your app, which is what makes click-to-edit work. A raw
682
+ * string is handed over exactly as written — use it wherever the value is
683
+ * not rendered as visible text: a slug, a class name, an `id`, a URL,
684
+ * anything parsed or compared.
685
+ *
686
+ * @example
687
+ * const schema = s.object({
688
+ * title: s.string(),
689
+ * slug: s.string().raw(),
690
+ * });
691
+ * export default c.define("/example.val.ts", schema, {
692
+ * title: "Hello",
693
+ * slug: "hello",
694
+ * });
695
+ */
601
696
  }, {
602
697
  key: "raw",
603
698
  value: function raw() {
@@ -663,6 +758,10 @@ var StringSchema = /*#__PURE__*/function (_Schema) {
663
758
  *
664
759
  * Static configuration, not a callback — see `render.ts`. What a CONTAINER
665
760
  * shows for its items is a `preview`, which is a different thing entirely.
761
+ *
762
+ * @example
763
+ * const schema = s.array(s.string().render({ as: "inline" }));
764
+ * export default c.define("/example.val.ts", schema, ["First", "Second"]);
666
765
  */
667
766
  }, {
668
767
  key: "render",
@@ -674,6 +773,12 @@ var StringSchema = /*#__PURE__*/function (_Schema) {
674
773
  * How this VALUE is shown where a preview of it is needed — a row in a
675
774
  * sortable list, a reference dropdown, a search hit. Never how the field
676
775
  * itself is edited (that is `render`). See `preview.ts`.
776
+ *
777
+ * @example
778
+ * const schema = s.array(
779
+ * s.string().preview(({ val }) => ({ title: val })),
780
+ * );
781
+ * export default c.define("/example.val.ts", schema, ["First", "Second"]);
677
782
  */
678
783
  }, {
679
784
  key: "preview",
@@ -734,12 +839,59 @@ var ObjectSchema = /*#__PURE__*/function (_Schema) {
734
839
  _this.previewInput = previewInput;
735
840
  return _this;
736
841
  }
842
+
843
+ /**
844
+ * Describe this field.
845
+ *
846
+ * The description is shown next to the field's label in the Val editor, so
847
+ * it is where you say what an editor needs to know but the field name cannot
848
+ * carry. It also travels in the serialized schema, which is what the AI
849
+ * assistant and the MCP tools read.
850
+ *
851
+ * Pass `null` to clear a description set earlier.
852
+ *
853
+ * @example
854
+ * const schema = s
855
+ * .object({ street: s.string(), city: s.string() })
856
+ * .describe("Where the office is — shown on the contact page");
857
+ * export default c.define("/example.val.ts", schema, {
858
+ * street: "Torggata 1",
859
+ * city: "Oslo",
860
+ * });
861
+ */
737
862
  _inherits(ObjectSchema, _Schema);
738
863
  return _createClass(ObjectSchema, [{
739
864
  key: "describe",
740
865
  value: function describe(description) {
741
866
  return new ObjectSchema(this.items, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
742
867
  }
868
+
869
+ /**
870
+ * Add a custom validation rule to this field.
871
+ *
872
+ * The function is called with the field's value and returns `false` when the
873
+ * value is fine, or a STRING with the message to show when it is not. Call it
874
+ * more than once to add more rules — they all run, and every message is
875
+ * reported.
876
+ *
877
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
878
+ * when the value is fine, and `true` is not one of the two answers.
879
+ *
880
+ * Validation runs in the Studio as you type, in `npx val validate` and
881
+ * before a publish.
882
+ *
883
+ * An object validator is the place for a rule that spans FIELDS — one field
884
+ * validated on its own belongs on that field's schema, where the error lands
885
+ * on the field itself.
886
+ *
887
+ * @example
888
+ * const schema = s
889
+ * .object({ from: s.number(), to: s.number() })
890
+ * .validate((val) =>
891
+ * val.from <= val.to ? false : "'from' must not be after 'to'",
892
+ * );
893
+ * export default c.define("/example.val.ts", schema, { from: 1, to: 4 });
894
+ */
743
895
  }, {
744
896
  key: "validate",
745
897
  value: function validate(validationFunction) {
@@ -892,6 +1044,16 @@ var ObjectSchema = /*#__PURE__*/function (_Schema) {
892
1044
  * instead of a preview row that navigates to it.
893
1045
  *
894
1046
  * Static configuration, not a callback — see `render.ts`.
1047
+ *
1048
+ * @example
1049
+ * // A page builder: each row edits the object in place, instead of
1050
+ * // navigating to it.
1051
+ * const block = s
1052
+ * .object({ heading: s.string(), body: s.string() })
1053
+ * .render({ as: "inline" });
1054
+ * export default c.define("/example.val.ts", s.array(block), [
1055
+ * { heading: "Hello", body: "World" },
1056
+ * ]);
895
1057
  */
896
1058
  }, {
897
1059
  key: "render",
@@ -903,6 +1065,14 @@ var ObjectSchema = /*#__PURE__*/function (_Schema) {
903
1065
  * How this VALUE is shown where a preview of it is needed — a row in a
904
1066
  * sortable list, a reference dropdown, a search hit. Never how the field
905
1067
  * itself is edited (that is `render`). See `preview.ts`.
1068
+ *
1069
+ * @example
1070
+ * const author = s
1071
+ * .object({ name: s.string(), role: s.string() })
1072
+ * .preview(({ val }) => ({ title: val.name, subtitle: val.role }));
1073
+ * export default c.define("/example.val.ts", s.array(author), [
1074
+ * { name: "Ada", role: "Engineer" },
1075
+ * ]);
906
1076
  */
907
1077
  }, {
908
1078
  key: "preview",
@@ -1005,12 +1175,54 @@ var ArraySchema = /*#__PURE__*/function (_Schema) {
1005
1175
  _this.renderInput = renderInput;
1006
1176
  return _this;
1007
1177
  }
1178
+
1179
+ /**
1180
+ * Describe this field.
1181
+ *
1182
+ * The description is shown next to the field's label in the Val editor, so
1183
+ * it is where you say what an editor needs to know but the field name cannot
1184
+ * carry. It also travels in the serialized schema, which is what the AI
1185
+ * assistant and the MCP tools read.
1186
+ *
1187
+ * Pass `null` to clear a description set earlier.
1188
+ *
1189
+ * @example
1190
+ * const schema = s
1191
+ * .array(s.string())
1192
+ * .describe("Bullet points shown under the heading");
1193
+ * export default c.define("/example.val.ts", schema, ["First", "Second"]);
1194
+ */
1008
1195
  _inherits(ArraySchema, _Schema);
1009
1196
  return _createClass(ArraySchema, [{
1010
1197
  key: "describe",
1011
1198
  value: function describe(description) {
1012
1199
  return new ArraySchema(this.item, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.previewInput, this.renderInput);
1013
1200
  }
1201
+
1202
+ /**
1203
+ * Add a custom validation rule to this field.
1204
+ *
1205
+ * The function is called with the field's value and returns `false` when the
1206
+ * value is fine, or a STRING with the message to show when it is not. Call it
1207
+ * more than once to add more rules — they all run, and every message is
1208
+ * reported.
1209
+ *
1210
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
1211
+ * when the value is fine, and `true` is not one of the two answers.
1212
+ *
1213
+ * Validation runs in the Studio as you type, in `npx val validate` and
1214
+ * before a publish.
1215
+ *
1216
+ * The function is given the whole array. To validate one item, put a
1217
+ * `.validate(...)` on the ITEM schema instead — that reports the error on
1218
+ * the item's own row.
1219
+ *
1220
+ * @example
1221
+ * const schema = s.array(s.string()).validate((val) =>
1222
+ * val.length <= 3 ? false : "At most 3 items",
1223
+ * );
1224
+ * export default c.define("/example.val.ts", schema, ["First", "Second"]);
1225
+ */
1014
1226
  }, {
1015
1227
  key: "validate",
1016
1228
  value: function validate(validationFunction) {
@@ -1218,6 +1430,25 @@ var ArraySchema = /*#__PURE__*/function (_Schema) {
1218
1430
  * is the item of another container, in search, in references. What its rows
1219
1431
  * show is the ITEM schema's `preview`, not this. Never how the field is
1220
1432
  * edited (that is `render`). See `preview.ts`.
1433
+ *
1434
+ * @example
1435
+ * // The preview of the ARRAY, for where it is an item of something else.
1436
+ * // What its own rows show is the ITEM schema's preview — see below.
1437
+ * const tags = s.array(s.string()).preview(({ val }) => ({
1438
+ * title: `${val.length} tags`,
1439
+ * }));
1440
+ * export default c.define("/example.val.ts", s.record(tags), {
1441
+ * "a-post": ["news", "release"],
1442
+ * });
1443
+ *
1444
+ * @example
1445
+ * // Rows of an array come from the ITEM's preview, not the array's:
1446
+ * const author = s
1447
+ * .object({ name: s.string(), role: s.string() })
1448
+ * .preview(({ val }) => ({ title: val.name, subtitle: val.role }));
1449
+ * export default c.define("/example.val.ts", s.array(author), [
1450
+ * { name: "Ada", role: "Engineer" },
1451
+ * ]);
1221
1452
  */
1222
1453
  }, {
1223
1454
  key: "preview",
@@ -1231,6 +1462,12 @@ var ArraySchema = /*#__PURE__*/function (_Schema) {
1231
1462
  * instead of a preview row that navigates to it.
1232
1463
  *
1233
1464
  * Static configuration, not a callback — see `render.ts`.
1465
+ *
1466
+ * @example
1467
+ * const schema = s.record(s.array(s.string()).render({ as: "inline" }));
1468
+ * export default c.define("/example.val.ts", schema, {
1469
+ * "a-post": ["news", "release"],
1470
+ * });
1234
1471
  */
1235
1472
  }, {
1236
1473
  key: "render",
@@ -1265,12 +1502,50 @@ var LiteralSchema = /*#__PURE__*/function (_Schema) {
1265
1502
  _this.previewInput = previewInput;
1266
1503
  return _this;
1267
1504
  }
1505
+
1506
+ /**
1507
+ * Describe this field.
1508
+ *
1509
+ * The description is shown next to the field's label in the Val editor, so
1510
+ * it is where you say what an editor needs to know but the field name cannot
1511
+ * carry. It also travels in the serialized schema, which is what the AI
1512
+ * assistant and the MCP tools read.
1513
+ *
1514
+ * Pass `null` to clear a description set earlier.
1515
+ *
1516
+ * @example
1517
+ * const schema = s
1518
+ * .literal("hero")
1519
+ * .describe("The block type — it identifies the variant");
1520
+ * export default c.define("/example.val.ts", schema, "hero");
1521
+ */
1268
1522
  _inherits(LiteralSchema, _Schema);
1269
1523
  return _createClass(LiteralSchema, [{
1270
1524
  key: "describe",
1271
1525
  value: function describe(description) {
1272
1526
  return new LiteralSchema(this.value, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
1273
1527
  }
1528
+
1529
+ /**
1530
+ * Add a custom validation rule to this field.
1531
+ *
1532
+ * The function is called with the field's value and returns `false` when the
1533
+ * value is fine, or a STRING with the message to show when it is not. Call it
1534
+ * more than once to add more rules — they all run, and every message is
1535
+ * reported.
1536
+ *
1537
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
1538
+ * when the value is fine, and `true` is not one of the two answers.
1539
+ *
1540
+ * Validation runs in the Studio as you type, in `npx val validate` and
1541
+ * before a publish.
1542
+ *
1543
+ * @example
1544
+ * const schema = s.literal("hero").validate((val) =>
1545
+ * val === "hero" ? false : "Unknown block type",
1546
+ * );
1547
+ * export default c.define("/example.val.ts", schema, "hero");
1548
+ */
1274
1549
  }, {
1275
1550
  key: "validate",
1276
1551
  value: function validate(validationFunction) {
@@ -1365,6 +1640,10 @@ var LiteralSchema = /*#__PURE__*/function (_Schema) {
1365
1640
  * instead of a preview row that navigates to it.
1366
1641
  *
1367
1642
  * Static configuration, not a callback — see `render.ts`.
1643
+ *
1644
+ * @example
1645
+ * const schema = s.array(s.literal("hero").render({ as: "inline" }));
1646
+ * export default c.define("/example.val.ts", schema, ["hero"]);
1368
1647
  */
1369
1648
  }, {
1370
1649
  key: "render",
@@ -1376,6 +1655,12 @@ var LiteralSchema = /*#__PURE__*/function (_Schema) {
1376
1655
  * How this VALUE is shown where a preview of it is needed — a row in a
1377
1656
  * sortable list, a reference dropdown, a search hit. Never how the field
1378
1657
  * itself is edited (that is `render`). See `preview.ts`.
1658
+ *
1659
+ * @example
1660
+ * const schema = s.array(
1661
+ * s.literal("hero").preview(({ val }) => ({ title: val })),
1662
+ * );
1663
+ * export default c.define("/example.val.ts", schema, ["hero"]);
1379
1664
  */
1380
1665
  }, {
1381
1666
  key: "preview",
@@ -1424,8 +1709,30 @@ var literal = function literal(value) {
1424
1709
  return new LiteralSchema(value);
1425
1710
  };
1426
1711
 
1427
- var UnionSchema = /*#__PURE__*/function (_Schema) {
1428
- function UnionSchema(key, items) {
1712
+ /** The variant objects a discriminated union on `Key` may be built from. */
1713
+
1714
+ /**
1715
+ * At least one variant, so a union with none cannot be written.
1716
+ *
1717
+ * Everything downstream reads the first one where it needs any — `emptyOf`
1718
+ * takes `items[0]` for the value a new entry starts as — and a union with
1719
+ * nothing to select is not a thing an author means. `s.enum` says the same
1720
+ * about its values.
1721
+ */
1722
+
1723
+ /** The source type a discriminated union over `T` accepts. */
1724
+
1725
+ /**
1726
+ * One of several object shapes, told apart by a tag field.
1727
+ *
1728
+ * Every variant is an object with `key` set to a distinct `s.literal(...)`, and
1729
+ * the value of that field decides which variant a value is. Unlike
1730
+ * {@link EnumSchema} this is a CONTAINER: the variant's fields are the fields
1731
+ * being edited, and everything that walks the schema tree has to descend
1732
+ * through the matching variant.
1733
+ */
1734
+ var DiscriminatedUnionSchema = /*#__PURE__*/function (_Schema) {
1735
+ function DiscriminatedUnionSchema(key, items) {
1429
1736
  var _this;
1430
1737
  var opt = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
1431
1738
  var customValidateFunctions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
@@ -1434,8 +1741,8 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
1434
1741
  var description = arguments.length > 6 ? arguments[6] : undefined;
1435
1742
  var renderInput = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : null;
1436
1743
  var previewInput = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : null;
1437
- _classCallCheck(this, UnionSchema);
1438
- _this = _callSuper(this, UnionSchema);
1744
+ _classCallCheck(this, DiscriminatedUnionSchema);
1745
+ _this = _callSuper(this, DiscriminatedUnionSchema);
1439
1746
  _this.key = key;
1440
1747
  _this.items = items;
1441
1748
  _this.opt = opt;
@@ -1447,16 +1754,66 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
1447
1754
  _this.previewInput = previewInput;
1448
1755
  return _this;
1449
1756
  }
1450
- _inherits(UnionSchema, _Schema);
1451
- return _createClass(UnionSchema, [{
1757
+
1758
+ /**
1759
+ * Describe this field.
1760
+ *
1761
+ * The description is shown next to the field's label in the Val editor, so it is
1762
+ * where you say what an editor needs to know but the field name cannot carry. It
1763
+ * also travels in the serialized schema, which is what the AI assistant and the
1764
+ * MCP tools read.
1765
+ *
1766
+ * Pass `null` to clear a description set earlier.
1767
+ *
1768
+ * @example
1769
+ * const hero = s.object({ type: s.literal("hero"), title: s.string() });
1770
+ * const text = s.object({ type: s.literal("text"), body: s.string() });
1771
+ * const schema = s
1772
+ * .discriminatedUnion("type", hero, text)
1773
+ * .describe("What this section of the page is");
1774
+ * export default c.define("/example.val.ts", schema, {
1775
+ * type: "hero",
1776
+ * title: "Hello",
1777
+ * });
1778
+ */
1779
+ _inherits(DiscriminatedUnionSchema, _Schema);
1780
+ return _createClass(DiscriminatedUnionSchema, [{
1452
1781
  key: "describe",
1453
1782
  value: function describe(description) {
1454
- return new UnionSchema(this.key, this.items, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
1783
+ return new DiscriminatedUnionSchema(this.key, this.items, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
1455
1784
  }
1785
+
1786
+ /**
1787
+ * Add a custom validation rule to this field.
1788
+ *
1789
+ * The function is called with the field's value and returns `false` when the
1790
+ * value is fine, or a STRING with the message to show when it is not. Call it
1791
+ * more than once to add more rules — they all run, and every message is
1792
+ * reported.
1793
+ *
1794
+ * Validation runs in the Studio as you type, in `npx val validate` and before a
1795
+ * publish.
1796
+ *
1797
+ * The function is given the whole value, whichever variant it took. A rule
1798
+ * that only concerns one variant belongs on that variant's object schema.
1799
+ *
1800
+ * @example
1801
+ * const hero = s.object({ type: s.literal("hero"), title: s.string() });
1802
+ * const text = s.object({ type: s.literal("text"), body: s.string() });
1803
+ * const schema = s
1804
+ * .discriminatedUnion("type", hero, text)
1805
+ * .validate((val) =>
1806
+ * val.type === "hero" && !val.title ? "A hero needs a title" : false,
1807
+ * );
1808
+ * export default c.define("/example.val.ts", schema, {
1809
+ * type: "hero",
1810
+ * title: "Hello",
1811
+ * });
1812
+ */
1456
1813
  }, {
1457
1814
  key: "validate",
1458
1815
  value: function validate(validationFunction) {
1459
- return new UnionSchema(this.key, this.items, this.opt, this.customValidateFunctions.concat(validationFunction), this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
1816
+ return new DiscriminatedUnionSchema(this.key, this.items, this.opt, this.customValidateFunctions.concat(validationFunction), this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
1460
1817
  }
1461
1818
  }, {
1462
1819
  key: "executeValidate",
@@ -1464,142 +1821,135 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
1464
1821
  var customValidationErrors = this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
1465
1822
  path: path
1466
1823
  });
1824
+ /**
1825
+ * A structural error at this path, unless the custom validators already
1826
+ * reported — in which case theirs are the answer and this one is dropped.
1827
+ * Faithful to what `s.union` did; changing it is a separate decision.
1828
+ */
1829
+ var structural = function structural(error) {
1830
+ return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : _defineProperty({}, path, [error]);
1831
+ };
1467
1832
  var unknownSrc = src;
1468
1833
  if (this.opt && unknownSrc === null) {
1469
1834
  return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : false;
1470
1835
  }
1471
1836
  if (!this.key) {
1472
- return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
1473
- message: "Missing required first argument in union",
1837
+ return structural({
1838
+ message: "Missing required first argument in discriminated union",
1474
1839
  schemaError: true
1475
- }]));
1840
+ });
1476
1841
  }
1477
1842
  var key = this.key;
1478
1843
  if (!Array.isArray(this.items)) {
1479
- return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
1480
- message: "A union schema must take more than 1 schema arguments",
1844
+ return structural({
1845
+ message: "A discriminated union schema must take more than 1 schema arguments",
1481
1846
  schemaError: true
1482
- }]));
1847
+ });
1483
1848
  }
1484
- if (typeof key === "string") {
1485
- // tagged union
1486
- if (this.items.some(function (item) {
1487
- return !(item instanceof ObjectSchema);
1488
- })) {
1489
- return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
1490
- message: "Key is a string, so all schema items must be objects",
1491
- schemaError: true
1492
- }]));
1493
- }
1494
- var objectSchemas = this.items;
1495
- var serializedSchemas = objectSchemas.map(function (schema) {
1496
- return schema["executeSerialize"]();
1849
+ if (typeof key !== "string") {
1850
+ return structural({
1851
+ message: "The key of a discriminated union must be a string",
1852
+ schemaError: true
1497
1853
  });
1498
- var illegalSchemas = serializedSchemas.filter(function (schema) {
1499
- return !(schema.type === "object") || !(schema.items[key].type === "literal");
1854
+ }
1855
+ if (this.items.some(function (item) {
1856
+ return !(item instanceof ObjectSchema);
1857
+ })) {
1858
+ return structural({
1859
+ message: "All schema items of a discriminated union must be objects",
1860
+ schemaError: true
1500
1861
  });
1501
- if (illegalSchemas.length > 0) {
1502
- return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
1503
- message: "All schema items must be objects with a key: ".concat(key, " that is a literal schema. Found: ").concat(JSON.stringify(illegalSchemas, null, 2)),
1504
- schemaError: true
1505
- }]));
1506
- }
1507
- var serializedObjectSchemas = serializedSchemas;
1508
- var optionalLiterals = serializedObjectSchemas.filter(function (schema) {
1509
- return schema.items[key].opt;
1862
+ }
1863
+ var objectSchemas = this.items;
1864
+ var serializedSchemas = objectSchemas.map(function (schema) {
1865
+ return schema["executeSerialize"]();
1866
+ });
1867
+ // `items[key]?` — a variant that OMITS the discriminator is exactly what
1868
+ // this check exists to report, so it must not throw while finding it.
1869
+ var illegalSchemas = serializedSchemas.filter(function (schema) {
1870
+ var _schema$items$key;
1871
+ return !(schema.type === "object") || ((_schema$items$key = schema.items[key]) === null || _schema$items$key === void 0 ? void 0 : _schema$items$key.type) !== "literal";
1872
+ });
1873
+ if (illegalSchemas.length > 0) {
1874
+ return structural({
1875
+ message: "All schema items must be objects with a key: ".concat(key, " that is a literal schema. Found: ").concat(JSON.stringify(illegalSchemas, null, 2)),
1876
+ schemaError: true
1510
1877
  });
1511
- if (optionalLiterals.length > 1) {
1512
- return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
1513
- message: "Schema cannot have an optional keys: ".concat(key),
1514
- schemaError: true
1515
- }]));
1516
- }
1517
- if (_typeof(unknownSrc) !== "object") {
1518
- return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
1519
- message: "Expected an object",
1520
- typeError: true
1521
- }]));
1522
- }
1523
- var objectSrc = unknownSrc;
1524
- if (objectSrc[key] === undefined) {
1525
- return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
1526
- message: "Missing required key: ".concat(key),
1527
- typeError: true
1528
- }]));
1529
- }
1530
- var foundSchemaLiterals = [];
1531
- var _iterator = _createForOfIteratorHelper(serializedObjectSchemas),
1532
- _step;
1533
- try {
1534
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
1535
- var schema = _step.value;
1536
- var schemaKey = schema.items[key];
1537
- if (schemaKey.type === "literal") {
1538
- if (!foundSchemaLiterals.includes(schemaKey.value)) {
1539
- foundSchemaLiterals.push(schemaKey.value);
1540
- } else {
1541
- return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
1542
- message: "Found duplicate key in schema: ".concat(schemaKey.value),
1543
- schemaError: true
1544
- }]));
1545
- }
1546
- }
1547
- }
1548
- } catch (err) {
1549
- _iterator.e(err);
1550
- } finally {
1551
- _iterator.f();
1552
- }
1553
- var objectSchemaAtKey = objectSchemas.find(function (schema) {
1554
- return !schema["items"][key]["executeValidate"](path, objectSrc[key]);
1878
+ }
1879
+ var serializedObjectSchemas = serializedSchemas;
1880
+ var optionalLiterals = serializedObjectSchemas.filter(function (schema) {
1881
+ return schema.items[key].opt;
1882
+ });
1883
+ if (optionalLiterals.length > 1) {
1884
+ return structural({
1885
+ message: "Schema cannot have an optional keys: ".concat(key),
1886
+ schemaError: true
1555
1887
  });
1556
- if (!objectSchemaAtKey) {
1557
- var keyPath = createValPathOfItem(path, key);
1558
- if (!keyPath) {
1559
- throw new Error("Internal error: could not create path at ".concat(!path && typeof path === "string" ? "<empty string>" : path, " at key ").concat(key));
1560
- }
1561
- return _defineProperty({}, keyPath, [{
1562
- message: "Invalid key: \"".concat(key, "\". Value was: \"").concat(objectSrc[key], "\". Valid values: ").concat(serializedObjectSchemas.map(function (schema) {
1563
- var keySchema = schema.items[key];
1564
- if (keySchema.type === "literal" && keySchema.value) {
1565
- return "\"".concat(keySchema.value, "\"");
1566
- } else {
1567
- // should not happen here, we already checked this
1568
- throw new Error("Expected literal schema, got ".concat(JSON.stringify(keySchema, null, 2)));
1569
- }
1570
- }).join(", "))
1571
- }]);
1572
- }
1573
- var error = objectSchemaAtKey["executeValidate"](path, objectSrc);
1574
- if (error) {
1575
- return error;
1576
- }
1577
- } else if (key instanceof LiteralSchema) {
1578
- if (this.items.some(function (item) {
1579
- return !(item instanceof LiteralSchema);
1580
- })) {
1581
- return _defineProperty({}, path, [{
1582
- message: "Key is a literal schema, so all schema items must be literals",
1583
- typeError: true
1584
- }]);
1585
- }
1586
- var literalItems = [key].concat(_toConsumableArray(this.items));
1587
- if (typeof unknownSrc === "string") {
1588
- var isMatch = literalItems.some(function (item) {
1589
- return !item["executeValidate"](path, unknownSrc);
1590
- });
1591
- if (!isMatch) {
1592
- return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
1593
- message: "Union must match one of the following: ".concat(literalItems.map(function (item) {
1594
- return "\"".concat(item["value"], "\"");
1595
- }).join(", "))
1596
- }]));
1888
+ }
1889
+
1890
+ // `typeof null === "object"`, so null has to be named separately or it
1891
+ // reaches `objectSrc[key]` below and throws instead of reporting.
1892
+ if (unknownSrc === null || _typeof(unknownSrc) !== "object") {
1893
+ return structural({
1894
+ message: "Expected an object, got ".concat(unknownSrc === null ? "null" : _typeof(unknownSrc)),
1895
+ typeError: true
1896
+ });
1897
+ }
1898
+ var objectSrc = unknownSrc;
1899
+ if (objectSrc[key] === undefined) {
1900
+ return structural({
1901
+ message: "Missing required key: ".concat(key),
1902
+ typeError: true
1903
+ });
1904
+ }
1905
+ var foundSchemaLiterals = [];
1906
+ var _iterator = _createForOfIteratorHelper(serializedObjectSchemas),
1907
+ _step;
1908
+ try {
1909
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
1910
+ var schema = _step.value;
1911
+ var schemaKey = schema.items[key];
1912
+ if (schemaKey.type === "literal") {
1913
+ if (!foundSchemaLiterals.includes(schemaKey.value)) {
1914
+ foundSchemaLiterals.push(schemaKey.value);
1915
+ } else {
1916
+ return structural({
1917
+ message: "Found duplicate key in schema: ".concat(schemaKey.value),
1918
+ schemaError: true
1919
+ });
1920
+ }
1597
1921
  }
1598
1922
  }
1599
- } else {
1600
- return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
1601
- message: "Expected a string or literal"
1602
- }]));
1923
+ } catch (err) {
1924
+ _iterator.e(err);
1925
+ } finally {
1926
+ _iterator.f();
1927
+ }
1928
+ var objectSchemaAtKey = objectSchemas.find(function (schema) {
1929
+ return !schema["items"][key]["executeValidate"](path, objectSrc[key]);
1930
+ });
1931
+ if (!objectSchemaAtKey) {
1932
+ var keyPath = createValPathOfItem(path, key);
1933
+ if (!keyPath) {
1934
+ throw new Error("Internal error: could not create path at ".concat(!path && typeof path === "string" ? "<empty string>" : path, " at key ").concat(key));
1935
+ }
1936
+ return _defineProperty({}, keyPath, [{
1937
+ message: "Invalid key: \"".concat(key, "\". Value was: \"").concat(objectSrc[key], "\". Valid values: ").concat(serializedObjectSchemas.map(function (schema) {
1938
+ var keySchema = schema.items[key];
1939
+ // The TYPE is the whole test: `s.literal("")` is a valid
1940
+ // discriminator, and a truthiness check threw on it here.
1941
+ if (keySchema.type === "literal") {
1942
+ return "\"".concat(keySchema.value, "\"");
1943
+ } else {
1944
+ // should not happen here, we already checked this
1945
+ throw new Error("Expected literal schema, got ".concat(JSON.stringify(keySchema, null, 2)));
1946
+ }
1947
+ }).join(", "))
1948
+ }]);
1949
+ }
1950
+ var error = objectSchemaAtKey["executeValidate"](path, objectSrc);
1951
+ if (error) {
1952
+ return error;
1603
1953
  }
1604
1954
  return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : false;
1605
1955
  }
@@ -1621,11 +1971,11 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
1621
1971
  }])
1622
1972
  };
1623
1973
  }
1624
- if (!this.key) {
1974
+ if (typeof this.key !== "string" || !this.key) {
1625
1975
  return {
1626
1976
  success: false,
1627
1977
  errors: _defineProperty({}, path, [{
1628
- message: "Missing required first argument in union schema",
1978
+ message: "Missing required first argument in discriminated union schema",
1629
1979
  schemaError: true
1630
1980
  }])
1631
1981
  };
@@ -1634,135 +1984,68 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
1634
1984
  return {
1635
1985
  success: false,
1636
1986
  errors: _defineProperty({}, path, [{
1637
- message: "The schema of this value is wrong. Schema is neither a union of literals nor a tagged union (of objects)",
1987
+ message: "The schema of this value is wrong. A discriminated union must have an array of object schemas",
1638
1988
  schemaError: true
1639
1989
  }])
1640
1990
  };
1641
1991
  }
1642
- if (this.key instanceof LiteralSchema) {
1643
- var _ref23;
1644
- var success = false;
1645
- var errors = {};
1646
- var _iterator2 = _createForOfIteratorHelper((_ref23 = [this.key]).concat.apply(_ref23, _toConsumableArray(this.items))),
1647
- _step2;
1648
- try {
1649
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
1650
- var itemSchema = _step2.value;
1651
- if (!(itemSchema instanceof LiteralSchema)) {
1652
- return {
1653
- success: false,
1654
- errors: _defineProperty({}, path, [{
1655
- message: "Schema of value is a union of string, so all schema items must be literals",
1656
- schemaError: true
1657
- }])
1658
- };
1659
- }
1660
- if (typeof src !== "string") {
1661
- errors[path] = [{
1662
- message: "Expected 'string', got '".concat(_typeof(src), "'"),
1663
- typeError: true
1664
- }];
1665
- continue;
1666
- }
1667
- var res = itemSchema["executeAssert"](path, src);
1668
- if (res.success) {
1669
- success = true;
1670
- break;
1671
- } else {
1672
- for (var _i = 0, _Object$entries = Object.entries(res.errors); _i < _Object$entries.length; _i++) {
1673
- var _errors5;
1674
- var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
1675
- _key = _Object$entries$_i[0],
1676
- value = _Object$entries$_i[1];
1677
- if (!errors[_key]) {
1678
- errors[_key] = [];
1679
- }
1680
- (_errors5 = errors[_key]).push.apply(_errors5, _toConsumableArray(value));
1681
- }
1682
- }
1683
- }
1684
- } catch (err) {
1685
- _iterator2.e(err);
1686
- } finally {
1687
- _iterator2.f();
1688
- }
1689
- if (!success) {
1690
- return {
1691
- success: false,
1692
- errors: errors
1693
- };
1694
- }
1695
- return {
1696
- success: true,
1697
- data: src
1698
- };
1699
- } else if (typeof this.key === "string") {
1700
- var _success = false;
1701
- var _errors6 = {};
1702
- var _iterator3 = _createForOfIteratorHelper(this.items),
1703
- _step3;
1704
- try {
1705
- for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
1706
- var _itemSchema = _step3.value;
1707
- var _res = _itemSchema["executeAssert"](path, src);
1708
- if (_res.success) {
1709
- _success = true;
1710
- break;
1711
- } else {
1712
- for (var _i2 = 0, _Object$entries2 = Object.entries(_res.errors); _i2 < _Object$entries2.length; _i2++) {
1713
- var _errors7;
1714
- var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
1715
- _key2 = _Object$entries2$_i[0],
1716
- _value = _Object$entries2$_i[1];
1717
- if (!_errors6[_key2]) {
1718
- _errors6[_key2] = [];
1719
- }
1720
- (_errors7 = _errors6[_key2]).push.apply(_errors7, _toConsumableArray(_value)); // by appending all type errors, we most likely get a lot of duplicate errors. Currently we believe this is correct though, but should probably be handled in when showing the errors to users
1992
+ var success = false;
1993
+ var errors = {};
1994
+ var _iterator2 = _createForOfIteratorHelper(this.items),
1995
+ _step2;
1996
+ try {
1997
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
1998
+ var itemSchema = _step2.value;
1999
+ var res = itemSchema["executeAssert"](path, src);
2000
+ if (res.success) {
2001
+ success = true;
2002
+ break;
2003
+ } else {
2004
+ for (var _i = 0, _Object$entries = Object.entries(res.errors); _i < _Object$entries.length; _i++) {
2005
+ var _errors4;
2006
+ var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
2007
+ _key = _Object$entries$_i[0],
2008
+ value = _Object$entries$_i[1];
2009
+ if (!errors[_key]) {
2010
+ errors[_key] = [];
1721
2011
  }
2012
+ (_errors4 = errors[_key]).push.apply(_errors4, _toConsumableArray(value)); // by appending all type errors, we most likely get a lot of duplicate errors. Currently we believe this is correct though, but should probably be handled in when showing the errors to users
1722
2013
  }
1723
2014
  }
1724
- } catch (err) {
1725
- _iterator3.e(err);
1726
- } finally {
1727
- _iterator3.f();
1728
2015
  }
1729
- if (!_success) {
1730
- return {
1731
- success: false,
1732
- errors: _errors6
1733
- };
1734
- }
1735
- return {
1736
- success: true,
1737
- data: src
1738
- };
1739
- } else {
2016
+ } catch (err) {
2017
+ _iterator2.e(err);
2018
+ } finally {
2019
+ _iterator2.f();
2020
+ }
2021
+ if (!success) {
1740
2022
  return {
1741
2023
  success: false,
1742
- errors: _defineProperty({}, path, [{
1743
- message: "The schema of this value is wrong. Schema is neither a union of literals nor a tagged union (of objects)",
1744
- schemaError: true
1745
- }])
2024
+ errors: errors
1746
2025
  };
1747
2026
  }
2027
+ return {
2028
+ success: true,
2029
+ data: src
2030
+ };
1748
2031
  }
1749
2032
  }, {
1750
2033
  key: "nullable",
1751
2034
  value: function nullable() {
1752
2035
  // Explicit type args: `previewInput` would otherwise pin inference to `Src`.
1753
- return new UnionSchema(this.key, this.items, true, [], this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
2036
+ return new DiscriminatedUnionSchema(this.key, this.items, true, [], this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
1754
2037
  }
1755
2038
  }, {
1756
2039
  key: "readonly",
1757
2040
  value: function readonly() {
1758
2041
  var isReadonly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
1759
- return new UnionSchema(this.key, this.items, this.opt, this.customValidateFunctions, isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
2042
+ return new DiscriminatedUnionSchema(this.key, this.items, this.opt, this.customValidateFunctions, isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
1760
2043
  }
1761
2044
  }, {
1762
2045
  key: "hidden",
1763
2046
  value: function hidden() {
1764
2047
  var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
1765
- return new UnionSchema(this.key, this.items, this.opt, this.customValidateFunctions, this.isReadonly, isHidden, this.description, this.renderInput, this.previewInput);
2048
+ return new DiscriminatedUnionSchema(this.key, this.items, this.opt, this.customValidateFunctions, this.isReadonly, isHidden, this.description, this.renderInput, this.previewInput);
1766
2049
  }
1767
2050
  }, {
1768
2051
  key: "executeCustomValidateAt",
@@ -1770,10 +2053,10 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
1770
2053
  var errors = this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
1771
2054
  path: path
1772
2055
  });
1773
- // A tagged union's variants share the union's path, so `Internal.resolvePath`
1774
- // stops here and a variant's OWN validator would never be reached. Dispatch
1775
- // into the variant this value takes — the union is the only node that knows
1776
- // which one that is.
2056
+ // A discriminated union's variants share the union's path, so
2057
+ // `Internal.resolvePath` stops here and a variant's OWN validator would
2058
+ // never be reached. Dispatch into the variant this value takes — the union
2059
+ // is the only node that knows which one that is.
1777
2060
  var matched = this.matchedVariant(src);
1778
2061
  if (matched) {
1779
2062
  errors.push.apply(errors, _toConsumableArray(matched["executeCustomValidateAt"](path, src)));
@@ -1782,10 +2065,8 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
1782
2065
  }
1783
2066
 
1784
2067
  /**
1785
- * The variant schema a value takes, for a TAGGED union (string `key`). `null`
1786
- * for a literal union (its variants are leaves with nothing to descend into) or
1787
- * when the value matches none of them — a structural error `executeValidate`
1788
- * already reports.
2068
+ * The variant schema a value takes. `null` when the value matches none of
2069
+ * them — a structural error `executeValidate` already reports.
1789
2070
  */
1790
2071
  }, {
1791
2072
  key: "matchedVariant",
@@ -1802,11 +2083,11 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
1802
2083
  return null;
1803
2084
  }
1804
2085
  var objectSchemas = this.items;
1805
- var _iterator4 = _createForOfIteratorHelper(objectSchemas),
1806
- _step4;
2086
+ var _iterator3 = _createForOfIteratorHelper(objectSchemas),
2087
+ _step3;
1807
2088
  try {
1808
- for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
1809
- var item = _step4.value;
2089
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
2090
+ var item = _step3.value;
1810
2091
  if (!(item instanceof ObjectSchema)) {
1811
2092
  continue;
1812
2093
  }
@@ -1816,9 +2097,9 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
1816
2097
  }
1817
2098
  }
1818
2099
  } catch (err) {
1819
- _iterator4.e(err);
2100
+ _iterator3.e(err);
1820
2101
  } finally {
1821
- _iterator4.f();
2102
+ _iterator3.f();
1822
2103
  }
1823
2104
  return null;
1824
2105
  }
@@ -1829,11 +2110,21 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
1829
2110
  * instead of a preview row that navigates to it.
1830
2111
  *
1831
2112
  * Static configuration, not a callback — see `render.ts`.
2113
+ *
2114
+ * @example
2115
+ * // A page builder: the row draws the tag selector and the matched
2116
+ * // variant's fields.
2117
+ * const hero = s.object({ type: s.literal("hero"), title: s.string() });
2118
+ * const text = s.object({ type: s.literal("text"), body: s.string() });
2119
+ * const block = s.discriminatedUnion("type", hero, text).render({ as: "inline" });
2120
+ * export default c.define("/example.val.ts", s.array(block), [
2121
+ * { type: "hero", title: "Hello" },
2122
+ * ]);
1832
2123
  */
1833
2124
  }, {
1834
2125
  key: "render",
1835
2126
  value: function render(input) {
1836
- return new UnionSchema(this.key, this.items, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, input, this.previewInput);
2127
+ return new DiscriminatedUnionSchema(this.key, this.items, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, input, this.previewInput);
1837
2128
  }
1838
2129
 
1839
2130
  /**
@@ -1841,13 +2132,24 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
1841
2132
  * sortable list, a reference dropdown, a search hit. Never how the field
1842
2133
  * itself is edited (that is `render`). See `preview.ts`.
1843
2134
  *
1844
- * Without one of its own, a tagged union previews as the VARIANT the value
1845
- * takes — declare `preview` on the member objects and the union dispatches.
2135
+ * Without one of its own, a discriminated union previews as the VARIANT the
2136
+ * value takes — declare `preview` on the member objects and the union
2137
+ * dispatches.
2138
+ *
2139
+ * @example
2140
+ * const hero = s.object({ type: s.literal("hero"), title: s.string() });
2141
+ * const text = s.object({ type: s.literal("text"), body: s.string() });
2142
+ * const block = s
2143
+ * .discriminatedUnion("type", hero, text)
2144
+ * .preview(({ val }) => ({ title: val.type }));
2145
+ * export default c.define("/example.val.ts", s.array(block), [
2146
+ * { type: "hero", title: "Hello" },
2147
+ * ]);
1846
2148
  */
1847
2149
  }, {
1848
2150
  key: "preview",
1849
2151
  value: function preview(select) {
1850
- return new UnionSchema(this.key, this.items, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, select);
2152
+ return new DiscriminatedUnionSchema(this.key, this.items, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, select);
1851
2153
  }
1852
2154
  }, {
1853
2155
  key: "executePreviewItem",
@@ -1878,34 +2180,19 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
1878
2180
  }, {
1879
2181
  key: "executeSerialize",
1880
2182
  value: function executeSerialize() {
1881
- var _this$renderInput2, _this$customValidateF2;
1882
- if (typeof this.key === "string") {
1883
- var _this$renderInput, _this$customValidateF;
1884
- return {
1885
- type: "union",
1886
- render: (_this$renderInput = this.renderInput) !== null && _this$renderInput !== void 0 ? _this$renderInput : undefined,
1887
- preview: this.previewInput ? true : undefined,
1888
- key: this.key,
1889
- items: this.items.map(function (o) {
1890
- return o["executeSerialize"]();
1891
- }),
1892
- opt: this.opt,
1893
- customValidate: this.customValidateFunctions && ((_this$customValidateF = this.customValidateFunctions) === null || _this$customValidateF === void 0 ? void 0 : _this$customValidateF.length) > 0,
1894
- readonly: this.isReadonly,
1895
- hidden: this.isHidden,
1896
- description: this.description
1897
- };
1898
- }
2183
+ var _this$renderInput, _this$customValidateF;
1899
2184
  return {
1900
- type: "union",
1901
- render: (_this$renderInput2 = this.renderInput) !== null && _this$renderInput2 !== void 0 ? _this$renderInput2 : undefined,
2185
+ type: "discriminated-union",
2186
+ render: (_this$renderInput = this.renderInput) !== null && _this$renderInput !== void 0 ? _this$renderInput : undefined,
1902
2187
  preview: this.previewInput ? true : undefined,
1903
- key: this.key["executeSerialize"](),
2188
+ key: this.key,
2189
+ // Every item is an ObjectSchema — `executeValidate` reports a schema
2190
+ // error for anything else, but the type of `T` cannot say so.
1904
2191
  items: this.items.map(function (o) {
1905
2192
  return o["executeSerialize"]();
1906
2193
  }),
1907
2194
  opt: this.opt,
1908
- customValidate: this.customValidateFunctions && ((_this$customValidateF2 = this.customValidateFunctions) === null || _this$customValidateF2 === void 0 ? void 0 : _this$customValidateF2.length) > 0,
2195
+ customValidate: this.customValidateFunctions && ((_this$customValidateF = this.customValidateFunctions) === null || _this$customValidateF === void 0 ? void 0 : _this$customValidateF.length) > 0,
1909
2196
  readonly: this.isReadonly,
1910
2197
  hidden: this.isHidden,
1911
2198
  description: this.description
@@ -1918,48 +2205,46 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
1918
2205
  if (src === null) {
1919
2206
  return res;
1920
2207
  }
1921
- if (this.key instanceof LiteralSchema) {
1922
- return res;
1923
- }
1924
2208
  var unionKey = this.key;
1925
- if (typeof unionKey === "string") {
1926
- var thisSchema = this.items.find(
1927
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1928
- function (item) {
1929
- if (item instanceof ObjectSchema) {
1930
- var itemKey = item["items"][unionKey];
1931
- if (itemKey instanceof LiteralSchema) {
1932
- return _typeof(src) === "object" && unionKey in src && itemKey["value"] === src[unionKey];
1933
- }
1934
- }
1935
- return false;
1936
- });
1937
- if (thisSchema) {
1938
- var itemResult = thisSchema["executePreview"](sourcePath, src, scope);
1939
- for (var keyS in itemResult) {
1940
- var _key3 = keyS;
1941
- res[_key3] = itemResult[_key3];
1942
- }
1943
- return res;
1944
- }
2209
+ if (typeof unionKey !== "string") {
1945
2210
  res[sourcePath] = {
1946
2211
  status: "error",
1947
- message: "Could not find a matching (object) schema for the union key: ".concat(unionKey)
2212
+ message: "The schema of this value is wrong. Expected the key of a discriminated union to be a string. Got: '".concat(JSON.stringify(unionKey, null, 2), "'")
1948
2213
  };
2214
+ return res;
2215
+ }
2216
+ var thisSchema = this.items.find(
2217
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2218
+ function (item) {
2219
+ if (item instanceof ObjectSchema) {
2220
+ var itemKey = item["items"][unionKey];
2221
+ if (itemKey instanceof LiteralSchema) {
2222
+ return _typeof(src) === "object" && unionKey in src && itemKey["value"] === src[unionKey];
2223
+ }
2224
+ }
2225
+ return false;
2226
+ });
2227
+ if (thisSchema) {
2228
+ var itemResult = thisSchema["executePreview"](sourcePath, src, scope);
2229
+ for (var keyS in itemResult) {
2230
+ var _key2 = keyS;
2231
+ res[_key2] = itemResult[_key2];
2232
+ }
2233
+ return res;
1949
2234
  }
1950
2235
  res[sourcePath] = {
1951
2236
  status: "error",
1952
- message: "The schema of this value is wrong. Expected a object union schema, but union key is not a string. Got: '".concat(JSON.stringify(unionKey, null, 2), "'")
2237
+ message: "Could not find a matching (object) schema for the discriminated union key: ".concat(unionKey)
1953
2238
  };
1954
2239
  return res;
1955
2240
  }
1956
2241
  }]);
1957
2242
  }(Schema);
1958
- var union = function union(key) {
1959
- for (var _len = arguments.length, objects = new Array(_len > 1 ? _len - 1 : 0), _key4 = 1; _key4 < _len; _key4++) {
1960
- objects[_key4 - 1] = arguments[_key4];
2243
+ var discriminatedUnion = function discriminatedUnion(key) {
2244
+ for (var _len = arguments.length, objects = new Array(_len > 1 ? _len - 1 : 0), _key3 = 1; _key3 < _len; _key3++) {
2245
+ objects[_key3 - 1] = arguments[_key3];
1961
2246
  }
1962
- return new UnionSchema(key, objects);
2247
+ return new DiscriminatedUnionSchema(key, objects);
1963
2248
  };
1964
2249
 
1965
2250
  var RegEx$1 = /^(https?:\/\/[^/]+)\/file\/p\/([^/]+)\/b\/([^/]+)\/v\/([^/]+)\/h\/([^/]+)\/f\/([^/]+)\/p\/(.+)$/;
@@ -2930,17 +3215,94 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
2930
3215
  _this.previewInput = previewInput;
2931
3216
  return _this;
2932
3217
  }
3218
+
3219
+ /**
3220
+ * Describe this field.
3221
+ *
3222
+ * The description is shown next to the field's label in the Val editor, so
3223
+ * it is where you say what an editor needs to know but the field name cannot
3224
+ * carry. It also travels in the serialized schema, which is what the AI
3225
+ * assistant and the MCP tools read.
3226
+ *
3227
+ * Pass `null` to clear a description set earlier.
3228
+ *
3229
+ * @example
3230
+ * const schema = s
3231
+ * .image()
3232
+ * .describe("Shown at the top of the page, 16:9 works best");
3233
+ * export default c.define("/example.val.ts", schema, {
3234
+ * path: "/public/val/example.png",
3235
+ * width: 100,
3236
+ * height: 100,
3237
+ * mimeType: "image/png",
3238
+ * });
3239
+ */
2933
3240
  _inherits(ImageSchema, _Schema);
2934
3241
  return _createClass(ImageSchema, [{
2935
3242
  key: "describe",
2936
3243
  value: function describe(description) {
2937
3244
  return new ImageSchema(this.options, this.opt, this.isRemote, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
2938
3245
  }
3246
+
3247
+ /**
3248
+ * Store the image on Val's remote content host instead of in your repository.
3249
+ *
3250
+ * The bytes still go into the patch store when the image is uploaded — the
3251
+ * push to the remote host happens at publish. What changes is where the
3252
+ * published image lives: `path` becomes a remote URL rather than a path
3253
+ * under `/public`, so the repository does not grow with every upload.
3254
+ *
3255
+ * The `path` of a remote image is a URL on the content host, and it is not
3256
+ * something to write by hand: upload the image in the Studio, or write a
3257
+ * local path and let `npx val validate --fix` upload it and rewrite the
3258
+ * `path` to the ref below.
3259
+ *
3260
+ * @example
3261
+ * const schema = s
3262
+ * .image({ accept: "image/webp", directory: "/public/val/images" })
3263
+ * .remote();
3264
+ * export default c.define("/example.val.ts", schema, {
3265
+ * path: "https://remote.val.build/file/p/my-project/b/01/v/1.0.0/h/8f2a1c/f/3b9d70/p/public/val/images/example.webp",
3266
+ * width: 100,
3267
+ * height: 100,
3268
+ * mimeType: "image/webp",
3269
+ * });
3270
+ */
2939
3271
  }, {
2940
3272
  key: "remote",
2941
3273
  value: function remote() {
2942
3274
  return new ImageSchema(this.options, this.opt, true, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
2943
3275
  }
3276
+
3277
+ /**
3278
+ * Add a custom validation rule to this field.
3279
+ *
3280
+ * The function is called with the field's value and returns `false` when the
3281
+ * value is fine, or a STRING with the message to show when it is not. Call it
3282
+ * more than once to add more rules — they all run, and every message is
3283
+ * reported.
3284
+ *
3285
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
3286
+ * when the value is fine, and `true` is not one of the two answers.
3287
+ *
3288
+ * Validation runs in the Studio as you type, in `npx val validate` and
3289
+ * before a publish.
3290
+ *
3291
+ * The second argument carries the `path` of the field being validated, for
3292
+ * when the message needs to say where the problem is.
3293
+ *
3294
+ * @example
3295
+ * const schema = s.image().validate((val) =>
3296
+ * val.alt ? false : "Every image needs alt text",
3297
+ * );
3298
+ * export default c.define("/example.val.ts", schema, {
3299
+ * path: "/public/val/example.png",
3300
+ * width: 100,
3301
+ * height: 100,
3302
+ * mimeType: "image/png",
3303
+ * alt: "An example",
3304
+ * });
3305
+ */
2944
3306
  }, {
2945
3307
  key: "validate",
2946
3308
  value: function validate(validationFunction) {
@@ -3158,6 +3520,17 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
3158
3520
  * instead of a preview row that navigates to it.
3159
3521
  *
3160
3522
  * Static configuration, not a callback — see `render.ts`.
3523
+ *
3524
+ * @example
3525
+ * const schema = s.array(s.image().render({ as: "inline" }));
3526
+ * export default c.define("/example.val.ts", schema, [
3527
+ * {
3528
+ * path: "/public/val/example.png",
3529
+ * width: 100,
3530
+ * height: 100,
3531
+ * mimeType: "image/png",
3532
+ * },
3533
+ * ]);
3161
3534
  */
3162
3535
  }, {
3163
3536
  key: "render",
@@ -3169,6 +3542,23 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
3169
3542
  * How this VALUE is shown where a preview of it is needed — a row in a
3170
3543
  * sortable list, a reference dropdown, a search hit. Never how the field
3171
3544
  * itself is edited (that is `render`). See `preview.ts`.
3545
+ *
3546
+ * @example
3547
+ * const schema = s.array(
3548
+ * s.image().preview(({ val }) => ({
3549
+ * title: val.alt ?? "Image",
3550
+ * image: val,
3551
+ * })),
3552
+ * );
3553
+ * export default c.define("/example.val.ts", schema, [
3554
+ * {
3555
+ * path: "/public/val/example.png",
3556
+ * width: 100,
3557
+ * height: 100,
3558
+ * mimeType: "image/png",
3559
+ * alt: "An example",
3560
+ * },
3561
+ * ]);
3172
3562
  */
3173
3563
  }, {
3174
3564
  key: "preview",
@@ -3265,6 +3655,21 @@ var RouteSchema = /*#__PURE__*/function (_Schema) {
3265
3655
  _this.previewInput = previewInput;
3266
3656
  return _this;
3267
3657
  }
3658
+
3659
+ /**
3660
+ * Describe this field.
3661
+ *
3662
+ * The description is shown next to the field's label in the Val editor, so
3663
+ * it is where you say what an editor needs to know but the field name cannot
3664
+ * carry. It also travels in the serialized schema, which is what the AI
3665
+ * assistant and the MCP tools read.
3666
+ *
3667
+ * Pass `null` to clear a description set earlier.
3668
+ *
3669
+ * @example
3670
+ * const schema = s.route().describe("Where the button goes");
3671
+ * export default c.define("/example.val.ts", schema, "/a-page-slug");
3672
+ */
3268
3673
  _inherits(RouteSchema, _Schema);
3269
3674
  return _createClass(RouteSchema, [{
3270
3675
  key: "describe",
@@ -3311,6 +3716,27 @@ var RouteSchema = /*#__PURE__*/function (_Schema) {
3311
3716
  exclude: pattern
3312
3717
  }), this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
3313
3718
  }
3719
+
3720
+ /**
3721
+ * Add a custom validation rule to this field.
3722
+ *
3723
+ * The function is called with the field's value and returns `false` when the
3724
+ * value is fine, or a STRING with the message to show when it is not. Call it
3725
+ * more than once to add more rules — they all run, and every message is
3726
+ * reported.
3727
+ *
3728
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
3729
+ * when the value is fine, and `true` is not one of the two answers.
3730
+ *
3731
+ * Validation runs in the Studio as you type, in `npx val validate` and
3732
+ * before a publish.
3733
+ *
3734
+ * @example
3735
+ * const schema = s.route().validate((val) =>
3736
+ * val.endsWith("/") ? "Leave off the trailing slash" : false,
3737
+ * );
3738
+ * export default c.define("/example.val.ts", schema, "/a-page-slug");
3739
+ */
3314
3740
  }, {
3315
3741
  key: "validate",
3316
3742
  value: function validate(validationFunction) {
@@ -3397,6 +3823,10 @@ var RouteSchema = /*#__PURE__*/function (_Schema) {
3397
3823
  * instead of a preview row that navigates to it.
3398
3824
  *
3399
3825
  * Static configuration, not a callback — see `render.ts`.
3826
+ *
3827
+ * @example
3828
+ * const schema = s.array(s.route().render({ as: "inline" }));
3829
+ * export default c.define("/example.val.ts", schema, ["/a-page-slug"]);
3400
3830
  */
3401
3831
  }, {
3402
3832
  key: "render",
@@ -3408,6 +3838,12 @@ var RouteSchema = /*#__PURE__*/function (_Schema) {
3408
3838
  * How this VALUE is shown where a preview of it is needed — a row in a
3409
3839
  * sortable list, a reference dropdown, a search hit. Never how the field
3410
3840
  * itself is edited (that is `render`). See `preview.ts`.
3841
+ *
3842
+ * @example
3843
+ * const schema = s.array(
3844
+ * s.route().preview(({ val }) => ({ title: val })),
3845
+ * );
3846
+ * export default c.define("/example.val.ts", schema, ["/a-page-slug"]);
3411
3847
  */
3412
3848
  }, {
3413
3849
  key: "preview",
@@ -3488,12 +3924,42 @@ var RichTextSchema = /*#__PURE__*/function (_Schema) {
3488
3924
  _this.previewInput = previewInput;
3489
3925
  return _this;
3490
3926
  }
3927
+
3928
+ /**
3929
+ * Describe this field.
3930
+ *
3931
+ * The description is shown next to the field's label in the Val editor, so
3932
+ * it is where you say what an editor needs to know but the field name cannot
3933
+ * carry. It also travels in the serialized schema, which is what the AI
3934
+ * assistant and the MCP tools read.
3935
+ *
3936
+ * Pass `null` to clear a description set earlier.
3937
+ *
3938
+ * @example
3939
+ * const schema = s.richtext().describe("The body of the article");
3940
+ * export default c.define("/example.val.ts", schema, [
3941
+ * { tag: "p", children: ["Hello"] },
3942
+ * ]);
3943
+ */
3491
3944
  _inherits(RichTextSchema, _Schema);
3492
3945
  return _createClass(RichTextSchema, [{
3493
3946
  key: "describe",
3494
3947
  value: function describe(description) {
3495
3948
  return new RichTextSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
3496
3949
  }
3950
+
3951
+ /**
3952
+ * Validate that the rich text holds at most `max` characters.
3953
+ *
3954
+ * Counted over the TEXT, not the markup: tags, attributes and the structure
3955
+ * of the document do not add to it.
3956
+ *
3957
+ * @example
3958
+ * const schema = s.richtext().maxLength(280);
3959
+ * export default c.define("/example.val.ts", schema, [
3960
+ * { tag: "p", children: ["Hello"] },
3961
+ * ]);
3962
+ */
3497
3963
  }, {
3498
3964
  key: "maxLength",
3499
3965
  value: function maxLength(max) {
@@ -3501,6 +3967,19 @@ var RichTextSchema = /*#__PURE__*/function (_Schema) {
3501
3967
  maxLength: max
3502
3968
  }), this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
3503
3969
  }
3970
+
3971
+ /**
3972
+ * Validate that the rich text holds at least `min` characters.
3973
+ *
3974
+ * Counted over the TEXT, not the markup: tags, attributes and the structure
3975
+ * of the document do not add to it.
3976
+ *
3977
+ * @example
3978
+ * const schema = s.richtext().minLength(20).maxLength(280);
3979
+ * export default c.define("/example.val.ts", schema, [
3980
+ * { tag: "p", children: ["Long enough to clear the minimum length."] },
3981
+ * ]);
3982
+ */
3504
3983
  }, {
3505
3984
  key: "minLength",
3506
3985
  value: function minLength(min) {
@@ -3508,6 +3987,29 @@ var RichTextSchema = /*#__PURE__*/function (_Schema) {
3508
3987
  minLength: min
3509
3988
  }), this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
3510
3989
  }
3990
+
3991
+ /**
3992
+ * Add a custom validation rule to this field.
3993
+ *
3994
+ * The function is called with the field's value and returns `false` when the
3995
+ * value is fine, or a STRING with the message to show when it is not. Call it
3996
+ * more than once to add more rules — they all run, and every message is
3997
+ * reported.
3998
+ *
3999
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
4000
+ * when the value is fine, and `true` is not one of the two answers.
4001
+ *
4002
+ * Validation runs in the Studio as you type, in `npx val validate` and
4003
+ * before a publish.
4004
+ *
4005
+ * @example
4006
+ * const schema = s.richtext().validate((val) =>
4007
+ * val.length > 0 ? false : "Write something",
4008
+ * );
4009
+ * export default c.define("/example.val.ts", schema, [
4010
+ * { tag: "p", children: ["Hello"] },
4011
+ * ]);
4012
+ */
3511
4013
  }, {
3512
4014
  key: "validate",
3513
4015
  value: function validate(validationFunction) {
@@ -3983,6 +4485,12 @@ var RichTextSchema = /*#__PURE__*/function (_Schema) {
3983
4485
  * instead of a preview row that navigates to it.
3984
4486
  *
3985
4487
  * Static configuration, not a callback — see `render.ts`.
4488
+ *
4489
+ * @example
4490
+ * const schema = s.array(s.richtext().render({ as: "inline" }));
4491
+ * export default c.define("/example.val.ts", schema, [
4492
+ * [{ tag: "p", children: ["Hello"] }],
4493
+ * ]);
3986
4494
  */
3987
4495
  }, {
3988
4496
  key: "render",
@@ -3994,6 +4502,16 @@ var RichTextSchema = /*#__PURE__*/function (_Schema) {
3994
4502
  * How this VALUE is shown where a preview of it is needed — a row in a
3995
4503
  * sortable list, a reference dropdown, a search hit. Never how the field
3996
4504
  * itself is edited (that is `render`). See `preview.ts`.
4505
+ *
4506
+ * @example
4507
+ * const schema = s.array(
4508
+ * s.richtext().preview(({ val }) => ({
4509
+ * title: val.length > 0 ? "Rich text" : "Empty",
4510
+ * })),
4511
+ * );
4512
+ * export default c.define("/example.val.ts", schema, [
4513
+ * [{ tag: "p", children: ["Hello"] }],
4514
+ * ]);
3997
4515
  */
3998
4516
  }, {
3999
4517
  key: "preview",
@@ -4502,12 +5020,55 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
4502
5020
  _this.externalLabel = externalLabel;
4503
5021
  return _this;
4504
5022
  }
5023
+
5024
+ /**
5025
+ * Describe this field.
5026
+ *
5027
+ * The description is shown next to the field's label in the Val editor, so
5028
+ * it is where you say what an editor needs to know but the field name cannot
5029
+ * carry. It also travels in the serialized schema, which is what the AI
5030
+ * assistant and the MCP tools read.
5031
+ *
5032
+ * Pass `null` to clear a description set earlier.
5033
+ *
5034
+ * @example
5035
+ * const schema = s
5036
+ * .record(s.string())
5037
+ * .describe("Button labels, keyed by locale");
5038
+ * export default c.define("/example.val.ts", schema, { en: "Read more" });
5039
+ */
4505
5040
  _inherits(RecordSchema, _Schema);
4506
5041
  return _createClass(RecordSchema, [{
4507
5042
  key: "describe",
4508
5043
  value: function describe(description) {
4509
5044
  return new RecordSchema(this.item, this.opt, this.customValidateFunctions, this.currentRouter, this.keySchema, this.mediaOptions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.isJsonValues, this.previewInput, this.renderInput, this.externalLabel);
4510
5045
  }
5046
+
5047
+ /**
5048
+ * Add a custom validation rule to this field.
5049
+ *
5050
+ * The function is called with the field's value and returns `false` when the
5051
+ * value is fine, or a STRING with the message to show when it is not. Call it
5052
+ * more than once to add more rules — they all run, and every message is
5053
+ * reported.
5054
+ *
5055
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
5056
+ * when the value is fine, and `true` is not one of the two answers.
5057
+ *
5058
+ * Validation runs in the Studio as you type, in `npx val validate` and
5059
+ * before a publish.
5060
+ *
5061
+ * The function is given the whole record. To validate one entry, put a
5062
+ * `.validate(...)` on the ITEM schema instead — that reports the error on
5063
+ * the entry's own row, and on a `.jsonValues()` record it does not force
5064
+ * every entry to be loaded.
5065
+ *
5066
+ * @example
5067
+ * const schema = s.record(s.string()).validate((val) =>
5068
+ * "en" in val ? false : "There has to be an 'en' entry",
5069
+ * );
5070
+ * export default c.define("/example.val.ts", schema, { en: "Read more" });
5071
+ */
4511
5072
  }, {
4512
5073
  key: "validate",
4513
5074
  value: function validate(validationFunction) {
@@ -4869,6 +5430,10 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
4869
5430
  * must come BEFORE `.external()`: afterwards the value is a `Schema`, and
4870
5431
  * there is no `.readonly()` left to call — which is the error the compiler
4871
5432
  * gives, and a clearer one than a runtime throw.
5433
+ *
5434
+ * @example
5435
+ * const schema = s.record(s.string()).readonly();
5436
+ * export default c.define("/example.val.ts", schema, { en: "Read more" });
4872
5437
  */
4873
5438
  }, {
4874
5439
  key: "readonly",
@@ -4882,11 +5447,54 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
4882
5447
  var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
4883
5448
  return new RecordSchema(this.item, this.opt, this.customValidateFunctions, this.currentRouter, this.keySchema, this.mediaOptions, this.isReadonly, isHidden, this.description, this.isJsonValues, this.previewInput, this.renderInput, this.externalLabel);
4884
5449
  }
5450
+
5451
+ /**
5452
+ * Turn this record into a page router: its keys are route paths of your
5453
+ * application, and they are validated against the router's conventions.
5454
+ *
5455
+ * `s.router(router, item)` builds the same thing in one call and is what
5456
+ * most code should use — this is for adding a router to a record that
5457
+ * already exists.
5458
+ *
5459
+ * @example
5460
+ * import { nextAppRouter } from "../val.config";
5461
+ * const schema = s
5462
+ * .record(s.object({ title: s.string() }))
5463
+ * .router(nextAppRouter);
5464
+ * export default c.define("/app/[slug]/page.val.ts", schema, {
5465
+ * "/a-page-slug": { title: "First Page" },
5466
+ * });
5467
+ */
4885
5468
  }, {
4886
5469
  key: "router",
4887
5470
  value: function router(_router) {
4888
5471
  return new RecordSchema(this.item, this.opt, this.customValidateFunctions, _router, this.keySchema, this.mediaOptions, this.isReadonly, this.isHidden, this.description, this.isJsonValues, this.previewInput, this.renderInput, this.externalLabel);
4889
5472
  }
5473
+
5474
+ /**
5475
+ * Allow the files in this gallery to be stored on Val's remote content host
5476
+ * instead of in your repository.
5477
+ *
5478
+ * For `s.images()` and `s.files()`, which are records of media. Remote is off
5479
+ * until this is called.
5480
+ *
5481
+ * Each entry is then keyed by its URL on the content host rather than by a
5482
+ * path under `/public`. That key is not something to write by hand: upload
5483
+ * in the Studio, or add a local path and let `npx val validate --fix`
5484
+ * upload it and rewrite the key.
5485
+ *
5486
+ * @example
5487
+ * const schema = s.images({ directory: "/public/val/images" }).remote();
5488
+ * export default c.define("/content/images.val.ts", schema, {
5489
+ * "https://remote.val.build/file/p/my-project/b/01/v/1.0.0/h/8f2a1c/f/3b9d70/p/public/val/images/hero.webp":
5490
+ * {
5491
+ * width: 1920,
5492
+ * height: 1080,
5493
+ * mimeType: "image/webp",
5494
+ * alt: "Hero image",
5495
+ * },
5496
+ * });
5497
+ */
4890
5498
  }, {
4891
5499
  key: "remote",
4892
5500
  value: function remote() {
@@ -4908,6 +5516,20 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
4908
5516
  * nested inside an object/array/record is rejected at startup with a module
4909
5517
  * error, because the single-entry fetch endpoint, the Studio's content
4910
5518
  * substitution and content validation are all root-only.
5519
+ *
5520
+ * Must come BEFORE `.validate()` and `.preview()`: those are typed against
5521
+ * the un-lazy source shape, so a validator or preview declared first cannot
5522
+ * be carried over, and declaring one first throws rather than silently
5523
+ * dropping it.
5524
+ *
5525
+ * @example
5526
+ * import { nextAppRouter } from "../val.config";
5527
+ * const schema = s
5528
+ * .router(nextAppRouter, s.object({ title: s.string(), body: s.string() }))
5529
+ * .jsonValues();
5530
+ * export default c.define("/app/support/[slug]/page.val.ts", schema, {
5531
+ * "/support/faq": c.json(() => import("./content/faq.val.json")),
5532
+ * });
4911
5533
  */
4912
5534
  }, {
4913
5535
  key: "jsonValues",
@@ -4955,6 +5577,19 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
4955
5577
  * nested external record would leave a hole in the middle of a module's
4956
5578
  * source, and the Studio, patching and validation all assume a module's
4957
5579
  * source is complete apart from its entries.
5580
+ *
5581
+ * @example
5582
+ * const schema = s.record(s.object({ title: s.string() })).external("posts");
5583
+ * export default c.define("/content/posts.val.ts", schema, c.external());
5584
+ *
5585
+ * @example
5586
+ * // A read-only external record: `.readonly()` must come FIRST, because
5587
+ * // afterwards there is no `.readonly()` left on the type to call.
5588
+ * const schema = s
5589
+ * .record(s.object({ title: s.string() }))
5590
+ * .readonly()
5591
+ * .external("posts");
5592
+ * export default c.define("/content/posts.val.ts", schema, c.external());
4958
5593
  */
4959
5594
  }, {
4960
5595
  key: "external",
@@ -5214,6 +5849,25 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
5214
5849
  * is the item of another container, in search, in references. What its
5215
5850
  * entries show is the ITEM schema's `preview`, not this. Never how the field
5216
5851
  * is edited (that is `render`). See `preview.ts`.
5852
+ *
5853
+ * @example
5854
+ * // The preview of the RECORD, for where it is an item of something else.
5855
+ * // What its own rows show is the ITEM schema's preview — see below.
5856
+ * const labels = s.record(s.string()).preview(({ val }) => ({
5857
+ * title: `${Object.keys(val).length} locales`,
5858
+ * }));
5859
+ * export default c.define("/example.val.ts", s.array(labels), [
5860
+ * { en: "Read more" },
5861
+ * ]);
5862
+ *
5863
+ * @example
5864
+ * // Rows of a record come from the ITEM's preview, not the record's:
5865
+ * const author = s
5866
+ * .object({ name: s.string(), role: s.string() })
5867
+ * .preview(({ val }) => ({ title: val.name, subtitle: val.role }));
5868
+ * export default c.define("/example.val.ts", s.record(author), {
5869
+ * ada: { name: "Ada", role: "Engineer" },
5870
+ * });
5217
5871
  */
5218
5872
  }, {
5219
5873
  key: "preview",
@@ -5227,6 +5881,10 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
5227
5881
  * instead of a preview row that navigates to it.
5228
5882
  *
5229
5883
  * Static configuration, not a callback — see `render.ts`.
5884
+ *
5885
+ * @example
5886
+ * const schema = s.array(s.record(s.string()).render({ as: "inline" }));
5887
+ * export default c.define("/example.val.ts", schema, [{ en: "Read more" }]);
5230
5888
  */
5231
5889
  }, {
5232
5890
  key: "render",
@@ -5355,12 +6013,48 @@ var BooleanSchema = /*#__PURE__*/function (_Schema) {
5355
6013
  _this.previewInput = previewInput;
5356
6014
  return _this;
5357
6015
  }
6016
+
6017
+ /**
6018
+ * Describe this field.
6019
+ *
6020
+ * The description is shown next to the field's label in the Val editor, so
6021
+ * it is where you say what an editor needs to know but the field name cannot
6022
+ * carry. It also travels in the serialized schema, which is what the AI
6023
+ * assistant and the MCP tools read.
6024
+ *
6025
+ * Pass `null` to clear a description set earlier.
6026
+ *
6027
+ * @example
6028
+ * const schema = s.boolean().describe("Show this item in the main menu");
6029
+ * export default c.define("/example.val.ts", schema, true);
6030
+ */
5358
6031
  _inherits(BooleanSchema, _Schema);
5359
6032
  return _createClass(BooleanSchema, [{
5360
6033
  key: "describe",
5361
6034
  value: function describe(description) {
5362
6035
  return new BooleanSchema(this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
5363
6036
  }
6037
+
6038
+ /**
6039
+ * Add a custom validation rule to this field.
6040
+ *
6041
+ * The function is called with the field's value and returns `false` when the
6042
+ * value is fine, or a STRING with the message to show when it is not. Call it
6043
+ * more than once to add more rules — they all run, and every message is
6044
+ * reported.
6045
+ *
6046
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
6047
+ * when the value is fine, and `true` is not one of the two answers.
6048
+ *
6049
+ * Validation runs in the Studio as you type, in `npx val validate` and
6050
+ * before a publish.
6051
+ *
6052
+ * @example
6053
+ * const schema = s.boolean().validate((val) =>
6054
+ * val === true ? false : "This has to be on for now",
6055
+ * );
6056
+ * export default c.define("/example.val.ts", schema, true);
6057
+ */
5364
6058
  }, {
5365
6059
  key: "validate",
5366
6060
  value: function validate(validationFunction) {
@@ -5443,6 +6137,10 @@ var BooleanSchema = /*#__PURE__*/function (_Schema) {
5443
6137
  * instead of a preview row that navigates to it.
5444
6138
  *
5445
6139
  * Static configuration, not a callback — see `render.ts`.
6140
+ *
6141
+ * @example
6142
+ * const schema = s.array(s.boolean().render({ as: "inline" }));
6143
+ * export default c.define("/example.val.ts", schema, [true, false]);
5446
6144
  */
5447
6145
  }, {
5448
6146
  key: "render",
@@ -5454,6 +6152,12 @@ var BooleanSchema = /*#__PURE__*/function (_Schema) {
5454
6152
  * How this VALUE is shown where a preview of it is needed — a row in a
5455
6153
  * sortable list, a reference dropdown, a search hit. Never how the field
5456
6154
  * itself is edited (that is `render`). See `preview.ts`.
6155
+ *
6156
+ * @example
6157
+ * const schema = s.array(
6158
+ * s.boolean().preview(({ val }) => ({ title: val ? "On" : "Off" })),
6159
+ * );
6160
+ * export default c.define("/example.val.ts", schema, [true, false]);
5457
6161
  */
5458
6162
  }, {
5459
6163
  key: "preview",
@@ -5812,10 +6516,8 @@ function isArraySchema(schema) {
5812
6516
  // );
5813
6517
  // }
5814
6518
 
5815
- function isUnionSchema(schema
5816
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
5817
- ) {
5818
- return schema instanceof UnionSchema || _typeof(schema) === "object" && "type" in schema && schema.type === "union";
6519
+ function isDiscriminatedUnionSchema(schema) {
6520
+ return schema instanceof DiscriminatedUnionSchema || _typeof(schema) === "object" && "type" in schema && schema.type === "discriminated-union";
5819
6521
  }
5820
6522
  function isRichTextSchema(schema) {
5821
6523
  return schema instanceof RichTextSchema || _typeof(schema) === "object" && "type" in schema && schema.type === "richtext";
@@ -5921,27 +6623,18 @@ function resolvePath(path, valModule, schema) {
5921
6623
  source: resolvedSource
5922
6624
  }
5923
6625
  };
5924
- } else if (isUnionSchema(resolvedSchema)) {
5925
- var _key = resolvedSchema.key;
5926
- if (typeof _key !== "string") {
5927
- return {
5928
- v: {
5929
- path: origParts.map(function (p) {
5930
- if (!Number.isNaN(Number(p))) {
5931
- return p;
5932
- } else {
5933
- return JSON.stringify(p);
5934
- }
5935
- }).join("."),
5936
- // TODO: create a function generate path from parts (not sure if this always works)
5937
- schema: resolvedSchema,
5938
- source: resolvedSource
5939
- }
5940
- };
6626
+ } else if (isDiscriminatedUnionSchema(resolvedSchema)) {
6627
+ var _key = resolvedSchema instanceof DiscriminatedUnionSchema ? resolvedSchema["key"] : resolvedSchema.key;
6628
+ // A nullable union holding `null` has no variant to descend into, and
6629
+ // `null[key]` throws before any of the reporting below can run.
6630
+ if (resolvedSource === null || _typeof(resolvedSource) !== "object") {
6631
+ throw Error("Schema type error: expected discriminated union source to be an object, but got ".concat(resolvedSource === null ? "null" : _typeof(resolvedSource), " in path: ").concat(path));
5941
6632
  }
5942
6633
  var keyValue = resolvedSource[_key];
5943
- if (!keyValue) {
5944
- throw Error("Invalid path: union source ".concat(resolvedSchema, " did not have required key ").concat(_key, " in path: ").concat(path));
6634
+ // `undefined`, not falsy: `s.literal("")` is a legal tag, and a variant
6635
+ // carrying it was reported as a missing key.
6636
+ if (keyValue === undefined) {
6637
+ throw Error("Invalid path: discriminated union source ".concat(resolvedSchema, " did not have required key ").concat(_key, " in path: ").concat(path));
5945
6638
  }
5946
6639
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
5947
6640
  var schemaOfUnionKey = resolvedSchema.items.find(
@@ -5951,7 +6644,7 @@ function resolvePath(path, valModule, schema) {
5951
6644
  return (child === null || child === void 0 || (_child$items = child.items) === null || _child$items === void 0 || (_child$items = _child$items[_key]) === null || _child$items === void 0 ? void 0 : _child$items.value) === keyValue;
5952
6645
  });
5953
6646
  if (!schemaOfUnionKey) {
5954
- throw Error("Invalid path: union schema ".concat(resolvedSchema, " did not have a child object with ").concat(_key, " of value ").concat(keyValue, " in path: ").concat(path));
6647
+ throw Error("Invalid path: discriminated union schema ".concat(resolvedSchema, " did not have a child object with ").concat(_key, " of value ").concat(keyValue, " in path: ").concat(path));
5955
6648
  }
5956
6649
  resolvedSchema = schemaOfUnionKey.items[part];
5957
6650
  resolvedSource = resolvedSource[part];
@@ -6171,31 +6864,25 @@ function safeResolvePath(path, valModule, schema) {
6171
6864
  source: resolvedSource
6172
6865
  }
6173
6866
  };
6174
- } else if (isUnionSchema(resolvedSchema)) {
6175
- var _key2 = resolvedSchema.key;
6176
- if (typeof _key2 !== "string") {
6867
+ } else if (isDiscriminatedUnionSchema(resolvedSchema)) {
6868
+ var _key2 = resolvedSchema instanceof DiscriminatedUnionSchema ? resolvedSchema["key"] : resolvedSchema.key;
6869
+ // See the note in `resolvePath`: a null union has no variant to descend
6870
+ // into, and this API promises a structured error rather than a throw.
6871
+ if (resolvedSource === null || _typeof(resolvedSource) !== "object") {
6177
6872
  return {
6178
6873
  v: {
6179
- status: "ok",
6180
- path: origParts.map(function (p) {
6181
- if (!Number.isNaN(Number(p))) {
6182
- return p;
6183
- } else {
6184
- return JSON.stringify(p);
6185
- }
6186
- }).join("."),
6187
- // TODO: create a function generate path from parts (not sure if this always works)
6188
- schema: resolvedSchema,
6189
- source: resolvedSource
6874
+ status: "error",
6875
+ message: "Schema type error: expected discriminated union source to be an object, but got ".concat(resolvedSource === null ? "null" : _typeof(resolvedSource), " in path: ").concat(path)
6190
6876
  }
6191
6877
  };
6192
6878
  }
6193
6879
  var keyValue = resolvedSource[_key2];
6194
- if (!keyValue) {
6880
+ // See the note in `resolvePath`: an empty-string tag is a present key.
6881
+ if (keyValue === undefined) {
6195
6882
  return {
6196
6883
  v: {
6197
6884
  status: "error",
6198
- message: "Invalid path: union source ".concat(resolvedSchema, " did not have required key ").concat(_key2, " in path: ").concat(path)
6885
+ message: "Invalid path: discriminated union source ".concat(resolvedSchema, " did not have required key ").concat(_key2, " in path: ").concat(path)
6199
6886
  }
6200
6887
  };
6201
6888
  }
@@ -6210,7 +6897,7 @@ function safeResolvePath(path, valModule, schema) {
6210
6897
  return {
6211
6898
  v: {
6212
6899
  status: "error",
6213
- message: "Invalid path: union schema ".concat(resolvedSchema, " did not have a child object with ").concat(_key2, " of value ").concat(keyValue, " in path: ").concat(path)
6900
+ message: "Invalid path: discriminated union schema ".concat(resolvedSchema, " did not have a child object with ").concat(_key2, " of value ").concat(keyValue, " in path: ").concat(path)
6214
6901
  }
6215
6902
  };
6216
6903
  }
@@ -6347,12 +7034,48 @@ var NumberSchema = /*#__PURE__*/function (_Schema) {
6347
7034
  _this.previewInput = previewInput;
6348
7035
  return _this;
6349
7036
  }
7037
+
7038
+ /**
7039
+ * Describe this field.
7040
+ *
7041
+ * The description is shown next to the field's label in the Val editor, so
7042
+ * it is where you say what an editor needs to know but the field name cannot
7043
+ * carry. It also travels in the serialized schema, which is what the AI
7044
+ * assistant and the MCP tools read.
7045
+ *
7046
+ * Pass `null` to clear a description set earlier.
7047
+ *
7048
+ * @example
7049
+ * const schema = s.number().describe("How many columns the grid uses");
7050
+ * export default c.define("/example.val.ts", schema, 3);
7051
+ */
6350
7052
  _inherits(NumberSchema, _Schema);
6351
7053
  return _createClass(NumberSchema, [{
6352
7054
  key: "describe",
6353
7055
  value: function describe(description) {
6354
7056
  return new NumberSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
6355
7057
  }
7058
+
7059
+ /**
7060
+ * Add a custom validation rule to this field.
7061
+ *
7062
+ * The function is called with the field's value and returns `false` when the
7063
+ * value is fine, or a STRING with the message to show when it is not. Call it
7064
+ * more than once to add more rules — they all run, and every message is
7065
+ * reported.
7066
+ *
7067
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
7068
+ * when the value is fine, and `true` is not one of the two answers.
7069
+ *
7070
+ * Validation runs in the Studio as you type, in `npx val validate` and
7071
+ * before a publish.
7072
+ *
7073
+ * @example
7074
+ * const schema = s.number().validate((val) =>
7075
+ * Number.isInteger(val) ? false : "Must be a whole number",
7076
+ * );
7077
+ * export default c.define("/example.val.ts", schema, 3);
7078
+ */
6356
7079
  }, {
6357
7080
  key: "validate",
6358
7081
  value: function validate(validationFunction) {
@@ -6440,6 +7163,14 @@ var NumberSchema = /*#__PURE__*/function (_Schema) {
6440
7163
  var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
6441
7164
  return new NumberSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, isHidden, this.description, this.renderInput, this.previewInput);
6442
7165
  }
7166
+
7167
+ /**
7168
+ * Validate that the number is at most `max` (inclusive).
7169
+ *
7170
+ * @example
7171
+ * const schema = s.number().max(4);
7172
+ * export default c.define("/example.val.ts", schema, 3);
7173
+ */
6443
7174
  }, {
6444
7175
  key: "max",
6445
7176
  value: function max(_max) {
@@ -6447,6 +7178,14 @@ var NumberSchema = /*#__PURE__*/function (_Schema) {
6447
7178
  max: _max
6448
7179
  }), this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
6449
7180
  }
7181
+
7182
+ /**
7183
+ * Validate that the number is at least `min` (inclusive).
7184
+ *
7185
+ * @example
7186
+ * const schema = s.number().min(1).max(4);
7187
+ * export default c.define("/example.val.ts", schema, 3);
7188
+ */
6450
7189
  }, {
6451
7190
  key: "min",
6452
7191
  value: function min(_min) {
@@ -6468,6 +7207,10 @@ var NumberSchema = /*#__PURE__*/function (_Schema) {
6468
7207
  * instead of a preview row that navigates to it.
6469
7208
  *
6470
7209
  * Static configuration, not a callback — see `render.ts`.
7210
+ *
7211
+ * @example
7212
+ * const schema = s.array(s.number().render({ as: "inline" }));
7213
+ * export default c.define("/example.val.ts", schema, [1, 2]);
6471
7214
  */
6472
7215
  }, {
6473
7216
  key: "render",
@@ -6479,6 +7222,12 @@ var NumberSchema = /*#__PURE__*/function (_Schema) {
6479
7222
  * How this VALUE is shown where a preview of it is needed — a row in a
6480
7223
  * sortable list, a reference dropdown, a search hit. Never how the field
6481
7224
  * itself is edited (that is `render`). See `preview.ts`.
7225
+ *
7226
+ * @example
7227
+ * const schema = s.array(
7228
+ * s.number().preview(({ val }) => ({ title: String(val) })),
7229
+ * );
7230
+ * export default c.define("/example.val.ts", schema, [1, 2]);
6482
7231
  */
6483
7232
  }, {
6484
7233
  key: "preview",
@@ -6521,11 +7270,363 @@ var NumberSchema = /*#__PURE__*/function (_Schema) {
6521
7270
  value: function executePreview() {
6522
7271
  return {};
6523
7272
  }
6524
- }]);
6525
- }(Schema);
6526
- var number = function number(options) {
6527
- return new NumberSchema(options);
6528
- };
7273
+ }]);
7274
+ }(Schema);
7275
+ var number = function number(options) {
7276
+ return new NumberSchema(options);
7277
+ };
7278
+
7279
+ /**
7280
+ * One of a fixed set of strings.
7281
+ *
7282
+ * The values are the schema — there are no member schemas to descend into, so
7283
+ * this is a LEAF, like `s.string()` with a closed domain. That is the whole
7284
+ * difference from {@link DiscriminatedUnionSchema}, and the reason the two are
7285
+ * separate: everything that walks a schema tree has to recurse into a
7286
+ * discriminated union's variants and must not try to recurse into these.
7287
+ */
7288
+ var EnumSchema = /*#__PURE__*/function (_Schema) {
7289
+ function EnumSchema(values) {
7290
+ var _this;
7291
+ var opt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
7292
+ var customValidateFunctions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
7293
+ var isReadonly = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
7294
+ var isHidden = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
7295
+ var description = arguments.length > 5 ? arguments[5] : undefined;
7296
+ var renderInput = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null;
7297
+ var previewInput = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : null;
7298
+ _classCallCheck(this, EnumSchema);
7299
+ _this = _callSuper(this, EnumSchema);
7300
+ _this.values = values;
7301
+ _this.opt = opt;
7302
+ _this.customValidateFunctions = customValidateFunctions;
7303
+ _this.isReadonly = isReadonly;
7304
+ _this.isHidden = isHidden;
7305
+ _this.description = description;
7306
+ _this.renderInput = renderInput;
7307
+ _this.previewInput = previewInput;
7308
+ return _this;
7309
+ }
7310
+
7311
+ /**
7312
+ * Describe this field.
7313
+ *
7314
+ * The description is shown next to the field's label in the Val editor, so it is
7315
+ * where you say what an editor needs to know but the field name cannot carry. It
7316
+ * also travels in the serialized schema, which is what the AI assistant and the
7317
+ * MCP tools read.
7318
+ *
7319
+ * Pass `null` to clear a description set earlier.
7320
+ *
7321
+ * @example
7322
+ * const schema = s
7323
+ * .enum("draft", "published")
7324
+ * .describe("Only published pages are built");
7325
+ * export default c.define("/example.val.ts", schema, "draft");
7326
+ */
7327
+ _inherits(EnumSchema, _Schema);
7328
+ return _createClass(EnumSchema, [{
7329
+ key: "describe",
7330
+ value: function describe(description) {
7331
+ return new EnumSchema(this.values, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
7332
+ }
7333
+
7334
+ /**
7335
+ * Add a custom validation rule to this field.
7336
+ *
7337
+ * The function is called with the field's value and returns `false` when the
7338
+ * value is fine, or a STRING with the message to show when it is not. Call it
7339
+ * more than once to add more rules — they all run, and every message is
7340
+ * reported.
7341
+ *
7342
+ * Validation runs in the Studio as you type, in `npx val validate` and before a
7343
+ * publish.
7344
+ *
7345
+ * @example
7346
+ * const schema = s
7347
+ * .enum("draft", "published")
7348
+ * .validate((val) =>
7349
+ * val === "published" ? "Publishing is frozen this week" : false,
7350
+ * );
7351
+ * export default c.define("/example.val.ts", schema, "draft");
7352
+ */
7353
+ }, {
7354
+ key: "validate",
7355
+ value: function validate(validationFunction) {
7356
+ return new EnumSchema(this.values, this.opt, this.customValidateFunctions.concat(validationFunction), this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
7357
+ }
7358
+ }, {
7359
+ key: "executeValidate",
7360
+ value: function executeValidate(path, src) {
7361
+ var customValidationErrors = this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
7362
+ path: path
7363
+ });
7364
+ // The custom validators always report, whatever the structural answer is.
7365
+ var errors = customValidationErrors;
7366
+ var unknownSrc = src;
7367
+ if (this.opt && (unknownSrc === null || unknownSrc === undefined)) {
7368
+ return errors.length > 0 ? _defineProperty({}, path, errors) : false;
7369
+ }
7370
+ if (!Array.isArray(this.values) || this.values.length === 0) {
7371
+ errors.push({
7372
+ message: "An enum schema must have at least one value",
7373
+ schemaError: true
7374
+ });
7375
+ } else if (typeof unknownSrc !== "string") {
7376
+ errors.push({
7377
+ message: "Expected 'string', got '".concat(unknownSrc === null ? "null" : _typeof(unknownSrc), "'"),
7378
+ value: src,
7379
+ typeError: true
7380
+ });
7381
+ } else if (!this.values.includes(unknownSrc)) {
7382
+ errors.push({
7383
+ message: "Value must be one of the following: ".concat(this.values.map(function (value) {
7384
+ return "\"".concat(value, "\"");
7385
+ }).join(", ")),
7386
+ value: src
7387
+ });
7388
+ }
7389
+ return errors.length > 0 ? _defineProperty({}, path, errors) : false;
7390
+ }
7391
+ }, {
7392
+ key: "executeAssert",
7393
+ value: function executeAssert(path, src) {
7394
+ if (this.opt && src === null) {
7395
+ return {
7396
+ success: true,
7397
+ data: src
7398
+ };
7399
+ }
7400
+ var errors = {};
7401
+ if (typeof src !== "string") {
7402
+ errors[path] = [{
7403
+ message: "Expected 'string', got '".concat(src === null ? "null" : _typeof(src), "'"),
7404
+ typeError: true
7405
+ }];
7406
+ return {
7407
+ success: false,
7408
+ errors: errors
7409
+ };
7410
+ }
7411
+ if (!Array.isArray(this.values) || this.values.length === 0) {
7412
+ errors[path] = [{
7413
+ message: "An enum schema must have at least one value",
7414
+ schemaError: true
7415
+ }];
7416
+ return {
7417
+ success: false,
7418
+ errors: errors
7419
+ };
7420
+ }
7421
+ if (!this.values.includes(src)) {
7422
+ errors[path] = [{
7423
+ message: "Expected one of ".concat(this.values.map(function (value) {
7424
+ return "'".concat(value, "'");
7425
+ }).join(", "), ", got '").concat(src, "'"),
7426
+ typeError: true
7427
+ }];
7428
+ return {
7429
+ success: false,
7430
+ errors: errors
7431
+ };
7432
+ }
7433
+ return {
7434
+ success: true,
7435
+ data: src
7436
+ };
7437
+ }
7438
+ }, {
7439
+ key: "nullable",
7440
+ value: function nullable() {
7441
+ // Explicit type args: `previewInput` would otherwise pin inference to `Src`.
7442
+ return new EnumSchema(this.values, true, [], this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
7443
+ }
7444
+ }, {
7445
+ key: "readonly",
7446
+ value: function readonly() {
7447
+ var isReadonly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
7448
+ return new EnumSchema(this.values, this.opt, this.customValidateFunctions, isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
7449
+ }
7450
+ }, {
7451
+ key: "hidden",
7452
+ value: function hidden() {
7453
+ var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
7454
+ return new EnumSchema(this.values, this.opt, this.customValidateFunctions, this.isReadonly, isHidden, this.description, this.renderInput, this.previewInput);
7455
+ }
7456
+ }, {
7457
+ key: "executeCustomValidateAt",
7458
+ value: function executeCustomValidateAt(path, src) {
7459
+ return this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
7460
+ path: path
7461
+ });
7462
+ }
7463
+
7464
+ /**
7465
+ * How this field is laid out in the editor when it is the item of an array
7466
+ * or record: `{ as: "inline" }` renders the field itself inside each row,
7467
+ * instead of a preview row that navigates to it.
7468
+ *
7469
+ * Static configuration, not a callback — see `render.ts`.
7470
+ *
7471
+ * @example
7472
+ * const schema = s.array(
7473
+ * s.enum("draft", "published").render({ as: "inline" }),
7474
+ * );
7475
+ * export default c.define("/example.val.ts", schema, ["draft"]);
7476
+ */
7477
+ }, {
7478
+ key: "render",
7479
+ value: function render(input) {
7480
+ return new EnumSchema(this.values, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, input, this.previewInput);
7481
+ }
7482
+
7483
+ /**
7484
+ * How this VALUE is shown where a preview of it is needed — a row in a
7485
+ * sortable list, a reference dropdown, a search hit. Never how the field
7486
+ * itself is edited (that is `render`). See `preview.ts`.
7487
+ *
7488
+ * @example
7489
+ * const schema = s.array(
7490
+ * s.enum("draft", "published").preview(({ val }) => ({ title: val })),
7491
+ * );
7492
+ * export default c.define("/example.val.ts", schema, ["draft"]);
7493
+ */
7494
+ }, {
7495
+ key: "preview",
7496
+ value: function preview(select) {
7497
+ return new EnumSchema(this.values, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, select);
7498
+ }
7499
+ }, {
7500
+ key: "executePreviewItem",
7501
+ value: function executePreviewItem(src) {
7502
+ if (this.previewInput === null) {
7503
+ return null;
7504
+ }
7505
+ return this.previewInput({
7506
+ val: src
7507
+ });
7508
+ }
7509
+ }, {
7510
+ key: "declaresItemPreview",
7511
+ value: function declaresItemPreview() {
7512
+ return this.previewInput !== null;
7513
+ }
7514
+ }, {
7515
+ key: "executeSerialize",
7516
+ value: function executeSerialize() {
7517
+ var _this$renderInput, _this$customValidateF;
7518
+ return {
7519
+ type: "enum",
7520
+ render: (_this$renderInput = this.renderInput) !== null && _this$renderInput !== void 0 ? _this$renderInput : undefined,
7521
+ preview: this.previewInput ? true : undefined,
7522
+ values: _toConsumableArray(this.values),
7523
+ opt: this.opt,
7524
+ customValidate: this.customValidateFunctions && ((_this$customValidateF = this.customValidateFunctions) === null || _this$customValidateF === void 0 ? void 0 : _this$customValidateF.length) > 0,
7525
+ readonly: this.isReadonly,
7526
+ hidden: this.isHidden,
7527
+ description: this.description
7528
+ };
7529
+ }
7530
+ }, {
7531
+ key: "executePreview",
7532
+ value: function executePreview() {
7533
+ // A leaf: nothing below it to preview.
7534
+ return {};
7535
+ }
7536
+ }]);
7537
+ }(Schema);
7538
+
7539
+ /**
7540
+ * Define a string that must be one of a fixed set of values.
7541
+ *
7542
+ * Named `enumSchema` rather than `enum` because `enum` is a reserved word and
7543
+ * cannot be a binding name; it is exposed as `s.enum`.
7544
+ */
7545
+ var enumSchema = function enumSchema() {
7546
+ for (var _len = arguments.length, values = new Array(_len), _key = 0; _key < _len; _key++) {
7547
+ values[_key] = arguments[_key];
7548
+ }
7549
+ return new EnumSchema(values);
7550
+ };
7551
+
7552
+ /**
7553
+ * @deprecated Use {@link SerializedDiscriminatedUnionSchema} or
7554
+ * {@link SerializedEnumSchema}. A serialized union is now one or the other,
7555
+ * distinguished by `type` rather than by the shape of `key`.
7556
+ */
7557
+
7558
+ /** @deprecated Use {@link SerializedEnumSchema}. */
7559
+
7560
+ /** @deprecated Use {@link SerializedDiscriminatedUnionSchema}. */
7561
+
7562
+ /**
7563
+ * @deprecated There is no single union schema class any more: name
7564
+ * {@link DiscriminatedUnionSchema} or {@link EnumSchema}. The type parameters
7565
+ * are kept so existing annotations still compile, but only `Src` is used.
7566
+ */
7567
+
7568
+ /**
7569
+ * The value type of a list of literal schemas — how `s.union` typed a union of
7570
+ * literals. Inferred from `Schema<infer S>` rather than `LiteralSchema<infer S>`
7571
+ * because a `LiteralSchema` is invariant in its source (its custom validate
7572
+ * functions put it in a parameter position), so `LiteralSchema<"a">` is not
7573
+ * assignable to `LiteralSchema<"a" | "b">`.
7574
+ */
7575
+
7576
+ /**
7577
+ * @deprecated Use `s.discriminatedUnion(key, ...objects)` for a tagged union of
7578
+ * objects, or `s.enum("a", "b")` for one of a fixed set of strings.
7579
+ *
7580
+ * One thing does NOT survive the literal form: an enum's values are strings,
7581
+ * so a member literal's own `.validate()` and `.describe()` are dropped rather
7582
+ * than carried over. `s.union(s.literal("a").validate(...), ...)` ran that
7583
+ * validator as part of deciding whether the value matched; `s.enum` has no
7584
+ * member to run. A validator on a single-valued literal could only accept or
7585
+ * reject that one value, which the enum's own value list already decides — but
7586
+ * if you rely on one, keep it by validating the enum itself.
7587
+ *
7588
+ * @example
7589
+ * // was: s.union("type", s.object({ type: s.literal("a"), a: s.string() }))
7590
+ * const schema = s.discriminatedUnion(
7591
+ * "type",
7592
+ * s.object({ type: s.literal("a"), a: s.string() }),
7593
+ * );
7594
+ * export default c.define("/example.val.ts", schema, { type: "a", a: "one" });
7595
+ *
7596
+ * @example
7597
+ * // was: s.union(s.literal("a"), s.literal("b"))
7598
+ * const schema = s.enum("a", "b");
7599
+ * export default c.define("/example.val.ts", schema, "a");
7600
+ */
7601
+
7602
+ function union(keyOrFirstLiteral) {
7603
+ for (var _len = arguments.length, rest = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
7604
+ rest[_key - 1] = arguments[_key];
7605
+ }
7606
+ if (typeof keyOrFirstLiteral === "string") {
7607
+ return new DiscriminatedUnionSchema(keyOrFirstLiteral, rest);
7608
+ }
7609
+ // A literal union is an enum: the values ARE the schema, so the literals are
7610
+ // flattened into them. `key` was only ever the first member.
7611
+ var literals = [keyOrFirstLiteral].concat(rest);
7612
+ var values = [];
7613
+ var _iterator = _createForOfIteratorHelper(literals),
7614
+ _step;
7615
+ try {
7616
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
7617
+ var literal = _step.value;
7618
+ if (!(literal instanceof LiteralSchema)) {
7619
+ throw new Error("s.union: expected either a string key followed by object schemas, or literal schemas. Got: ".concat(JSON.stringify(literal)));
7620
+ }
7621
+ values.push(literal["value"]);
7622
+ }
7623
+ } catch (err) {
7624
+ _iterator.e(err);
7625
+ } finally {
7626
+ _iterator.f();
7627
+ }
7628
+ return new EnumSchema(values);
7629
+ }
6529
7630
 
6530
7631
  var KeyOfSchema = /*#__PURE__*/function (_Schema) {
6531
7632
  function KeyOfSchema(schema, sourcePath) {
@@ -6550,12 +7651,52 @@ var KeyOfSchema = /*#__PURE__*/function (_Schema) {
6550
7651
  _this.previewInput = previewInput;
6551
7652
  return _this;
6552
7653
  }
7654
+
7655
+ /**
7656
+ * Describe this field.
7657
+ *
7658
+ * The description is shown next to the field's label in the Val editor, so
7659
+ * it is where you say what an editor needs to know but the field name cannot
7660
+ * carry. It also travels in the serialized schema, which is what the AI
7661
+ * assistant and the MCP tools read.
7662
+ *
7663
+ * Pass `null` to clear a description set earlier.
7664
+ *
7665
+ * @example
7666
+ * import authorsVal from "./authors.val"; // a record module
7667
+ * const schema = s.keyOf(authorsVal).describe("Who wrote this post");
7668
+ * export default c.define("/example.val.ts", schema, "ada");
7669
+ */
6553
7670
  _inherits(KeyOfSchema, _Schema);
6554
7671
  return _createClass(KeyOfSchema, [{
6555
7672
  key: "describe",
6556
7673
  value: function describe(description) {
6557
7674
  return new KeyOfSchema(this.schema, this.sourcePath, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
6558
7675
  }
7676
+
7677
+ /**
7678
+ * Add a custom validation rule to this field.
7679
+ *
7680
+ * The function is called with the field's value and returns `false` when the
7681
+ * value is fine, or a STRING with the message to show when it is not. Call it
7682
+ * more than once to add more rules — they all run, and every message is
7683
+ * reported.
7684
+ *
7685
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
7686
+ * when the value is fine, and `true` is not one of the two answers.
7687
+ *
7688
+ * Validation runs in the Studio as you type, in `npx val validate` and
7689
+ * before a publish.
7690
+ *
7691
+ * @example
7692
+ * import authorsVal from "./authors.val"; // a record module
7693
+ * const schema = s
7694
+ * .keyOf(authorsVal)
7695
+ * .validate((val) =>
7696
+ * val === "placeholder" ? "Pick a real author" : false,
7697
+ * );
7698
+ * export default c.define("/example.val.ts", schema, "ada");
7699
+ */
6559
7700
  }, {
6560
7701
  key: "validate",
6561
7702
  value: function validate(validationFunction) {
@@ -6717,6 +7858,11 @@ var KeyOfSchema = /*#__PURE__*/function (_Schema) {
6717
7858
  * instead of a preview row that navigates to it.
6718
7859
  *
6719
7860
  * Static configuration, not a callback — see `render.ts`.
7861
+ *
7862
+ * @example
7863
+ * import authorsVal from "./authors.val"; // a record module
7864
+ * const schema = s.array(s.keyOf(authorsVal).render({ as: "inline" }));
7865
+ * export default c.define("/example.val.ts", schema, ["ada"]);
6720
7866
  */
6721
7867
  }, {
6722
7868
  key: "render",
@@ -6728,6 +7874,13 @@ var KeyOfSchema = /*#__PURE__*/function (_Schema) {
6728
7874
  * How this VALUE is shown where a preview of it is needed — a row in a
6729
7875
  * sortable list, a reference dropdown, a search hit. Never how the field
6730
7876
  * itself is edited (that is `render`). See `preview.ts`.
7877
+ *
7878
+ * @example
7879
+ * import authorsVal from "./authors.val"; // a record module
7880
+ * const schema = s.array(
7881
+ * s.keyOf(authorsVal).preview(({ val }) => ({ title: val })),
7882
+ * );
7883
+ * export default c.define("/example.val.ts", schema, ["ada"]);
6731
7884
  */
6732
7885
  }, {
6733
7886
  key: "preview",
@@ -6844,17 +7997,83 @@ var FileSchema = /*#__PURE__*/function (_Schema) {
6844
7997
  _this.previewInput = previewInput;
6845
7998
  return _this;
6846
7999
  }
8000
+
8001
+ /**
8002
+ * Describe this field.
8003
+ *
8004
+ * The description is shown next to the field's label in the Val editor, so
8005
+ * it is where you say what an editor needs to know but the field name cannot
8006
+ * carry. It also travels in the serialized schema, which is what the AI
8007
+ * assistant and the MCP tools read.
8008
+ *
8009
+ * Pass `null` to clear a description set earlier.
8010
+ *
8011
+ * @example
8012
+ * const schema = s.file().describe("The PDF offered for download");
8013
+ * export default c.define("/example.val.ts", schema, {
8014
+ * path: "/public/val/example.pdf",
8015
+ * mimeType: "application/pdf",
8016
+ * });
8017
+ */
6847
8018
  _inherits(FileSchema, _Schema);
6848
8019
  return _createClass(FileSchema, [{
6849
8020
  key: "describe",
6850
8021
  value: function describe(description) {
6851
8022
  return new FileSchema(this.options, this.opt, this.isRemote, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
6852
8023
  }
8024
+
8025
+ /**
8026
+ * Store the file on Val's remote content host instead of in your repository.
8027
+ *
8028
+ * The bytes still go into the patch store when the file is uploaded — the
8029
+ * push to the remote host happens at publish. What changes is where the
8030
+ * published file lives: `path` becomes a remote URL rather than a path under
8031
+ * `/public`, so the repository does not grow with every upload.
8032
+ *
8033
+ * The `path` of a remote file is a URL on the content host, and it is not
8034
+ * something to write by hand: upload the file in the Studio, or write a
8035
+ * local path and let `npx val validate --fix` upload it and rewrite the
8036
+ * `path` to the ref below.
8037
+ *
8038
+ * @example
8039
+ * const schema = s.file({ accept: "application/pdf" }).remote();
8040
+ * export default c.define("/example.val.ts", schema, {
8041
+ * path: "https://remote.val.build/file/p/my-project/b/01/v/1.0.0/h/8f2a1c/f/3b9d70/p/public/val/example.pdf",
8042
+ * mimeType: "application/pdf",
8043
+ * });
8044
+ */
6853
8045
  }, {
6854
8046
  key: "remote",
6855
8047
  value: function remote() {
6856
8048
  return new FileSchema(this.options, this.opt, true, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
6857
8049
  }
8050
+
8051
+ /**
8052
+ * Add a custom validation rule to this field.
8053
+ *
8054
+ * The function is called with the field's value and returns `false` when the
8055
+ * value is fine, or a STRING with the message to show when it is not. Call it
8056
+ * more than once to add more rules — they all run, and every message is
8057
+ * reported.
8058
+ *
8059
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
8060
+ * when the value is fine, and `true` is not one of the two answers.
8061
+ *
8062
+ * Validation runs in the Studio as you type, in `npx val validate` and
8063
+ * before a publish.
8064
+ *
8065
+ * The second argument carries the `path` of the field being validated, for
8066
+ * when the message needs to say where the problem is.
8067
+ *
8068
+ * @example
8069
+ * const schema = s.file().validate((val) =>
8070
+ * val.path.endsWith(".pdf") ? false : "Must be a PDF",
8071
+ * );
8072
+ * export default c.define("/example.val.ts", schema, {
8073
+ * path: "/public/val/example.pdf",
8074
+ * mimeType: "application/pdf",
8075
+ * });
8076
+ */
6858
8077
  }, {
6859
8078
  key: "validate",
6860
8079
  value: function validate(validationFunction) {
@@ -7061,6 +8280,12 @@ var FileSchema = /*#__PURE__*/function (_Schema) {
7061
8280
  * instead of a preview row that navigates to it.
7062
8281
  *
7063
8282
  * Static configuration, not a callback — see `render.ts`.
8283
+ *
8284
+ * @example
8285
+ * const schema = s.array(s.file().render({ as: "inline" }));
8286
+ * export default c.define("/example.val.ts", schema, [
8287
+ * { path: "/public/val/example.pdf", mimeType: "application/pdf" },
8288
+ * ]);
7064
8289
  */
7065
8290
  }, {
7066
8291
  key: "render",
@@ -7072,6 +8297,14 @@ var FileSchema = /*#__PURE__*/function (_Schema) {
7072
8297
  * How this VALUE is shown where a preview of it is needed — a row in a
7073
8298
  * sortable list, a reference dropdown, a search hit. Never how the field
7074
8299
  * itself is edited (that is `render`). See `preview.ts`.
8300
+ *
8301
+ * @example
8302
+ * const schema = s.array(
8303
+ * s.file().preview(({ val }) => ({ title: val.path })),
8304
+ * );
8305
+ * export default c.define("/example.val.ts", schema, [
8306
+ * { path: "/public/val/example.pdf", mimeType: "application/pdf" },
8307
+ * ]);
7075
8308
  */
7076
8309
  }, {
7077
8310
  key: "preview",
@@ -7205,12 +8438,48 @@ var DateSchema = /*#__PURE__*/function (_Schema) {
7205
8438
  _this.previewInput = previewInput;
7206
8439
  return _this;
7207
8440
  }
8441
+
8442
+ /**
8443
+ * Describe this field.
8444
+ *
8445
+ * The description is shown next to the field's label in the Val editor, so
8446
+ * it is where you say what an editor needs to know but the field name cannot
8447
+ * carry. It also travels in the serialized schema, which is what the AI
8448
+ * assistant and the MCP tools read.
8449
+ *
8450
+ * Pass `null` to clear a description set earlier.
8451
+ *
8452
+ * @example
8453
+ * const schema = s.date().describe("First day the campaign is live");
8454
+ * export default c.define("/example.val.ts", schema, "2025-06-01");
8455
+ */
7208
8456
  _inherits(DateSchema, _Schema);
7209
8457
  return _createClass(DateSchema, [{
7210
8458
  key: "describe",
7211
8459
  value: function describe(description) {
7212
8460
  return new DateSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
7213
8461
  }
8462
+
8463
+ /**
8464
+ * Add a custom validation rule to this field.
8465
+ *
8466
+ * The function is called with the field's value and returns `false` when the
8467
+ * value is fine, or a STRING with the message to show when it is not. Call it
8468
+ * more than once to add more rules — they all run, and every message is
8469
+ * reported.
8470
+ *
8471
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
8472
+ * when the value is fine, and `true` is not one of the two answers.
8473
+ *
8474
+ * Validation runs in the Studio as you type, in `npx val validate` and
8475
+ * before a publish.
8476
+ *
8477
+ * @example
8478
+ * const schema = s.date().validate((val) =>
8479
+ * val >= "2025-01-01" ? false : "Must be in 2025 or later",
8480
+ * );
8481
+ * export default c.define("/example.val.ts", schema, "2025-06-01");
8482
+ */
7214
8483
  }, {
7215
8484
  key: "validate",
7216
8485
  value: function validate(validationFunction) {
@@ -7298,6 +8567,16 @@ var DateSchema = /*#__PURE__*/function (_Schema) {
7298
8567
  data: src
7299
8568
  };
7300
8569
  }
8570
+
8571
+ /**
8572
+ * Validate that the date is this date or after (inclusive).
8573
+ *
8574
+ * Written as `YYYY-MM-DD`, the same shape the value has.
8575
+ *
8576
+ * @example
8577
+ * const schema = s.date().from("2025-01-01");
8578
+ * export default c.define("/example.val.ts", schema, "2025-06-01");
8579
+ */
7301
8580
  }, {
7302
8581
  key: "from",
7303
8582
  value: function from(_from) {
@@ -7305,6 +8584,16 @@ var DateSchema = /*#__PURE__*/function (_Schema) {
7305
8584
  from: _from
7306
8585
  }), this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
7307
8586
  }
8587
+
8588
+ /**
8589
+ * Validate that the date is this date or before (inclusive).
8590
+ *
8591
+ * Written as `YYYY-MM-DD`, the same shape the value has.
8592
+ *
8593
+ * @example
8594
+ * const schema = s.date().from("2025-01-01").to("2025-12-31");
8595
+ * export default c.define("/example.val.ts", schema, "2025-06-01");
8596
+ */
7308
8597
  }, {
7309
8598
  key: "to",
7310
8599
  value: function to(_to) {
@@ -7343,6 +8632,10 @@ var DateSchema = /*#__PURE__*/function (_Schema) {
7343
8632
  * instead of a preview row that navigates to it.
7344
8633
  *
7345
8634
  * Static configuration, not a callback — see `render.ts`.
8635
+ *
8636
+ * @example
8637
+ * const schema = s.array(s.date().render({ as: "inline" }));
8638
+ * export default c.define("/example.val.ts", schema, ["2025-06-01"]);
7346
8639
  */
7347
8640
  }, {
7348
8641
  key: "render",
@@ -7354,6 +8647,12 @@ var DateSchema = /*#__PURE__*/function (_Schema) {
7354
8647
  * How this VALUE is shown where a preview of it is needed — a row in a
7355
8648
  * sortable list, a reference dropdown, a search hit. Never how the field
7356
8649
  * itself is edited (that is `render`). See `preview.ts`.
8650
+ *
8651
+ * @example
8652
+ * const schema = s.array(
8653
+ * s.date().preview(({ val }) => ({ title: val })),
8654
+ * );
8655
+ * export default c.define("/example.val.ts", schema, ["2025-06-01"]);
7357
8656
  */
7358
8657
  }, {
7359
8658
  key: "preview",
@@ -7424,12 +8723,56 @@ var DateTimeSchema = /*#__PURE__*/function (_Schema) {
7424
8723
  _this.previewInput = previewInput;
7425
8724
  return _this;
7426
8725
  }
8726
+
8727
+ /**
8728
+ * Describe this field.
8729
+ *
8730
+ * The description is shown next to the field's label in the Val editor, so
8731
+ * it is where you say what an editor needs to know but the field name cannot
8732
+ * carry. It also travels in the serialized schema, which is what the AI
8733
+ * assistant and the MCP tools read.
8734
+ *
8735
+ * Pass `null` to clear a description set earlier.
8736
+ *
8737
+ * @example
8738
+ * const schema = s.datetime().describe("When the article goes live");
8739
+ * export default c.define(
8740
+ * "/example.val.ts",
8741
+ * schema,
8742
+ * "2025-06-01T09:00:00.000Z",
8743
+ * );
8744
+ */
7427
8745
  _inherits(DateTimeSchema, _Schema);
7428
8746
  return _createClass(DateTimeSchema, [{
7429
8747
  key: "describe",
7430
8748
  value: function describe(description) {
7431
8749
  return new DateTimeSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
7432
8750
  }
8751
+
8752
+ /**
8753
+ * Add a custom validation rule to this field.
8754
+ *
8755
+ * The function is called with the field's value and returns `false` when the
8756
+ * value is fine, or a STRING with the message to show when it is not. Call it
8757
+ * more than once to add more rules — they all run, and every message is
8758
+ * reported.
8759
+ *
8760
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
8761
+ * when the value is fine, and `true` is not one of the two answers.
8762
+ *
8763
+ * Validation runs in the Studio as you type, in `npx val validate` and
8764
+ * before a publish.
8765
+ *
8766
+ * @example
8767
+ * const schema = s.datetime().validate((val) =>
8768
+ * val.endsWith("Z") ? false : "Must be in UTC",
8769
+ * );
8770
+ * export default c.define(
8771
+ * "/example.val.ts",
8772
+ * schema,
8773
+ * "2025-06-01T09:00:00.000Z",
8774
+ * );
8775
+ */
7433
8776
  }, {
7434
8777
  key: "validate",
7435
8778
  value: function validate(validationFunction) {
@@ -7549,6 +8892,20 @@ var DateTimeSchema = /*#__PURE__*/function (_Schema) {
7549
8892
  data: src
7550
8893
  };
7551
8894
  }
8895
+
8896
+ /**
8897
+ * Validate that the datetime is this datetime or after (inclusive).
8898
+ *
8899
+ * Any ISO 8601 datetime string `Date.parse` understands.
8900
+ *
8901
+ * @example
8902
+ * const schema = s.datetime().from("2025-01-01T00:00:00Z");
8903
+ * export default c.define(
8904
+ * "/example.val.ts",
8905
+ * schema,
8906
+ * "2025-06-01T09:00:00.000Z",
8907
+ * );
8908
+ */
7552
8909
  }, {
7553
8910
  key: "from",
7554
8911
  value: function from(_from) {
@@ -7556,6 +8913,23 @@ var DateTimeSchema = /*#__PURE__*/function (_Schema) {
7556
8913
  from: _from
7557
8914
  }), this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
7558
8915
  }
8916
+
8917
+ /**
8918
+ * Validate that the datetime is this datetime or before (inclusive).
8919
+ *
8920
+ * Any ISO 8601 datetime string `Date.parse` understands.
8921
+ *
8922
+ * @example
8923
+ * const schema = s
8924
+ * .datetime()
8925
+ * .from("2025-01-01T00:00:00Z")
8926
+ * .to("2025-12-31T23:59:59Z");
8927
+ * export default c.define(
8928
+ * "/example.val.ts",
8929
+ * schema,
8930
+ * "2025-06-01T09:00:00.000Z",
8931
+ * );
8932
+ */
7559
8933
  }, {
7560
8934
  key: "to",
7561
8935
  value: function to(_to) {
@@ -7594,6 +8968,12 @@ var DateTimeSchema = /*#__PURE__*/function (_Schema) {
7594
8968
  * instead of a preview row that navigates to it.
7595
8969
  *
7596
8970
  * Static configuration, not a callback — see `render.ts`.
8971
+ *
8972
+ * @example
8973
+ * const schema = s.array(s.datetime().render({ as: "inline" }));
8974
+ * export default c.define("/example.val.ts", schema, [
8975
+ * "2025-06-01T09:00:00.000Z",
8976
+ * ]);
7597
8977
  */
7598
8978
  }, {
7599
8979
  key: "render",
@@ -7605,6 +8985,14 @@ var DateTimeSchema = /*#__PURE__*/function (_Schema) {
7605
8985
  * How this VALUE is shown where a preview of it is needed — a row in a
7606
8986
  * sortable list, a reference dropdown, a search hit. Never how the field
7607
8987
  * itself is edited (that is `render`). See `preview.ts`.
8988
+ *
8989
+ * @example
8990
+ * const schema = s.array(
8991
+ * s.datetime().preview(({ val }) => ({ title: val })),
8992
+ * );
8993
+ * export default c.define("/example.val.ts", schema, [
8994
+ * "2025-06-01T09:00:00.000Z",
8995
+ * ]);
7608
8996
  */
7609
8997
  }, {
7610
8998
  key: "preview",
@@ -7689,12 +9077,59 @@ var CodeSchema = /*#__PURE__*/function (_Schema) {
7689
9077
  _this.previewInput = previewInput;
7690
9078
  return _this;
7691
9079
  }
9080
+
9081
+ /**
9082
+ * Describe this field.
9083
+ *
9084
+ * The description is shown next to the field's label in the Val editor, so
9085
+ * it is where you say what an editor needs to know but the field name cannot
9086
+ * carry. It also travels in the serialized schema, which is what the AI
9087
+ * assistant and the MCP tools read.
9088
+ *
9089
+ * Pass `null` to clear a description set earlier.
9090
+ *
9091
+ * @example
9092
+ * const schema = s
9093
+ * .code({ language: "css" })
9094
+ * .describe("Injected into the page head — keep it small");
9095
+ * export default c.define(
9096
+ * "/example.val.ts",
9097
+ * schema,
9098
+ * ".hero { color: red; }",
9099
+ * );
9100
+ */
7692
9101
  _inherits(CodeSchema, _Schema);
7693
9102
  return _createClass(CodeSchema, [{
7694
9103
  key: "describe",
7695
9104
  value: function describe(description) {
7696
9105
  return new CodeSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
7697
9106
  }
9107
+
9108
+ /**
9109
+ * Add a custom validation rule to this field.
9110
+ *
9111
+ * The function is called with the field's value and returns `false` when the
9112
+ * value is fine, or a STRING with the message to show when it is not. Call it
9113
+ * more than once to add more rules — they all run, and every message is
9114
+ * reported.
9115
+ *
9116
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
9117
+ * when the value is fine, and `true` is not one of the two answers.
9118
+ *
9119
+ * Validation runs in the Studio as you type, in `npx val validate` and
9120
+ * before a publish.
9121
+ *
9122
+ * @example
9123
+ * const schema = s.code({ language: "json" }).validate((val) => {
9124
+ * try {
9125
+ * JSON.parse(val);
9126
+ * return false;
9127
+ * } catch {
9128
+ * return "Must be valid JSON";
9129
+ * }
9130
+ * });
9131
+ * export default c.define("/example.val.ts", schema, '{ "a": 1 }');
9132
+ */
7698
9133
  }, {
7699
9134
  key: "validate",
7700
9135
  value: function validate(validationFunction) {
@@ -7774,6 +9209,14 @@ var CodeSchema = /*#__PURE__*/function (_Schema) {
7774
9209
  * instead of a preview row that navigates to it.
7775
9210
  *
7776
9211
  * Static configuration, not a callback — see `render.ts`.
9212
+ *
9213
+ * @example
9214
+ * const schema = s.array(
9215
+ * s.code({ language: "css" }).render({ as: "inline" }),
9216
+ * );
9217
+ * export default c.define("/example.val.ts", schema, [
9218
+ * ".hero { color: red; }",
9219
+ * ]);
7777
9220
  */
7778
9221
  }, {
7779
9222
  key: "render",
@@ -7785,6 +9228,16 @@ var CodeSchema = /*#__PURE__*/function (_Schema) {
7785
9228
  * How this VALUE is shown where a preview of it is needed — a row in a
7786
9229
  * sortable list, a reference dropdown, a search hit. Never how the field
7787
9230
  * itself is edited (that is `render`). See `preview.ts`.
9231
+ *
9232
+ * @example
9233
+ * const schema = s.array(
9234
+ * s.code({ language: "css" }).preview(({ val }) => ({
9235
+ * title: val.split("\n")[0],
9236
+ * })),
9237
+ * );
9238
+ * export default c.define("/example.val.ts", schema, [
9239
+ * ".hero { color: red; }",
9240
+ * ]);
7788
9241
  */
7789
9242
  }, {
7790
9243
  key: "preview",
@@ -8335,12 +9788,54 @@ var ColorSchema = /*#__PURE__*/function (_Schema) {
8335
9788
  _this.previewInput = previewInput;
8336
9789
  return _this;
8337
9790
  }
9791
+
9792
+ /**
9793
+ * Describe this field.
9794
+ *
9795
+ * The description is shown next to the field's label in the Val editor, so
9796
+ * it is where you say what an editor needs to know but the field name cannot
9797
+ * carry. It also travels in the serialized schema, which is what the AI
9798
+ * assistant and the MCP tools read.
9799
+ *
9800
+ * Pass `null` to clear a description set earlier.
9801
+ *
9802
+ * @example
9803
+ * const schema = s.color().describe("Background of the hero section");
9804
+ * export default c.define(
9805
+ * "/example.val.ts",
9806
+ * schema,
9807
+ * "hsl(217.22 91.22% 59.8%)",
9808
+ * );
9809
+ */
8338
9810
  _inherits(ColorSchema, _Schema);
8339
9811
  return _createClass(ColorSchema, [{
8340
9812
  key: "describe",
8341
9813
  value: function describe(description) {
8342
9814
  return new ColorSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
8343
9815
  }
9816
+
9817
+ /**
9818
+ * Add a custom validation rule to this field.
9819
+ *
9820
+ * The function is called with the field's value and returns `false` when the
9821
+ * value is fine, or a STRING with the message to show when it is not. Call it
9822
+ * more than once to add more rules — they all run, and every message is
9823
+ * reported.
9824
+ *
9825
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
9826
+ * when the value is fine, and `true` is not one of the two answers.
9827
+ *
9828
+ * Validation runs in the Studio as you type, in `npx val validate` and
9829
+ * before a publish.
9830
+ *
9831
+ * @example
9832
+ * const schema = s
9833
+ * .color({ format: "hex" })
9834
+ * .validate((val) =>
9835
+ * val === val.toLowerCase() ? false : "Write hex in lower case",
9836
+ * );
9837
+ * export default c.define("/example.val.ts", schema, "#3b82f6");
9838
+ */
8344
9839
  }, {
8345
9840
  key: "validate",
8346
9841
  value: function validate(validationFunction) {
@@ -8462,6 +9957,12 @@ var ColorSchema = /*#__PURE__*/function (_Schema) {
8462
9957
  * instead of a preview row that navigates to it.
8463
9958
  *
8464
9959
  * Static configuration, not a callback — see `render.ts`.
9960
+ *
9961
+ * @example
9962
+ * const schema = s.array(s.color().render({ as: "inline" }));
9963
+ * export default c.define("/example.val.ts", schema, [
9964
+ * "hsl(217.22 91.22% 59.8%)",
9965
+ * ]);
8465
9966
  */
8466
9967
  }, {
8467
9968
  key: "render",
@@ -8473,6 +9974,14 @@ var ColorSchema = /*#__PURE__*/function (_Schema) {
8473
9974
  * How this VALUE is shown where a preview of it is needed — a row in a
8474
9975
  * sortable list, a reference dropdown, a search hit. Never how the field
8475
9976
  * itself is edited (that is `render`). See `preview.ts`.
9977
+ *
9978
+ * @example
9979
+ * const schema = s.array(
9980
+ * s.color().preview(({ val }) => ({ title: val })),
9981
+ * );
9982
+ * export default c.define("/example.val.ts", schema, [
9983
+ * "hsl(217.22 91.22% 59.8%)",
9984
+ * ]);
8476
9985
  */
8477
9986
  }, {
8478
9987
  key: "preview",
@@ -8601,6 +10110,8 @@ function initSchema() {
8601
10110
  array: array,
8602
10111
  object: object,
8603
10112
  number: number,
10113
+ discriminatedUnion: discriminatedUnion,
10114
+ "enum": enumSchema,
8604
10115
  union: union,
8605
10116
  // oneOf,
8606
10117
  richtext: richtext,
@@ -9519,32 +11030,26 @@ function hasRemoteFileSchema(schema) {
9519
11030
  }
9520
11031
  }
9521
11032
  return false;
9522
- } else if (schema.type === "union") {
9523
- var unionStringSchema = _typeof(schema.key) === "object" && schema.key.type === "literal" ? schema : undefined;
9524
- var unionObjectSchema = typeof schema.key === "string" ? schema : undefined;
9525
- if (unionStringSchema) {
9526
- // A string union's items are literals, so there is nothing to look inside.
9527
- return false;
9528
- }
9529
- if (unionObjectSchema) {
9530
- var _iterator = _createForOfIteratorHelper(unionObjectSchema.items),
9531
- _step;
9532
- try {
9533
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
9534
- var item = _step.value;
9535
- var _hasRemoteFile = hasRemoteFileSchema(item);
9536
- if (_hasRemoteFile) {
9537
- return true;
9538
- }
11033
+ } else if (schema.type === "discriminated-union") {
11034
+ var _iterator = _createForOfIteratorHelper(schema.items),
11035
+ _step;
11036
+ try {
11037
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
11038
+ var item = _step.value;
11039
+ var _hasRemoteFile = hasRemoteFileSchema(item);
11040
+ if (_hasRemoteFile) {
11041
+ return true;
9539
11042
  }
9540
- } catch (err) {
9541
- _iterator.e(err);
9542
- } finally {
9543
- _iterator.f();
9544
11043
  }
11044
+ } catch (err) {
11045
+ _iterator.e(err);
11046
+ } finally {
11047
+ _iterator.f();
9545
11048
  }
9546
11049
  return false;
9547
- } else if (schema.type === "boolean" || schema.type === "number" || schema.type === "string" || schema.type === "literal" || schema.type === "date" || schema.type === "dateTime" || schema.type === "color" || schema.type === "code" || schema.type === "keyOf" || schema.type === "route") {
11050
+ } else if (schema.type === "boolean" ||
11051
+ // An enum's values are strings, so there is nothing to look inside.
11052
+ schema.type === "enum" || schema.type === "number" || schema.type === "string" || schema.type === "literal" || schema.type === "date" || schema.type === "dateTime" || schema.type === "color" || schema.type === "code" || schema.type === "keyOf" || schema.type === "route") {
9548
11053
  return false;
9549
11054
  } else {
9550
11055
  var exhaustiveCheck = schema;
@@ -9598,27 +11103,25 @@ function hasMediaSchema(schema) {
9598
11103
  }
9599
11104
  }
9600
11105
  return false;
9601
- } else if (schema.type === "union") {
9602
- var unionObjectSchema = typeof schema.key === "string" ? schema : undefined;
9603
- if (unionObjectSchema) {
9604
- var _iterator2 = _createForOfIteratorHelper(unionObjectSchema.items),
9605
- _step2;
9606
- try {
9607
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
9608
- var item = _step2.value;
9609
- if (hasMediaSchema(item)) {
9610
- return true;
9611
- }
11106
+ } else if (schema.type === "discriminated-union") {
11107
+ var _iterator2 = _createForOfIteratorHelper(schema.items),
11108
+ _step2;
11109
+ try {
11110
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
11111
+ var item = _step2.value;
11112
+ if (hasMediaSchema(item)) {
11113
+ return true;
9612
11114
  }
9613
- } catch (err) {
9614
- _iterator2.e(err);
9615
- } finally {
9616
- _iterator2.f();
9617
11115
  }
11116
+ } catch (err) {
11117
+ _iterator2.e(err);
11118
+ } finally {
11119
+ _iterator2.f();
9618
11120
  }
9619
- // A string union's items are literals, so there is nothing to look inside.
9620
11121
  return false;
9621
- } else if (schema.type === "boolean" || schema.type === "number" || schema.type === "string" || schema.type === "literal" || schema.type === "date" || schema.type === "dateTime" || schema.type === "color" || schema.type === "code" || schema.type === "keyOf" || schema.type === "route" ||
11122
+ } else if (schema.type === "boolean" ||
11123
+ // An enum's values are strings, so there is nothing to look inside.
11124
+ schema.type === "enum" || schema.type === "number" || schema.type === "string" || schema.type === "literal" || schema.type === "date" || schema.type === "dateTime" || schema.type === "color" || schema.type === "code" || schema.type === "keyOf" || schema.type === "route" ||
9622
11125
  // A settings module holds the assistant's configuration, not content, and
9623
11126
  // nothing in it is media.
9624
11127
  schema.type === "settings") {
@@ -9908,7 +11411,7 @@ function deserializeSchema(serialized) {
9908
11411
  return schema;
9909
11412
  }
9910
11413
  function deserializeSchemaImpl(serialized) {
9911
- var _serialized$options, _serialized$options2, _serialized$render, _serialized$multiline, _serialized$render2, _serialized$render3, _serialized$render4, _serialized$render5, _serialized$render6, _serialized$render7, _serialized$accept, _serialized$directory, _serialized$remote, _serialized$jsonValue, _serialized$render9, _serialized$external, _serialized$render0, _serialized$render10, _serialized$render11, _serialized$render12, _serialized$render13, _serialized$render14, _serialized$render15;
11414
+ var _serialized$options, _serialized$options2, _serialized$render, _serialized$multiline, _serialized$render2, _serialized$render3, _serialized$render4, _serialized$render5, _serialized$render6, _serialized$render7, _serialized$render8, _serialized$accept, _serialized$directory, _serialized$remote, _serialized$jsonValue, _serialized$render0, _serialized$external, _serialized$render1, _serialized$render11, _serialized$render12, _serialized$render13, _serialized$render14, _serialized$render15, _serialized$render16;
9912
11415
  switch (serialized.type) {
9913
11416
  case "string":
9914
11417
  return new StringSchema(_objectSpread2(_objectSpread2({}, serialized.options), {}, {
@@ -9942,23 +11445,22 @@ function deserializeSchemaImpl(serialized) {
9942
11445
  return new ArraySchema(deserializeSchema(serialized.item), serialized.opt, [], false, false, serialized.description,
9943
11446
  // The preview closure cannot survive serialization; the render can.
9944
11447
  null, (_serialized$render6 = serialized.render) !== null && _serialized$render6 !== void 0 ? _serialized$render6 : null);
9945
- case "union":
9946
- return new UnionSchema(typeof serialized.key === "string" ? serialized.key :
9947
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
9948
- deserializeSchema(serialized.key),
9949
- // TODO: we do not really need any here - right?
11448
+ case "discriminated-union":
11449
+ return new DiscriminatedUnionSchema(serialized.key,
9950
11450
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
9951
11451
  serialized.items.map(deserializeSchema),
9952
11452
  // TODO: we do not really need any here - right?
9953
11453
  serialized.opt, [], false, false, serialized.description, (_serialized$render7 = serialized.render) !== null && _serialized$render7 !== void 0 ? _serialized$render7 : null);
11454
+ case "enum":
11455
+ return new EnumSchema(serialized.values, serialized.opt, [], false, false, serialized.description, (_serialized$render8 = serialized.render) !== null && _serialized$render8 !== void 0 ? _serialized$render8 : null);
9954
11456
  case "richtext":
9955
11457
  {
9956
- var _serialized$options3, _serialized$options4, _serialized$options5, _serialized$options6, _serialized$render8;
11458
+ var _serialized$options3, _serialized$options4, _serialized$options5, _serialized$options6, _serialized$render9;
9957
11459
  var deserializedOptions = _objectSpread2(_objectSpread2({}, serialized.options || {}), {}, {
9958
11460
  a: _typeof((_serialized$options3 = serialized.options) === null || _serialized$options3 === void 0 ? void 0 : _serialized$options3.a) === "object" ? deserializeSchema(serialized.options.a) : (_serialized$options4 = serialized.options) === null || _serialized$options4 === void 0 ? void 0 : _serialized$options4.a,
9959
11461
  img: _typeof((_serialized$options5 = serialized.options) === null || _serialized$options5 === void 0 ? void 0 : _serialized$options5.img) === "object" ? deserializeSchema(serialized.options.img) : (_serialized$options6 = serialized.options) === null || _serialized$options6 === void 0 ? void 0 : _serialized$options6.img
9960
11462
  });
9961
- return new RichTextSchema(deserializedOptions, serialized.opt, [], false, false, serialized.description, (_serialized$render8 = serialized.render) !== null && _serialized$render8 !== void 0 ? _serialized$render8 : null);
11463
+ return new RichTextSchema(deserializedOptions, serialized.opt, [], false, false, serialized.description, (_serialized$render9 = serialized.render) !== null && _serialized$render9 !== void 0 ? _serialized$render9 : null);
9962
11464
  }
9963
11465
  case "record":
9964
11466
  return new RecordSchema(deserializeSchema(serialized.item), serialized.opt, [], null, serialized.key ? deserializeSchema(serialized.key) : null, serialized.mediaType ? {
@@ -9969,33 +11471,33 @@ function deserializeSchemaImpl(serialized) {
9969
11471
  altSchema: serialized.alt ? deserializeSchema(serialized.alt) : undefined
9970
11472
  } : undefined, false, false, serialized.description, (_serialized$jsonValue = serialized.jsonValues) !== null && _serialized$jsonValue !== void 0 ? _serialized$jsonValue : false,
9971
11473
  // The preview closure cannot survive serialization; the render can.
9972
- null, (_serialized$render9 = serialized.render) !== null && _serialized$render9 !== void 0 ? _serialized$render9 : null, // The external label is static data, so it survives serialization and
11474
+ null, (_serialized$render0 = serialized.render) !== null && _serialized$render0 !== void 0 ? _serialized$render0 : null, // The external label is static data, so it survives serialization and
9973
11475
  // must be carried back: a deserialized schema that forgot it would walk
9974
11476
  // an external record as if its entries were local.
9975
11477
  (_serialized$external = serialized.external) !== null && _serialized$external !== void 0 ? _serialized$external : null);
9976
11478
  case "keyOf":
9977
- return new KeyOfSchema(serialized.schema, serialized.path, serialized.opt, [], false, false, serialized.description, (_serialized$render0 = serialized.render) !== null && _serialized$render0 !== void 0 ? _serialized$render0 : null);
11479
+ return new KeyOfSchema(serialized.schema, serialized.path, serialized.opt, [], false, false, serialized.description, (_serialized$render1 = serialized.render) !== null && _serialized$render1 !== void 0 ? _serialized$render1 : null);
9978
11480
  case "route":
9979
11481
  {
9980
- var _serialized$render1;
11482
+ var _serialized$render10;
9981
11483
  var routeOptions = serialized.options ? {
9982
11484
  include: serialized.options.include ? new RegExp(serialized.options.include.source, serialized.options.include.flags) : undefined,
9983
11485
  exclude: serialized.options.exclude ? new RegExp(serialized.options.exclude.source, serialized.options.exclude.flags) : undefined
9984
11486
  } : undefined;
9985
- return new RouteSchema(routeOptions, serialized.opt, [], false, false, serialized.description, (_serialized$render1 = serialized.render) !== null && _serialized$render1 !== void 0 ? _serialized$render1 : null);
11487
+ return new RouteSchema(routeOptions, serialized.opt, [], false, false, serialized.description, (_serialized$render10 = serialized.render) !== null && _serialized$render10 !== void 0 ? _serialized$render10 : null);
9986
11488
  }
9987
11489
  case "file":
9988
- return new FileSchema(serialized.options, serialized.opt, serialized.remote, [], {}, false, false, serialized.description, (_serialized$render10 = serialized.render) !== null && _serialized$render10 !== void 0 ? _serialized$render10 : null);
11490
+ return new FileSchema(serialized.options, serialized.opt, serialized.remote, [], {}, false, false, serialized.description, (_serialized$render11 = serialized.render) !== null && _serialized$render11 !== void 0 ? _serialized$render11 : null);
9989
11491
  case "image":
9990
- return new ImageSchema(serialized.options, serialized.opt, serialized.remote, [], {}, false, false, serialized.description, (_serialized$render11 = serialized.render) !== null && _serialized$render11 !== void 0 ? _serialized$render11 : null);
11492
+ return new ImageSchema(serialized.options, serialized.opt, serialized.remote, [], {}, false, false, serialized.description, (_serialized$render12 = serialized.render) !== null && _serialized$render12 !== void 0 ? _serialized$render12 : null);
9991
11493
  case "date":
9992
- return new DateSchema(serialized.options, serialized.opt, [], false, false, serialized.description, (_serialized$render12 = serialized.render) !== null && _serialized$render12 !== void 0 ? _serialized$render12 : null);
11494
+ return new DateSchema(serialized.options, serialized.opt, [], false, false, serialized.description, (_serialized$render13 = serialized.render) !== null && _serialized$render13 !== void 0 ? _serialized$render13 : null);
9993
11495
  case "dateTime":
9994
- return new DateTimeSchema(serialized.options, serialized.opt, [], false, false, serialized.description, (_serialized$render13 = serialized.render) !== null && _serialized$render13 !== void 0 ? _serialized$render13 : null);
11496
+ return new DateTimeSchema(serialized.options, serialized.opt, [], false, false, serialized.description, (_serialized$render14 = serialized.render) !== null && _serialized$render14 !== void 0 ? _serialized$render14 : null);
9995
11497
  case "color":
9996
- return new ColorSchema(serialized.options, serialized.opt, [], false, false, serialized.description, (_serialized$render14 = serialized.render) !== null && _serialized$render14 !== void 0 ? _serialized$render14 : null);
11498
+ return new ColorSchema(serialized.options, serialized.opt, [], false, false, serialized.description, (_serialized$render15 = serialized.render) !== null && _serialized$render15 !== void 0 ? _serialized$render15 : null);
9997
11499
  case "code":
9998
- return new CodeSchema(serialized.options, serialized.opt, [], false, false, serialized.description, (_serialized$render15 = serialized.render) !== null && _serialized$render15 !== void 0 ? _serialized$render15 : null);
11500
+ return new CodeSchema(serialized.options, serialized.opt, [], false, false, serialized.description, (_serialized$render16 = serialized.render) !== null && _serialized$render16 !== void 0 ? _serialized$render16 : null);
9999
11501
  default:
10000
11502
  {
10001
11503
  var exhaustiveCheck = serialized;
@@ -10204,10 +11706,11 @@ function previewScope(paths) {
10204
11706
  * question, and a disagreement between them is a row you can edit in place but
10205
11707
  * that "add" navigates away from.
10206
11708
  *
10207
- * A tagged union counts as inline when the union itself declares it OR when
10208
- * ANY of its variants does. A page-builder list is `s.array(s.union("type",
10209
- * block, block, ...))` and the natural place to write the render is on the
10210
- * blocks, one per block type — the union is a dispatch, not something the
11709
+ * A discriminated union counts as inline when the union itself declares it OR
11710
+ * when ANY of its variants does. A page-builder list is
11711
+ * `s.array(s.discriminatedUnion("type", block, block, ...))` and the natural
11712
+ * place to write the render is on the blocks, one per block type — the union
11713
+ * is a dispatch, not something the
10211
11714
  * author thinks of as the field. `some` rather than `every` because the row
10212
11715
  * draws the union's own editor (the tag selector plus the matched variant's
10213
11716
  * fields), which handles every variant either way: with `every`, adding one
@@ -10224,7 +11727,7 @@ function isInlineRender(schema) {
10224
11727
  if (((_schema$render = schema.render) === null || _schema$render === void 0 ? void 0 : _schema$render.as) === "inline") {
10225
11728
  return true;
10226
11729
  }
10227
- if (schema.type === "union") {
11730
+ if (schema.type === "discriminated-union") {
10228
11731
  return schema.items.some(function (item) {
10229
11732
  var _item$render;
10230
11733
  return ((_item$render = item.render) === null || _item$render === void 0 ? void 0 : _item$render.as) === "inline";
@@ -10449,23 +11952,190 @@ function parseNextJsRoutePattern(moduleFilePath) {
10449
11952
  return [];
10450
11953
  }
10451
11954
 
11955
+ /**
11956
+ * Parse a TanStack Router route pattern out of a Val module file path.
11957
+ *
11958
+ * TanStack Router's file conventions are not Next's, so this is a different
11959
+ * parser rather than a flag on the one above. A Val module for a route lives
11960
+ * beside the route file and is named the same way — `routes/posts.$postId.tsx`
11961
+ * is served content by `routes/posts.$postId.val.ts` — so the pattern is the
11962
+ * file path with the conventions applied:
11963
+ *
11964
+ * - `.` and `/` both separate segments (`posts.$postId.val.ts` and
11965
+ * `posts/$postId.val.ts` are the same route)
11966
+ * - `$param` is a dynamic segment, `$` on its own is a splat
11967
+ * - `index` is the directory's own route and contributes no segment
11968
+ * - `route` is a layout for the directory, likewise
11969
+ * - `(group)` folders and `_pathless` layout segments are not in the URL
11970
+ * - a trailing `_` on a segment opts out of nesting and is not in the URL
11971
+ *
11972
+ * The result is expressed in the SAME vocabulary the Next parser uses
11973
+ * (`[param]`, `[...param]`), because everything downstream — validation, the
11974
+ * sitemap, the key inputs in the Studio — is written against that vocabulary
11975
+ * and there is no reason for two.
11976
+ *
11977
+ * - /src/routes/posts.$postId.val.ts -> ["posts", "[postId]"]
11978
+ * - /routes/posts/$postId.val.ts -> ["posts", "[postId]"]
11979
+ * - /src/routes/index.val.ts -> []
11980
+ * - /src/routes/files.$.val.ts -> ["files", "[..._splat]"]
11981
+ * - /src/routes/(app)/_layout.about.val.ts -> ["about"]
11982
+ */
11983
+ function parseTanStackRoutePattern(moduleFilePath) {
11984
+ var segments = tanStackRouteSegments(moduleFilePath);
11985
+ if (segments === null) {
11986
+ return [];
11987
+ }
11988
+ return segments;
11989
+ }
11990
+
11991
+ /**
11992
+ * The segments, or `null` when the path is not a TanStack route module at all.
11993
+ *
11994
+ * Distinct from `parseTanStackRoutePattern`'s empty array, which is a real
11995
+ * answer: the root route `/` has no segments.
11996
+ */
11997
+ function tanStackRouteSegments(moduleFilePath) {
11998
+ if (!moduleFilePath || typeof moduleFilePath !== "string") {
11999
+ return null;
12000
+ }
12001
+ var match = moduleFilePath.match(/^(?:\/src)?\/routes\/(.+)\.val\.[tj]sx?$/);
12002
+ if (!match) {
12003
+ return null;
12004
+ }
12005
+ return tanStackSegmentsOfRoutePath(match[1]);
12006
+ }
12007
+
12008
+ /**
12009
+ * The URL segments of a TanStack route path, given relative to `routes/`.
12010
+ *
12011
+ * Exported because the Studio derives the same pattern from the same file path
12012
+ * and must not disagree with validation about what a route is.
12013
+ */
12014
+ function tanStackSegmentsOfRoutePath(routePath) {
12015
+ // `.` is a separator exactly like `/`, so flatten both before looking at any
12016
+ // segment: `posts/$postId.edit` and `posts.$postId.edit` are one route.
12017
+ var rawSegments = routePath.split("/").flatMap(function (part) {
12018
+ return part.split(".");
12019
+ }).filter(function (part) {
12020
+ return part !== "";
12021
+ });
12022
+ var segments = [];
12023
+ var _iterator3 = _createForOfIteratorHelper(rawSegments),
12024
+ _step3;
12025
+ try {
12026
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
12027
+ var rawSegment = _step3.value;
12028
+ // A route group: a folder that organises files without appearing in the URL.
12029
+ if (rawSegment.startsWith("(") && rawSegment.endsWith(")")) {
12030
+ continue;
12031
+ }
12032
+ // A pathless layout route. `_layout` nests its children without adding a
12033
+ // segment; `index`/`route` are the directory's own route and its layout.
12034
+ if (rawSegment.startsWith("_")) {
12035
+ continue;
12036
+ }
12037
+ if (rawSegment === "index" || rawSegment === "route") {
12038
+ continue;
12039
+ }
12040
+ // A trailing `_` opts the segment out of layout nesting; the URL keeps the
12041
+ // name without it.
12042
+ var segment = rawSegment.endsWith("_") ? rawSegment.slice(0, -1) : rawSegment;
12043
+ if (segment === "$") {
12044
+ // A splat. Named `_splat` because that is the param name TanStack gives
12045
+ // it, so `useValRoute(pageVal, params)` can be handed the route's own
12046
+ // params object unchanged.
12047
+ segments.push("[..._splat]");
12048
+ continue;
12049
+ }
12050
+ if (segment.startsWith("$")) {
12051
+ segments.push("[".concat(segment.slice(1), "]"));
12052
+ continue;
12053
+ }
12054
+ segments.push(segment);
12055
+ }
12056
+ } catch (err) {
12057
+ _iterator3.e(err);
12058
+ } finally {
12059
+ _iterator3.f();
12060
+ }
12061
+ return segments;
12062
+ }
12063
+
12064
+ /**
12065
+ * The router for a TanStack Router (and TanStack Start) app.
12066
+ *
12067
+ * Like `nextAppRouter` this does not belong in core — it is here for the same
12068
+ * reason that one is: the serialized schema carries only a router id, so the
12069
+ * thing that turns an id back into a validator has to be somewhere every
12070
+ * consumer can reach.
12071
+ */
12072
+ var tanstackRouter = {
12073
+ getRouterId: function getRouterId() {
12074
+ return "tanstack-router";
12075
+ },
12076
+ validate: function validate(moduleFilePath, urlPaths) {
12077
+ var routePattern = parseTanStackRoutePattern(moduleFilePath);
12078
+ var errors = [];
12079
+ var _iterator4 = _createForOfIteratorHelper(urlPaths),
12080
+ _step4;
12081
+ try {
12082
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
12083
+ var urlPath = _step4.value;
12084
+ var validation = validateUrlAgainstPattern(urlPath, routePattern);
12085
+ if (!validation.isValid) {
12086
+ errors.push({
12087
+ error: {
12088
+ message: "URL path \"".concat(urlPath, "\" does not match the route pattern for \"").concat(moduleFilePath, "\""),
12089
+ urlPath: urlPath,
12090
+ expectedPath: validation.expectedPath || null
12091
+ }
12092
+ });
12093
+ }
12094
+ }
12095
+ } catch (err) {
12096
+ _iterator4.e(err);
12097
+ } finally {
12098
+ _iterator4.f();
12099
+ }
12100
+ return errors;
12101
+ }
12102
+ };
12103
+
12104
+ /**
12105
+ * The routers whose keys are URL paths of THIS site, and how to read the route
12106
+ * pattern a module of each serves.
12107
+ *
12108
+ * Keyed by router id because that is all a serialized schema carries. A router
12109
+ * that is not in here — `external-url-router` today — has keys that are URLs of
12110
+ * somewhere else, so matching this site's pathname against them is meaningless
12111
+ * rather than merely unsupported.
12112
+ */
12113
+ var PAGE_ROUTE_PATTERN_PARSERS = {
12114
+ "next-app-router": parseNextJsRoutePattern,
12115
+ "tanstack-router": parseTanStackRoutePattern
12116
+ };
12117
+
10452
12118
  /**
10453
12119
  * Given a URL pathname (e.g. "/blogs/blog-1") and all serialized module schemas,
10454
- * finds the matching next-app-router module and returns the module file path
10455
- * and the source path for that route's content.
12120
+ * finds the page-router module that serves that route and returns the module
12121
+ * file path and the source path for that route's content.
10456
12122
  *
10457
12123
  * External routers (e.g. external-url-router) are intentionally skipped.
10458
- * Returns null if no next-app-router module matches the pathname.
12124
+ * Returns null if no page-router module matches the pathname.
10459
12125
  */
10460
12126
  function getSourcePathFromRoute(pathname, schemas) {
10461
12127
  for (var _i = 0, _arr = Object.entries(schemas); _i < _arr.length; _i++) {
10462
12128
  var _arr$_i = _slicedToArray(_arr[_i], 2),
10463
12129
  moduleFilePath = _arr$_i[0],
10464
12130
  schema = _arr$_i[1];
10465
- if (schema.type !== "record" || schema.router !== "next-app-router") {
12131
+ if (schema.type !== "record" || !schema.router) {
10466
12132
  continue;
10467
12133
  }
10468
- var routePattern = parseNextJsRoutePattern(moduleFilePath);
12134
+ var parseRoutePattern = PAGE_ROUTE_PATTERN_PARSERS[schema.router];
12135
+ if (!parseRoutePattern) {
12136
+ continue;
12137
+ }
12138
+ var routePattern = parseRoutePattern(moduleFilePath);
10469
12139
  var _validateUrlAgainstPa = validateUrlAgainstPattern(pathname, routePattern),
10470
12140
  isValid = _validateUrlAgainstPa.isValid;
10471
12141
  if (isValid) {
@@ -10480,20 +12150,81 @@ function getSourcePathFromRoute(pathname, schemas) {
10480
12150
  return null;
10481
12151
  }
10482
12152
 
12153
+ /**
12154
+ * Whether a router id is one whose keys are routes of this site.
12155
+ *
12156
+ * The same question `getSourcePathFromRoute` asks, exported because the Studio
12157
+ * asks it too — a page router gets the sitemap and the "Pages" menu, an
12158
+ * external one gets a flat list of URLs — and the two must not disagree about
12159
+ * which is which.
12160
+ */
12161
+ function isPageRouter(routerId) {
12162
+ return routerId in PAGE_ROUTE_PATTERN_PARSERS;
12163
+ }
12164
+
12165
+ var corePackageJson = {
12166
+ name: "@valbuild/core",
12167
+ version: "0.126.0",
12168
+ "private": false,
12169
+ description: "Val - supercharged hard-coded content",
12170
+ repository: {
12171
+ type: "git",
12172
+ url: "git+https://github.com/valbuild/val.git"
12173
+ },
12174
+ scripts: {
12175
+ typecheck: "tsc --noEmit",
12176
+ test: "jest",
12177
+ "analyze-trace": "npx tsc -p tsconfig.json --skipLibCheck --generateTrace trace; npx -p @typescript/analyze-trace analyze-trace trace; npx speedscope trace/trace.json"
12178
+ },
12179
+ main: "dist/valbuild-core.cjs.js",
12180
+ module: "dist/valbuild-core.esm.js",
12181
+ exports: {
12182
+ ".": {
12183
+ module: "./dist/valbuild-core.esm.js",
12184
+ "default": "./dist/valbuild-core.cjs.js"
12185
+ },
12186
+ "./fp": {
12187
+ module: "./fp/dist/valbuild-core-fp.esm.js",
12188
+ "default": "./fp/dist/valbuild-core-fp.cjs.js"
12189
+ },
12190
+ "./patch": {
12191
+ module: "./patch/dist/valbuild-core-patch.esm.js",
12192
+ "default": "./patch/dist/valbuild-core-patch.cjs.js"
12193
+ },
12194
+ "./package.json": "./package.json"
12195
+ },
12196
+ types: "dist/valbuild-core.cjs.d.ts",
12197
+ preconstruct: {
12198
+ entrypoints: [
12199
+ "./index.ts",
12200
+ "./fp/index.ts",
12201
+ "./patch/index.ts"
12202
+ ],
12203
+ exports: true
12204
+ },
12205
+ devDependencies: {
12206
+ typescript: "^6.0.3"
12207
+ },
12208
+ dependencies: {
12209
+ "ts-toolbelt": "^9.6.0"
12210
+ },
12211
+ files: [
12212
+ "CHANGELOG.md",
12213
+ "dist",
12214
+ "fp/dist",
12215
+ "fp/package.json",
12216
+ "patch/dist",
12217
+ "patch/package.json"
12218
+ ]
12219
+ };
12220
+
10483
12221
  var ModuleFilePathSep = "?p=";
10484
12222
  var FATAL_ERROR_TYPES = ["no-schema", "no-source", "invalid-id", "no-module", "invalid-patch"];
10485
12223
  var DEFAULT_CONTENT_HOST = "https://content.val.build";
10486
12224
  var DEFAULT_APP_HOST = "https://admin.val.build";
10487
12225
  var Internal = {
10488
12226
  VERSION: {
10489
- core: function () {
10490
- try {
10491
- // eslint-disable-next-line @typescript-eslint/no-require-imports
10492
- return require("../package.json").version;
10493
- } catch (_unused) {
10494
- return null;
10495
- }
10496
- }()
12227
+ core: corePackageJson.version
10497
12228
  },
10498
12229
  mediaUrl: mediaUrl,
10499
12230
  resolveMedia: resolveMedia,
@@ -10510,6 +12241,7 @@ var Internal = {
10510
12241
  splitModuleFilePathAndModulePath: splitModuleFilePathAndModulePath,
10511
12242
  joinModuleFilePathAndModulePath: joinModuleFilePathAndModulePath,
10512
12243
  nextAppRouter: nextAppRouter,
12244
+ tanstackRouter: tanstackRouter,
10513
12245
  externalPageRouter: externalPageRouter,
10514
12246
  color: {
10515
12247
  parseColor: parseColor,
@@ -10598,9 +12330,9 @@ var Internal = {
10598
12330
  function tryJsonParse(str) {
10599
12331
  try {
10600
12332
  return JSON.parse(str);
10601
- } catch (_unused2) {
12333
+ } catch (_unused) {
10602
12334
  return str;
10603
12335
  }
10604
12336
  }
10605
12337
 
10606
- export { ArraySchema as A, BooleanSchema as B, ColorSchema as C, DEFAULT_CONTENT_HOST as D, COLOR_FORMATS as E, FATAL_ERROR_TYPES as F, GenericSelector as G, DEFAULT_COLOR_FORMAT as H, Internal as I, DateTimeSchema as J, KeyOfSchema as K, RouteSchema as L, ModuleFilePathSep as M, NumberSchema as N, ObjectSchema as O, PatchError as P, RichTextSchema as Q, RecordSchema as R, Schema as S, LiteralSchema as T, UnionSchema as U, VAL_EXTENSION as V, deserializeSchema as W, previewScope as X, isInlineRender as Y, getSourcePathFromRoute as Z, _typeof as _, _slicedToArray as a, _createClass as b, _classCallCheck as c, _toConsumableArray as d, DEFAULT_APP_HOST as e, extractValModules as f, computeValModuleShas as g, hasRemoteFileSchema as h, initVal as i, hasMediaSchema as j, DEFAULT_VAL_REMOTE_HOST as k, derefPatch as l, modules as m, StringSchema as n, ImageSchema as o, FileSchema as p, DateSchema as q, SettingsSchema as r, splitModuleFilePathAndModulePath as s, ASSISTANT_SETTINGS_MAX_LENGTH as t, assistantAvailability as u, SETTINGS_MODULE_CONVENTION as v, isRootModuleFilePath as w, resolveSettingsModule as x, CodeSchema as y, CODE_LANGUAGES as z };
12338
+ export { parseNextJsRoutePattern as $, ArraySchema as A, BooleanSchema as B, ColorSchema as C, DEFAULT_CONTENT_HOST as D, COLOR_FORMATS as E, FATAL_ERROR_TYPES as F, GenericSelector as G, DEFAULT_COLOR_FORMAT as H, Internal as I, DateTimeSchema as J, KeyOfSchema as K, RouteSchema as L, ModuleFilePathSep as M, NumberSchema as N, ObjectSchema as O, PatchError as P, RichTextSchema as Q, RecordSchema as R, Schema as S, DiscriminatedUnionSchema as T, EnumSchema as U, VAL_EXTENSION as V, LiteralSchema as W, deserializeSchema as X, previewScope as Y, isInlineRender as Z, _typeof as _, _slicedToArray as a, parseTanStackRoutePattern as a0, tanStackSegmentsOfRoutePath as a1, validateUrlAgainstPattern as a2, getSourcePathFromRoute as a3, isPageRouter as a4, _createClass as b, _classCallCheck as c, _toConsumableArray as d, DEFAULT_APP_HOST as e, extractValModules as f, computeValModuleShas as g, hasRemoteFileSchema as h, initVal as i, hasMediaSchema as j, DEFAULT_VAL_REMOTE_HOST as k, derefPatch as l, modules as m, StringSchema as n, ImageSchema as o, FileSchema as p, DateSchema as q, SettingsSchema as r, splitModuleFilePathAndModulePath as s, ASSISTANT_SETTINGS_MAX_LENGTH as t, assistantAvailability as u, SETTINGS_MODULE_CONVENTION as v, isRootModuleFilePath as w, resolveSettingsModule as x, CodeSchema as y, CODE_LANGUAGES as z };