@valbuild/core 0.120.0 → 0.124.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 (44) hide show
  1. package/CHANGELOG.md +123 -0
  2. package/dist/declarations/src/index.d.ts +12 -1
  3. package/dist/declarations/src/initSchema.d.ts +27 -0
  4. package/dist/declarations/src/initVal.d.ts +13 -8
  5. package/dist/declarations/src/module.d.ts +18 -1
  6. package/dist/declarations/src/schema/array.d.ts +2 -2
  7. package/dist/declarations/src/schema/boolean.d.ts +2 -2
  8. package/dist/declarations/src/schema/code.d.ts +2 -2
  9. package/dist/declarations/src/schema/color.d.ts +2 -2
  10. package/dist/declarations/src/schema/date.d.ts +2 -2
  11. package/dist/declarations/src/schema/datetime.d.ts +2 -2
  12. package/dist/declarations/src/schema/file.d.ts +2 -2
  13. package/dist/declarations/src/schema/files.d.ts +2 -5
  14. package/dist/declarations/src/schema/hasRemoteFileSchema.d.ts +21 -3
  15. package/dist/declarations/src/schema/image.d.ts +2 -2
  16. package/dist/declarations/src/schema/images.d.ts +1 -6
  17. package/dist/declarations/src/schema/index.d.ts +12 -3
  18. package/dist/declarations/src/schema/keyOf.d.ts +2 -2
  19. package/dist/declarations/src/schema/literal.d.ts +2 -2
  20. package/dist/declarations/src/schema/number.d.ts +2 -2
  21. package/dist/declarations/src/schema/object.d.ts +2 -2
  22. package/dist/declarations/src/schema/record.d.ts +80 -4
  23. package/dist/declarations/src/schema/richtext.d.ts +2 -2
  24. package/dist/declarations/src/schema/route.d.ts +2 -2
  25. package/dist/declarations/src/schema/settings.d.ts +102 -0
  26. package/dist/declarations/src/schema/string.d.ts +2 -2
  27. package/dist/declarations/src/schema/union.d.ts +2 -2
  28. package/dist/declarations/src/schema/validation/ValidationFix.d.ts +1 -1
  29. package/dist/declarations/src/selector/index.d.ts +4 -2
  30. package/dist/declarations/src/settingsModule.d.ts +60 -0
  31. package/dist/declarations/src/source/external.d.ts +91 -0
  32. package/dist/declarations/src/source/externalRef.d.ts +46 -0
  33. package/dist/declarations/src/source/index.d.ts +4 -2
  34. package/dist/declarations/src/source/settings.d.ts +94 -0
  35. package/dist/{index-861944d8.cjs.prod.js → index-22a40d42.cjs.prod.js} +1324 -446
  36. package/dist/{index-2f65e194.esm.js → index-9c14df37.esm.js} +1318 -447
  37. package/dist/{index-01f673d2.cjs.dev.js → index-fcd087bd.cjs.dev.js} +1324 -446
  38. package/dist/valbuild-core.cjs.dev.js +8 -1
  39. package/dist/valbuild-core.cjs.prod.js +8 -1
  40. package/dist/valbuild-core.esm.js +1 -1
  41. package/package.json +1 -1
  42. package/patch/dist/valbuild-core-patch.cjs.dev.js +1 -1
  43. package/patch/dist/valbuild-core-patch.cjs.prod.js +1 -1
  44. package/patch/dist/valbuild-core-patch.esm.js +2 -2
@@ -589,12 +589,14 @@ var StringSchema = /*#__PURE__*/function (_Schema) {
589
589
  }, {
590
590
  key: "readonly",
591
591
  value: function readonly() {
592
- return new StringSchema(this.options, this.opt, this.isRaw, this.customValidateFunctions, this.renderInput, true, this.isHidden, this.description, this.previewInput, this.isMultiline);
592
+ var isReadonly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
593
+ return new StringSchema(this.options, this.opt, this.isRaw, this.customValidateFunctions, this.renderInput, isReadonly, this.isHidden, this.description, this.previewInput, this.isMultiline);
593
594
  }
594
595
  }, {
595
596
  key: "hidden",
596
597
  value: function hidden() {
597
- return new StringSchema(this.options, this.opt, this.isRaw, this.customValidateFunctions, this.renderInput, this.isReadonly, true, this.description, this.previewInput, this.isMultiline);
598
+ var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
599
+ return new StringSchema(this.options, this.opt, this.isRaw, this.customValidateFunctions, this.renderInput, this.isReadonly, isHidden, this.description, this.previewInput, this.isMultiline);
598
600
  }
599
601
  }, {
600
602
  key: "raw",
@@ -867,12 +869,14 @@ var ObjectSchema = /*#__PURE__*/function (_Schema) {
867
869
  }, {
868
870
  key: "readonly",
869
871
  value: function readonly() {
870
- return new ObjectSchema(this.items, this.opt, this.customValidateFunctions, true, this.isHidden, this.description, this.renderInput, this.previewInput);
872
+ var isReadonly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
873
+ return new ObjectSchema(this.items, this.opt, this.customValidateFunctions, isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
871
874
  }
872
875
  }, {
873
876
  key: "hidden",
874
877
  value: function hidden() {
875
- return new ObjectSchema(this.items, this.opt, this.customValidateFunctions, this.isReadonly, true, this.description, this.renderInput, this.previewInput);
878
+ var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
879
+ return new ObjectSchema(this.items, this.opt, this.customValidateFunctions, this.isReadonly, isHidden, this.description, this.renderInput, this.previewInput);
876
880
  }
877
881
  }, {
878
882
  key: "executeCustomValidateAt",
@@ -1083,12 +1087,14 @@ var ArraySchema = /*#__PURE__*/function (_Schema) {
1083
1087
  }, {
1084
1088
  key: "readonly",
1085
1089
  value: function readonly() {
1086
- return new ArraySchema(this.item, this.opt, this.customValidateFunctions, true, this.isHidden, this.description, this.previewInput, this.renderInput);
1090
+ var isReadonly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
1091
+ return new ArraySchema(this.item, this.opt, this.customValidateFunctions, isReadonly, this.isHidden, this.description, this.previewInput, this.renderInput);
1087
1092
  }
1088
1093
  }, {
1089
1094
  key: "hidden",
1090
1095
  value: function hidden() {
1091
- return new ArraySchema(this.item, this.opt, this.customValidateFunctions, this.isReadonly, true, this.description, this.previewInput, this.renderInput);
1096
+ var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
1097
+ return new ArraySchema(this.item, this.opt, this.customValidateFunctions, this.isReadonly, isHidden, this.description, this.previewInput, this.renderInput);
1092
1098
  }
1093
1099
  }, {
1094
1100
  key: "executeCustomValidateAt",
@@ -1336,12 +1342,14 @@ var LiteralSchema = /*#__PURE__*/function (_Schema) {
1336
1342
  }, {
1337
1343
  key: "readonly",
1338
1344
  value: function readonly() {
1339
- return new LiteralSchema(this.value, this.opt, this.customValidateFunctions, true, this.isHidden, this.description, this.renderInput, this.previewInput);
1345
+ var isReadonly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
1346
+ return new LiteralSchema(this.value, this.opt, this.customValidateFunctions, isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
1340
1347
  }
1341
1348
  }, {
1342
1349
  key: "hidden",
1343
1350
  value: function hidden() {
1344
- return new LiteralSchema(this.value, this.opt, this.customValidateFunctions, this.isReadonly, true, this.description, this.renderInput, this.previewInput);
1351
+ var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
1352
+ return new LiteralSchema(this.value, this.opt, this.customValidateFunctions, this.isReadonly, isHidden, this.description, this.renderInput, this.previewInput);
1345
1353
  }
1346
1354
  }, {
1347
1355
  key: "executeCustomValidateAt",
@@ -1747,12 +1755,14 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
1747
1755
  }, {
1748
1756
  key: "readonly",
1749
1757
  value: function readonly() {
1750
- return new UnionSchema(this.key, this.items, this.opt, this.customValidateFunctions, true, this.isHidden, this.description, this.renderInput, this.previewInput);
1758
+ 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);
1751
1760
  }
1752
1761
  }, {
1753
1762
  key: "hidden",
1754
1763
  value: function hidden() {
1755
- return new UnionSchema(this.key, this.items, this.opt, this.customValidateFunctions, this.isReadonly, true, this.description, this.renderInput, this.previewInput);
1764
+ 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);
1756
1766
  }
1757
1767
  }, {
1758
1768
  key: "executeCustomValidateAt",
@@ -1952,7 +1962,7 @@ var union = function union(key) {
1952
1962
  return new UnionSchema(key, objects);
1953
1963
  };
1954
1964
 
1955
- var RegEx = /^(https?:\/\/[^/]+)\/file\/p\/([^/]+)\/b\/([^/]+)\/v\/([^/]+)\/h\/([^/]+)\/f\/([^/]+)\/p\/(.+)$/;
1965
+ var RegEx$1 = /^(https?:\/\/[^/]+)\/file\/p\/([^/]+)\/b\/([^/]+)\/v\/([^/]+)\/h\/([^/]+)\/f\/([^/]+)\/p\/(.+)$/;
1956
1966
  function splitRemoteRef(ref) {
1957
1967
  if (ref[0] === "/") {
1958
1968
  return {
@@ -1960,7 +1970,7 @@ function splitRemoteRef(ref) {
1960
1970
  error: "Not a remote ref: " + ref
1961
1971
  };
1962
1972
  }
1963
- var match = ref.match(RegEx);
1973
+ var match = ref.match(RegEx$1);
1964
1974
  if (!match) {
1965
1975
  return {
1966
1976
  status: "error",
@@ -3125,12 +3135,14 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
3125
3135
  }, {
3126
3136
  key: "readonly",
3127
3137
  value: function readonly() {
3128
- return new ImageSchema(this.options, this.opt, this.isRemote, this.customValidateFunctions, this.moduleMetadata, true, this.isHidden, this.description, this.renderInput, this.previewInput);
3138
+ var isReadonly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
3139
+ return new ImageSchema(this.options, this.opt, this.isRemote, this.customValidateFunctions, this.moduleMetadata, isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
3129
3140
  }
3130
3141
  }, {
3131
3142
  key: "hidden",
3132
3143
  value: function hidden() {
3133
- return new ImageSchema(this.options, this.opt, this.isRemote, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, true, this.description, this.renderInput, this.previewInput);
3144
+ var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
3145
+ return new ImageSchema(this.options, this.opt, this.isRemote, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, isHidden, this.description, this.renderInput, this.previewInput);
3134
3146
  }
3135
3147
  }, {
3136
3148
  key: "executeCustomValidateAt",
@@ -3362,12 +3374,14 @@ var RouteSchema = /*#__PURE__*/function (_Schema) {
3362
3374
  }, {
3363
3375
  key: "readonly",
3364
3376
  value: function readonly() {
3365
- return new RouteSchema(this.options, this.opt, this.customValidateFunctions, true, this.isHidden, this.description, this.renderInput, this.previewInput);
3377
+ var isReadonly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
3378
+ return new RouteSchema(this.options, this.opt, this.customValidateFunctions, isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
3366
3379
  }
3367
3380
  }, {
3368
3381
  key: "hidden",
3369
3382
  value: function hidden() {
3370
- return new RouteSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, true, this.description, this.renderInput, this.previewInput);
3383
+ var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
3384
+ return new RouteSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, isHidden, this.description, this.renderInput, this.previewInput);
3371
3385
  }
3372
3386
  }, {
3373
3387
  key: "executeCustomValidateAt",
@@ -3946,12 +3960,14 @@ var RichTextSchema = /*#__PURE__*/function (_Schema) {
3946
3960
  }, {
3947
3961
  key: "readonly",
3948
3962
  value: function readonly() {
3949
- return new RichTextSchema(this.options, this.opt, this.customValidateFunctions, true, this.isHidden, this.description, this.renderInput, this.previewInput);
3963
+ var isReadonly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
3964
+ return new RichTextSchema(this.options, this.opt, this.customValidateFunctions, isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
3950
3965
  }
3951
3966
  }, {
3952
3967
  key: "hidden",
3953
3968
  value: function hidden() {
3954
- return new RichTextSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, true, this.description, this.renderInput, this.previewInput);
3969
+ var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
3970
+ return new RichTextSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, isHidden, this.description, this.renderInput, this.previewInput);
3955
3971
  }
3956
3972
  }, {
3957
3973
  key: "executeCustomValidateAt",
@@ -4352,6 +4368,94 @@ function _resolveJsonValues() {
4352
4368
  return _resolveJsonValues.apply(this, arguments);
4353
4369
  }
4354
4370
 
4371
+ /**
4372
+ * The string used as the `_type` discriminator of an {@link ExternalRecordSrc}.
4373
+ */
4374
+ var EXTERNAL_VAL_EXTENSION_TAG = "external";
4375
+
4376
+ /**
4377
+ * Type-level-only slots. Declared here rather than reusing `PhantomType`
4378
+ * (`source/index.ts`) because three separate facts have to ride along, and that
4379
+ * helper carries one.
4380
+ *
4381
+ * None of them exist at runtime: `c.external()` produces `{ _type: "external" }`
4382
+ * and nothing else.
4383
+ */
4384
+
4385
+ /**
4386
+ * The source of a record whose entries live behind an adapter — a database, an
4387
+ * HTTP API, a bucket — instead of in the module.
4388
+ *
4389
+ * This is what `c.external()` returns, and it is the counterpart of the
4390
+ * `c.json(() => import(...))` marker a `.jsonValues()` entry carries: a value
4391
+ * that says "the content is not here" without saying anything about what is.
4392
+ * The schema says *which* adapter (`.external("posts")`); this says *that* the
4393
+ * entries are elsewhere, which is what every source-walking consumer needs to
4394
+ * know without holding a schema.
4395
+ *
4396
+ * Three phantom parameters, each earning its place:
4397
+ *
4398
+ * - `T` — the item type. Without it `c.define` would return a module whose type
4399
+ * is "a marker", the item type would be gone, and an adapter could not be
4400
+ * typed from the schema at all.
4401
+ * - `L` — the label from `.external(label)`, so a binding can be checked against
4402
+ * the schema that declared it.
4403
+ * - `RO` — whether the schema said `.readonly()`, which decides whether the
4404
+ * adapter must implement writes or is forbidden from doing so.
4405
+ *
4406
+ * The defaults are the WIDEST instantiation on purpose: the bare name appears in
4407
+ * the `Source` and `SelectorSource` unions, and every narrower instantiation has
4408
+ * to be assignable to it. The `external()` factory below defaults the other way,
4409
+ * exactly as `JsonSource<T = unknown>` and `json<T = Json>()` do.
4410
+ */
4411
+
4412
+ /**
4413
+ * The marker written as a module's source when its record is `.external()`.
4414
+ *
4415
+ * Takes no arguments: everything it carries is inferred from the schema it is
4416
+ * checked against in `c.define`. The assertion mirrors `json()` — the phantom
4417
+ * slots are symbol-keyed and have no runtime representation, so there is nothing
4418
+ * to construct for them.
4419
+ */
4420
+ function external() {
4421
+ return _defineProperty({}, VAL_EXTENSION, EXTERNAL_VAL_EXTENSION_TAG);
4422
+ }
4423
+ function isExternal(obj) {
4424
+ return _typeof(obj) === "object" && obj !== null && VAL_EXTENSION in obj && obj[VAL_EXTENSION] === EXTERNAL_VAL_EXTENSION_TAG;
4425
+ }
4426
+
4427
+ /**
4428
+ * The item type an external record holds, read back off a module.
4429
+ *
4430
+ * `GenericSelector` is not imported here — that would be a cycle through
4431
+ * `../selector` — so this is written against the phantom slot directly and the
4432
+ * selector-shaped overloads live where the selector types do.
4433
+ */
4434
+
4435
+ /** The label an external record was declared with. */
4436
+
4437
+ /** Whether the schema behind an external record said `.readonly()`. */
4438
+
4439
+ /**
4440
+ * The source of an external record as it may be WRITTEN.
4441
+ *
4442
+ * Either the marker, or entries inline in the `.val.ts`. Inline entries are
4443
+ * accepted by the type on purpose, for the same reason `.jsonValues()` accepts
4444
+ * them (see `JsonValuesRecordSrc`): pasting content straight into the module is
4445
+ * the natural first thing to write, and a type error there is a dead end — the
4446
+ * author cannot see what to write instead. Validation reports the inline entries
4447
+ * as an `external:upload` fix instead, so the mistake is repaired rather than
4448
+ * blocking authoring, and they are readable at runtime meanwhile.
4449
+ */
4450
+
4451
+ /**
4452
+ * Is this module source an external record that still has entries written
4453
+ * inline? Used by validation to raise `external:upload`.
4454
+ */
4455
+ function hasInlineExternalEntries(source) {
4456
+ return _typeof(source) === "object" && source !== null && !Array.isArray(source) && !isExternal(source) && Object.keys(source).length > 0;
4457
+ }
4458
+
4355
4459
  /**
4356
4460
  * The source type of a `.jsonValues()` record: every entry value is EITHER a
4357
4461
  * lazily loaded {@link JsonSource} whose resolved content is the (loosened, see
@@ -4380,6 +4484,7 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
4380
4484
  var isJsonValues = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : false;
4381
4485
  var previewInput = arguments.length > 10 && arguments[10] !== undefined ? arguments[10] : null;
4382
4486
  var renderInput = arguments.length > 11 && arguments[11] !== undefined ? arguments[11] : null;
4487
+ var externalLabel = arguments.length > 12 && arguments[12] !== undefined ? arguments[12] : null;
4383
4488
  _classCallCheck(this, RecordSchema);
4384
4489
  _this = _callSuper(this, RecordSchema);
4385
4490
  _this.item = item;
@@ -4394,24 +4499,28 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
4394
4499
  _this.isJsonValues = isJsonValues;
4395
4500
  _this.previewInput = previewInput;
4396
4501
  _this.renderInput = renderInput;
4502
+ _this.externalLabel = externalLabel;
4397
4503
  return _this;
4398
4504
  }
4399
4505
  _inherits(RecordSchema, _Schema);
4400
4506
  return _createClass(RecordSchema, [{
4401
4507
  key: "describe",
4402
4508
  value: function describe(description) {
4403
- 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);
4509
+ 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);
4404
4510
  }
4405
4511
  }, {
4406
4512
  key: "validate",
4407
4513
  value: function validate(validationFunction) {
4408
- return new RecordSchema(this.item, this.opt, [].concat(_toConsumableArray(this.customValidateFunctions), [validationFunction]), this.currentRouter, this.keySchema, this.mediaOptions, this.isReadonly, this.isHidden, this.description, this.isJsonValues, this.previewInput, this.renderInput);
4514
+ return new RecordSchema(this.item, this.opt, [].concat(_toConsumableArray(this.customValidateFunctions), [validationFunction]), this.currentRouter, this.keySchema, this.mediaOptions, this.isReadonly, this.isHidden, this.description, this.isJsonValues, this.previewInput, this.renderInput, this.externalLabel);
4409
4515
  }
4410
4516
  }, {
4411
4517
  key: "executeValidate",
4412
4518
  value: function executeValidate(path, src) {
4413
4519
  var _this2 = this;
4414
4520
  var error = false;
4521
+ if (this.externalLabel !== null) {
4522
+ return this.validateExternal(path, src);
4523
+ }
4415
4524
  var customValidationErrors = this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
4416
4525
  path: path
4417
4526
  });
@@ -4748,29 +4857,42 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
4748
4857
  }, {
4749
4858
  key: "nullable",
4750
4859
  value: function nullable() {
4751
- return new RecordSchema(this.item, true, this.customValidateFunctions, this.currentRouter, this.keySchema, this.mediaOptions, this.isReadonly, this.isHidden, this.description, this.isJsonValues, this.previewInput, this.renderInput);
4860
+ return new RecordSchema(this.item, true, this.customValidateFunctions, this.currentRouter, this.keySchema, this.mediaOptions, this.isReadonly, this.isHidden, this.description, this.isJsonValues, this.previewInput, this.renderInput, this.externalLabel);
4752
4861
  }
4862
+
4863
+ /**
4864
+ * A record you can look at but not change.
4865
+ *
4866
+ * The flag rides in the TYPE as well as in the instance, so `.external()` can
4867
+ * freeze it into the source marker and the adapter's write methods become
4868
+ * required or forbidden on the strength of it. That is also why `.readonly()`
4869
+ * must come BEFORE `.external()`: afterwards the value is a `Schema`, and
4870
+ * there is no `.readonly()` left to call — which is the error the compiler
4871
+ * gives, and a clearer one than a runtime throw.
4872
+ */
4753
4873
  }, {
4754
4874
  key: "readonly",
4755
4875
  value: function readonly() {
4756
- return new RecordSchema(this.item, this.opt, this.customValidateFunctions, this.currentRouter, this.keySchema, this.mediaOptions, true, this.isHidden, this.description, this.isJsonValues, this.previewInput, this.renderInput);
4876
+ var isReadonly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
4877
+ return new RecordSchema(this.item, this.opt, this.customValidateFunctions, this.currentRouter, this.keySchema, this.mediaOptions, isReadonly, this.isHidden, this.description, this.isJsonValues, this.previewInput, this.renderInput, this.externalLabel);
4757
4878
  }
4758
4879
  }, {
4759
4880
  key: "hidden",
4760
4881
  value: function hidden() {
4761
- return new RecordSchema(this.item, this.opt, this.customValidateFunctions, this.currentRouter, this.keySchema, this.mediaOptions, this.isReadonly, true, this.description, this.isJsonValues, this.previewInput, this.renderInput);
4882
+ var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
4883
+ 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);
4762
4884
  }
4763
4885
  }, {
4764
4886
  key: "router",
4765
4887
  value: function router(_router) {
4766
- 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);
4888
+ 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);
4767
4889
  }
4768
4890
  }, {
4769
4891
  key: "remote",
4770
4892
  value: function remote() {
4771
4893
  return new RecordSchema(this.item, this.opt, this.customValidateFunctions, this.currentRouter, this.keySchema, this.mediaOptions ? _objectSpread2(_objectSpread2({}, this.mediaOptions), {}, {
4772
4894
  remote: true
4773
- }) : undefined, this.isReadonly, this.isHidden, this.description, this.isJsonValues, this.previewInput, this.renderInput);
4895
+ }) : undefined, this.isReadonly, this.isHidden, this.description, this.isJsonValues, this.previewInput, this.renderInput, this.externalLabel);
4774
4896
  }
4775
4897
 
4776
4898
  /**
@@ -4812,7 +4934,84 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
4812
4934
  // Empty by construction: the guard above rejects any that were registered.
4813
4935
  [], this.currentRouter, this.keySchema, this.mediaOptions, this.isReadonly, this.isHidden, this.description, true,
4814
4936
  // Null by construction: the guard above rejects any that was declared.
4815
- null, this.renderInput);
4937
+ null, this.renderInput, this.externalLabel);
4938
+ }
4939
+
4940
+ /**
4941
+ * Store this record's entries behind an adapter — a database, an HTTP API, a
4942
+ * bucket — instead of in the module.
4943
+ *
4944
+ * Available on every record-derived schema, which is `s.record()`,
4945
+ * `s.router()`, `s.images()` and `s.files()` alike: a router is a
4946
+ * `RecordSchema` with a `ValRouter`, a gallery one with media options, so all
4947
+ * four get external storage from this one method.
4948
+ *
4949
+ * `label` does not address the binding — the registry is keyed by module, and
4950
+ * so is the wire protocol. It exists so a reader of the schema can see what
4951
+ * backs it, and it is checked against the binding that claims it, so the two
4952
+ * cannot drift.
4953
+ *
4954
+ * Only supported on a module's ROOT record, exactly as `.jsonValues()` is: a
4955
+ * nested external record would leave a hole in the middle of a module's
4956
+ * source, and the Studio, patching and validation all assume a module's
4957
+ * source is complete apart from its entries.
4958
+ */
4959
+ }, {
4960
+ key: "external",
4961
+ value: function external(label) {
4962
+ if (this.isJsonValues) {
4963
+ throw new Error(".external() cannot be combined with .jsonValues(): entries live in one place or the other, not both.");
4964
+ }
4965
+ if (!label) {
4966
+ throw new Error('.external() requires a label, e.g. .external("posts")');
4967
+ }
4968
+ return new RecordSchema(this.item, this.opt,
4969
+ // Empty by construction: a validator declared before `.external()` is
4970
+ // typed against the un-external source shape and cannot be carried over.
4971
+ [], this.currentRouter, this.keySchema, this.mediaOptions, this.isReadonly, this.isHidden, this.description, this.isJsonValues, null, this.renderInput, label);
4972
+ }
4973
+
4974
+ /**
4975
+ * An external record's source is either the `c.external()` marker or entries
4976
+ * still written inline in the `.val.ts`.
4977
+ *
4978
+ * Inline entries are NOT a type error (see `ExternalRecordWritableSrc`), so
4979
+ * this is where they surface: as an `external:upload` fix, per key, the way
4980
+ * `.jsonValues()` reports an un-extracted entry. Reporting per key rather than
4981
+ * once for the record is what lets the fix be applied to one entry, and what
4982
+ * puts the error at a path the editor can navigate to.
4983
+ */
4984
+ }, {
4985
+ key: "validateExternal",
4986
+ value: function validateExternal(path, src) {
4987
+ if (this.opt && (src === null || src === undefined)) {
4988
+ return false;
4989
+ }
4990
+ if (src === null || _typeof(src) !== "object" || Array.isArray(src)) {
4991
+ return _defineProperty({}, path, [{
4992
+ message: "Expected the c.external() marker or inline entries, got '".concat(src === null ? "null" : Array.isArray(src) ? "array" : _typeof(src), "'"),
4993
+ value: src,
4994
+ schemaError: true
4995
+ }]);
4996
+ }
4997
+ if (isExternal(src)) {
4998
+ // The marker: the entries are the adapter's, and there is nothing here to
4999
+ // check. Their content is validated as it is read.
5000
+ return false;
5001
+ }
5002
+ var error = false;
5003
+ for (var _i = 0, _Object$keys = Object.keys(src); _i < _Object$keys.length; _i++) {
5004
+ var _key = _Object$keys[_i];
5005
+ var subPath = createValPathOfItem(path, _key);
5006
+ if (!subPath) {
5007
+ continue;
5008
+ }
5009
+ error = this.appendValidationError(error, subPath, "Entry is written inline, but this record is .external(\"".concat(this.externalLabel, "\"). Run 'val external upload' to move it into the store."), src[_key]);
5010
+ var errors = error;
5011
+ var last = errors[subPath][errors[subPath].length - 1];
5012
+ last.fixes = ["external:upload"];
5013
+ }
5014
+ return error;
4816
5015
  }
4817
5016
  }, {
4818
5017
  key: "getRouterValidations",
@@ -4866,7 +5065,7 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
4866
5065
  }, {
4867
5066
  key: "executeSerialize",
4868
5067
  value: function executeSerialize() {
4869
- var _this$renderInput, _this$keySchema, _this$currentRouter, _this$customValidateF;
5068
+ var _this$renderInput, _this$keySchema, _this$currentRouter, _this$customValidateF, _this$externalLabel;
4870
5069
  var result = {
4871
5070
  type: "record",
4872
5071
  render: (_this$renderInput = this.renderInput) !== null && _this$renderInput !== void 0 ? _this$renderInput : undefined,
@@ -4877,6 +5076,7 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
4877
5076
  router: (_this$currentRouter = this.currentRouter) === null || _this$currentRouter === void 0 ? void 0 : _this$currentRouter.getRouterId(),
4878
5077
  customValidate: this.customValidateFunctions && ((_this$customValidateF = this.customValidateFunctions) === null || _this$customValidateF === void 0 ? void 0 : _this$customValidateF.length) > 0,
4879
5078
  jsonValues: this.isJsonValues ? true : undefined,
5079
+ external: (_this$externalLabel = this.externalLabel) !== null && _this$externalLabel !== void 0 ? _this$externalLabel : undefined,
4880
5080
  readonly: this.isReadonly,
4881
5081
  hidden: this.isHidden,
4882
5082
  description: this.description
@@ -4914,8 +5114,12 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
4914
5114
  if (src === null) {
4915
5115
  return res;
4916
5116
  }
4917
- for (var _key in src) {
4918
- var itemSrc = src[_key];
5117
+ if (isExternal(src)) {
5118
+ // The entries are the adapter's; there is nothing here to preview.
5119
+ return res;
5120
+ }
5121
+ for (var _key2 in src) {
5122
+ var itemSrc = src[_key2];
4919
5123
  if (itemSrc === null || itemSrc === undefined) {
4920
5124
  continue;
4921
5125
  }
@@ -4926,14 +5130,14 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
4926
5130
  // keys, and the caller shows a placeholder for the rest.
4927
5131
  continue;
4928
5132
  }
4929
- var subPath = unsafeCreateSourcePath(sourcePath, _key);
5133
+ var subPath = unsafeCreateSourcePath(sourcePath, _key2);
4930
5134
  if (scope !== undefined && !scope.wantsUnder(subPath)) {
4931
5135
  continue;
4932
5136
  }
4933
5137
  var itemResult = this.item["executePreview"](subPath, itemSrc, scope);
4934
5138
  for (var keyS in itemResult) {
4935
- var _key2 = keyS;
4936
- res[_key2] = itemResult[_key2];
5139
+ var _key3 = keyS;
5140
+ res[_key3] = itemResult[_key3];
4937
5141
  }
4938
5142
  }
4939
5143
  // The entries preview comes from the ITEM schema's own `preview` — the
@@ -4944,9 +5148,9 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
4944
5148
  // is being shown, only the wanted entries when it is not.
4945
5149
  var window = scope !== undefined && !scope.wants(sourcePath) ? scope : null;
4946
5150
  var items = [];
4947
- for (var _i = 0, _Object$entries = Object.entries(src); _i < _Object$entries.length; _i++) {
4948
- var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
4949
- _key3 = _Object$entries$_i[0],
5151
+ for (var _i2 = 0, _Object$entries = Object.entries(src); _i2 < _Object$entries.length; _i2++) {
5152
+ var _Object$entries$_i = _slicedToArray(_Object$entries[_i2], 2),
5153
+ _key4 = _Object$entries$_i[0],
4950
5154
  val = _Object$entries$_i[1];
4951
5155
  if (isJson(val)) {
4952
5156
  continue; // as above: nothing to select from an un-loaded entry
@@ -4954,7 +5158,7 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
4954
5158
  if (val === null || val === undefined) {
4955
5159
  continue;
4956
5160
  }
4957
- if (window !== null && !window.wantsUnder(unsafeCreateSourcePath(sourcePath, _key3))) {
5161
+ if (window !== null && !window.wantsUnder(unsafeCreateSourcePath(sourcePath, _key4))) {
4958
5162
  continue;
4959
5163
  }
4960
5164
  // Per KEY, not per record: the closure is user code, and one entry whose
@@ -4966,14 +5170,14 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
4966
5170
  var title = _item.title,
4967
5171
  subtitle = _item.subtitle,
4968
5172
  image = _item.image;
4969
- items.push([_key3, {
5173
+ items.push([_key4, {
4970
5174
  title: title,
4971
5175
  subtitle: subtitle,
4972
5176
  image: image
4973
5177
  }]);
4974
5178
  }
4975
5179
  } catch (e) {
4976
- res[unsafeCreateSourcePath(sourcePath, _key3)] = {
5180
+ res[unsafeCreateSourcePath(sourcePath, _key4)] = {
4977
5181
  status: "error",
4978
5182
  message: e instanceof Error ? e.message : "Unknown error"
4979
5183
  };
@@ -5014,7 +5218,7 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
5014
5218
  }, {
5015
5219
  key: "preview",
5016
5220
  value: function preview(select) {
5017
- return new RecordSchema(this.item, this.opt, this.customValidateFunctions, this.currentRouter, this.keySchema, this.mediaOptions, this.isReadonly, this.isHidden, this.description, this.isJsonValues, select, this.renderInput);
5221
+ return new RecordSchema(this.item, this.opt, this.customValidateFunctions, this.currentRouter, this.keySchema, this.mediaOptions, this.isReadonly, this.isHidden, this.description, this.isJsonValues, select, this.renderInput, this.externalLabel);
5018
5222
  }
5019
5223
 
5020
5224
  /**
@@ -5027,7 +5231,7 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
5027
5231
  }, {
5028
5232
  key: "render",
5029
5233
  value: function render(input) {
5030
- return new RecordSchema(this.item, this.opt, this.customValidateFunctions, this.currentRouter, this.keySchema, this.mediaOptions, this.isReadonly, this.isHidden, this.description, this.isJsonValues, this.previewInput, input);
5234
+ return new RecordSchema(this.item, this.opt, this.customValidateFunctions, this.currentRouter, this.keySchema, this.mediaOptions, this.isReadonly, this.isHidden, this.description, this.isJsonValues, this.previewInput, input, this.externalLabel);
5031
5235
  }
5032
5236
  }]);
5033
5237
  }(Schema);
@@ -5047,135 +5251,653 @@ function record(keyOrSchema, schema) {
5047
5251
  }
5048
5252
  }
5049
5253
 
5050
- function define(id,
5051
- // TODO: `/${string}`
5052
- schema, source) {
5053
- return _defineProperty(_defineProperty(_defineProperty({}, GetSource, source), GetSchema, schema), Path, id);
5054
- }
5055
- function getSource(valModule) {
5056
- return valModule[GetSource];
5057
- }
5254
+ /**
5255
+ * The source of the project's settings module — `s.settings()`.
5256
+ *
5257
+ * **Every key is optional, at every level, and that is the whole point.** A
5258
+ * settings module is written as
5259
+ *
5260
+ * ```typescript
5261
+ * export default c.define("/settings.val.ts", s.settings(), {});
5262
+ * ```
5263
+ *
5264
+ * and `{}` has to keep validating as sections are added to it. A project that
5265
+ * never touched the assistant's settings should not have to edit its settings
5266
+ * file the day `locales` or `permissions` land.
5267
+ *
5268
+ * That is why settings is not sugar over `s.object()`: an object schema errors
5269
+ * with `Expected key 'assistant' not found in object` for any absent key (see
5270
+ * `ObjectSchema.executeAssert`), and `.nullable()` permits `null`, not absence.
5271
+ * `SettingsSchema` gives absent keys the meaning "unset" instead.
5272
+ *
5273
+ * `null` means unset too, so the editor can clear a field it has already
5274
+ * written without removing the key.
5275
+ */
5058
5276
 
5059
5277
  /**
5060
- * Whether `value` is a Val module, i.e. something {@link define} produced.
5278
+ * The assistant: whether editors have one, and what it is told about the
5279
+ * project on every message.
5061
5280
  *
5062
- * Checks for the three symbols `define` writes, rather than a class identity:
5063
- * a module may have been created by a different copy of `@valbuild/core` (the
5064
- * editor SPA and the host bundle each ship their own, and the CLI evaluates
5065
- * user modules inside a `node:vm` context). The symbols are created with
5066
- * `Symbol.for`, so they are shared across all of those; a constructor is not.
5281
+ * `context` and `tone` are prose the model reads, not instructions Val
5282
+ * interprets, and both are capped (see {@link ASSISTANT_SETTINGS_MAX_LENGTH}):
5283
+ * they are prepended to every request the chat makes, so an unbounded field
5284
+ * here is an unbounded cost on every turn.
5067
5285
  */
5068
- function isValModule(value) {
5069
- return _typeof(value) === "object" && value !== null && GetSource in value && GetSchema in value && Path in value;
5070
- }
5071
- function splitModuleFilePathAndModulePath(path) {
5072
- var pathOfSep = path.indexOf(ModuleFilePathSep);
5073
- if (pathOfSep === -1) {
5074
- return [path, ""];
5075
- }
5076
- return [path.slice(0, pathOfSep), path.slice(pathOfSep + ModuleFilePathSep.length)];
5077
- }
5078
- function joinModuleFilePathAndModulePath(moduleFilePath, modulePath) {
5079
- if (modulePath === "") {
5080
- return moduleFilePath;
5081
- }
5082
- return "".concat(moduleFilePath).concat(ModuleFilePathSep).concat(modulePath);
5083
- }
5084
- function isObjectSchema(schema) {
5085
- return schema instanceof ObjectSchema || _typeof(schema) === "object" && "type" in schema && schema.type === "object";
5086
- }
5087
- function isRecordSchema(schema) {
5088
- return schema instanceof RecordSchema || _typeof(schema) === "object" && "type" in schema && schema.type === "record";
5089
- }
5090
- function isArraySchema(schema) {
5091
- return schema instanceof ArraySchema || _typeof(schema) === "object" && "type" in schema && schema.type === "array";
5092
- }
5093
5286
 
5094
- // function isI18nSchema(
5095
- // schema: Schema<SelectorSource> | SerializedSchema
5096
- // ): schema is I18nSchema<readonly string[]> | SerializedI18nSchema {
5097
- // return (
5098
- // schema instanceof I18nSchema ||
5099
- // (typeof schema === "object" && "type" in schema && schema.type === "i18n")
5100
- // );
5101
- // }
5287
+ /**
5288
+ * The cap on each of the assistant's prose fields, in characters.
5289
+ *
5290
+ * Roughly a thousand tokens each. Generous enough for a paragraph of
5291
+ * background and a house style, small enough that the two of them together do
5292
+ * not dominate the system prompt they are appended to.
5293
+ */
5294
+ var ASSISTANT_SETTINGS_MAX_LENGTH = 4000;
5102
5295
 
5103
- function isUnionSchema(schema
5104
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
5105
- ) {
5106
- return schema instanceof UnionSchema || _typeof(schema) === "object" && "type" in schema && schema.type === "union";
5107
- }
5108
- function isRichTextSchema(schema) {
5109
- return schema instanceof RichTextSchema || _typeof(schema) === "object" && "type" in schema && schema.type === "richtext";
5110
- }
5111
- function isImageSchema(schema) {
5112
- return schema instanceof ImageSchema || _typeof(schema) === "object" && "type" in schema && schema.type === "image";
5113
- }
5296
+ /**
5297
+ * Whether a project has an assistant — and the answer is not a boolean.
5298
+ *
5299
+ * - `"on"`: use it.
5300
+ * - `"off"`: every trace of it goes. No button in the top bar, no row in the
5301
+ * quick actions, no panel, nothing sent. A project that says `false` has
5302
+ * decided, and the Studio does not keep offering.
5303
+ * - `"unconfigured"`: nobody has said. The affordances are SHOWN, and asking to
5304
+ * use the assistant asks to turn it on first. That is the difference between
5305
+ * this and `"off"`, and the reason `enabled` is a tri-state: hiding an
5306
+ * unconfigured assistant means nobody discovers it, and quietly enabling one
5307
+ * means a project starts sending its content to a model because it did not
5308
+ * know to say no.
5309
+ *
5310
+ * A project with NO settings module is `"on"`. There is nowhere to record a
5311
+ * decision, so there is nothing to prompt for and nothing to prompt INTO — the
5312
+ * prompt writes to a settings module, and that project has none.
5313
+ *
5314
+ * This is the only answer to "does this project have an assistant":
5315
+ * `config.ai.chat` is gone, and with it the chat's title, description and
5316
+ * suggestions, which nothing replaces. The AI commit-message summariser is
5317
+ * deliberately not part of this — `config.ai.commitMessages` stays where it is,
5318
+ * and gets settings of its own later.
5319
+ */
5114
5320
 
5115
- // function isOneOfSchema(
5116
- // schema: Schema<SelectorSource> | SerializedSchema
5117
- // ): schema is OneOfSchema<GenericSelector<SourceArray>> | SerializedOneOfSchema {
5118
- // return (
5119
- // schema instanceof OneOfSchema ||
5120
- // (typeof schema === "object" && "type" in schema && schema.type === "oneOf")
5121
- // );
5122
- // }
5321
+ function assistantAvailability(/** The settings module's source, or `undefined` where the project has none. */
5322
+ settings) {
5323
+ var _settings$assistant;
5324
+ if (settings === undefined) {
5325
+ return "on";
5326
+ }
5327
+ var enabled = (_settings$assistant = settings.assistant) === null || _settings$assistant === void 0 ? void 0 : _settings$assistant.enabled;
5328
+ if (enabled === true) {
5329
+ return "on";
5330
+ }
5331
+ if (enabled === false) {
5332
+ return "off";
5333
+ }
5334
+ return "unconfigured";
5335
+ }
5123
5336
 
5124
- function resolvePath(path, valModule, schema) {
5125
- var parts = splitModulePath(path);
5126
- var origParts = _toConsumableArray(parts);
5127
- var resolvedSchema = schema;
5128
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
5129
- var resolvedSource = valModule;
5130
- var _loop = function _loop() {
5131
- var part = parts.shift();
5132
- if (part === undefined) {
5133
- throw Error("Unexpected undefined part");
5337
+ var BooleanSchema = /*#__PURE__*/function (_Schema) {
5338
+ function BooleanSchema() {
5339
+ var _this;
5340
+ var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
5341
+ var customValidateFunctions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
5342
+ var isReadonly = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
5343
+ var isHidden = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
5344
+ var description = arguments.length > 4 ? arguments[4] : undefined;
5345
+ var renderInput = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : null;
5346
+ var previewInput = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null;
5347
+ _classCallCheck(this, BooleanSchema);
5348
+ _this = _callSuper(this, BooleanSchema);
5349
+ _this.opt = opt;
5350
+ _this.customValidateFunctions = customValidateFunctions;
5351
+ _this.isReadonly = isReadonly;
5352
+ _this.isHidden = isHidden;
5353
+ _this.description = description;
5354
+ _this.renderInput = renderInput;
5355
+ _this.previewInput = previewInput;
5356
+ return _this;
5357
+ }
5358
+ _inherits(BooleanSchema, _Schema);
5359
+ return _createClass(BooleanSchema, [{
5360
+ key: "describe",
5361
+ value: function describe(description) {
5362
+ return new BooleanSchema(this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
5363
+ }
5364
+ }, {
5365
+ key: "validate",
5366
+ value: function validate(validationFunction) {
5367
+ return new BooleanSchema(this.opt, [].concat(_toConsumableArray(this.customValidateFunctions), [validationFunction]), this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
5368
+ }
5369
+ }, {
5370
+ key: "executeValidate",
5371
+ value: function executeValidate(path, src) {
5372
+ if (this.opt && (src === null || src === undefined)) {
5373
+ return false;
5134
5374
  }
5135
- if (isArraySchema(resolvedSchema)) {
5136
- var _resolvedSchema;
5137
- if (Number.isNaN(Number(part))) {
5138
- throw Error("Invalid path: array schema ".concat(JSON.stringify(resolvedSchema), " must have a number as path, but got ").concat(part, ". Path: ").concat(path));
5139
- }
5140
- if (_typeof(resolvedSource) !== "object" && !Array.isArray(resolvedSource)) {
5141
- throw Error("Schema type error: expected source to be type of array, but got ".concat(_typeof(resolvedSource)));
5142
- }
5143
- resolvedSource = resolvedSource[part];
5144
- resolvedSchema = resolvedSchema instanceof ArraySchema ? (_resolvedSchema = resolvedSchema) === null || _resolvedSchema === void 0 ? void 0 : _resolvedSchema["item"] : resolvedSchema.item;
5145
- } else if (isRecordSchema(resolvedSchema)) {
5146
- var _resolvedSchema2;
5147
- if (typeof part !== "string") {
5148
- throw Error("Invalid path: record schema ".concat(resolvedSchema, " must have path: ").concat(part, " as string"));
5149
- }
5150
- if (_typeof(resolvedSource) !== "object" && !Array.isArray(resolvedSource)) {
5151
- throw Error("Schema type error: expected source to be type of record, but got ".concat(_typeof(resolvedSource)));
5152
- }
5153
- if (!resolvedSource[part]) {
5154
- throw Error("Invalid path: record source did not have key ".concat(part, " from path: ").concat(path));
5155
- }
5156
- resolvedSource = resolvedSource[part];
5157
- resolvedSchema = resolvedSchema instanceof RecordSchema ? (_resolvedSchema2 = resolvedSchema) === null || _resolvedSchema2 === void 0 ? void 0 : _resolvedSchema2["item"] : resolvedSchema.item;
5158
- // A `.jsonValues()` entry value is a lazily-loaded JsonSource marker. We
5159
- // can resolve the entry itself (schema is now `item`), but we cannot
5160
- // descend deeper until the backing `*.val.json` content has been loaded
5161
- // and substituted into the source tree (done by the UI/server layer).
5162
- if (isJson(resolvedSource) && parts.length > 0) {
5163
- throw Error("Cannot resolve path into a jsonValues entry until its content is loaded. Path: ".concat(path));
5164
- }
5165
- } else if (isObjectSchema(resolvedSchema)) {
5166
- if (_typeof(resolvedSource) !== "object") {
5167
- throw Error("Schema type error: expected source to be type of object, but got ".concat(_typeof(resolvedSource)));
5168
- }
5169
- if (resolvedSource !== null && resolvedSource[part] === undefined) {
5170
- throw Error("Invalid path: object source did not have key ".concat(part, " from path: ").concat(path));
5171
- }
5172
- resolvedSource = resolvedSource === null ? resolvedSource : resolvedSource[part];
5173
- resolvedSchema = resolvedSchema instanceof ObjectSchema ? resolvedSchema["items"][part] : resolvedSchema.items[part];
5174
- // } else if (isI18nSchema(resolvedSchema)) {
5175
- // if (!resolvedSchema.locales.includes(part)) {
5176
- // throw Error(
5177
- // `Invalid path: i18n schema ${resolvedSchema} supports locales ${resolvedSchema.locales.join(
5178
- // ", "
5375
+ if (typeof src !== "boolean") {
5376
+ return _defineProperty({}, path, [{
5377
+ message: "Expected 'boolean', got '".concat(_typeof(src), "'"),
5378
+ value: src
5379
+ }]);
5380
+ }
5381
+ return false;
5382
+ }
5383
+ }, {
5384
+ key: "executeAssert",
5385
+ value: function executeAssert(path, src) {
5386
+ if (this.opt && src === null) {
5387
+ return {
5388
+ success: true,
5389
+ data: src
5390
+ };
5391
+ }
5392
+ if (src === null) {
5393
+ return {
5394
+ success: false,
5395
+ errors: _defineProperty({}, path, [{
5396
+ message: "Expected 'boolean', got 'null'",
5397
+ typeError: true
5398
+ }])
5399
+ };
5400
+ }
5401
+ if (typeof src !== "boolean") {
5402
+ return {
5403
+ success: false,
5404
+ errors: _defineProperty({}, path, [{
5405
+ message: "Expected 'boolean', got '".concat(_typeof(src), "'"),
5406
+ typeError: true
5407
+ }])
5408
+ };
5409
+ }
5410
+ return {
5411
+ success: true,
5412
+ data: src
5413
+ };
5414
+ }
5415
+ }, {
5416
+ key: "nullable",
5417
+ value: function nullable() {
5418
+ return new BooleanSchema(true, [], this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
5419
+ }
5420
+ }, {
5421
+ key: "readonly",
5422
+ value: function readonly() {
5423
+ var isReadonly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
5424
+ return new BooleanSchema(this.opt, this.customValidateFunctions, isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
5425
+ }
5426
+ }, {
5427
+ key: "hidden",
5428
+ value: function hidden() {
5429
+ var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
5430
+ return new BooleanSchema(this.opt, this.customValidateFunctions, this.isReadonly, isHidden, this.description, this.renderInput, this.previewInput);
5431
+ }
5432
+ }, {
5433
+ key: "executeCustomValidateAt",
5434
+ value: function executeCustomValidateAt(path, src) {
5435
+ return this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
5436
+ path: path
5437
+ });
5438
+ }
5439
+
5440
+ /**
5441
+ * How this field is laid out in the editor when it is the item of an array
5442
+ * or record: `{ as: "inline" }` renders the field itself inside each row,
5443
+ * instead of a preview row that navigates to it.
5444
+ *
5445
+ * Static configuration, not a callback — see `render.ts`.
5446
+ */
5447
+ }, {
5448
+ key: "render",
5449
+ value: function render(input) {
5450
+ return new BooleanSchema(this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, input, this.previewInput);
5451
+ }
5452
+
5453
+ /**
5454
+ * How this VALUE is shown where a preview of it is needed — a row in a
5455
+ * sortable list, a reference dropdown, a search hit. Never how the field
5456
+ * itself is edited (that is `render`). See `preview.ts`.
5457
+ */
5458
+ }, {
5459
+ key: "preview",
5460
+ value: function preview(select) {
5461
+ return new BooleanSchema(this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, select);
5462
+ }
5463
+ }, {
5464
+ key: "executePreviewItem",
5465
+ value: function executePreviewItem(src) {
5466
+ if (this.previewInput === null) {
5467
+ return null;
5468
+ }
5469
+ return this.previewInput({
5470
+ val: src
5471
+ });
5472
+ }
5473
+ }, {
5474
+ key: "declaresItemPreview",
5475
+ value: function declaresItemPreview() {
5476
+ return this.previewInput !== null;
5477
+ }
5478
+ }, {
5479
+ key: "executeSerialize",
5480
+ value: function executeSerialize() {
5481
+ var _this$renderInput, _this$customValidateF;
5482
+ return {
5483
+ type: "boolean",
5484
+ render: (_this$renderInput = this.renderInput) !== null && _this$renderInput !== void 0 ? _this$renderInput : undefined,
5485
+ preview: this.previewInput ? true : undefined,
5486
+ opt: this.opt,
5487
+ customValidate: this.customValidateFunctions && ((_this$customValidateF = this.customValidateFunctions) === null || _this$customValidateF === void 0 ? void 0 : _this$customValidateF.length) > 0,
5488
+ readonly: this.isReadonly,
5489
+ hidden: this.isHidden,
5490
+ description: this.description
5491
+ };
5492
+ }
5493
+ }, {
5494
+ key: "executePreview",
5495
+ value: function executePreview() {
5496
+ return {};
5497
+ }
5498
+ }]);
5499
+ }(Schema);
5500
+ var _boolean = function _boolean() {
5501
+ return new BooleanSchema();
5502
+ };
5503
+
5504
+ /**
5505
+ * An object whose keys are all optional: absent means unset.
5506
+ *
5507
+ * Both the settings module itself and each of its sections are this. See
5508
+ * {@link SettingsSource} for why settings cannot be an object schema, and
5509
+ * {@link settings} for what a settings module holds.
5510
+ *
5511
+ * There is no `describe`, `validate`, `render` or `preview` on purpose: the
5512
+ * shape is Val's, not the schema author's — `s.settings()` takes no arguments —
5513
+ * and the Studio renders each section with a UI built for it.
5514
+ */
5515
+ var SettingsSchema = /*#__PURE__*/function (_Schema) {
5516
+ function SettingsSchema(items) {
5517
+ var _this;
5518
+ var opt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
5519
+ var isReadonly = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
5520
+ var isHidden = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
5521
+ var description = arguments.length > 4 ? arguments[4] : undefined;
5522
+ _classCallCheck(this, SettingsSchema);
5523
+ _this = _callSuper(this, SettingsSchema);
5524
+ _this.items = items;
5525
+ _this.opt = opt;
5526
+ _this.isReadonly = isReadonly;
5527
+ _this.isHidden = isHidden;
5528
+ _this.description = description;
5529
+ return _this;
5530
+ }
5531
+ _inherits(SettingsSchema, _Schema);
5532
+ return _createClass(SettingsSchema, [{
5533
+ key: "executeValidate",
5534
+ value: function executeValidate(path, src) {
5535
+ var error = false;
5536
+ if (src === null || src === undefined) {
5537
+ if (this.opt) {
5538
+ return false;
5539
+ }
5540
+ return _defineProperty({}, path, [{
5541
+ message: "Expected 'object', got '".concat(src, "'")
5542
+ }]);
5543
+ }
5544
+ if (_typeof(src) !== "object") {
5545
+ return _defineProperty({}, path, [{
5546
+ message: "Expected 'object', got '".concat(_typeof(src), "'")
5547
+ }]);
5548
+ }
5549
+ if (Array.isArray(src)) {
5550
+ return _defineProperty({}, path, [{
5551
+ message: "Expected 'object', got 'array'"
5552
+ }]);
5553
+ }
5554
+ for (var _i = 0, _Object$entries = Object.entries(this.items); _i < _Object$entries.length; _i++) {
5555
+ var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
5556
+ _key = _Object$entries$_i[0],
5557
+ schema = _Object$entries$_i[1];
5558
+ // Absent is the unset value, so there is nothing to validate. A key that
5559
+ // is present as `undefined` is the same statement written differently.
5560
+ if (src[_key] === undefined) {
5561
+ continue;
5562
+ }
5563
+ var subPath = createValPathOfItem(path, _key);
5564
+ if (!subPath) {
5565
+ error = this.appendValidationError(error, path, "Internal error: could not create path at ".concat(!path && typeof path === "string" ? "<empty string>" : path, " at key ").concat(_key),
5566
+ // Should! never happen
5567
+ src);
5568
+ } else {
5569
+ var subError = schema["executeValidate"](subPath, src[_key]);
5570
+ error = this.mergeValidationErrors(error, subError);
5571
+ }
5572
+ }
5573
+ // An unknown key is reported rather than ignored (which is what an object
5574
+ // schema does with extra keys): the shape is closed and Val-defined, so the
5575
+ // realistic cause is a typo — `toneOfVoice` for `tone` — and silence there
5576
+ // means a setting that never takes effect and never says why.
5577
+ for (var _i2 = 0, _Object$keys = Object.keys(src); _i2 < _Object$keys.length; _i2++) {
5578
+ var _key2 = _Object$keys[_i2];
5579
+ if (!(_key2 in this.items)) {
5580
+ error = this.appendValidationError(error, path, "Unknown settings key: '".concat(_key2, "'. Expected one of: ").concat(Object.keys(this.items).map(function (key) {
5581
+ return "'".concat(key, "'");
5582
+ }).join(", ")), src, true);
5583
+ }
5584
+ }
5585
+ return error;
5586
+ }
5587
+ }, {
5588
+ key: "executeAssert",
5589
+ value: function executeAssert(path, src) {
5590
+ if (this.opt && src === null) {
5591
+ return {
5592
+ success: true,
5593
+ data: src
5594
+ };
5595
+ }
5596
+ var typeError = function typeError(got) {
5597
+ return {
5598
+ message: "Expected 'object', got '".concat(got, "'"),
5599
+ typeError: true
5600
+ };
5601
+ };
5602
+ if (src === null) {
5603
+ return {
5604
+ success: false,
5605
+ errors: _defineProperty({}, path, [typeError("null")])
5606
+ };
5607
+ }
5608
+ if (_typeof(src) !== "object") {
5609
+ return {
5610
+ success: false,
5611
+ errors: _defineProperty({}, path, [typeError(_typeof(src))])
5612
+ };
5613
+ }
5614
+ if (Array.isArray(src)) {
5615
+ return {
5616
+ success: false,
5617
+ errors: _defineProperty({}, path, [typeError("array")])
5618
+ };
5619
+ }
5620
+ // No per-key check, unlike an object schema: every key is optional, so an
5621
+ // object is all this can assert.
5622
+ return {
5623
+ success: true,
5624
+ data: src
5625
+ };
5626
+ }
5627
+ }, {
5628
+ key: "nullable",
5629
+ value: function nullable() {
5630
+ return new SettingsSchema(this.items, true, this.isReadonly, this.isHidden, this.description);
5631
+ }
5632
+ }, {
5633
+ key: "readonly",
5634
+ value: function readonly() {
5635
+ return new SettingsSchema(this.items, this.opt, true, this.isHidden, this.description);
5636
+ }
5637
+ }, {
5638
+ key: "hidden",
5639
+ value: function hidden() {
5640
+ return new SettingsSchema(this.items, this.opt, this.isReadonly, true, this.description);
5641
+ }
5642
+ }, {
5643
+ key: "executeCustomValidateAt",
5644
+ value: function executeCustomValidateAt() {
5645
+ // Settings declares no `validate`, so there are no custom validators to
5646
+ // run. Implemented rather than inherited because the base class makes this
5647
+ // abstract on purpose — see `Schema.executeCustomValidateAt`.
5648
+ return [];
5649
+ }
5650
+ }, {
5651
+ key: "executeSerialize",
5652
+ value: function executeSerialize() {
5653
+ return {
5654
+ type: "settings",
5655
+ items: Object.fromEntries(Object.entries(this.items).map(function (_ref4) {
5656
+ var _ref5 = _slicedToArray(_ref4, 2),
5657
+ key = _ref5[0],
5658
+ schema = _ref5[1];
5659
+ return [key, schema["executeSerialize"]()];
5660
+ })),
5661
+ opt: this.opt,
5662
+ readonly: this.isReadonly,
5663
+ hidden: this.isHidden,
5664
+ description: this.description
5665
+ };
5666
+ }
5667
+ }, {
5668
+ key: "executePreview",
5669
+ value: function executePreview(sourcePath, src, scope) {
5670
+ var res = {};
5671
+ if (src === null) {
5672
+ return res;
5673
+ }
5674
+ for (var _key3 in this.items) {
5675
+ var itemSrc = src[_key3];
5676
+ if (itemSrc === null || itemSrc === undefined) {
5677
+ continue;
5678
+ }
5679
+ var subPath = unsafeCreateSourcePath(sourcePath, _key3);
5680
+ if (scope !== undefined && !scope.wantsUnder(subPath)) {
5681
+ continue;
5682
+ }
5683
+ var itemResult = this.items[_key3]["executePreview"](subPath, itemSrc, scope);
5684
+ for (var keyS in itemResult) {
5685
+ var _key4 = keyS;
5686
+ res[_key4] = itemResult[_key4];
5687
+ }
5688
+ }
5689
+ return res;
5690
+ }
5691
+ }]);
5692
+ }(Schema);
5693
+
5694
+ /**
5695
+ * Define the project's settings.
5696
+ *
5697
+ * One settings module per project, at the root of the content tree — a module
5698
+ * file path with no directory segment, `/settings.val.ts` by convention:
5699
+ *
5700
+ * ```typescript
5701
+ * export default c.define("/settings.val.ts", s.settings(), {});
5702
+ * ```
5703
+ *
5704
+ * Every section is optional, so `{}` is a complete settings module and stays
5705
+ * one as sections are added. Fill in what the project needs:
5706
+ *
5707
+ * ```typescript
5708
+ * export default c.define("/settings.val.ts", s.settings(), {
5709
+ * assistant: {
5710
+ * enabled: true,
5711
+ * context: "Val is a CMS for developers. British English, and 'Val' is never 'VAL'.",
5712
+ * tone: "Plain and direct. No exclamation marks, sentence case in headings.",
5713
+ * },
5714
+ * });
5715
+ * ```
5716
+ *
5717
+ * The Studio edits it under the cog at the foot of the left rail, and the
5718
+ * assistant is told `assistant.context` and `assistant.tone` on every message.
5719
+ *
5720
+ * `s.settings()` takes no arguments: the shape is Val's, which is what lets the
5721
+ * Studio render a UI built for each field rather than a generic form. A
5722
+ * project's own global content — a site name, social links — belongs in a
5723
+ * module of its own.
5724
+ */
5725
+ function settings() {
5726
+ return new SettingsSchema({
5727
+ assistant: new SettingsSchema({
5728
+ enabled: _boolean().nullable().describe("Whether editors have an assistant in this project. Unset means nobody has decided: it is offered, and turned on when someone accepts."),
5729
+ context: string().multiline().maxLength(ASSISTANT_SETTINGS_MAX_LENGTH).nullable().describe("Background the assistant would otherwise have to guess: what this site is, who runs it, names and spellings that matter."),
5730
+ tone: string().multiline().maxLength(ASSISTANT_SETTINGS_MAX_LENGTH).nullable().describe("How the assistant should write when it writes content: formal or playful, British or American, how headings are cased.")
5731
+ })
5732
+ });
5733
+ }
5734
+
5735
+ /**
5736
+ * What may be WRITTEN as an external record's source, on top of the marker.
5737
+ *
5738
+ * Entries inline in the `.val.ts` are accepted on purpose — the same call
5739
+ * `.jsonValues()` makes for the same reason: pasting content straight into the
5740
+ * module is the natural first thing to write, and a type error there is a dead
5741
+ * end, because the author cannot see what to write instead. Validation reports
5742
+ * them as an `external:upload` fix, and they are readable at runtime meanwhile.
5743
+ *
5744
+ * Widened HERE rather than in the schema's own source type so that the MODULE
5745
+ * stays typed on the marker alone. An adapter is bound to a module, and a module
5746
+ * whose type were "marker or plain record" would be indistinguishable from an
5747
+ * ordinary record — which would let `entry()` accept a module that is not
5748
+ * external at all.
5749
+ */
5750
+
5751
+ function define(id,
5752
+ // TODO: `/${string}`
5753
+ schema, source) {
5754
+ return _defineProperty(_defineProperty(_defineProperty({}, GetSource, source), GetSchema, schema), Path, id);
5755
+ }
5756
+ function getSource(valModule) {
5757
+ return valModule[GetSource];
5758
+ }
5759
+
5760
+ /**
5761
+ * Whether `value` is a Val module, i.e. something {@link define} produced.
5762
+ *
5763
+ * Checks for the three symbols `define` writes, rather than a class identity:
5764
+ * a module may have been created by a different copy of `@valbuild/core` (the
5765
+ * editor SPA and the host bundle each ship their own, and the CLI evaluates
5766
+ * user modules inside a `node:vm` context). The symbols are created with
5767
+ * `Symbol.for`, so they are shared across all of those; a constructor is not.
5768
+ */
5769
+ function isValModule(value) {
5770
+ return _typeof(value) === "object" && value !== null && GetSource in value && GetSchema in value && Path in value;
5771
+ }
5772
+ function splitModuleFilePathAndModulePath(path) {
5773
+ var pathOfSep = path.indexOf(ModuleFilePathSep);
5774
+ if (pathOfSep === -1) {
5775
+ return [path, ""];
5776
+ }
5777
+ return [path.slice(0, pathOfSep), path.slice(pathOfSep + ModuleFilePathSep.length)];
5778
+ }
5779
+ function joinModuleFilePathAndModulePath(moduleFilePath, modulePath) {
5780
+ if (modulePath === "") {
5781
+ return moduleFilePath;
5782
+ }
5783
+ return "".concat(moduleFilePath).concat(ModuleFilePathSep).concat(modulePath);
5784
+ }
5785
+ function isObjectSchema(schema) {
5786
+ return schema instanceof ObjectSchema || _typeof(schema) === "object" && "type" in schema && schema.type === "object";
5787
+ }
5788
+
5789
+ /**
5790
+ * Settings, which walks like an object but whose keys are all OPTIONAL.
5791
+ *
5792
+ * That difference is the whole reason it is not an object schema: descending
5793
+ * into an unset section must resolve to `undefined`, not fail — see
5794
+ * `SettingsSource`.
5795
+ */
5796
+ function isSettingsSchema(schema) {
5797
+ return schema instanceof SettingsSchema || _typeof(schema) === "object" && "type" in schema && schema.type === "settings";
5798
+ }
5799
+ function isRecordSchema(schema) {
5800
+ return schema instanceof RecordSchema || _typeof(schema) === "object" && "type" in schema && schema.type === "record";
5801
+ }
5802
+ function isArraySchema(schema) {
5803
+ return schema instanceof ArraySchema || _typeof(schema) === "object" && "type" in schema && schema.type === "array";
5804
+ }
5805
+
5806
+ // function isI18nSchema(
5807
+ // schema: Schema<SelectorSource> | SerializedSchema
5808
+ // ): schema is I18nSchema<readonly string[]> | SerializedI18nSchema {
5809
+ // return (
5810
+ // schema instanceof I18nSchema ||
5811
+ // (typeof schema === "object" && "type" in schema && schema.type === "i18n")
5812
+ // );
5813
+ // }
5814
+
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";
5819
+ }
5820
+ function isRichTextSchema(schema) {
5821
+ return schema instanceof RichTextSchema || _typeof(schema) === "object" && "type" in schema && schema.type === "richtext";
5822
+ }
5823
+ function isImageSchema(schema) {
5824
+ return schema instanceof ImageSchema || _typeof(schema) === "object" && "type" in schema && schema.type === "image";
5825
+ }
5826
+
5827
+ // function isOneOfSchema(
5828
+ // schema: Schema<SelectorSource> | SerializedSchema
5829
+ // ): schema is OneOfSchema<GenericSelector<SourceArray>> | SerializedOneOfSchema {
5830
+ // return (
5831
+ // schema instanceof OneOfSchema ||
5832
+ // (typeof schema === "object" && "type" in schema && schema.type === "oneOf")
5833
+ // );
5834
+ // }
5835
+
5836
+ function resolvePath(path, valModule, schema) {
5837
+ var parts = splitModulePath(path);
5838
+ var origParts = _toConsumableArray(parts);
5839
+ var resolvedSchema = schema;
5840
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
5841
+ var resolvedSource = valModule;
5842
+ var _loop = function _loop() {
5843
+ var part = parts.shift();
5844
+ if (part === undefined) {
5845
+ throw Error("Unexpected undefined part");
5846
+ }
5847
+ if (isArraySchema(resolvedSchema)) {
5848
+ var _resolvedSchema;
5849
+ if (Number.isNaN(Number(part))) {
5850
+ throw Error("Invalid path: array schema ".concat(JSON.stringify(resolvedSchema), " must have a number as path, but got ").concat(part, ". Path: ").concat(path));
5851
+ }
5852
+ if (_typeof(resolvedSource) !== "object" && !Array.isArray(resolvedSource)) {
5853
+ throw Error("Schema type error: expected source to be type of array, but got ".concat(_typeof(resolvedSource)));
5854
+ }
5855
+ resolvedSource = resolvedSource[part];
5856
+ resolvedSchema = resolvedSchema instanceof ArraySchema ? (_resolvedSchema = resolvedSchema) === null || _resolvedSchema === void 0 ? void 0 : _resolvedSchema["item"] : resolvedSchema.item;
5857
+ } else if (isRecordSchema(resolvedSchema)) {
5858
+ var _resolvedSchema2;
5859
+ if (typeof part !== "string") {
5860
+ throw Error("Invalid path: record schema ".concat(resolvedSchema, " must have path: ").concat(part, " as string"));
5861
+ }
5862
+ if (_typeof(resolvedSource) !== "object" && !Array.isArray(resolvedSource)) {
5863
+ throw Error("Schema type error: expected source to be type of record, but got ".concat(_typeof(resolvedSource)));
5864
+ }
5865
+ if (!resolvedSource[part]) {
5866
+ throw Error("Invalid path: record source did not have key ".concat(part, " from path: ").concat(path));
5867
+ }
5868
+ resolvedSource = resolvedSource[part];
5869
+ resolvedSchema = resolvedSchema instanceof RecordSchema ? (_resolvedSchema2 = resolvedSchema) === null || _resolvedSchema2 === void 0 ? void 0 : _resolvedSchema2["item"] : resolvedSchema.item;
5870
+ // A `.jsonValues()` entry value is a lazily-loaded JsonSource marker. We
5871
+ // can resolve the entry itself (schema is now `item`), but we cannot
5872
+ // descend deeper until the backing `*.val.json` content has been loaded
5873
+ // and substituted into the source tree (done by the UI/server layer).
5874
+ if (isJson(resolvedSource) && parts.length > 0) {
5875
+ throw Error("Cannot resolve path into a jsonValues entry until its content is loaded. Path: ".concat(path));
5876
+ }
5877
+ } else if (isSettingsSchema(resolvedSchema)) {
5878
+ if (resolvedSource !== null && resolvedSource !== undefined && _typeof(resolvedSource) !== "object") {
5879
+ throw Error("Schema type error: expected source to be type of object, but got ".concat(_typeof(resolvedSource)));
5880
+ }
5881
+ // An absent key is NOT an error here, unlike an object's: every settings
5882
+ // key is optional, so a path into a section the project has not set
5883
+ // resolves to `undefined` — and keeps resolving, one level per part, so a
5884
+ // path two deep into an unset section still lands on the right schema.
5885
+ resolvedSource = resolvedSource === null || resolvedSource === undefined ? resolvedSource : resolvedSource[part];
5886
+ resolvedSchema = resolvedSchema instanceof SettingsSchema ? resolvedSchema["items"][part] : resolvedSchema.items[part];
5887
+ } else if (isObjectSchema(resolvedSchema)) {
5888
+ if (_typeof(resolvedSource) !== "object") {
5889
+ throw Error("Schema type error: expected source to be type of object, but got ".concat(_typeof(resolvedSource)));
5890
+ }
5891
+ if (resolvedSource !== null && resolvedSource[part] === undefined) {
5892
+ throw Error("Invalid path: object source did not have key ".concat(part, " from path: ").concat(path));
5893
+ }
5894
+ resolvedSource = resolvedSource === null ? resolvedSource : resolvedSource[part];
5895
+ resolvedSchema = resolvedSchema instanceof ObjectSchema ? resolvedSchema["items"][part] : resolvedSchema.items[part];
5896
+ // } else if (isI18nSchema(resolvedSchema)) {
5897
+ // if (!resolvedSchema.locales.includes(part)) {
5898
+ // throw Error(
5899
+ // `Invalid path: i18n schema ${resolvedSchema} supports locales ${resolvedSchema.locales.join(
5900
+ // ", "
5179
5901
  // )}, but found: ${part}`
5180
5902
  // );
5181
5903
  // }
@@ -5376,6 +6098,21 @@ function safeResolvePath(path, valModule, schema) {
5376
6098
  }
5377
6099
  };
5378
6100
  }
6101
+ } else if (isSettingsSchema(resolvedSchema)) {
6102
+ if (resolvedSource !== null && resolvedSource !== undefined && _typeof(resolvedSource) !== "object") {
6103
+ return {
6104
+ v: {
6105
+ status: "error",
6106
+ message: "Schema type error: expected source to be type of object, but got ".concat(_typeof(resolvedSource))
6107
+ }
6108
+ };
6109
+ }
6110
+ // Absent is a value here — see the note in `resolvePath`. `undefined` has
6111
+ // to be let through as well as `null`: descending into a section the
6112
+ // project has not set produces one, and the NEXT part then arrives with
6113
+ // an undefined source that is not an error either.
6114
+ resolvedSource = resolvedSource === null || resolvedSource === undefined ? resolvedSource : resolvedSource[part];
6115
+ resolvedSchema = resolvedSchema instanceof SettingsSchema ? resolvedSchema["items"][part] : resolvedSchema.items[part];
5379
6116
  } else if (isObjectSchema(resolvedSchema)) {
5380
6117
  if (resolvedSource === undefined) {
5381
6118
  return {
@@ -5563,243 +6300,44 @@ function splitModulePath(input) {
5563
6300
  }
5564
6301
  return result;
5565
6302
  }
5566
- function splitJoinedSourcePaths(input) {
5567
- // TODO: This is a very simple implementation that does not handle escaped commas
5568
- return input.split(",");
5569
- }
5570
- function parentOfSourcePath(sourcePath) {
5571
- var _splitModuleFilePathA = splitModuleFilePathAndModulePath(sourcePath),
5572
- _splitModuleFilePathA2 = _slicedToArray(_splitModuleFilePathA, 2),
5573
- moduleFilePath = _splitModuleFilePathA2[0],
5574
- modulePath = _splitModuleFilePathA2[1];
5575
- var modulePathParts = splitModulePath(modulePath).slice(0, -1);
5576
- if (modulePathParts.length > 0) {
5577
- return joinModuleFilePathAndModulePath(moduleFilePath, patchPathToModulePath(modulePathParts));
5578
- }
5579
- return moduleFilePath;
5580
- }
5581
- function patchPathToModulePath(patchPath) {
5582
- return patchPath.map(function (segment) {
5583
- // TODO: I am worried that something is lost here: what if the segment is a string that happens to be a parsable as a number? We could make those keys illegal?
5584
- if (Number.isInteger(Number(segment))) {
5585
- return segment;
5586
- }
5587
- return JSON.stringify(segment);
5588
- }).join(".");
5589
- }
5590
-
5591
- var NumberSchema = /*#__PURE__*/function (_Schema) {
5592
- function NumberSchema(options) {
5593
- var _this;
5594
- var opt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
5595
- var customValidateFunctions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
5596
- var isReadonly = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
5597
- var isHidden = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
5598
- var description = arguments.length > 5 ? arguments[5] : undefined;
5599
- var renderInput = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null;
5600
- var previewInput = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : null;
5601
- _classCallCheck(this, NumberSchema);
5602
- _this = _callSuper(this, NumberSchema);
5603
- _this.options = options;
5604
- _this.opt = opt;
5605
- _this.customValidateFunctions = customValidateFunctions;
5606
- _this.isReadonly = isReadonly;
5607
- _this.isHidden = isHidden;
5608
- _this.description = description;
5609
- _this.renderInput = renderInput;
5610
- _this.previewInput = previewInput;
5611
- return _this;
5612
- }
5613
- _inherits(NumberSchema, _Schema);
5614
- return _createClass(NumberSchema, [{
5615
- key: "describe",
5616
- value: function describe(description) {
5617
- return new NumberSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
5618
- }
5619
- }, {
5620
- key: "validate",
5621
- value: function validate(validationFunction) {
5622
- return new NumberSchema(this.options, this.opt, [].concat(_toConsumableArray(this.customValidateFunctions), [validationFunction]), this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
5623
- }
5624
- }, {
5625
- key: "executeValidate",
5626
- value: function executeValidate(path, src) {
5627
- var _this$options, _this$options2;
5628
- var customValidationErrors = this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
5629
- path: path
5630
- });
5631
- if (this.opt && (src === null || src === undefined)) {
5632
- return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : false;
5633
- }
5634
- if (typeof src !== "number") {
5635
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
5636
- message: "Expected 'number', got '".concat(_typeof(src), "'"),
5637
- value: src
5638
- }]));
5639
- }
5640
- if ((_this$options = this.options) !== null && _this$options !== void 0 && _this$options.max && src > this.options.max) {
5641
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
5642
- message: "Expected 'number' less than ".concat(this.options.max),
5643
- value: src
5644
- }]));
5645
- }
5646
- if ((_this$options2 = this.options) !== null && _this$options2 !== void 0 && _this$options2.min && src < this.options.min) {
5647
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
5648
- message: "Expected 'number' greater than ".concat(this.options.min),
5649
- value: src
5650
- }]));
5651
- }
5652
- if (customValidationErrors.length > 0) {
5653
- return _defineProperty({}, path, customValidationErrors);
5654
- }
5655
- return false;
5656
- }
5657
- }, {
5658
- key: "executeAssert",
5659
- value: function executeAssert(path, src) {
5660
- if (this.opt && src === null) {
5661
- return {
5662
- success: true,
5663
- data: src
5664
- };
5665
- }
5666
- if (src === null) {
5667
- return {
5668
- success: false,
5669
- errors: _defineProperty({}, path, [{
5670
- message: "Expected 'number', got 'null'",
5671
- typeError: true
5672
- }])
5673
- };
5674
- }
5675
- if (typeof src === "number") {
5676
- return {
5677
- success: true,
5678
- data: src
5679
- };
5680
- }
5681
- return {
5682
- success: false,
5683
- errors: _defineProperty({}, path, [{
5684
- message: "Expected 'number', got '".concat(_typeof(src), "'"),
5685
- typeError: true
5686
- }])
5687
- };
5688
- }
5689
- }, {
5690
- key: "nullable",
5691
- value: function nullable() {
5692
- return new NumberSchema(this.options, true, [], this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
5693
- }
5694
- }, {
5695
- key: "readonly",
5696
- value: function readonly() {
5697
- return new NumberSchema(this.options, this.opt, this.customValidateFunctions, true, this.isHidden, this.description, this.renderInput, this.previewInput);
5698
- }
5699
- }, {
5700
- key: "hidden",
5701
- value: function hidden() {
5702
- return new NumberSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, true, this.description, this.renderInput, this.previewInput);
5703
- }
5704
- }, {
5705
- key: "max",
5706
- value: function max(_max) {
5707
- return new NumberSchema(_objectSpread2(_objectSpread2({}, this.options), {}, {
5708
- max: _max
5709
- }), this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
5710
- }
5711
- }, {
5712
- key: "min",
5713
- value: function min(_min) {
5714
- return new NumberSchema(_objectSpread2(_objectSpread2({}, this.options), {}, {
5715
- min: _min
5716
- }), this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
5717
- }
5718
- }, {
5719
- key: "executeCustomValidateAt",
5720
- value: function executeCustomValidateAt(path, src) {
5721
- return this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
5722
- path: path
5723
- });
5724
- }
5725
-
5726
- /**
5727
- * How this field is laid out in the editor when it is the item of an array
5728
- * or record: `{ as: "inline" }` renders the field itself inside each row,
5729
- * instead of a preview row that navigates to it.
5730
- *
5731
- * Static configuration, not a callback — see `render.ts`.
5732
- */
5733
- }, {
5734
- key: "render",
5735
- value: function render(input) {
5736
- return new NumberSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, input, this.previewInput);
5737
- }
5738
-
5739
- /**
5740
- * How this VALUE is shown where a preview of it is needed — a row in a
5741
- * sortable list, a reference dropdown, a search hit. Never how the field
5742
- * itself is edited (that is `render`). See `preview.ts`.
5743
- */
5744
- }, {
5745
- key: "preview",
5746
- value: function preview(select) {
5747
- return new NumberSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, select);
5748
- }
5749
- }, {
5750
- key: "executePreviewItem",
5751
- value: function executePreviewItem(src) {
5752
- if (this.previewInput === null) {
5753
- return null;
5754
- }
5755
- return this.previewInput({
5756
- val: src
5757
- });
5758
- }
5759
- }, {
5760
- key: "declaresItemPreview",
5761
- value: function declaresItemPreview() {
5762
- return this.previewInput !== null;
5763
- }
5764
- }, {
5765
- key: "executeSerialize",
5766
- value: function executeSerialize() {
5767
- var _this$renderInput, _this$customValidateF;
5768
- return {
5769
- type: "number",
5770
- render: (_this$renderInput = this.renderInput) !== null && _this$renderInput !== void 0 ? _this$renderInput : undefined,
5771
- preview: this.previewInput ? true : undefined,
5772
- options: this.options,
5773
- opt: this.opt,
5774
- customValidate: this.customValidateFunctions && ((_this$customValidateF = this.customValidateFunctions) === null || _this$customValidateF === void 0 ? void 0 : _this$customValidateF.length) > 0,
5775
- readonly: this.isReadonly,
5776
- hidden: this.isHidden,
5777
- description: this.description
5778
- };
5779
- }
5780
- }, {
5781
- key: "executePreview",
5782
- value: function executePreview() {
5783
- return {};
6303
+ function splitJoinedSourcePaths(input) {
6304
+ // TODO: This is a very simple implementation that does not handle escaped commas
6305
+ return input.split(",");
6306
+ }
6307
+ function parentOfSourcePath(sourcePath) {
6308
+ var _splitModuleFilePathA = splitModuleFilePathAndModulePath(sourcePath),
6309
+ _splitModuleFilePathA2 = _slicedToArray(_splitModuleFilePathA, 2),
6310
+ moduleFilePath = _splitModuleFilePathA2[0],
6311
+ modulePath = _splitModuleFilePathA2[1];
6312
+ var modulePathParts = splitModulePath(modulePath).slice(0, -1);
6313
+ if (modulePathParts.length > 0) {
6314
+ return joinModuleFilePathAndModulePath(moduleFilePath, patchPathToModulePath(modulePathParts));
6315
+ }
6316
+ return moduleFilePath;
6317
+ }
6318
+ function patchPathToModulePath(patchPath) {
6319
+ return patchPath.map(function (segment) {
6320
+ // TODO: I am worried that something is lost here: what if the segment is a string that happens to be a parsable as a number? We could make those keys illegal?
6321
+ if (Number.isInteger(Number(segment))) {
6322
+ return segment;
5784
6323
  }
5785
- }]);
5786
- }(Schema);
5787
- var number = function number(options) {
5788
- return new NumberSchema(options);
5789
- };
6324
+ return JSON.stringify(segment);
6325
+ }).join(".");
6326
+ }
5790
6327
 
5791
- var BooleanSchema = /*#__PURE__*/function (_Schema) {
5792
- function BooleanSchema() {
6328
+ var NumberSchema = /*#__PURE__*/function (_Schema) {
6329
+ function NumberSchema(options) {
5793
6330
  var _this;
5794
- var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
5795
- var customValidateFunctions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
5796
- var isReadonly = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
5797
- var isHidden = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
5798
- var description = arguments.length > 4 ? arguments[4] : undefined;
5799
- var renderInput = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : null;
5800
- var previewInput = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null;
5801
- _classCallCheck(this, BooleanSchema);
5802
- _this = _callSuper(this, BooleanSchema);
6331
+ var opt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
6332
+ var customValidateFunctions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
6333
+ var isReadonly = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
6334
+ var isHidden = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
6335
+ var description = arguments.length > 5 ? arguments[5] : undefined;
6336
+ var renderInput = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null;
6337
+ var previewInput = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : null;
6338
+ _classCallCheck(this, NumberSchema);
6339
+ _this = _callSuper(this, NumberSchema);
6340
+ _this.options = options;
5803
6341
  _this.opt = opt;
5804
6342
  _this.customValidateFunctions = customValidateFunctions;
5805
6343
  _this.isReadonly = isReadonly;
@@ -5809,28 +6347,47 @@ var BooleanSchema = /*#__PURE__*/function (_Schema) {
5809
6347
  _this.previewInput = previewInput;
5810
6348
  return _this;
5811
6349
  }
5812
- _inherits(BooleanSchema, _Schema);
5813
- return _createClass(BooleanSchema, [{
6350
+ _inherits(NumberSchema, _Schema);
6351
+ return _createClass(NumberSchema, [{
5814
6352
  key: "describe",
5815
6353
  value: function describe(description) {
5816
- return new BooleanSchema(this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
6354
+ return new NumberSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
5817
6355
  }
5818
6356
  }, {
5819
6357
  key: "validate",
5820
6358
  value: function validate(validationFunction) {
5821
- return new BooleanSchema(this.opt, [].concat(_toConsumableArray(this.customValidateFunctions), [validationFunction]), this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
6359
+ return new NumberSchema(this.options, this.opt, [].concat(_toConsumableArray(this.customValidateFunctions), [validationFunction]), this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
5822
6360
  }
5823
6361
  }, {
5824
6362
  key: "executeValidate",
5825
6363
  value: function executeValidate(path, src) {
6364
+ var _this$options, _this$options2;
6365
+ var customValidationErrors = this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
6366
+ path: path
6367
+ });
5826
6368
  if (this.opt && (src === null || src === undefined)) {
5827
- return false;
6369
+ return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : false;
5828
6370
  }
5829
- if (typeof src !== "boolean") {
5830
- return _defineProperty({}, path, [{
5831
- message: "Expected 'boolean', got '".concat(_typeof(src), "'"),
6371
+ if (typeof src !== "number") {
6372
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
6373
+ message: "Expected 'number', got '".concat(_typeof(src), "'"),
5832
6374
  value: src
5833
- }]);
6375
+ }]));
6376
+ }
6377
+ if ((_this$options = this.options) !== null && _this$options !== void 0 && _this$options.max && src > this.options.max) {
6378
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
6379
+ message: "Expected 'number' less than ".concat(this.options.max),
6380
+ value: src
6381
+ }]));
6382
+ }
6383
+ if ((_this$options2 = this.options) !== null && _this$options2 !== void 0 && _this$options2.min && src < this.options.min) {
6384
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
6385
+ message: "Expected 'number' greater than ".concat(this.options.min),
6386
+ value: src
6387
+ }]));
6388
+ }
6389
+ if (customValidationErrors.length > 0) {
6390
+ return _defineProperty({}, path, customValidationErrors);
5834
6391
  }
5835
6392
  return false;
5836
6393
  }
@@ -5847,39 +6404,55 @@ var BooleanSchema = /*#__PURE__*/function (_Schema) {
5847
6404
  return {
5848
6405
  success: false,
5849
6406
  errors: _defineProperty({}, path, [{
5850
- message: "Expected 'boolean', got 'null'",
6407
+ message: "Expected 'number', got 'null'",
5851
6408
  typeError: true
5852
6409
  }])
5853
6410
  };
5854
6411
  }
5855
- if (typeof src !== "boolean") {
6412
+ if (typeof src === "number") {
5856
6413
  return {
5857
- success: false,
5858
- errors: _defineProperty({}, path, [{
5859
- message: "Expected 'boolean', got '".concat(_typeof(src), "'"),
5860
- typeError: true
5861
- }])
6414
+ success: true,
6415
+ data: src
5862
6416
  };
5863
6417
  }
5864
6418
  return {
5865
- success: true,
5866
- data: src
6419
+ success: false,
6420
+ errors: _defineProperty({}, path, [{
6421
+ message: "Expected 'number', got '".concat(_typeof(src), "'"),
6422
+ typeError: true
6423
+ }])
5867
6424
  };
5868
6425
  }
5869
6426
  }, {
5870
6427
  key: "nullable",
5871
6428
  value: function nullable() {
5872
- return new BooleanSchema(true, [], this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
6429
+ return new NumberSchema(this.options, true, [], this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
5873
6430
  }
5874
6431
  }, {
5875
6432
  key: "readonly",
5876
6433
  value: function readonly() {
5877
- return new BooleanSchema(this.opt, this.customValidateFunctions, true, this.isHidden, this.description, this.renderInput, this.previewInput);
6434
+ var isReadonly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
6435
+ return new NumberSchema(this.options, this.opt, this.customValidateFunctions, isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
5878
6436
  }
5879
6437
  }, {
5880
6438
  key: "hidden",
5881
6439
  value: function hidden() {
5882
- return new BooleanSchema(this.opt, this.customValidateFunctions, this.isReadonly, true, this.description, this.renderInput, this.previewInput);
6440
+ var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
6441
+ return new NumberSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, isHidden, this.description, this.renderInput, this.previewInput);
6442
+ }
6443
+ }, {
6444
+ key: "max",
6445
+ value: function max(_max) {
6446
+ return new NumberSchema(_objectSpread2(_objectSpread2({}, this.options), {}, {
6447
+ max: _max
6448
+ }), this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
6449
+ }
6450
+ }, {
6451
+ key: "min",
6452
+ value: function min(_min) {
6453
+ return new NumberSchema(_objectSpread2(_objectSpread2({}, this.options), {}, {
6454
+ min: _min
6455
+ }), this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
5883
6456
  }
5884
6457
  }, {
5885
6458
  key: "executeCustomValidateAt",
@@ -5899,7 +6472,7 @@ var BooleanSchema = /*#__PURE__*/function (_Schema) {
5899
6472
  }, {
5900
6473
  key: "render",
5901
6474
  value: function render(input) {
5902
- return new BooleanSchema(this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, input, this.previewInput);
6475
+ return new NumberSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, input, this.previewInput);
5903
6476
  }
5904
6477
 
5905
6478
  /**
@@ -5910,7 +6483,7 @@ var BooleanSchema = /*#__PURE__*/function (_Schema) {
5910
6483
  }, {
5911
6484
  key: "preview",
5912
6485
  value: function preview(select) {
5913
- return new BooleanSchema(this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, select);
6486
+ return new NumberSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, select);
5914
6487
  }
5915
6488
  }, {
5916
6489
  key: "executePreviewItem",
@@ -5932,9 +6505,10 @@ var BooleanSchema = /*#__PURE__*/function (_Schema) {
5932
6505
  value: function executeSerialize() {
5933
6506
  var _this$renderInput, _this$customValidateF;
5934
6507
  return {
5935
- type: "boolean",
6508
+ type: "number",
5936
6509
  render: (_this$renderInput = this.renderInput) !== null && _this$renderInput !== void 0 ? _this$renderInput : undefined,
5937
6510
  preview: this.previewInput ? true : undefined,
6511
+ options: this.options,
5938
6512
  opt: this.opt,
5939
6513
  customValidate: this.customValidateFunctions && ((_this$customValidateF = this.customValidateFunctions) === null || _this$customValidateF === void 0 ? void 0 : _this$customValidateF.length) > 0,
5940
6514
  readonly: this.isReadonly,
@@ -5949,8 +6523,8 @@ var BooleanSchema = /*#__PURE__*/function (_Schema) {
5949
6523
  }
5950
6524
  }]);
5951
6525
  }(Schema);
5952
- var _boolean = function _boolean() {
5953
- return new BooleanSchema();
6526
+ var number = function number(options) {
6527
+ return new NumberSchema(options);
5954
6528
  };
5955
6529
 
5956
6530
  var KeyOfSchema = /*#__PURE__*/function (_Schema) {
@@ -6120,12 +6694,14 @@ var KeyOfSchema = /*#__PURE__*/function (_Schema) {
6120
6694
  }, {
6121
6695
  key: "readonly",
6122
6696
  value: function readonly() {
6123
- return new KeyOfSchema(this.schema, this.sourcePath, this.opt, this.customValidateFunctions, true, this.isHidden, this.description, this.renderInput, this.previewInput);
6697
+ var isReadonly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
6698
+ return new KeyOfSchema(this.schema, this.sourcePath, this.opt, this.customValidateFunctions, isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
6124
6699
  }
6125
6700
  }, {
6126
6701
  key: "hidden",
6127
6702
  value: function hidden() {
6128
- return new KeyOfSchema(this.schema, this.sourcePath, this.opt, this.customValidateFunctions, this.isReadonly, true, this.description, this.renderInput, this.previewInput);
6703
+ var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
6704
+ return new KeyOfSchema(this.schema, this.sourcePath, this.opt, this.customValidateFunctions, this.isReadonly, isHidden, this.description, this.renderInput, this.previewInput);
6129
6705
  }
6130
6706
  }, {
6131
6707
  key: "executeCustomValidateAt",
@@ -6462,12 +7038,14 @@ var FileSchema = /*#__PURE__*/function (_Schema) {
6462
7038
  }, {
6463
7039
  key: "readonly",
6464
7040
  value: function readonly() {
6465
- return new FileSchema(this.options, this.opt, this.isRemote, this.customValidateFunctions, this.moduleMetadata, true, this.isHidden, this.description, this.renderInput, this.previewInput);
7041
+ var isReadonly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
7042
+ return new FileSchema(this.options, this.opt, this.isRemote, this.customValidateFunctions, this.moduleMetadata, isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
6466
7043
  }
6467
7044
  }, {
6468
7045
  key: "hidden",
6469
7046
  value: function hidden() {
6470
- return new FileSchema(this.options, this.opt, this.isRemote, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, true, this.description, this.renderInput, this.previewInput);
7047
+ var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
7048
+ return new FileSchema(this.options, this.opt, this.isRemote, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, isHidden, this.description, this.renderInput, this.previewInput);
6471
7049
  }
6472
7050
  }, {
6473
7051
  key: "executeCustomValidateAt",
@@ -6577,6 +7155,8 @@ function file(options) {
6577
7155
  /**
6578
7156
  * Define a collection of files.
6579
7157
  *
7158
+ * Remote is off by default: call `.remote()` on the result to allow remote files.
7159
+ *
6580
7160
  * @example
6581
7161
  * ```typescript
6582
7162
  * const schema = s.files({
@@ -6591,7 +7171,6 @@ function file(options) {
6591
7171
  * ```
6592
7172
  */
6593
7173
  var files = function files(options) {
6594
- var _options$remote;
6595
7174
  var directory = options.directory;
6596
7175
  var itemSchema = new ObjectSchema({
6597
7176
  mimeType: new StringSchema({}, false)
@@ -6600,7 +7179,7 @@ var files = function files(options) {
6600
7179
  type: "files",
6601
7180
  accept: options.accept,
6602
7181
  directory: directory,
6603
- remote: (_options$remote = options.remote) !== null && _options$remote !== void 0 ? _options$remote : false
7182
+ remote: false
6604
7183
  });
6605
7184
  };
6606
7185
 
@@ -6741,12 +7320,14 @@ var DateSchema = /*#__PURE__*/function (_Schema) {
6741
7320
  }, {
6742
7321
  key: "readonly",
6743
7322
  value: function readonly() {
6744
- return new DateSchema(this.options, this.opt, this.customValidateFunctions, true, this.isHidden, this.description, this.renderInput, this.previewInput);
7323
+ var isReadonly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
7324
+ return new DateSchema(this.options, this.opt, this.customValidateFunctions, isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
6745
7325
  }
6746
7326
  }, {
6747
7327
  key: "hidden",
6748
7328
  value: function hidden() {
6749
- return new DateSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, true, this.description, this.renderInput, this.previewInput);
7329
+ var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
7330
+ return new DateSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, isHidden, this.description, this.renderInput, this.previewInput);
6750
7331
  }
6751
7332
  }, {
6752
7333
  key: "executeCustomValidateAt",
@@ -6990,12 +7571,14 @@ var DateTimeSchema = /*#__PURE__*/function (_Schema) {
6990
7571
  }, {
6991
7572
  key: "readonly",
6992
7573
  value: function readonly() {
6993
- return new DateTimeSchema(this.options, this.opt, this.customValidateFunctions, true, this.isHidden, this.description, this.renderInput, this.previewInput);
7574
+ var isReadonly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
7575
+ return new DateTimeSchema(this.options, this.opt, this.customValidateFunctions, isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
6994
7576
  }
6995
7577
  }, {
6996
7578
  key: "hidden",
6997
7579
  value: function hidden() {
6998
- return new DateTimeSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, true, this.description, this.renderInput, this.previewInput);
7580
+ var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
7581
+ return new DateTimeSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, isHidden, this.description, this.renderInput, this.previewInput);
6999
7582
  }
7000
7583
  }, {
7001
7584
  key: "executeCustomValidateAt",
@@ -7175,12 +7758,14 @@ var CodeSchema = /*#__PURE__*/function (_Schema) {
7175
7758
  }, {
7176
7759
  key: "readonly",
7177
7760
  value: function readonly() {
7178
- return new CodeSchema(this.options, this.opt, this.customValidateFunctions, true, this.isHidden, this.description, this.renderInput, this.previewInput);
7761
+ var isReadonly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
7762
+ return new CodeSchema(this.options, this.opt, this.customValidateFunctions, isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
7179
7763
  }
7180
7764
  }, {
7181
7765
  key: "hidden",
7182
7766
  value: function hidden() {
7183
- return new CodeSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, true, this.description, this.renderInput, this.previewInput);
7767
+ var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
7768
+ return new CodeSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, isHidden, this.description, this.renderInput, this.previewInput);
7184
7769
  }
7185
7770
 
7186
7771
  /**
@@ -7861,12 +8446,14 @@ var ColorSchema = /*#__PURE__*/function (_Schema) {
7861
8446
  }, {
7862
8447
  key: "readonly",
7863
8448
  value: function readonly() {
7864
- return new ColorSchema(this.options, this.opt, this.customValidateFunctions, true, this.isHidden, this.description, this.renderInput, this.previewInput);
8449
+ var isReadonly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
8450
+ return new ColorSchema(this.options, this.opt, this.customValidateFunctions, isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
7865
8451
  }
7866
8452
  }, {
7867
8453
  key: "hidden",
7868
8454
  value: function hidden() {
7869
- return new ColorSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, true, this.description, this.renderInput, this.previewInput);
8455
+ var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
8456
+ return new ColorSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, isHidden, this.description, this.renderInput, this.previewInput);
7870
8457
  }
7871
8458
 
7872
8459
  /**
@@ -7960,7 +8547,7 @@ function router(router, keyOrItem, maybeItem) {
7960
8547
  *
7961
8548
  * `directory` is required — it decides where uploads land, so it is not something
7962
8549
  * to be inferred. The rest defaults: any image type (`"image/*"`), nullable alt
7963
- * text, remote disabled.
8550
+ * text, remote disabled. Call `.remote()` on the result to allow remote images.
7964
8551
  *
7965
8552
  * @example
7966
8553
  * ```typescript
@@ -7980,7 +8567,7 @@ function router(router, keyOrItem, maybeItem) {
7980
8567
  * ```
7981
8568
  */
7982
8569
  var images = function images(options) {
7983
- var _options$alt, _options$accept, _options$remote;
8570
+ var _options$alt, _options$accept;
7984
8571
  var directory = options.directory;
7985
8572
  var altSchema = (_options$alt = options.alt) !== null && _options$alt !== void 0 ? _options$alt : string().nullable();
7986
8573
  var itemSchema = new ObjectSchema({
@@ -7993,7 +8580,7 @@ var images = function images(options) {
7993
8580
  type: "images",
7994
8581
  accept: (_options$accept = options.accept) !== null && _options$accept !== void 0 ? _options$accept : "image/*",
7995
8582
  directory: directory,
7996
- remote: (_options$remote = options.remote) !== null && _options$remote !== void 0 ? _options$remote : false,
8583
+ remote: false,
7997
8584
  altSchema: altSchema,
7998
8585
  encode: options.encode
7999
8586
  });
@@ -8029,7 +8616,8 @@ function initSchema() {
8029
8616
  code: code,
8030
8617
  route: route,
8031
8618
  router: router,
8032
- images: images
8619
+ images: images,
8620
+ settings: settings
8033
8621
  // i18n: i18n(locales),
8034
8622
  };
8035
8623
  }
@@ -8070,7 +8658,8 @@ var initVal = function initVal(config) {
8070
8658
  },
8071
8659
  c: {
8072
8660
  define: define,
8073
- json: json
8661
+ json: json,
8662
+ external: external
8074
8663
  },
8075
8664
  s: s,
8076
8665
  config: config
@@ -8430,6 +9019,98 @@ var getSHA256Hash = function getSHA256Hash(bits) {
8430
9019
  return createHash().update(bits).digest("hex");
8431
9020
  };
8432
9021
 
9022
+ /**
9023
+ * Where a settings module goes unless a project has a reason not to.
9024
+ *
9025
+ * A convention, not a rule: any module file path at the root of the content
9026
+ * tree may hold `s.settings()` — see {@link resolveSettingsModule}.
9027
+ */
9028
+ var SETTINGS_MODULE_CONVENTION = "/settings.val.ts";
9029
+
9030
+ /**
9031
+ * Whether a module file path is at the root of the content tree.
9032
+ *
9033
+ * `/settings.val.ts` is; `/content/settings.val.ts` is not. The settings module
9034
+ * is the project's, not a folder's, and a project-wide setting found three
9035
+ * directories down reads as one section's — so the position is part of what it
9036
+ * means.
9037
+ */
9038
+ function isRootModuleFilePath(moduleFilePath) {
9039
+ return moduleFilePath.startsWith("/") && !moduleFilePath.slice(1).includes("/");
9040
+ }
9041
+
9042
+ /**
9043
+ * Structurally an `ExtractedModuleError`, declared here rather than imported to
9044
+ * keep `extractValModules` -> `settingsModule` a one-way dependency.
9045
+ */
9046
+
9047
+ /**
9048
+ * Find the project's settings module among all its schemas.
9049
+ *
9050
+ * One per project, at the root: a settings module in a subdirectory is an
9051
+ * error, and so is a second one. Both are reported rather than resolved by
9052
+ * picking a winner — a project with two settings modules has a question to
9053
+ * answer, and answering it by sort order means the answer changes when a file
9054
+ * is renamed.
9055
+ */
9056
+ function resolveSettingsModule(schemas) {
9057
+ var rootModules = [];
9058
+ var nestedModules = [];
9059
+ var _iterator = _createForOfIteratorHelper(Object.keys(schemas).sort()),
9060
+ _step;
9061
+ try {
9062
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
9063
+ var _schemas$_moduleFileP;
9064
+ var moduleFilePathS = _step.value;
9065
+ var _moduleFilePath2 = moduleFilePathS;
9066
+ if (((_schemas$_moduleFileP = schemas[_moduleFilePath2]) === null || _schemas$_moduleFileP === void 0 ? void 0 : _schemas$_moduleFileP.type) !== "settings") {
9067
+ continue;
9068
+ }
9069
+ if (isRootModuleFilePath(_moduleFilePath2)) {
9070
+ rootModules.push(_moduleFilePath2);
9071
+ } else {
9072
+ nestedModules.push(_moduleFilePath2);
9073
+ }
9074
+ }
9075
+ } catch (err) {
9076
+ _iterator.e(err);
9077
+ } finally {
9078
+ _iterator.f();
9079
+ }
9080
+ var errors = [];
9081
+ for (var _i = 0, _nestedModules = nestedModules; _i < _nestedModules.length; _i++) {
9082
+ var moduleFilePath = _nestedModules[_i];
9083
+ errors.push({
9084
+ path: moduleFilePath,
9085
+ message: "Settings must be defined at the root of the content tree, but s.settings() was found in '".concat(moduleFilePath, "'. Move it to a module file path with no directory in it, e.g. '").concat(SETTINGS_MODULE_CONVENTION, "'.")
9086
+ });
9087
+ }
9088
+ if (rootModules.length > 1) {
9089
+ var listed = rootModules.map(function (moduleFilePath) {
9090
+ return "'".concat(moduleFilePath, "'");
9091
+ }).join(" and ");
9092
+ var _iterator2 = _createForOfIteratorHelper(rootModules),
9093
+ _step2;
9094
+ try {
9095
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
9096
+ var _moduleFilePath = _step2.value;
9097
+ errors.push({
9098
+ path: _moduleFilePath,
9099
+ message: "A project can only define settings once, but s.settings() was found in ".concat(listed, ". Keep one of them.")
9100
+ });
9101
+ }
9102
+ } catch (err) {
9103
+ _iterator2.e(err);
9104
+ } finally {
9105
+ _iterator2.f();
9106
+ }
9107
+ }
9108
+ return {
9109
+ moduleFilePath: errors.length === 0 && rootModules.length === 1 ? rootModules[0] : null,
9110
+ errors: errors
9111
+ };
9112
+ }
9113
+
8433
9114
  // Lazily constructed: this module is also evaluated inside the `vm` sandbox
8434
9115
  // used by loadValModules (when user val modules import @valbuild/core), and
8435
9116
  // that sandbox has no `TextEncoder` global. `hash()` is never called from
@@ -8597,7 +9278,7 @@ function extractValModules(_x) {
8597
9278
  }
8598
9279
  function _extractValModules() {
8599
9280
  _extractValModules = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(valModules) {
8600
- var moduleErrors, addModuleError, sources, schemas, serializedSchemas, shaEntries, moduleIdx, module, at, value, path, schema, source, serializedSchema, pathM, _t, _t2;
9281
+ var moduleErrors, addModuleError, sources, schemas, serializedSchemas, shaEntries, moduleIdx, module, at, value, path, schema, source, serializedSchema, pathM, _iterator2, _step2, error, _t, _t2;
8601
9282
  return _regenerator().w(function (_context) {
8602
9283
  while (1) switch (_context.p = _context.n) {
8603
9284
  case 0:
@@ -8736,6 +9417,25 @@ function _extractValModules() {
8736
9417
  _context.n = 1;
8737
9418
  break;
8738
9419
  case 18:
9420
+ // Settings is the one rule that cannot be checked while looking at a single
9421
+ // module: "one per project, at the root" is a statement about the whole set.
9422
+ // Reported here so that every consumer of extraction gets it — the dev
9423
+ // server, `val validate` and the Studio all read `moduleErrors`.
9424
+ //
9425
+ // Appended AFTER the loop on purpose: each entry's `moduleErrorsAt` is the
9426
+ // error count at the time it was folded in, so the SHAs stay a function of
9427
+ // the modules themselves.
9428
+ _iterator2 = _createForOfIteratorHelper(resolveSettingsModule(serializedSchemas).errors);
9429
+ try {
9430
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
9431
+ error = _step2.value;
9432
+ moduleErrors.push(error);
9433
+ }
9434
+ } catch (err) {
9435
+ _iterator2.e(err);
9436
+ } finally {
9437
+ _iterator2.f();
9438
+ }
8739
9439
  return _context.a(2, _objectSpread2(_objectSpread2({
8740
9440
  sources: sources,
8741
9441
  schemas: schemas,
@@ -8756,9 +9456,10 @@ function _extractValModules() {
8756
9456
  * The one answer to that question. There used to be two — `hasRemoteFileSchema`
8757
9457
  * in the server, gating whether `/save` demands remote credentials, and
8758
9458
  * `findRequiredRemoteFiles` in the Studio, gating the `/remote/settings` fetch —
8759
- * and they disagreed about `s.images({ remote: true })`: the Studio's counted a
8760
- * remote media record, the server's did not, because a media collection
8761
- * serializes as a `record` of metadata rather than as an image schema.
9459
+ * and they disagreed about `s.images({ ... }).remote()`: the Studio's version
9460
+ * counted a remote media record, the server's did not, because a media
9461
+ * collection serializes as a `record` of metadata rather than as an image
9462
+ * schema.
8762
9463
  *
8763
9464
  * The server's answer was the wrong one, and silently so. With it false,
8764
9465
  * `/save` runs `saveOrUploadFiles` in `skip-remote` mode, and that mode does not
@@ -8807,7 +9508,10 @@ function hasRemoteFileSchema(schema) {
8807
9508
  return true;
8808
9509
  }
8809
9510
  return hasRemoteFileSchema(schema.item);
8810
- } else if (schema.type === "object") {
9511
+ } else if (schema.type === "object" || schema.type === "settings") {
9512
+ // Settings holds its sections the way an object holds its keys, so looking
9513
+ // inside is the same walk. Nothing in settings takes a file today, but the
9514
+ // answer should stay right when something does.
8811
9515
  for (var key in schema.items) {
8812
9516
  var hasRemoteFile = hasRemoteFileSchema(schema.items[key]);
8813
9517
  if (hasRemoteFile) {
@@ -8848,6 +9552,85 @@ function hasRemoteFileSchema(schema) {
8848
9552
  }
8849
9553
  }
8850
9554
 
9555
+ /**
9556
+ * Does this schema hold any media at all — remote or not?
9557
+ *
9558
+ * The sibling of {@link hasRemoteFileSchema}, and the same walk minus the
9559
+ * `remote` predicate. It answers the question an external record has to ask
9560
+ * before it will accept a binding: an item schema containing media needs a
9561
+ * `putFile`/`getFile` pair, and without one that is a schema error.
9562
+ *
9563
+ * It is a walk over the SERIALIZED schema for the reasons given above, and for
9564
+ * one more that is specific to this question: the two cases most likely to be
9565
+ * missed are invisible to a value type. A media collection (`s.images()` /
9566
+ * `s.files()`) serializes as a record of metadata with no image schema inside
9567
+ * it, and a richtext inline image lives in a constructor argument. A check
9568
+ * written against the item TYPE would silently pass both — and the gallery case
9569
+ * already has a data-loss incident attached to it (see above).
9570
+ */
9571
+ function hasMediaSchema(schema) {
9572
+ if (schema.type === "file" || schema.type === "image") {
9573
+ return true;
9574
+ } else if (schema.type === "richtext") {
9575
+ var _schema$options2;
9576
+ // `img` is `boolean | SerializedImageSchema`: `true` means inline images are
9577
+ // allowed with the DEFAULT image schema, and is just as much media as a
9578
+ // spelled-out one. `hasRemoteFileSchema` tests only for an object because a
9579
+ // default image is not remote — a different question with a different
9580
+ // answer, which is why these two walks are separate functions.
9581
+ if ((_schema$options2 = schema.options) !== null && _schema$options2 !== void 0 && _schema$options2.img) {
9582
+ return true;
9583
+ }
9584
+ return false;
9585
+ } else if (schema.type === "array") {
9586
+ return hasMediaSchema(schema.item);
9587
+ } else if (schema.type === "record") {
9588
+ // A media collection names its file by the record's KEY, so there is no
9589
+ // image schema inside to find: `mediaType` is where the answer is written.
9590
+ if (schema.mediaType) {
9591
+ return true;
9592
+ }
9593
+ return hasMediaSchema(schema.item);
9594
+ } else if (schema.type === "object") {
9595
+ for (var key in schema.items) {
9596
+ if (hasMediaSchema(schema.items[key])) {
9597
+ return true;
9598
+ }
9599
+ }
9600
+ 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
+ }
9612
+ }
9613
+ } catch (err) {
9614
+ _iterator2.e(err);
9615
+ } finally {
9616
+ _iterator2.f();
9617
+ }
9618
+ }
9619
+ // A string union's items are literals, so there is nothing to look inside.
9620
+ 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" ||
9622
+ // A settings module holds the assistant's configuration, not content, and
9623
+ // nothing in it is media.
9624
+ schema.type === "settings") {
9625
+ return false;
9626
+ } else {
9627
+ // Same contract as above: adding a schema type without teaching this
9628
+ // function about it must not compile.
9629
+ var exhaustiveCheck = schema;
9630
+ throw new Error("Unexpected schema: ".concat(JSON.stringify(exhaustiveCheck)));
9631
+ }
9632
+ }
9633
+
8851
9634
  var DEFAULT_VAL_REMOTE_HOST = "https://remote.val.build";
8852
9635
 
8853
9636
  var PatchError = /*#__PURE__*/_createClass(function PatchError(message) {
@@ -8992,6 +9775,79 @@ function mediaPathOf(value) {
8992
9775
  return typeof path === "string" ? path : null;
8993
9776
  }
8994
9777
 
9778
+ /**
9779
+ * The reference stored for a file whose bytes live behind an external adapter.
9780
+ *
9781
+ * Deliberately the same shape of idea as a remote ref (`remote/splitRemoteRef`):
9782
+ * a URL-ish string that **ends with the file's virtual path**, so the file's
9783
+ * logical identity survives wherever its bytes happen to be.
9784
+ *
9785
+ * /api/val/external/documents/f/{fileHash}/p/public/val/documents/report_a1b2c.pdf
9786
+ * \__________________________/ \________/ \_______________________________/
9787
+ * route + label content the path a LOCAL file
9788
+ * address would have had
9789
+ *
9790
+ * Three things follow from that shape, and each is load-bearing:
9791
+ *
9792
+ * - **`media.ts` needs no change.** `isRemote` is `!path.startsWith("/public")`,
9793
+ * and this does not, so `Internal.mediaUrl` returns the ref as-is and Val's
9794
+ * route serves it. The media rule that has been got wrong repeatedly is left
9795
+ * exactly alone.
9796
+ * - **Moving between storage modes is mechanical.** External → local reads the
9797
+ * `public/…` suffix back out, fetches the bytes and writes them there; local →
9798
+ * external uploads the file already at that path. Nothing is renamed.
9799
+ * - **The filename is Val's, not the adapter's**, produced by the same
9800
+ * `createFilename` a local or remote file uses — so the same bytes get the
9801
+ * same name under all three storage modes.
9802
+ */
9803
+
9804
+ var RegEx = /^\/api\/val\/external\/([^/]+)\/f\/([^/]+)\/p\/(.+)$/;
9805
+ function createExternalFileRef(_ref) {
9806
+ var label = _ref.label,
9807
+ fileHash = _ref.fileHash,
9808
+ filePath = _ref.filePath;
9809
+ var withoutLeadingSlash = filePath.startsWith("/") ? filePath.slice(1) : filePath;
9810
+ if (!withoutLeadingSlash.startsWith("public/")) {
9811
+ throw new Error("External file paths must be under '/public', got: '".concat(filePath, "'"));
9812
+ }
9813
+ return "/api/val/external/".concat(label, "/f/").concat(fileHash, "/p/").concat(withoutLeadingSlash);
9814
+ }
9815
+ function splitExternalFileRef(ref) {
9816
+ var match = ref.match(RegEx);
9817
+ if (!match) {
9818
+ return {
9819
+ status: "error",
9820
+ error: "Not an external file ref: " + ref
9821
+ };
9822
+ }
9823
+ var filePath = match[3];
9824
+ if (!filePath.startsWith("public/")) {
9825
+ return {
9826
+ status: "error",
9827
+ error: "Invalid external file ref: " + ref
9828
+ };
9829
+ }
9830
+ // Traversal check, for the same reason `splitRemoteRef` has one: this path is
9831
+ // used to read and write files.
9832
+ if (filePath.split("/").some(function (segment) {
9833
+ return segment === "." || segment === "..";
9834
+ })) {
9835
+ return {
9836
+ status: "error",
9837
+ error: "Invalid external file ref: " + ref
9838
+ };
9839
+ }
9840
+ return {
9841
+ status: "success",
9842
+ label: match[1],
9843
+ fileHash: match[2],
9844
+ filePath: filePath
9845
+ };
9846
+ }
9847
+ function isExternalFileRef(ref) {
9848
+ return RegEx.test(ref);
9849
+ }
9850
+
8995
9851
  // NOTE: the segments must match the ref built by createRemoteRef below and the RegEx in splitRemoteRef.
8996
9852
 
8997
9853
  function createRemoteRef(remoteHost, _ref) {
@@ -9052,7 +9908,7 @@ function deserializeSchema(serialized) {
9052
9908
  return schema;
9053
9909
  }
9054
9910
  function deserializeSchemaImpl(serialized) {
9055
- 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$render0, _serialized$render10, _serialized$render11, _serialized$render12, _serialized$render13, _serialized$render14, _serialized$render15;
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;
9056
9912
  switch (serialized.type) {
9057
9913
  case "string":
9058
9914
  return new StringSchema(_objectSpread2(_objectSpread2({}, serialized.options), {}, {
@@ -9075,6 +9931,13 @@ function deserializeSchemaImpl(serialized) {
9075
9931
  item = _ref2[1];
9076
9932
  return [key, deserializeSchema(item)];
9077
9933
  })), serialized.opt, [], false, false, serialized.description, (_serialized$render5 = serialized.render) !== null && _serialized$render5 !== void 0 ? _serialized$render5 : null);
9934
+ case "settings":
9935
+ return new SettingsSchema(Object.fromEntries(Object.entries(serialized.items).map(function (_ref3) {
9936
+ var _ref4 = _slicedToArray(_ref3, 2),
9937
+ key = _ref4[0],
9938
+ item = _ref4[1];
9939
+ return [key, deserializeSchema(item)];
9940
+ })), serialized.opt, false, false, serialized.description);
9078
9941
  case "array":
9079
9942
  return new ArraySchema(deserializeSchema(serialized.item), serialized.opt, [], false, false, serialized.description,
9080
9943
  // The preview closure cannot survive serialization; the render can.
@@ -9106,7 +9969,10 @@ function deserializeSchemaImpl(serialized) {
9106
9969
  altSchema: serialized.alt ? deserializeSchema(serialized.alt) : undefined
9107
9970
  } : undefined, false, false, serialized.description, (_serialized$jsonValue = serialized.jsonValues) !== null && _serialized$jsonValue !== void 0 ? _serialized$jsonValue : false,
9108
9971
  // The preview closure cannot survive serialization; the render can.
9109
- null, (_serialized$render9 = serialized.render) !== null && _serialized$render9 !== void 0 ? _serialized$render9 : null);
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
9973
+ // must be carried back: a deserialized schema that forgot it would walk
9974
+ // an external record as if its entries were local.
9975
+ (_serialized$external = serialized.external) !== null && _serialized$external !== void 0 ? _serialized$external : null);
9110
9976
  case "keyOf":
9111
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);
9112
9978
  case "route":
@@ -9668,6 +10534,11 @@ var Internal = {
9668
10534
  isJson: isJson,
9669
10535
  getJsonImport: getJsonImport,
9670
10536
  resolveJsonValues: resolveJsonValues,
10537
+ isExternal: isExternal,
10538
+ hasInlineExternalEntries: hasInlineExternalEntries,
10539
+ createExternalFileRef: createExternalFileRef,
10540
+ splitExternalFileRef: splitExternalFileRef,
10541
+ isExternalFileRef: isExternalFileRef,
9671
10542
  createValPathOfItem: createValPathOfItem,
9672
10543
  getSHA256Hash: getSHA256Hash,
9673
10544
  initSchema: initSchema,
@@ -9732,4 +10603,4 @@ function tryJsonParse(str) {
9732
10603
  }
9733
10604
  }
9734
10605
 
9735
- export { ArraySchema as A, BooleanSchema as B, ColorSchema as C, DEFAULT_CONTENT_HOST as D, isInlineRender as E, FATAL_ERROR_TYPES as F, GenericSelector as G, getSourcePathFromRoute as H, Internal as I, KeyOfSchema as K, LiteralSchema as L, ModuleFilePathSep as M, NumberSchema as N, ObjectSchema as O, PatchError as P, RecordSchema as R, Schema as S, UnionSchema as U, VAL_EXTENSION as V, _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, DEFAULT_VAL_REMOTE_HOST as j, derefPatch as k, StringSchema as l, modules as m, ImageSchema as n, FileSchema as o, DateSchema as p, CodeSchema as q, CODE_LANGUAGES as r, splitModuleFilePathAndModulePath as s, COLOR_FORMATS as t, DEFAULT_COLOR_FORMAT as u, DateTimeSchema as v, RouteSchema as w, RichTextSchema as x, deserializeSchema as y, previewScope as z };
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 };