@valbuild/core 0.102.0 → 0.105.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 (48) hide show
  1. package/dist/declarations/src/index.d.ts +13 -11
  2. package/dist/declarations/src/initSchema.d.ts +27 -14
  3. package/dist/declarations/src/initVal.d.ts +0 -6
  4. package/dist/declarations/src/module.d.ts +1 -4
  5. package/dist/declarations/src/preview.d.ts +98 -0
  6. package/dist/declarations/src/render.d.ts +29 -93
  7. package/dist/declarations/src/schema/array.d.ts +22 -23
  8. package/dist/declarations/src/schema/boolean.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 +19 -19
  13. package/dist/declarations/src/schema/image.d.ts +17 -8
  14. package/dist/declarations/src/schema/index.d.ts +7 -7
  15. package/dist/declarations/src/schema/keyOf.d.ts +2 -2
  16. package/dist/declarations/src/schema/literal.d.ts +2 -2
  17. package/dist/declarations/src/schema/number.d.ts +2 -2
  18. package/dist/declarations/src/schema/object.d.ts +2 -2
  19. package/dist/declarations/src/schema/record.d.ts +19 -31
  20. package/dist/declarations/src/schema/remote.d.ts +0 -10
  21. package/dist/declarations/src/schema/richtext.d.ts +2 -2
  22. package/dist/declarations/src/schema/route.d.ts +2 -2
  23. package/dist/declarations/src/schema/string.d.ts +28 -17
  24. package/dist/declarations/src/schema/union.d.ts +2 -2
  25. package/dist/declarations/src/selector/SelectorProxy.d.ts +9 -2
  26. package/dist/declarations/src/selector/index.d.ts +3 -7
  27. package/dist/declarations/src/source/file.d.ts +6 -24
  28. package/dist/declarations/src/source/index.d.ts +3 -7
  29. package/dist/declarations/src/source/json.d.ts +1 -1
  30. package/dist/declarations/src/source/media.d.ts +98 -0
  31. package/dist/declarations/src/source/remote.d.ts +0 -14
  32. package/dist/declarations/src/source/richtext.d.ts +5 -7
  33. package/dist/declarations/src/val/index.d.ts +2 -5
  34. package/dist/{index-30ecb49c.cjs.dev.js → index-730a5254.cjs.dev.js} +980 -901
  35. package/dist/{index-796fd204.esm.js → index-d7cc2231.esm.js} +980 -900
  36. package/dist/{index-ca1bbeb2.cjs.prod.js → index-e990b6ad.cjs.prod.js} +980 -901
  37. package/dist/{result-4bd63123.esm.js → result-daff1cae.esm.js} +1 -1
  38. package/dist/valbuild-core.cjs.dev.js +3 -4
  39. package/dist/valbuild-core.cjs.prod.js +3 -4
  40. package/dist/valbuild-core.esm.js +2 -2
  41. package/fp/dist/valbuild-core-fp.esm.js +1 -1
  42. package/package.json +1 -1
  43. package/patch/dist/valbuild-core-patch.cjs.dev.js +1 -1
  44. package/patch/dist/valbuild-core-patch.cjs.prod.js +1 -1
  45. package/patch/dist/valbuild-core-patch.esm.js +3 -3
  46. package/dist/declarations/src/selector/file.d.ts +0 -10
  47. package/dist/declarations/src/selector/image.d.ts +0 -3
  48. package/dist/declarations/src/source/image.d.ts +0 -19
@@ -1,4 +1,44 @@
1
- import { _ as _arrayLikeToArray, a as _unsupportedIterableToArray, b as _createForOfIteratorHelper, i as isErr, c as isOk, e as err, o as ok } from './result-4bd63123.esm.js';
1
+ import { _ as _unsupportedIterableToArray, a as _arrayLikeToArray, b as _createForOfIteratorHelper, i as isErr, c as isOk, e as err, o as ok } from './result-daff1cae.esm.js';
2
+
3
+ function _arrayWithHoles(r) {
4
+ if (Array.isArray(r)) return r;
5
+ }
6
+
7
+ function _iterableToArrayLimit(r, l) {
8
+ var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
9
+ if (null != t) {
10
+ var e,
11
+ n,
12
+ i,
13
+ u,
14
+ a = [],
15
+ f = !0,
16
+ o = !1;
17
+ try {
18
+ if (i = (t = t.call(r)).next, 0 === l) {
19
+ if (Object(t) !== t) return;
20
+ f = !1;
21
+ } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
22
+ } catch (r) {
23
+ o = !0, n = r;
24
+ } finally {
25
+ try {
26
+ if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
27
+ } finally {
28
+ if (o) throw n;
29
+ }
30
+ }
31
+ return a;
32
+ }
33
+ }
34
+
35
+ function _nonIterableRest() {
36
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
37
+ }
38
+
39
+ function _slicedToArray(r, e) {
40
+ return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
41
+ }
2
42
 
3
43
  function _arrayWithoutHoles(r) {
4
44
  if (Array.isArray(r)) return _arrayLikeToArray(r);
@@ -51,82 +91,69 @@ function _defineProperty(e, r, t) {
51
91
  }) : e[r] = t, e;
52
92
  }
53
93
 
54
- function ownKeys(e, r) {
55
- var t = Object.keys(e);
56
- if (Object.getOwnPropertySymbols) {
57
- var o = Object.getOwnPropertySymbols(e);
58
- r && (o = o.filter(function (r) {
59
- return Object.getOwnPropertyDescriptor(e, r).enumerable;
60
- })), t.push.apply(t, o);
61
- }
62
- return t;
94
+ function _classCallCheck(a, n) {
95
+ if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function");
63
96
  }
64
- function _objectSpread2(e) {
65
- for (var r = 1; r < arguments.length; r++) {
66
- var t = null != arguments[r] ? arguments[r] : {};
67
- r % 2 ? ownKeys(Object(t), !0).forEach(function (r) {
68
- _defineProperty(e, r, t[r]);
69
- }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
70
- Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
71
- });
97
+
98
+ function _defineProperties(e, r) {
99
+ for (var t = 0; t < r.length; t++) {
100
+ var o = r[t];
101
+ o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o);
72
102
  }
73
- return e;
103
+ }
104
+ function _createClass(e, r, t) {
105
+ return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", {
106
+ writable: !1
107
+ }), e;
74
108
  }
75
109
 
76
- function _arrayWithHoles(r) {
77
- if (Array.isArray(r)) return r;
110
+ function _getPrototypeOf(t) {
111
+ return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) {
112
+ return t.__proto__ || Object.getPrototypeOf(t);
113
+ }, _getPrototypeOf(t);
78
114
  }
79
115
 
80
- function _iterableToArrayLimit(r, l) {
81
- var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
82
- if (null != t) {
83
- var e,
84
- n,
85
- i,
86
- u,
87
- a = [],
88
- f = !0,
89
- o = !1;
90
- try {
91
- if (i = (t = t.call(r)).next, 0 === l) {
92
- if (Object(t) !== t) return;
93
- f = !1;
94
- } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
95
- } catch (r) {
96
- o = !0, n = r;
97
- } finally {
98
- try {
99
- if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
100
- } finally {
101
- if (o) throw n;
102
- }
103
- }
104
- return a;
105
- }
116
+ function _isNativeReflectConstruct() {
117
+ try {
118
+ var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
119
+ } catch (t) {}
120
+ return (_isNativeReflectConstruct = function () {
121
+ return !!t;
122
+ })();
106
123
  }
107
124
 
108
- function _nonIterableRest() {
109
- throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
125
+ function _assertThisInitialized(e) {
126
+ if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
127
+ return e;
110
128
  }
111
129
 
112
- function _slicedToArray(r, e) {
113
- return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
130
+ function _possibleConstructorReturn(t, e) {
131
+ if (e && ("object" == typeof e || "function" == typeof e)) return e;
132
+ if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined");
133
+ return _assertThisInitialized(t);
114
134
  }
115
135
 
116
- function _classCallCheck(a, n) {
117
- if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function");
136
+ function _callSuper(t, o, e) {
137
+ return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e));
118
138
  }
119
139
 
120
- function _defineProperties(e, r) {
121
- for (var t = 0; t < r.length; t++) {
122
- var o = r[t];
123
- o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o);
124
- }
140
+ function _setPrototypeOf(t, e) {
141
+ return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) {
142
+ return t.__proto__ = e, t;
143
+ }, _setPrototypeOf(t, e);
125
144
  }
126
- function _createClass(e, r, t) {
127
- return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", {
145
+
146
+ function _inherits(t, e) {
147
+ if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function");
148
+ t.prototype = Object.create(e && e.prototype, {
149
+ constructor: {
150
+ value: t,
151
+ writable: !0,
152
+ configurable: !0
153
+ }
154
+ }), Object.defineProperty(t, "prototype", {
128
155
  writable: !1
129
- }), e;
156
+ }), e && _setPrototypeOf(t, e);
130
157
  }
131
158
 
132
159
  // import { RemoteCompatibleSource, RemoteSource } from "../source/remote";
@@ -253,55 +280,6 @@ var Schema = /*#__PURE__*/function () {
253
280
 
254
281
  // TODO: SourceError<"Could not determine type of Schema">
255
282
 
256
- function _getPrototypeOf(t) {
257
- return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) {
258
- return t.__proto__ || Object.getPrototypeOf(t);
259
- }, _getPrototypeOf(t);
260
- }
261
-
262
- function _isNativeReflectConstruct() {
263
- try {
264
- var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
265
- } catch (t) {}
266
- return (_isNativeReflectConstruct = function () {
267
- return !!t;
268
- })();
269
- }
270
-
271
- function _assertThisInitialized(e) {
272
- if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
273
- return e;
274
- }
275
-
276
- function _possibleConstructorReturn(t, e) {
277
- if (e && ("object" == typeof e || "function" == typeof e)) return e;
278
- if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined");
279
- return _assertThisInitialized(t);
280
- }
281
-
282
- function _callSuper(t, o, e) {
283
- return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e));
284
- }
285
-
286
- function _setPrototypeOf(t, e) {
287
- return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) {
288
- return t.__proto__ = e, t;
289
- }, _setPrototypeOf(t, e);
290
- }
291
-
292
- function _inherits(t, e) {
293
- if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function");
294
- t.prototype = Object.create(e && e.prototype, {
295
- constructor: {
296
- value: t,
297
- writable: !0,
298
- configurable: !0
299
- }
300
- }), Object.defineProperty(t, "prototype", {
301
- writable: !1
302
- }), e && _setPrototypeOf(t, e);
303
- }
304
-
305
283
  // Identity symbols are registered in the global Symbol registry so that
306
284
  // multiple bundled copies of @valbuild/core (e.g. the editor SPA bundle vs.
307
285
  // the host Next.js bundle) resolve to the same Symbol instance. Without
@@ -343,73 +321,6 @@ function getSchema(selector) {
343
321
  return selector[GetSchema];
344
322
  }
345
323
 
346
- /* Branded extension types: file, remote, i18n */
347
- var VAL_EXTENSION = "_type";
348
-
349
- /**
350
- * A phantom type parameter is one that doesn't show up at runtime, but is checked statically (and only) at compile time.
351
- *
352
- * An example where this is useful is remote types, where the type of the remote source is known at compile time,
353
- * but the value is not there before it is fetched.
354
- *
355
- * @example
356
- * type Example<T> = string & PhantomType<T>;
357
- *
358
- **/
359
-
360
- var FILE_REF_PROP = "_ref";
361
- var FILE_REF_SUBTYPE_TAG = "_tag"; // TODO: used earlier by c.rt.image, when we remove c.rt we can remove this
362
-
363
- /**
364
- * A file source represents the path to a (local) file.
365
- *
366
- * It will be resolved into a Asset object.
367
- *
368
- */
369
-
370
- var initFile = function initFile(config) {
371
- var _config$files$directo, _config$files;
372
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
373
- (_config$files$directo = config === null || config === void 0 || (_config$files = config.files) === null || _config$files === void 0 ? void 0 : _config$files.directory) !== null && _config$files$directo !== void 0 ? _config$files$directo : "/public/val";
374
- function file(ref, metadata) {
375
- return _defineProperty(_defineProperty(_defineProperty({}, FILE_REF_PROP, ref), VAL_EXTENSION, "file"), "metadata", metadata);
376
- }
377
- return file;
378
- };
379
-
380
- // type Directory =
381
- // | (typeof config extends { files: { directory: infer D } } ? D : never)
382
- // | `/public/val`;
383
- // console.log("path", config);
384
- // const userSpecifiedDirectory: Directory = config ?? "/public/val";
385
-
386
- // const directory = userSpecifiedDirectory;
387
-
388
- // export function file<Metadata extends { readonly [key: string]: Json }>(
389
- // ref: `${typeof directory}/${string}`,
390
- // metadata: Metadata
391
- // ): FileSource<Metadata>;
392
- // export function file(
393
- // ref: `${typeof directory}/${string}`,
394
- // metadata?: undefined
395
- // ): FileSource<undefined>;
396
- // export function file<
397
- // Metadata extends { readonly [key: string]: Json } | undefined
398
- // >(
399
- // ref: `${typeof directory}/${string}`,
400
- // metadata?: Metadata
401
- // ): FileSource<Metadata> {
402
- // return {
403
- // [FILE_REF_PROP]: ref,
404
- // [VAL_EXTENSION]: "file",
405
- // metadata,
406
- // } as FileSource<Metadata>;
407
- // }
408
-
409
- function isFile(obj) {
410
- return _typeof(obj) === "object" && obj !== null && VAL_EXTENSION in obj && obj[VAL_EXTENSION] === "file" && FILE_REF_PROP in obj && typeof obj[FILE_REF_PROP] === "string";
411
- }
412
-
413
324
  function isVal(val) {
414
325
  return _typeof(val) === "object" && val !== null && val !== undefined && Path in val && "val" in val;
415
326
  }
@@ -436,290 +347,21 @@ function isVal(val) {
436
347
  */
437
348
 
438
349
  /**
439
- * The patchId of the parent patch, or "head" if there is no parent patch.
440
- */
441
-
442
- function getValPath(valOrSelector) {
443
- return valOrSelector[Path];
444
- }
445
-
446
- var FileSchema = /*#__PURE__*/function (_Schema) {
447
- function FileSchema(options) {
448
- var _this;
449
- var opt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
450
- var isRemote = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
451
- var customValidateFunctions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
452
- var moduleMetadata = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
453
- var isReadonly = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false;
454
- var isHidden = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : false;
455
- var description = arguments.length > 7 ? arguments[7] : undefined;
456
- _classCallCheck(this, FileSchema);
457
- _this = _callSuper(this, FileSchema);
458
- _this.options = options;
459
- _this.opt = opt;
460
- _this.isRemote = isRemote;
461
- _this.customValidateFunctions = customValidateFunctions;
462
- _this.moduleMetadata = moduleMetadata;
463
- _this.isReadonly = isReadonly;
464
- _this.isHidden = isHidden;
465
- _this.description = description;
466
- return _this;
467
- }
468
- _inherits(FileSchema, _Schema);
469
- return _createClass(FileSchema, [{
470
- key: "describe",
471
- value: function describe(description) {
472
- return new FileSchema(this.options, this.opt, this.isRemote, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined);
473
- }
474
- }, {
475
- key: "remote",
476
- value: function remote() {
477
- return new FileSchema(this.options, this.opt, true, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, this.isHidden, this.description);
478
- }
479
- }, {
480
- key: "validate",
481
- value: function validate(validationFunction) {
482
- return new FileSchema(this.options, this.opt, this.isRemote, [].concat(_toConsumableArray(this.customValidateFunctions), [validationFunction]), this.moduleMetadata, this.isReadonly, this.isHidden, this.description);
483
- }
484
- }, {
485
- key: "executeValidate",
486
- value: function executeValidate(path, src) {
487
- var customValidationErrors = this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
488
- path: path
489
- });
490
- if (this.opt && (src === null || src === undefined)) {
491
- return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : false;
492
- }
493
- if (src === null || src === undefined) {
494
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
495
- message: "Non-optional file was null or undefined.",
496
- value: src
497
- }]));
498
- }
499
- if (typeof src[FILE_REF_PROP] !== "string") {
500
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
501
- message: "File did not have a file reference string. Got: ".concat(_typeof(src[FILE_REF_PROP])),
502
- value: src
503
- }]));
504
- }
505
- if (this.isRemote && src[VAL_EXTENSION] !== "remote") {
506
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
507
- message: "Expected a remote file, but got a local file.",
508
- value: src,
509
- fixes: ["file:upload-remote"]
510
- }]));
511
- }
512
- if (this.isRemote && src[VAL_EXTENSION] === "remote") {
513
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
514
- message: "Remote file was not checked.",
515
- value: src,
516
- fixes: ["file:check-remote"]
517
- }]));
518
- }
519
- if (!this.isRemote && src[VAL_EXTENSION] === "remote") {
520
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
521
- message: "Expected locale file, but found remote.",
522
- value: src,
523
- fixes: ["file:download-remote"]
524
- }]));
525
- }
526
- if (src[VAL_EXTENSION] !== "file") {
527
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
528
- message: "File did not have the valid file extension type. Got: ".concat(src[VAL_EXTENSION]),
529
- value: src
530
- }]));
531
- }
532
- var _ref8 = this.options || {},
533
- accept = _ref8.accept;
534
- var _ref9 = src.metadata || {},
535
- mimeType = _ref9.mimeType;
536
- if (accept && mimeType && !mimeType.includes("/")) {
537
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
538
- message: "Invalid mime type format. Got: ".concat(mimeType),
539
- value: src
540
- }]));
541
- }
542
- if (accept && mimeType && mimeType.includes("/")) {
543
- var acceptedTypes = accept.split(",").map(function (type) {
544
- return type.trim();
545
- });
546
- var isValidMimeType = acceptedTypes.some(function (acceptedType) {
547
- if (acceptedType === "*/*") {
548
- return true;
549
- }
550
- if (acceptedType.endsWith("/*")) {
551
- var baseType = acceptedType.slice(0, -2);
552
- return mimeType.startsWith(baseType);
553
- }
554
- return acceptedType === mimeType;
555
- });
556
- if (!isValidMimeType) {
557
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
558
- message: "Mime type mismatch. Found '".concat(mimeType, "' but schema accepts '").concat(accept, "'"),
559
- value: src
560
- }]));
561
- }
562
- }
563
- var fileMimeType = Internal.filenameToMimeType(src[FILE_REF_PROP]);
564
- if (!fileMimeType) {
565
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
566
- message: "Could not determine mime type from file extension. Got: ".concat(src[FILE_REF_PROP]),
567
- value: src
568
- }]));
569
- }
570
- if (fileMimeType !== mimeType) {
571
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
572
- message: "Mime type and file extension not matching. Mime type is '".concat(mimeType, "' but file extension is '").concat(fileMimeType, "'"),
573
- value: src
574
- }]));
575
- }
576
- if (src.metadata) {
577
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
578
- message: "Found metadata, but it could not be validated. File metadata must be an object with the mimeType.",
579
- // These validation errors will have to be picked up by logic outside of this package and revalidated. Reasons: 1) we have to read files to verify the metadata, which is handled differently in different runtimes (Browser, QuickJS, Node.js); 2) we want to keep this package dependency free.
580
- value: src,
581
- fixes: ["file:check-metadata"]
582
- }]));
583
- }
584
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
585
- message: "Missing File metadata.",
586
- value: src,
587
- fixes: ["file:add-metadata"]
588
- }]));
589
- }
590
- }, {
591
- key: "executeAssert",
592
- value: function executeAssert(path, src) {
593
- if (this.opt && src === null) {
594
- return {
595
- success: true,
596
- data: src
597
- };
598
- }
599
- if (src === null) {
600
- return {
601
- success: false,
602
- errors: _defineProperty({}, path, [{
603
- message: "Expected 'object', got 'null'",
604
- typeError: true
605
- }])
606
- };
607
- }
608
- if (_typeof(src) !== "object") {
609
- return {
610
- success: false,
611
- errors: _defineProperty({}, path, [{
612
- message: "Expected object, got '".concat(_typeof(src), "'"),
613
- typeError: true
614
- }])
615
- };
616
- }
617
- if (!(FILE_REF_PROP in src)) {
618
- return {
619
- success: false,
620
- errors: _defineProperty({}, path, [{
621
- message: "Value of this schema must use: 'c.file' (error type: missing_ref_prop)",
622
- typeError: true
623
- }])
624
- };
625
- }
626
- if (!(VAL_EXTENSION in src && src[VAL_EXTENSION] === "file")) {
627
- return {
628
- success: false,
629
- errors: _defineProperty({}, path, [{
630
- message: "Value of this schema must use: 'c.file' (error type: missing_file_extension)",
631
- typeError: true
632
- }])
633
- };
634
- }
635
- return {
636
- success: true,
637
- data: src
638
- };
639
- }
640
- }, {
641
- key: "nullable",
642
- value: function nullable() {
643
- return new FileSchema(this.options, true, this.isRemote, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, this.isHidden, this.description);
644
- }
645
- }, {
646
- key: "readonly",
647
- value: function readonly() {
648
- return new FileSchema(this.options, this.opt, this.isRemote, this.customValidateFunctions, this.moduleMetadata, true, this.isHidden, this.description);
649
- }
650
- }, {
651
- key: "hidden",
652
- value: function hidden() {
653
- return new FileSchema(this.options, this.opt, this.isRemote, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, true, this.description);
654
- }
655
- }, {
656
- key: "executeCustomValidateAt",
657
- value: function executeCustomValidateAt(path, src) {
658
- return this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
659
- path: path
660
- });
661
- }
662
- }, {
663
- key: "executeSerialize",
664
- value: function executeSerialize() {
665
- var _this$customValidateF;
666
- var modulePaths = this.moduleMetadata ? Object.keys(this.moduleMetadata) : [];
667
- return {
668
- type: "file",
669
- options: this.options,
670
- opt: this.opt,
671
- remote: this.isRemote,
672
- customValidate: this.customValidateFunctions && ((_this$customValidateF = this.customValidateFunctions) === null || _this$customValidateF === void 0 ? void 0 : _this$customValidateF.length) > 0,
673
- referencedModule: modulePaths.length > 0 ? modulePaths[0] : undefined,
674
- readonly: this.isReadonly,
675
- hidden: this.isHidden,
676
- description: this.description
677
- };
678
- }
679
- }, {
680
- key: "executeRender",
681
- value: function executeRender() {
682
- return {};
683
- }
684
- }]);
685
- }(Schema);
686
- var file = function file(options) {
687
- var isModule = !!options && !!Internal.getValPath(options);
688
- if (isModule) {
689
- var allModules = {};
690
- for (var _i = 0, _arr = [options]; _i < _arr.length; _i++) {
691
- var valModule = _arr[_i];
692
- var modulePath = getValPath(valModule);
693
- if (modulePath === undefined) {
694
- throw new Error("Invalid argument passed to s.file(). Expected a ValModule constructed through c.define, but got an object without a valid module path.");
695
- }
696
- allModules[modulePath] = getSource(valModule);
697
- }
698
- return new FileSchema({}, false, false, [], allModules);
699
- }
700
- return new FileSchema(options);
701
- };
702
- function convertFileSource(src) {
703
- // TODO: /public should be configurable
704
- if (!src[FILE_REF_PROP].startsWith("/public")) {
705
- return {
706
- url: src[FILE_REF_PROP] + (src.patch_id ? "?patch_id=".concat(src["patch_id"]) : ""),
707
- metadata: src.metadata
708
- };
709
- }
710
- if (src.patch_id) {
711
- return {
712
- url: "/api/val/files" + src[FILE_REF_PROP] + "?patch_id=".concat(src["patch_id"]),
713
- metadata: src.metadata
714
- };
715
- }
716
- return {
717
- url: src[FILE_REF_PROP].slice("/public".length),
718
- metadata: src.metadata
719
- };
350
+ * The patchId of the parent patch, or "head" if there is no parent patch.
351
+ */
352
+
353
+ function getValPath(valOrSelector) {
354
+ return valOrSelector[Path];
720
355
  }
721
356
 
722
- function createValPathOfItem(arrayPath, prop) {
357
+ function createValPathOfItem(
358
+ /**
359
+ * `ModuleFilePath` is accepted because the no-separator branch below is
360
+ * exactly that case: a path with no `?p=` yet gets one, and the key becomes
361
+ * the first module-path segment. Callers walking a module from its root had
362
+ * to widen the type themselves, and hand-rolled the concatenation instead.
363
+ */
364
+ arrayPath, prop) {
723
365
  if (_typeof(prop) === "symbol") {
724
366
  throw Error("Cannot create val path of array item with symbol prop: ".concat(prop.toString()));
725
367
  }
@@ -746,6 +388,28 @@ function unsafeCreateSourcePath(path, itemKey) {
746
388
  return "".concat(path).concat(Internal.ModuleFilePathSep).concat(JSON.stringify(itemKey));
747
389
  }
748
390
 
391
+ function ownKeys(e, r) {
392
+ var t = Object.keys(e);
393
+ if (Object.getOwnPropertySymbols) {
394
+ var o = Object.getOwnPropertySymbols(e);
395
+ r && (o = o.filter(function (r) {
396
+ return Object.getOwnPropertyDescriptor(e, r).enumerable;
397
+ })), t.push.apply(t, o);
398
+ }
399
+ return t;
400
+ }
401
+ function _objectSpread2(e) {
402
+ for (var r = 1; r < arguments.length; r++) {
403
+ var t = null != arguments[r] ? arguments[r] : {};
404
+ r % 2 ? ownKeys(Object(t), !0).forEach(function (r) {
405
+ _defineProperty(e, r, t[r]);
406
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
407
+ Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
408
+ });
409
+ }
410
+ return e;
411
+ }
412
+
749
413
  var StringSchema = /*#__PURE__*/function (_Schema) {
750
414
  function StringSchema(options) {
751
415
  var _this;
@@ -917,10 +581,10 @@ var StringSchema = /*#__PURE__*/function (_Schema) {
917
581
  }, {
918
582
  key: "executeSerialize",
919
583
  value: function executeSerialize() {
920
- var _this$options4, _this$options5, _this$options6, _this$customValidateF, _this$customValidateF2;
584
+ var _this$renderInput, _this$options4, _this$options5, _this$options6, _this$customValidateF, _this$customValidateF2;
921
585
  return {
922
586
  type: "string",
923
- render: this.renderInput ? true : undefined,
587
+ render: (_this$renderInput = this.renderInput) !== null && _this$renderInput !== void 0 ? _this$renderInput : undefined,
924
588
  options: {
925
589
  maxLength: (_this$options4 = this.options) === null || _this$options4 === void 0 ? void 0 : _this$options4.maxLength,
926
590
  minLength: (_this$options5 = this.options) === null || _this$options5 === void 0 ? void 0 : _this$options5.minLength,
@@ -939,36 +603,28 @@ var StringSchema = /*#__PURE__*/function (_Schema) {
939
603
  description: this.description
940
604
  };
941
605
  }
606
+
607
+ /**
608
+ * How this field is laid out in the editor: a textarea, or a code editor for
609
+ * the given language.
610
+ *
611
+ * Static configuration, not a callback — see `render.ts`. What a CONTAINER
612
+ * shows for its items is a `preview`, which is a different thing entirely.
613
+ */
942
614
  }, {
943
615
  key: "render",
944
616
  value: function render(input) {
945
617
  return new StringSchema(this.options, this.opt, this.isRaw, this.customValidateFunctions, input, this.isReadonly, this.isHidden, this.description);
946
618
  }
619
+
620
+ /**
621
+ * Nothing: a string has no items, so there is nothing to preview. Its layout
622
+ * is a `render`, which travels in the serialized schema instead of through
623
+ * this pipeline.
624
+ */
947
625
  }, {
948
- key: "executeRender",
949
- value: function executeRender(sourcePath, src,
950
- // Accepted and unused: a string's render is a static layout hint
951
- // (`{as:"textarea"}` / `{as:"code",language}`) with no closure behind it, so
952
- // there is nothing a scope could prune. Declared so the signature is uniform
953
- // across every schema rather than something a reader has to check.
954
- _scope) {
955
- if (this.renderInput) {
956
- if (this.renderInput.as === "code") {
957
- return _defineProperty({}, sourcePath, {
958
- status: "success",
959
- data: {
960
- layout: this.renderInput.as,
961
- language: this.renderInput.language
962
- }
963
- });
964
- }
965
- return _defineProperty({}, sourcePath, {
966
- status: "success",
967
- data: {
968
- layout: this.renderInput.as
969
- }
970
- });
971
- }
626
+ key: "executePreview",
627
+ value: function executePreview() {
972
628
  return {};
973
629
  }
974
630
  }]);
@@ -1163,8 +819,8 @@ var ObjectSchema = /*#__PURE__*/function (_Schema) {
1163
819
  };
1164
820
  }
1165
821
  }, {
1166
- key: "executeRender",
1167
- value: function executeRender(sourcePath, src, scope) {
822
+ key: "executePreview",
823
+ value: function executePreview(sourcePath, src, scope) {
1168
824
  var res = {};
1169
825
  if (src === null) {
1170
826
  return res;
@@ -1175,13 +831,13 @@ var ObjectSchema = /*#__PURE__*/function (_Schema) {
1175
831
  continue;
1176
832
  }
1177
833
  var subPath = unsafeCreateSourcePath(sourcePath, _key3);
1178
- // An object produces no render of its own, so it is pure recursion — and
834
+ // An object produces no preview of its own, so it is pure recursion — and
1179
835
  // pruning it is the whole contribution: a field deep in one branch stops
1180
- // paying for every sibling branch's renders.
836
+ // paying for every sibling branch's previews.
1181
837
  if (scope !== undefined && !scope.wantsUnder(subPath)) {
1182
838
  continue;
1183
839
  }
1184
- var itemResult = this.items[_key3]["executeRender"](subPath, itemSrc, scope);
840
+ var itemResult = this.items[_key3]["executePreview"](subPath, itemSrc, scope);
1185
841
  for (var keyS in itemResult) {
1186
842
  var _key4 = keyS;
1187
843
  res[_key4] = itemResult[_key4];
@@ -1208,7 +864,7 @@ var ArraySchema = /*#__PURE__*/function (_Schema) {
1208
864
  var isReadonly = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
1209
865
  var isHidden = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
1210
866
  var description = arguments.length > 5 ? arguments[5] : undefined;
1211
- var renderInput = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null;
867
+ var previewInput = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null;
1212
868
  _classCallCheck(this, ArraySchema);
1213
869
  _this = _callSuper(this, ArraySchema);
1214
870
  _this.item = item;
@@ -1217,19 +873,19 @@ var ArraySchema = /*#__PURE__*/function (_Schema) {
1217
873
  _this.isReadonly = isReadonly;
1218
874
  _this.isHidden = isHidden;
1219
875
  _this.description = description;
1220
- _this.renderInput = renderInput;
876
+ _this.previewInput = previewInput;
1221
877
  return _this;
1222
878
  }
1223
879
  _inherits(ArraySchema, _Schema);
1224
880
  return _createClass(ArraySchema, [{
1225
881
  key: "describe",
1226
882
  value: function describe(description) {
1227
- return new ArraySchema(this.item, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput);
883
+ return new ArraySchema(this.item, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.previewInput);
1228
884
  }
1229
885
  }, {
1230
886
  key: "validate",
1231
887
  value: function validate(validationFunction) {
1232
- return new ArraySchema(this.item, this.opt, [].concat(_toConsumableArray(this.customValidateFunctions), [validationFunction]), this.isReadonly, this.isHidden, this.description, this.renderInput);
888
+ return new ArraySchema(this.item, this.opt, [].concat(_toConsumableArray(this.customValidateFunctions), [validationFunction]), this.isReadonly, this.isHidden, this.description, this.previewInput);
1233
889
  }
1234
890
  }, {
1235
891
  key: "executeValidate",
@@ -1296,17 +952,17 @@ var ArraySchema = /*#__PURE__*/function (_Schema) {
1296
952
  }, {
1297
953
  key: "nullable",
1298
954
  value: function nullable() {
1299
- return new ArraySchema(this.item, true, [], this.isReadonly, this.isHidden, this.description, this.renderInput);
955
+ return new ArraySchema(this.item, true, [], this.isReadonly, this.isHidden, this.description, this.previewInput);
1300
956
  }
1301
957
  }, {
1302
958
  key: "readonly",
1303
959
  value: function readonly() {
1304
- return new ArraySchema(this.item, this.opt, this.customValidateFunctions, true, this.isHidden, this.description, this.renderInput);
960
+ return new ArraySchema(this.item, this.opt, this.customValidateFunctions, true, this.isHidden, this.description, this.previewInput);
1305
961
  }
1306
962
  }, {
1307
963
  key: "hidden",
1308
964
  value: function hidden() {
1309
- return new ArraySchema(this.item, this.opt, this.customValidateFunctions, this.isReadonly, true, this.description, this.renderInput);
965
+ return new ArraySchema(this.item, this.opt, this.customValidateFunctions, this.isReadonly, true, this.description, this.previewInput);
1310
966
  }
1311
967
  }, {
1312
968
  key: "executeCustomValidateAt",
@@ -1323,7 +979,7 @@ var ArraySchema = /*#__PURE__*/function (_Schema) {
1323
979
  type: "array",
1324
980
  item: this.item["executeSerialize"](),
1325
981
  opt: this.opt,
1326
- render: this.renderInput ? true : undefined,
982
+ preview: this.previewInput ? true : undefined,
1327
983
  customValidate: this.customValidateFunctions && ((_this$customValidateF = this.customValidateFunctions) === null || _this$customValidateF === void 0 ? void 0 : _this$customValidateF.length) > 0,
1328
984
  readonly: this.isReadonly,
1329
985
  hidden: this.isHidden,
@@ -1331,8 +987,8 @@ var ArraySchema = /*#__PURE__*/function (_Schema) {
1331
987
  };
1332
988
  }
1333
989
  }, {
1334
- key: "executeRender",
1335
- value: function executeRender(sourcePath, src, scope) {
990
+ key: "executePreview",
991
+ value: function executePreview(sourcePath, src, scope) {
1336
992
  var res = {};
1337
993
  if (src === null) {
1338
994
  return res;
@@ -1347,26 +1003,18 @@ var ArraySchema = /*#__PURE__*/function (_Schema) {
1347
1003
  if (scope !== undefined && !scope.wantsUnder(subPath)) {
1348
1004
  continue;
1349
1005
  }
1350
- var itemResult = this.item["executeRender"](subPath, itemSrc, scope);
1006
+ var itemResult = this.item["executePreview"](subPath, itemSrc, scope);
1351
1007
  for (var keyS in itemResult) {
1352
1008
  var _key = keyS;
1353
1009
  res[_key] = itemResult[_key];
1354
1010
  }
1355
1011
  }
1356
- if (this.renderInput) {
1357
- var _this$renderInput = this.renderInput,
1358
- select = _this$renderInput.select,
1359
- layout = _this$renderInput.as;
1360
- if (layout !== "list") {
1361
- res[sourcePath] = {
1362
- status: "error",
1363
- message: "Unknown layout type: " + layout
1364
- };
1365
- }
1012
+ if (this.previewInput) {
1013
+ var select = this.previewInput;
1366
1014
  // The whole list when the LIST is what is being shown; only the wanted
1367
- // rows when it is not. `select` is the user's closure and the real expense
1368
- // — a list view asks for the container and gets every row, a single field
1369
- // asks for its own path and costs one call.
1015
+ // rows when it is not. The user's closure is the real expense — a list
1016
+ // view asks for the container and gets every row, a single field asks for
1017
+ // its own path and costs one call.
1370
1018
  // Non-null once, as a value, rather than a boolean the compiler cannot
1371
1019
  // tie back to `scope`: no scope and a scope that wants this exact path
1372
1020
  // both mean the whole list, and anything else is a window.
@@ -1376,10 +1024,10 @@ var ArraySchema = /*#__PURE__*/function (_Schema) {
1376
1024
  if (window !== null && !window.wantsUnder(unsafeCreateSourcePath(sourcePath, index))) {
1377
1025
  continue;
1378
1026
  }
1379
- // Per ITEM, not per list, matching what `record` already does: `select`
1380
- // is user code, and one row whose data trips it up must not take out the
1381
- // whole list. Before scoping, one throwing row produced an error at the
1382
- // container and no items at all.
1027
+ // Per ITEM, not per list, matching what `record` already does: the
1028
+ // closure is user code, and one row whose data trips it up must not take
1029
+ // out the whole list. Before scoping, one throwing row produced an error
1030
+ // at the container and no items at all.
1383
1031
  try {
1384
1032
  // NB NB: display is actually defined by the user
1385
1033
  var _select = select({
@@ -1403,7 +1051,6 @@ var ArraySchema = /*#__PURE__*/function (_Schema) {
1403
1051
  res[sourcePath] = {
1404
1052
  status: "success",
1405
1053
  data: {
1406
- layout: "list",
1407
1054
  parent: "array",
1408
1055
  items: items
1409
1056
  }
@@ -1411,10 +1058,18 @@ var ArraySchema = /*#__PURE__*/function (_Schema) {
1411
1058
  }
1412
1059
  return res;
1413
1060
  }
1061
+
1062
+ /**
1063
+ * What the editor shows for each ITEM of this array: a title, and optionally a
1064
+ * subtitle and an image.
1065
+ *
1066
+ * `select` is your own code over the item's source, so it is run on demand for
1067
+ * the rows that are actually being looked at — see `PreviewScope`.
1068
+ */
1414
1069
  }, {
1415
- key: "render",
1416
- value: function render(input) {
1417
- return new ArraySchema(this.item, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, input);
1070
+ key: "preview",
1071
+ value: function preview(select) {
1072
+ return new ArraySchema(this.item, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, select);
1418
1073
  }
1419
1074
  }]);
1420
1075
  }(Schema);
@@ -1546,8 +1201,8 @@ var LiteralSchema = /*#__PURE__*/function (_Schema) {
1546
1201
  };
1547
1202
  }
1548
1203
  }, {
1549
- key: "executeRender",
1550
- value: function executeRender() {
1204
+ key: "executePreview",
1205
+ value: function executePreview() {
1551
1206
  return {};
1552
1207
  }
1553
1208
  }]);
@@ -1980,8 +1635,8 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
1980
1635
  };
1981
1636
  }
1982
1637
  }, {
1983
- key: "executeRender",
1984
- value: function executeRender(sourcePath, src, scope) {
1638
+ key: "executePreview",
1639
+ value: function executePreview(sourcePath, src, scope) {
1985
1640
  var res = {};
1986
1641
  if (src === null) {
1987
1642
  return res;
@@ -2003,7 +1658,7 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
2003
1658
  return false;
2004
1659
  });
2005
1660
  if (thisSchema) {
2006
- var itemResult = thisSchema["executeRender"](sourcePath, src, scope);
1661
+ var itemResult = thisSchema["executePreview"](sourcePath, src, scope);
2007
1662
  for (var keyS in itemResult) {
2008
1663
  var _key3 = keyS;
2009
1664
  res[_key3] = itemResult[_key3];
@@ -2030,6 +1685,170 @@ var union = function union(key) {
2030
1685
  return new UnionSchema(key, objects);
2031
1686
  };
2032
1687
 
1688
+ var RegEx = /^(https?:\/\/[^/]+)\/file\/p\/([^/]+)\/b\/([^/]+)\/v\/([^/]+)\/h\/([^/]+)\/f\/([^/]+)\/p\/(.+)$/;
1689
+ function splitRemoteRef(ref) {
1690
+ if (ref[0] === "/") {
1691
+ return {
1692
+ status: "error",
1693
+ error: "Not a remote ref: " + ref
1694
+ };
1695
+ }
1696
+ var match = ref.match(RegEx);
1697
+ if (!match) {
1698
+ return {
1699
+ status: "error",
1700
+ error: "Invalid remote ref: " + ref
1701
+ };
1702
+ }
1703
+ if (match[7].indexOf("public/") !== 0) {
1704
+ return {
1705
+ status: "error",
1706
+ error: "Invalid remote ref: " + ref
1707
+ };
1708
+ }
1709
+ if (match[7].split("/").some(function (segment) {
1710
+ return segment === "." || segment === "..";
1711
+ })) {
1712
+ return {
1713
+ status: "error",
1714
+ error: "Invalid remote ref: " + ref
1715
+ };
1716
+ }
1717
+ return {
1718
+ status: "success",
1719
+ remoteHost: match[1],
1720
+ projectId: match[2],
1721
+ bucket: match[3],
1722
+ version: match[4],
1723
+ validationHash: match[5],
1724
+ fileHash: match[6],
1725
+ filePath: match[7]
1726
+ };
1727
+ }
1728
+
1729
+ /** What must stay in frame when a page crops an image. */
1730
+
1731
+ /**
1732
+ * The authored fields of a gallery-backed image (`s.image(galleryModule)`):
1733
+ * `width`/`height`/`mimeType` live in the gallery, so they are not repeated
1734
+ * here. One place per fact.
1735
+ */
1736
+
1737
+ /**
1738
+ * The structural supertype of every media source.
1739
+ *
1740
+ * It is a named member of the `Source` / `SelectorSource` unions rather than
1741
+ * "just an object" because `SourceObject` is `{[key: string]: Source}` and
1742
+ * `Source` excludes `undefined` — an object with optional properties does not
1743
+ * satisfy it.
1744
+ */
1745
+
1746
+ /** A path is remote unless it is under `/public`. */
1747
+ function isRemoteMediaPath(path) {
1748
+ return !path.startsWith("/public");
1749
+ }
1750
+
1751
+ /**
1752
+ * Where the bytes of a media source are actually served from.
1753
+ *
1754
+ * Two states, and conflating them is the recurring bug: uncommitted bytes live
1755
+ * in the patch directory and are served by the API with the `patch_id` that put
1756
+ * them there; committed bytes live at the path itself, with `/public` stripped.
1757
+ */
1758
+ function mediaUrl(src) {
1759
+ var path = src.path;
1760
+ // TODO: /public should be configurable
1761
+ if (!isRemoteMediaPath(path)) {
1762
+ if (src.patch_id) {
1763
+ return "/api/val/files".concat(path, "?patch_id=").concat(src.patch_id);
1764
+ }
1765
+ return path.slice("/public".length);
1766
+ }
1767
+ if (src.patch_id) {
1768
+ var splitRemoteRefRes = splitRemoteRef(path);
1769
+ if (splitRemoteRefRes.status === "success") {
1770
+ return "/api/val/files/".concat(splitRemoteRefRes.filePath, "?patch_id=").concat(src.patch_id, "&remote=true&ref=").concat(encodeURIComponent(path));
1771
+ }
1772
+ // Not a remote ref either — an absolute path outside /public. Serve it as
1773
+ // written, but keep the patch id so a draft still resolves.
1774
+ return "".concat(path, "?patch_id=").concat(src.patch_id);
1775
+ }
1776
+ return path;
1777
+ }
1778
+
1779
+ /**
1780
+ * A media source plus the URL its bytes are served from.
1781
+ *
1782
+ * `url` is the only generated field: everything else the consumer sees was
1783
+ * either authored or filled in from the gallery.
1784
+ */
1785
+ function resolveMedia(src) {
1786
+ return _objectSpread2(_objectSpread2({}, src), {}, {
1787
+ url: mediaUrl(src)
1788
+ });
1789
+ }
1790
+ function isMediaSchema(schema) {
1791
+ return _typeof(schema) === "object" && schema !== null && "type" in schema && (schema.type === "image" || schema.type === "file");
1792
+ }
1793
+
1794
+ /**
1795
+ * Fill in what a gallery-backed field does not carry itself.
1796
+ *
1797
+ * `s.image(galleryModule)` stores only `{path, alt?, hotspot?}` — the
1798
+ * dimensions and mime type live in the gallery module, keyed by path. This is
1799
+ * the single implementation of that lookup; core, stega/RSC and the Studio all
1800
+ * call it rather than each rolling their own.
1801
+ *
1802
+ * `alt` is filled in too, because a gallery holds the alt text an editor typed
1803
+ * once for a file used in several places — but only when the field does not
1804
+ * have its own, so a per-image override wins. A gallery whose `alt` schema is a
1805
+ * locale record holds an object rather than a string; that is left alone rather
1806
+ * than copied into a field typed `string`, and making the override
1807
+ * locale-shaped is a separate change.
1808
+ *
1809
+ * The double lookup is load-bearing: a remote gallery keys its entries by the
1810
+ * remote URL while the file itself stays on disk under its local path.
1811
+ */
1812
+ function fillFromGallery(src, schema, getModuleSource) {
1813
+ if (!isMediaSchema(schema) || !schema.referencedModule) {
1814
+ return src;
1815
+ }
1816
+ var moduleSource = getModuleSource(schema.referencedModule);
1817
+ if (!moduleSource || _typeof(moduleSource) !== "object" || Array.isArray(moduleSource)) {
1818
+ return src;
1819
+ }
1820
+ var entries = moduleSource;
1821
+ var key = src.path in entries ? src.path : null;
1822
+ if (key === null) {
1823
+ var splitRemoteRefRes = splitRemoteRef(src.path);
1824
+ if (splitRemoteRefRes.status === "success" && splitRemoteRefRes.filePath in entries) {
1825
+ key = splitRemoteRefRes.filePath;
1826
+ }
1827
+ }
1828
+ if (key === null) {
1829
+ return src;
1830
+ }
1831
+ var entry = entries[key];
1832
+ if (!entry || _typeof(entry) !== "object" || Array.isArray(entry)) {
1833
+ return src;
1834
+ }
1835
+ var _ref = entry,
1836
+ width = _ref.width,
1837
+ height = _ref.height,
1838
+ mimeType = _ref.mimeType,
1839
+ alt = _ref.alt;
1840
+ var hasOwnAlt = typeof src.alt === "string";
1841
+ return _objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, src), width !== undefined ? {
1842
+ width: width
1843
+ } : {}), height !== undefined ? {
1844
+ height: height
1845
+ } : {}), mimeType !== undefined ? {
1846
+ mimeType: mimeType
1847
+ } : {}), !hasOwnAlt && typeof alt === "string" ? {
1848
+ alt: alt
1849
+ } : {});
1850
+ }
1851
+
2033
1852
  var ImageSchema = /*#__PURE__*/function (_Schema) {
2034
1853
  function ImageSchema(options) {
2035
1854
  var _this;
@@ -2071,7 +1890,7 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
2071
1890
  }, {
2072
1891
  key: "executeValidate",
2073
1892
  value: function executeValidate(path, src) {
2074
- var _src$metadata$mimeTyp, _src$metadata;
1893
+ var _src$mimeType;
2075
1894
  var customValidationErrors = this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
2076
1895
  path: path
2077
1896
  });
@@ -2084,42 +1903,68 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
2084
1903
  value: src
2085
1904
  }]));
2086
1905
  }
2087
- if (this.isRemote && src[VAL_EXTENSION] !== "remote") {
1906
+ if (typeof src.path !== "string") {
1907
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
1908
+ message: "Image did not have a path string. Got: ".concat(_typeof(src.path)),
1909
+ value: src
1910
+ }]));
1911
+ }
1912
+ // Remote-ness is a property of the path, not of a marker on the value:
1913
+ // anything outside /public is remote.
1914
+ var isRemotePath = isRemoteMediaPath(src.path);
1915
+ if (this.isRemote && !isRemotePath) {
2088
1916
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2089
1917
  message: "Expected a remote image, but got a local image.",
2090
1918
  value: src,
2091
1919
  fixes: ["image:upload-remote"]
2092
1920
  }]));
2093
1921
  }
2094
- if (this.isRemote && src[VAL_EXTENSION] === "remote") {
1922
+ if (this.isRemote && isRemotePath) {
2095
1923
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2096
1924
  message: "Remote image was not checked.",
2097
1925
  value: src,
2098
1926
  fixes: ["image:check-remote"]
2099
1927
  }]));
2100
1928
  }
2101
- if (!this.isRemote && src[VAL_EXTENSION] === "remote") {
1929
+ if (!this.isRemote && isRemotePath) {
2102
1930
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2103
- message: "Expected locale image, but found remote.",
1931
+ message: "Expected local image, but found remote.",
2104
1932
  value: src,
2105
1933
  fixes: ["image:download-remote"]
2106
1934
  }]));
2107
1935
  }
2108
- if (typeof src[FILE_REF_PROP] !== "string") {
2109
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2110
- message: "Image did not have a file reference string. Got: ".concat(_typeof(src[FILE_REF_PROP])),
2111
- value: src
2112
- }]));
1936
+ if (src.hotspot !== undefined) {
1937
+ if (_typeof(src.hotspot) !== "object" || src.hotspot === null || typeof src.hotspot.x !== "number" || typeof src.hotspot.y !== "number") {
1938
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
1939
+ message: "Hotspot must be an object with x and y as numbers.",
1940
+ value: src
1941
+ }]));
1942
+ }
2113
1943
  }
2114
- if (src[VAL_EXTENSION] !== "file") {
2115
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2116
- message: "Image did not have the valid file extension type. Got: ".concat(src[VAL_EXTENSION]),
2117
- value: src
2118
- }]));
1944
+ var galleryEntries = this.galleryEntries();
1945
+ if (galleryEntries) {
1946
+ // The dimensions and mime type of a gallery image are stored once, in the
1947
+ // gallery. Repeating them on the field is how the two get to disagree.
1948
+ var repeated = ["width", "height", "mimeType"].filter(function (key) {
1949
+ return src[key] !== undefined;
1950
+ });
1951
+ if (repeated.length > 0) {
1952
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
1953
+ message: "An image from a gallery must not carry its own ".concat(repeated.join(", "), ": ").concat(repeated.length === 1 ? "it is" : "they are", " stored in the gallery module."),
1954
+ value: src
1955
+ }]));
1956
+ }
1957
+ if (!(src.path in galleryEntries)) {
1958
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
1959
+ message: "The gallery does not have an image at '".concat(src.path, "'."),
1960
+ value: src
1961
+ }]));
1962
+ }
1963
+ return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : false;
2119
1964
  }
2120
- var _ref8 = this.options || {},
2121
- accept = _ref8.accept;
2122
- var mimeType = (_src$metadata$mimeTyp = (_src$metadata = src.metadata) === null || _src$metadata === void 0 ? void 0 : _src$metadata.mimeType) !== null && _src$metadata$mimeTyp !== void 0 ? _src$metadata$mimeTyp : "";
1965
+ var _ref1 = this.options || {},
1966
+ accept = _ref1.accept;
1967
+ var mimeType = (_src$mimeType = src.mimeType) !== null && _src$mimeType !== void 0 ? _src$mimeType : "";
2123
1968
  if (accept && mimeType && !mimeType.includes("/")) {
2124
1969
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2125
1970
  message: "Invalid mime type format. Got: '".concat(mimeType, "'"),
@@ -2149,10 +1994,10 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
2149
1994
  }]));
2150
1995
  }
2151
1996
  }
2152
- var fileMimeType = Internal.filenameToMimeType(src[FILE_REF_PROP]);
1997
+ var fileMimeType = Internal.filenameToMimeType(src.path);
2153
1998
  if (!fileMimeType) {
2154
1999
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2155
- message: "Could not determine mime type from file extension. Got: ".concat(src[FILE_REF_PROP]),
2000
+ message: "Could not determine mime type from file extension. Got: ".concat(src.path),
2156
2001
  value: src,
2157
2002
  fixes: ["image:check-metadata"]
2158
2003
  }]));
@@ -2164,35 +2009,37 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
2164
2009
  fixes: ["image:check-metadata"]
2165
2010
  }]));
2166
2011
  }
2167
- if (src.metadata) {
2168
- if (src.metadata.hotspot) {
2169
- if (_typeof(src.metadata.hotspot) !== "object" || typeof src.metadata.hotspot.x !== "number" || typeof src.metadata.hotspot.y !== "number") {
2170
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2171
- message: "Hotspot must be an object with x and y as numbers.",
2172
- value: src
2173
- }]));
2174
- }
2175
- }
2012
+
2013
+ // Whether the dimensions match the bytes can only be answered by reading
2014
+ // the file, which this package deliberately cannot do — so it is always
2015
+ // handed on as a fix.
2016
+ if (src.width !== undefined || src.height !== undefined || src.mimeType !== undefined) {
2176
2017
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2177
- message: "Found metadata, but it could not be validated. Image metadata must be an object with the required props: width (positive number), height (positive number) and the mime type.",
2178
- // These validation errors will have to be picked up by logic outside of this package and revalidated. Reasons: 1) we have to read files to verify the metadata, which is handled differently in different runtimes (Browser, QuickJS, Node.js); 2) we want to keep this package dependency free.
2018
+ message: "Found image metadata, but it could not be validated. An image must have a width (positive number), a height (positive number) and a mime type.",
2179
2019
  value: src,
2180
2020
  fixes: ["image:check-metadata"]
2181
2021
  }]));
2182
2022
  }
2183
- var isReferencedModule = Object.keys(this.moduleMetadata).length > 0;
2184
- if (src.metadata === undefined && isReferencedModule) {
2185
- if (customValidationErrors.length === 0) {
2186
- return false;
2187
- }
2188
- return _defineProperty({}, path, _toConsumableArray(customValidationErrors));
2189
- }
2190
2023
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2191
2024
  message: "Could not validate Image metadata.",
2192
2025
  value: src,
2193
2026
  fixes: ["image:add-metadata"]
2194
2027
  }]));
2195
2028
  }
2029
+
2030
+ /**
2031
+ * The entries of the gallery this field points at, or null when it is a
2032
+ * standalone field.
2033
+ */
2034
+ }, {
2035
+ key: "galleryEntries",
2036
+ value: function galleryEntries() {
2037
+ var modulePaths = Object.keys(this.moduleMetadata);
2038
+ if (modulePaths.length === 0) {
2039
+ return null;
2040
+ }
2041
+ return this.moduleMetadata[modulePaths[0]];
2042
+ }
2196
2043
  }, {
2197
2044
  key: "executeAssert",
2198
2045
  value: function executeAssert(path, src) {
@@ -2220,20 +2067,11 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
2220
2067
  }])
2221
2068
  };
2222
2069
  }
2223
- if (!(FILE_REF_PROP in src)) {
2224
- return {
2225
- success: false,
2226
- errors: _defineProperty({}, path, [{
2227
- message: "Value of this schema must use: 'c.image' (error type: missing_ref_prop)",
2228
- typeError: true
2229
- }])
2230
- };
2231
- }
2232
- if (!(VAL_EXTENSION in src && src[VAL_EXTENSION] === "file")) {
2070
+ if (!("path" in src) || typeof src.path !== "string") {
2233
2071
  return {
2234
2072
  success: false,
2235
2073
  errors: _defineProperty({}, path, [{
2236
- message: "Value of this schema must use: 'c.image' (error type: missing_file_extension)",
2074
+ message: "An image must be an object with a 'path' (error type: missing_path)",
2237
2075
  typeError: true
2238
2076
  }])
2239
2077
  };
@@ -2283,13 +2121,21 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
2283
2121
  };
2284
2122
  }
2285
2123
  }, {
2286
- key: "executeRender",
2287
- value: function executeRender() {
2124
+ key: "executePreview",
2125
+ value: function executePreview() {
2288
2126
  return {};
2289
2127
  }
2290
2128
  }]);
2291
2129
  }(Schema);
2292
- var image = function image(options) {
2130
+
2131
+ /**
2132
+ * An image picked from a gallery. Its dimensions and mime type live in the
2133
+ * gallery, so the field carries only what a person typed.
2134
+ */
2135
+
2136
+ /** An image of its own, carrying its own dimensions and mime type. */
2137
+
2138
+ function image(options) {
2293
2139
  var isModule = !!options && !!Internal.getValPath(options);
2294
2140
  if (isModule) {
2295
2141
  var allModules = {};
@@ -2304,7 +2150,7 @@ var image = function image(options) {
2304
2150
  return new ImageSchema({}, false, false, [], allModules);
2305
2151
  }
2306
2152
  return new ImageSchema(options);
2307
- };
2153
+ }
2308
2154
 
2309
2155
  var RouteSchema = /*#__PURE__*/function (_Schema) {
2310
2156
  function RouteSchema(options) {
@@ -2472,8 +2318,8 @@ var RouteSchema = /*#__PURE__*/function (_Schema) {
2472
2318
  };
2473
2319
  }
2474
2320
  }, {
2475
- key: "executeRender",
2476
- value: function executeRender() {
2321
+ key: "executePreview",
2322
+ value: function executePreview() {
2477
2323
  return {};
2478
2324
  }
2479
2325
  }]);
@@ -3031,8 +2877,8 @@ var RichTextSchema = /*#__PURE__*/function (_Schema) {
3031
2877
  };
3032
2878
  }
3033
2879
  }, {
3034
- key: "executeRender",
3035
- value: function executeRender() {
2880
+ key: "executePreview",
2881
+ value: function executePreview() {
3036
2882
  return {};
3037
2883
  }
3038
2884
  }]);
@@ -3177,6 +3023,20 @@ function _asyncToGenerator(n) {
3177
3023
  };
3178
3024
  }
3179
3025
 
3026
+ /* Branded extension types: file, remote, i18n */
3027
+ var VAL_EXTENSION = "_type";
3028
+
3029
+ /**
3030
+ * A phantom type parameter is one that doesn't show up at runtime, but is checked statically (and only) at compile time.
3031
+ *
3032
+ * An example where this is useful is remote types, where the type of the remote source is known at compile time,
3033
+ * but the value is not there before it is fetched.
3034
+ *
3035
+ * @example
3036
+ * type Example<T> = string & PhantomType<T>;
3037
+ *
3038
+ **/
3039
+
3180
3040
  /**
3181
3041
  * The string used as the `_type` discriminator of a {@link JsonSource}.
3182
3042
  */
@@ -3325,47 +3185,6 @@ function _resolveJsonValues() {
3325
3185
  return _resolveJsonValues.apply(this, arguments);
3326
3186
  }
3327
3187
 
3328
- var RegEx = /^(https?:\/\/[^/]+)\/file\/p\/([^/]+)\/b\/([^/]+)\/v\/([^/]+)\/h\/([^/]+)\/f\/([^/]+)\/p\/(.+)$/;
3329
- function splitRemoteRef(ref) {
3330
- if (ref[0] === "/") {
3331
- return {
3332
- status: "error",
3333
- error: "Not a remote ref: " + ref
3334
- };
3335
- }
3336
- var match = ref.match(RegEx);
3337
- if (!match) {
3338
- return {
3339
- status: "error",
3340
- error: "Invalid remote ref: " + ref
3341
- };
3342
- }
3343
- if (match[7].indexOf("public/") !== 0) {
3344
- return {
3345
- status: "error",
3346
- error: "Invalid remote ref: " + ref
3347
- };
3348
- }
3349
- if (match[7].split("/").some(function (segment) {
3350
- return segment === "." || segment === "..";
3351
- })) {
3352
- return {
3353
- status: "error",
3354
- error: "Invalid remote ref: " + ref
3355
- };
3356
- }
3357
- return {
3358
- status: "success",
3359
- remoteHost: match[1],
3360
- projectId: match[2],
3361
- bucket: match[3],
3362
- version: match[4],
3363
- validationHash: match[5],
3364
- fileHash: match[6],
3365
- filePath: match[7]
3366
- };
3367
- }
3368
-
3369
3188
  /**
3370
3189
  * The source type of a `.jsonValues()` record: every entry value is EITHER a
3371
3190
  * lazily loaded {@link JsonSource} whose resolved content is the (loosened, see
@@ -3392,7 +3211,7 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
3392
3211
  var isHidden = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : false;
3393
3212
  var description = arguments.length > 8 ? arguments[8] : undefined;
3394
3213
  var isJsonValues = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : false;
3395
- var renderInput = arguments.length > 10 && arguments[10] !== undefined ? arguments[10] : null;
3214
+ var previewInput = arguments.length > 10 && arguments[10] !== undefined ? arguments[10] : null;
3396
3215
  _classCallCheck(this, RecordSchema);
3397
3216
  _this = _callSuper(this, RecordSchema);
3398
3217
  _this.item = item;
@@ -3405,19 +3224,19 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
3405
3224
  _this.isHidden = isHidden;
3406
3225
  _this.description = description;
3407
3226
  _this.isJsonValues = isJsonValues;
3408
- _this.renderInput = renderInput;
3227
+ _this.previewInput = previewInput;
3409
3228
  return _this;
3410
3229
  }
3411
3230
  _inherits(RecordSchema, _Schema);
3412
3231
  return _createClass(RecordSchema, [{
3413
3232
  key: "describe",
3414
3233
  value: function describe(description) {
3415
- 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.renderInput);
3234
+ 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);
3416
3235
  }
3417
3236
  }, {
3418
3237
  key: "validate",
3419
3238
  value: function validate(validationFunction) {
3420
- 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.renderInput);
3239
+ 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);
3421
3240
  }
3422
3241
  }, {
3423
3242
  key: "executeValidate",
@@ -3776,29 +3595,29 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
3776
3595
  }, {
3777
3596
  key: "nullable",
3778
3597
  value: function nullable() {
3779
- return new RecordSchema(this.item, true, this.customValidateFunctions, this.currentRouter, this.keySchema, this.mediaOptions, this.isReadonly, this.isHidden, this.description, this.isJsonValues, this.renderInput);
3598
+ return new RecordSchema(this.item, true, this.customValidateFunctions, this.currentRouter, this.keySchema, this.mediaOptions, this.isReadonly, this.isHidden, this.description, this.isJsonValues, this.previewInput);
3780
3599
  }
3781
3600
  }, {
3782
3601
  key: "readonly",
3783
3602
  value: function readonly() {
3784
- return new RecordSchema(this.item, this.opt, this.customValidateFunctions, this.currentRouter, this.keySchema, this.mediaOptions, true, this.isHidden, this.description, this.isJsonValues, this.renderInput);
3603
+ return new RecordSchema(this.item, this.opt, this.customValidateFunctions, this.currentRouter, this.keySchema, this.mediaOptions, true, this.isHidden, this.description, this.isJsonValues, this.previewInput);
3785
3604
  }
3786
3605
  }, {
3787
3606
  key: "hidden",
3788
3607
  value: function hidden() {
3789
- return new RecordSchema(this.item, this.opt, this.customValidateFunctions, this.currentRouter, this.keySchema, this.mediaOptions, this.isReadonly, true, this.description, this.isJsonValues, this.renderInput);
3608
+ return new RecordSchema(this.item, this.opt, this.customValidateFunctions, this.currentRouter, this.keySchema, this.mediaOptions, this.isReadonly, true, this.description, this.isJsonValues, this.previewInput);
3790
3609
  }
3791
3610
  }, {
3792
3611
  key: "router",
3793
3612
  value: function router(_router) {
3794
- return new RecordSchema(this.item, this.opt, this.customValidateFunctions, _router, this.keySchema, this.mediaOptions, this.isReadonly, this.isHidden, this.description, this.isJsonValues, this.renderInput);
3613
+ return new RecordSchema(this.item, this.opt, this.customValidateFunctions, _router, this.keySchema, this.mediaOptions, this.isReadonly, this.isHidden, this.description, this.isJsonValues, this.previewInput);
3795
3614
  }
3796
3615
  }, {
3797
3616
  key: "remote",
3798
3617
  value: function remote() {
3799
3618
  return new RecordSchema(this.item, this.opt, this.customValidateFunctions, this.currentRouter, this.keySchema, this.mediaOptions ? _objectSpread2(_objectSpread2({}, this.mediaOptions), {}, {
3800
3619
  remote: true
3801
- }) : undefined, this.isReadonly, this.isHidden, this.description, this.isJsonValues, this.renderInput);
3620
+ }) : undefined, this.isReadonly, this.isHidden, this.description, this.isJsonValues, this.previewInput);
3802
3621
  }
3803
3622
 
3804
3623
  /**
@@ -3830,7 +3649,7 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
3830
3649
  }
3831
3650
  return new RecordSchema(this.item, this.opt,
3832
3651
  // Empty by construction: the guard above rejects any that were registered.
3833
- [], this.currentRouter, this.keySchema, this.mediaOptions, this.isReadonly, this.isHidden, this.description, true, this.renderInput);
3652
+ [], this.currentRouter, this.keySchema, this.mediaOptions, this.isReadonly, this.isHidden, this.description, true, this.previewInput);
3834
3653
  }
3835
3654
  }, {
3836
3655
  key: "getRouterValidations",
@@ -3890,7 +3709,7 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
3890
3709
  item: this.item["executeSerialize"](),
3891
3710
  key: (_this$keySchema = this.keySchema) === null || _this$keySchema === void 0 ? void 0 : _this$keySchema["executeSerialize"](),
3892
3711
  opt: this.opt,
3893
- render: this.renderInput ? true : undefined,
3712
+ preview: this.previewInput ? true : undefined,
3894
3713
  router: (_this$currentRouter = this.currentRouter) === null || _this$currentRouter === void 0 ? void 0 : _this$currentRouter.getRouterId(),
3895
3714
  customValidate: this.customValidateFunctions && ((_this$customValidateF = this.customValidateFunctions) === null || _this$customValidateF === void 0 ? void 0 : _this$customValidateF.length) > 0,
3896
3715
  jsonValues: this.isJsonValues ? true : undefined,
@@ -3922,8 +3741,8 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
3922
3741
  return this.item["executeValidate"](path, content);
3923
3742
  }
3924
3743
  }, {
3925
- key: "executeRender",
3926
- value: function executeRender(sourcePath, src, scope) {
3744
+ key: "executePreview",
3745
+ value: function executePreview(sourcePath, src, scope) {
3927
3746
  var res = {};
3928
3747
  if (src === null) {
3929
3748
  return res;
@@ -3935,31 +3754,23 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
3935
3754
  }
3936
3755
  if (isJson(itemSrc)) {
3937
3756
  // An un-loaded `.jsonValues()` entry: an opaque marker, not the item this
3938
- // schema describes. Skipping it is what makes rendering a partially
3757
+ // schema describes. Skipping it is what makes previewing a partially
3939
3758
  // loaded record work — the result comes out covering exactly the loaded
3940
- // keys, and the caller renders a placeholder for the rest.
3759
+ // keys, and the caller shows a placeholder for the rest.
3941
3760
  continue;
3942
3761
  }
3943
3762
  var subPath = unsafeCreateSourcePath(sourcePath, _key);
3944
3763
  if (scope !== undefined && !scope.wantsUnder(subPath)) {
3945
3764
  continue;
3946
3765
  }
3947
- var itemResult = this.item["executeRender"](subPath, itemSrc, scope);
3766
+ var itemResult = this.item["executePreview"](subPath, itemSrc, scope);
3948
3767
  for (var keyS in itemResult) {
3949
3768
  var _key2 = keyS;
3950
3769
  res[_key2] = itemResult[_key2];
3951
3770
  }
3952
3771
  }
3953
- if (this.renderInput) {
3954
- var _this$renderInput = this.renderInput,
3955
- prepare = _this$renderInput.select,
3956
- layout = _this$renderInput.layout;
3957
- if (layout !== "list") {
3958
- res[sourcePath] = {
3959
- status: "error",
3960
- message: "Unknown layout type: " + layout
3961
- };
3962
- }
3772
+ if (this.previewInput) {
3773
+ var prepare = this.previewInput;
3963
3774
  // See the same block in `array`: the whole record when the record is what
3964
3775
  // is being shown, only the wanted entries when it is not.
3965
3776
  var window = scope !== undefined && !scope.wants(sourcePath) ? scope : null;
@@ -3974,7 +3785,7 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
3974
3785
  if (window !== null && !window.wantsUnder(unsafeCreateSourcePath(sourcePath, _key3))) {
3975
3786
  continue;
3976
3787
  }
3977
- // Per KEY, not per record: `select` is user code, and one entry whose
3788
+ // Per KEY, not per record: the closure is user code, and one entry whose
3978
3789
  // data trips it up must not take out the whole list.
3979
3790
  try {
3980
3791
  // NB NB: display is actually defined by the user
@@ -4000,7 +3811,6 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
4000
3811
  res[sourcePath] = {
4001
3812
  status: "success",
4002
3813
  data: {
4003
- layout: "list",
4004
3814
  parent: "record",
4005
3815
  items: items
4006
3816
  }
@@ -4008,13 +3818,19 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
4008
3818
  }
4009
3819
  return res;
4010
3820
  }
4011
- }, {
4012
- key: "render",
4013
- value: function render(input) {
4014
- return new RecordSchema(this.item, this.opt, this.customValidateFunctions, this.currentRouter, this.keySchema, this.mediaOptions, this.isReadonly, this.isHidden, this.description, this.isJsonValues, {
4015
- layout: input.as,
4016
- select: input.select
4017
- });
3821
+
3822
+ /**
3823
+ * What the editor shows for each ENTRY of this record: a title, and optionally
3824
+ * a subtitle and an image.
3825
+ *
3826
+ * `select` is your own code over the entry's key and source, so it is run on
3827
+ * demand for the entries that are actually being looked at — see
3828
+ * `PreviewScope`.
3829
+ */
3830
+ }, {
3831
+ key: "preview",
3832
+ value: function preview(select) {
3833
+ return new RecordSchema(this.item, this.opt, this.customValidateFunctions, this.currentRouter, this.keySchema, this.mediaOptions, this.isReadonly, this.isHidden, this.description, this.isJsonValues, select);
4018
3834
  }
4019
3835
  }]);
4020
3836
  }(Schema);
@@ -4707,8 +4523,8 @@ var NumberSchema = /*#__PURE__*/function (_Schema) {
4707
4523
  };
4708
4524
  }
4709
4525
  }, {
4710
- key: "executeRender",
4711
- value: function executeRender() {
4526
+ key: "executePreview",
4527
+ value: function executePreview() {
4712
4528
  return {};
4713
4529
  }
4714
4530
  }]);
@@ -4827,8 +4643,8 @@ var BooleanSchema = /*#__PURE__*/function (_Schema) {
4827
4643
  };
4828
4644
  }
4829
4645
  }, {
4830
- key: "executeRender",
4831
- value: function executeRender() {
4646
+ key: "executePreview",
4647
+ value: function executePreview() {
4832
4648
  return {};
4833
4649
  }
4834
4650
  }]);
@@ -4881,48 +4697,378 @@ var KeyOfSchema = /*#__PURE__*/function (_Schema) {
4881
4697
  message: "Schema not found for module. keyOf must be used with a Val Module"
4882
4698
  }]));
4883
4699
  }
4884
- var serializedSchema = this.schema;
4885
- if (!(serializedSchema.type === "object" || serializedSchema.type === "record")) {
4700
+ var serializedSchema = this.schema;
4701
+ if (!(serializedSchema.type === "object" || serializedSchema.type === "record")) {
4702
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4703
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
4704
+ message: "Schema in keyOf must be an 'object' or 'record'. Found '".concat(serializedSchema.type || "unknown", "'")
4705
+ }]));
4706
+ }
4707
+ if (serializedSchema.opt && (src === null || src === undefined)) {
4708
+ return false;
4709
+ }
4710
+ if (serializedSchema.type === "record" && typeof src !== "string") {
4711
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4712
+ message: "Type of value in keyof (record) must be 'string'"
4713
+ }]));
4714
+ }
4715
+ if (serializedSchema.type === "object") {
4716
+ var keys = serializedSchema.keys;
4717
+ if (!keys.includes(src)) {
4718
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4719
+ message: "Value of keyOf (object) must be: ".concat(keys.join(", "), ". Found: ").concat(src)
4720
+ }]));
4721
+ }
4722
+ }
4723
+ if (serializedSchema.type === "record") {
4724
+ if (typeof src !== "string") {
4725
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4726
+ message: "Value of keyOf (record) must be 'string'. Found: ".concat(_typeof(src))
4727
+ }]));
4728
+ }
4729
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4730
+ fixes: ["keyof:check-keys"],
4731
+ message: "Did not validate keyOf (record). This error (keyof:check-keys) should typically be processed by Val internally. Seeing this error most likely means you have a Val version mismatch.",
4732
+ value: {
4733
+ key: src,
4734
+ sourcePath: this.sourcePath
4735
+ }
4736
+ }]));
4737
+ }
4738
+ if (customValidationErrors.length > 0) {
4739
+ return _defineProperty({}, path, customValidationErrors);
4740
+ }
4741
+ return false;
4742
+ }
4743
+ }, {
4744
+ key: "executeAssert",
4745
+ value: function executeAssert(path, src) {
4746
+ if (this.opt && src === null) {
4747
+ return {
4748
+ success: true,
4749
+ data: src
4750
+ };
4751
+ }
4752
+ if (src === null) {
4753
+ return {
4754
+ success: false,
4755
+ errors: _defineProperty({}, path, [{
4756
+ message: "Expected 'string', got 'null'",
4757
+ typeError: true
4758
+ }])
4759
+ };
4760
+ }
4761
+ var schema = this.schema;
4762
+ if (!schema) {
4763
+ return {
4764
+ success: false,
4765
+ errors: _defineProperty({}, path, [{
4766
+ message: "Neither key nor schema was found. keyOf is missing an argument.",
4767
+ typeError: true
4768
+ }])
4769
+ };
4770
+ }
4771
+ var serializedSchema = schema;
4772
+ if (!(serializedSchema.type === "object" || serializedSchema.type === "record")) {
4773
+ return {
4774
+ success: false,
4775
+ errors: _defineProperty({}, path, [{
4776
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
4777
+ message: "Schema of first argument must be either: 'array', 'object' or 'record'. Found '".concat(serializedSchema.type || "unknown", "'"),
4778
+ typeError: true
4779
+ }])
4780
+ };
4781
+ }
4782
+ if (serializedSchema.type === "record" && typeof src !== "string") {
4783
+ return {
4784
+ success: false,
4785
+ errors: _defineProperty({}, path, [{
4786
+ message: "Value of keyOf (record) must be 'string', got '".concat(_typeof(src), "'"),
4787
+ typeError: true
4788
+ }])
4789
+ };
4790
+ }
4791
+ // We check actual value here, since TypeScript also does this. Literals are used in other types (unions),
4792
+ // and there it also makes sense to check the actual string values (i.e. that it is not just a string) since
4793
+ // missing one would lead to a runtime error. At least this is what we are thinking currently.
4794
+ if (serializedSchema.type === "object") {
4795
+ var keys = serializedSchema.keys;
4796
+ if (!keys.includes(src)) {
4797
+ return {
4798
+ success: false,
4799
+ errors: _defineProperty({}, path, [{
4800
+ message: "Value of keyOf (object) must be: ".concat(keys.join(", "), ". Found: ").concat(src),
4801
+ typeError: true
4802
+ }])
4803
+ };
4804
+ }
4805
+ }
4806
+ return {
4807
+ success: true,
4808
+ data: src
4809
+ };
4810
+ }
4811
+ }, {
4812
+ key: "nullable",
4813
+ value: function nullable() {
4814
+ return new KeyOfSchema(this.schema, this.sourcePath, true, [], this.isReadonly, this.isHidden, this.description);
4815
+ }
4816
+ }, {
4817
+ key: "readonly",
4818
+ value: function readonly() {
4819
+ return new KeyOfSchema(this.schema, this.sourcePath, this.opt, this.customValidateFunctions, true, this.isHidden, this.description);
4820
+ }
4821
+ }, {
4822
+ key: "hidden",
4823
+ value: function hidden() {
4824
+ return new KeyOfSchema(this.schema, this.sourcePath, this.opt, this.customValidateFunctions, this.isReadonly, true, this.description);
4825
+ }
4826
+ }, {
4827
+ key: "executeCustomValidateAt",
4828
+ value: function executeCustomValidateAt(path, src) {
4829
+ return this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
4830
+ path: path
4831
+ });
4832
+ }
4833
+ }, {
4834
+ key: "executeSerialize",
4835
+ value: function executeSerialize() {
4836
+ var _this$customValidateF;
4837
+ var path = this.sourcePath;
4838
+ if (!path) {
4839
+ throw new Error("Cannot serialize keyOf schema with empty selector. TIP: keyOf must be used with a Val Module of record schema.");
4840
+ }
4841
+ var serializedSchema = this.schema;
4842
+ if (!serializedSchema) {
4843
+ throw new Error("Cannot serialize keyOf schema with empty selector.");
4844
+ }
4845
+ var values;
4846
+ switch (serializedSchema.type) {
4847
+ case "record":
4848
+ values = "string";
4849
+ break;
4850
+ case "object":
4851
+ values = serializedSchema.keys;
4852
+ break;
4853
+ default:
4854
+ throw new Error(// eslint-disable-next-line @typescript-eslint/no-explicit-any
4855
+ "Cannot serialize keyOf schema with selector of type '".concat(serializedSchema.type || "unknown", "'"));
4856
+ }
4857
+ return {
4858
+ type: "keyOf",
4859
+ path: path,
4860
+ schema: serializedSchema,
4861
+ opt: this.opt,
4862
+ values: values,
4863
+ customValidate: this.customValidateFunctions && ((_this$customValidateF = this.customValidateFunctions) === null || _this$customValidateF === void 0 ? void 0 : _this$customValidateF.length) > 0,
4864
+ readonly: this.isReadonly,
4865
+ hidden: this.isHidden,
4866
+ description: this.description
4867
+ };
4868
+ }
4869
+ }, {
4870
+ key: "executePreview",
4871
+ value: function executePreview() {
4872
+ return {};
4873
+ }
4874
+ }]);
4875
+ }(Schema);
4876
+ var keyOf = function keyOf(valModule) {
4877
+ var refSchema = valModule === null || valModule === void 0 ? void 0 : valModule[GetSchema];
4878
+ var serializedRefSchema = undefined;
4879
+ if (refSchema instanceof ObjectSchema) {
4880
+ var keys = [];
4881
+ try {
4882
+ keys = Object.keys((refSchema === null || refSchema === void 0 ? void 0 : refSchema["items"]) || {});
4883
+ } catch (e) {
4884
+ // ignore this error here
4885
+ }
4886
+ serializedRefSchema = {
4887
+ type: "object",
4888
+ keys: keys,
4889
+ opt: refSchema === null || refSchema === void 0 ? void 0 : refSchema["opt"]
4890
+ };
4891
+ } else if (refSchema instanceof RecordSchema) {
4892
+ serializedRefSchema = {
4893
+ type: "record",
4894
+ opt: refSchema === null || refSchema === void 0 ? void 0 : refSchema["opt"]
4895
+ };
4896
+ }
4897
+ return new KeyOfSchema(serializedRefSchema, getValPath(valModule));
4898
+ };
4899
+
4900
+ var FileSchema = /*#__PURE__*/function (_Schema) {
4901
+ function FileSchema(options) {
4902
+ var _this;
4903
+ var opt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
4904
+ var isRemote = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
4905
+ var customValidateFunctions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
4906
+ var moduleMetadata = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
4907
+ var isReadonly = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false;
4908
+ var isHidden = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : false;
4909
+ var description = arguments.length > 7 ? arguments[7] : undefined;
4910
+ _classCallCheck(this, FileSchema);
4911
+ _this = _callSuper(this, FileSchema);
4912
+ _this.options = options;
4913
+ _this.opt = opt;
4914
+ _this.isRemote = isRemote;
4915
+ _this.customValidateFunctions = customValidateFunctions;
4916
+ _this.moduleMetadata = moduleMetadata;
4917
+ _this.isReadonly = isReadonly;
4918
+ _this.isHidden = isHidden;
4919
+ _this.description = description;
4920
+ return _this;
4921
+ }
4922
+ _inherits(FileSchema, _Schema);
4923
+ return _createClass(FileSchema, [{
4924
+ key: "describe",
4925
+ value: function describe(description) {
4926
+ return new FileSchema(this.options, this.opt, this.isRemote, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined);
4927
+ }
4928
+ }, {
4929
+ key: "remote",
4930
+ value: function remote() {
4931
+ return new FileSchema(this.options, this.opt, true, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, this.isHidden, this.description);
4932
+ }
4933
+ }, {
4934
+ key: "validate",
4935
+ value: function validate(validationFunction) {
4936
+ return new FileSchema(this.options, this.opt, this.isRemote, [].concat(_toConsumableArray(this.customValidateFunctions), [validationFunction]), this.moduleMetadata, this.isReadonly, this.isHidden, this.description);
4937
+ }
4938
+ }, {
4939
+ key: "executeValidate",
4940
+ value: function executeValidate(path, src) {
4941
+ var customValidationErrors = this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
4942
+ path: path
4943
+ });
4944
+ if (this.opt && (src === null || src === undefined)) {
4945
+ return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : false;
4946
+ }
4947
+ if (src === null || src === undefined) {
4948
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4949
+ message: "Non-optional file was null or undefined.",
4950
+ value: src
4951
+ }]));
4952
+ }
4953
+ if (typeof src.path !== "string") {
4954
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4955
+ message: "File did not have a path string. Got: ".concat(_typeof(src.path)),
4956
+ value: src
4957
+ }]));
4958
+ }
4959
+ // Remote-ness is a property of the path, not of a marker on the value:
4960
+ // anything outside /public is remote.
4961
+ var isRemotePath = isRemoteMediaPath(src.path);
4962
+ if (this.isRemote && !isRemotePath) {
4886
4963
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4887
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
4888
- message: "Schema in keyOf must be an 'object' or 'record'. Found '".concat(serializedSchema.type || "unknown", "'")
4964
+ message: "Expected a remote file, but got a local file.",
4965
+ value: src,
4966
+ fixes: ["file:upload-remote"]
4889
4967
  }]));
4890
4968
  }
4891
- if (serializedSchema.opt && (src === null || src === undefined)) {
4892
- return false;
4969
+ if (this.isRemote && isRemotePath) {
4970
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4971
+ message: "Remote file was not checked.",
4972
+ value: src,
4973
+ fixes: ["file:check-remote"]
4974
+ }]));
4893
4975
  }
4894
- if (serializedSchema.type === "record" && typeof src !== "string") {
4976
+ if (!this.isRemote && isRemotePath) {
4895
4977
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4896
- message: "Type of value in keyof (record) must be 'string'"
4978
+ message: "Expected local file, but found remote.",
4979
+ value: src,
4980
+ fixes: ["file:download-remote"]
4897
4981
  }]));
4898
4982
  }
4899
- if (serializedSchema.type === "object") {
4900
- var keys = serializedSchema.keys;
4901
- if (!keys.includes(src)) {
4983
+ var galleryEntries = this.galleryEntries();
4984
+ if (galleryEntries) {
4985
+ if (src.mimeType !== undefined) {
4902
4986
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4903
- message: "Value of keyOf (object) must be: ".concat(keys.join(", "), ". Found: ").concat(src)
4987
+ message: "A file from a gallery must not carry its own mimeType: it is stored in the gallery module.",
4988
+ value: src
4904
4989
  }]));
4905
4990
  }
4906
- }
4907
- if (serializedSchema.type === "record") {
4908
- if (typeof src !== "string") {
4991
+ if (!(src.path in galleryEntries)) {
4909
4992
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4910
- message: "Value of keyOf (record) must be 'string'. Found: ".concat(_typeof(src))
4993
+ message: "The gallery does not have a file at '".concat(src.path, "'."),
4994
+ value: src
4911
4995
  }]));
4912
4996
  }
4997
+ return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : false;
4998
+ }
4999
+ var _ref0 = this.options || {},
5000
+ accept = _ref0.accept;
5001
+ var mimeType = src.mimeType;
5002
+ if (accept && mimeType && !mimeType.includes("/")) {
4913
5003
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4914
- fixes: ["keyof:check-keys"],
4915
- message: "Did not validate keyOf (record). This error (keyof:check-keys) should typically be processed by Val internally. Seeing this error most likely means you have a Val version mismatch.",
4916
- value: {
4917
- key: src,
4918
- sourcePath: this.sourcePath
5004
+ message: "Invalid mime type format. Got: ".concat(mimeType),
5005
+ value: src
5006
+ }]));
5007
+ }
5008
+ if (accept && mimeType && mimeType.includes("/")) {
5009
+ var acceptedTypes = accept.split(",").map(function (type) {
5010
+ return type.trim();
5011
+ });
5012
+ var isValidMimeType = acceptedTypes.some(function (acceptedType) {
5013
+ if (acceptedType === "*/*") {
5014
+ return true;
5015
+ }
5016
+ if (acceptedType.endsWith("/*")) {
5017
+ var baseType = acceptedType.slice(0, -2);
5018
+ return mimeType.startsWith(baseType);
4919
5019
  }
5020
+ return acceptedType === mimeType;
5021
+ });
5022
+ if (!isValidMimeType) {
5023
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
5024
+ message: "Mime type mismatch. Found '".concat(mimeType, "' but schema accepts '").concat(accept, "'"),
5025
+ value: src
5026
+ }]));
5027
+ }
5028
+ }
5029
+ var fileMimeType = Internal.filenameToMimeType(src.path);
5030
+ if (!fileMimeType) {
5031
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
5032
+ message: "Could not determine mime type from file extension. Got: ".concat(src.path),
5033
+ value: src
4920
5034
  }]));
4921
5035
  }
4922
- if (customValidationErrors.length > 0) {
4923
- return _defineProperty({}, path, customValidationErrors);
5036
+ if (fileMimeType !== mimeType) {
5037
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
5038
+ message: "Mime type and file extension not matching. Mime type is '".concat(mimeType, "' but file extension is '").concat(fileMimeType, "'"),
5039
+ value: src
5040
+ }]));
4924
5041
  }
4925
- return false;
5042
+
5043
+ // The mime type read so far came from the filename. Whether it matches the
5044
+ // bytes can only be answered by reading the file, which this package
5045
+ // deliberately cannot do — so it is always handed on as a fix.
5046
+ if (mimeType !== undefined) {
5047
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
5048
+ message: "Found mimeType, but it could not be validated.",
5049
+ value: src,
5050
+ fixes: ["file:check-metadata"]
5051
+ }]));
5052
+ }
5053
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
5054
+ message: "Missing File mimeType.",
5055
+ value: src,
5056
+ fixes: ["file:add-metadata"]
5057
+ }]));
5058
+ }
5059
+
5060
+ /**
5061
+ * The entries of the gallery this field points at, or null when it is a
5062
+ * standalone field.
5063
+ */
5064
+ }, {
5065
+ key: "galleryEntries",
5066
+ value: function galleryEntries() {
5067
+ var modulePaths = Object.keys(this.moduleMetadata);
5068
+ if (modulePaths.length === 0) {
5069
+ return null;
5070
+ }
5071
+ return this.moduleMetadata[modulePaths[0]];
4926
5072
  }
4927
5073
  }, {
4928
5074
  key: "executeAssert",
@@ -4937,56 +5083,29 @@ var KeyOfSchema = /*#__PURE__*/function (_Schema) {
4937
5083
  return {
4938
5084
  success: false,
4939
5085
  errors: _defineProperty({}, path, [{
4940
- message: "Expected 'string', got 'null'",
4941
- typeError: true
4942
- }])
4943
- };
4944
- }
4945
- var schema = this.schema;
4946
- if (!schema) {
4947
- return {
4948
- success: false,
4949
- errors: _defineProperty({}, path, [{
4950
- message: "Neither key nor schema was found. keyOf is missing an argument.",
5086
+ message: "Expected 'object', got 'null'",
4951
5087
  typeError: true
4952
5088
  }])
4953
5089
  };
4954
5090
  }
4955
- var serializedSchema = schema;
4956
- if (!(serializedSchema.type === "object" || serializedSchema.type === "record")) {
5091
+ if (_typeof(src) !== "object") {
4957
5092
  return {
4958
5093
  success: false,
4959
5094
  errors: _defineProperty({}, path, [{
4960
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
4961
- message: "Schema of first argument must be either: 'array', 'object' or 'record'. Found '".concat(serializedSchema.type || "unknown", "'"),
5095
+ message: "Expected object, got '".concat(_typeof(src), "'"),
4962
5096
  typeError: true
4963
5097
  }])
4964
5098
  };
4965
5099
  }
4966
- if (serializedSchema.type === "record" && typeof src !== "string") {
5100
+ if (!("path" in src) || typeof src.path !== "string") {
4967
5101
  return {
4968
5102
  success: false,
4969
5103
  errors: _defineProperty({}, path, [{
4970
- message: "Value of keyOf (record) must be 'string', got '".concat(_typeof(src), "'"),
5104
+ message: "A file must be an object with a 'path' (error type: missing_path)",
4971
5105
  typeError: true
4972
5106
  }])
4973
5107
  };
4974
5108
  }
4975
- // We check actual value here, since TypeScript also does this. Literals are used in other types (unions),
4976
- // and there it also makes sense to check the actual string values (i.e. that it is not just a string) since
4977
- // missing one would lead to a runtime error. At least this is what we are thinking currently.
4978
- if (serializedSchema.type === "object") {
4979
- var keys = serializedSchema.keys;
4980
- if (!keys.includes(src)) {
4981
- return {
4982
- success: false,
4983
- errors: _defineProperty({}, path, [{
4984
- message: "Value of keyOf (object) must be: ".concat(keys.join(", "), ". Found: ").concat(src),
4985
- typeError: true
4986
- }])
4987
- };
4988
- }
4989
- }
4990
5109
  return {
4991
5110
  success: true,
4992
5111
  data: src
@@ -4995,17 +5114,17 @@ var KeyOfSchema = /*#__PURE__*/function (_Schema) {
4995
5114
  }, {
4996
5115
  key: "nullable",
4997
5116
  value: function nullable() {
4998
- return new KeyOfSchema(this.schema, this.sourcePath, true, [], this.isReadonly, this.isHidden, this.description);
5117
+ return new FileSchema(this.options, true, this.isRemote, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, this.isHidden, this.description);
4999
5118
  }
5000
5119
  }, {
5001
5120
  key: "readonly",
5002
5121
  value: function readonly() {
5003
- return new KeyOfSchema(this.schema, this.sourcePath, this.opt, this.customValidateFunctions, true, this.isHidden, this.description);
5122
+ return new FileSchema(this.options, this.opt, this.isRemote, this.customValidateFunctions, this.moduleMetadata, true, this.isHidden, this.description);
5004
5123
  }
5005
5124
  }, {
5006
5125
  key: "hidden",
5007
5126
  value: function hidden() {
5008
- return new KeyOfSchema(this.schema, this.sourcePath, this.opt, this.customValidateFunctions, this.isReadonly, true, this.description);
5127
+ return new FileSchema(this.options, this.opt, this.isRemote, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, true, this.description);
5009
5128
  }
5010
5129
  }, {
5011
5130
  key: "executeCustomValidateAt",
@@ -5018,68 +5137,50 @@ var KeyOfSchema = /*#__PURE__*/function (_Schema) {
5018
5137
  key: "executeSerialize",
5019
5138
  value: function executeSerialize() {
5020
5139
  var _this$customValidateF;
5021
- var path = this.sourcePath;
5022
- if (!path) {
5023
- throw new Error("Cannot serialize keyOf schema with empty selector. TIP: keyOf must be used with a Val Module of record schema.");
5024
- }
5025
- var serializedSchema = this.schema;
5026
- if (!serializedSchema) {
5027
- throw new Error("Cannot serialize keyOf schema with empty selector.");
5028
- }
5029
- var values;
5030
- switch (serializedSchema.type) {
5031
- case "record":
5032
- values = "string";
5033
- break;
5034
- case "object":
5035
- values = serializedSchema.keys;
5036
- break;
5037
- default:
5038
- throw new Error(// eslint-disable-next-line @typescript-eslint/no-explicit-any
5039
- "Cannot serialize keyOf schema with selector of type '".concat(serializedSchema.type || "unknown", "'"));
5040
- }
5140
+ var modulePaths = this.moduleMetadata ? Object.keys(this.moduleMetadata) : [];
5041
5141
  return {
5042
- type: "keyOf",
5043
- path: path,
5044
- schema: serializedSchema,
5142
+ type: "file",
5143
+ options: this.options,
5045
5144
  opt: this.opt,
5046
- values: values,
5145
+ remote: this.isRemote,
5047
5146
  customValidate: this.customValidateFunctions && ((_this$customValidateF = this.customValidateFunctions) === null || _this$customValidateF === void 0 ? void 0 : _this$customValidateF.length) > 0,
5147
+ referencedModule: modulePaths.length > 0 ? modulePaths[0] : undefined,
5048
5148
  readonly: this.isReadonly,
5049
5149
  hidden: this.isHidden,
5050
5150
  description: this.description
5051
5151
  };
5052
5152
  }
5053
5153
  }, {
5054
- key: "executeRender",
5055
- value: function executeRender() {
5154
+ key: "executePreview",
5155
+ value: function executePreview() {
5056
5156
  return {};
5057
5157
  }
5058
5158
  }]);
5059
5159
  }(Schema);
5060
- var keyOf = function keyOf(valModule) {
5061
- var refSchema = valModule === null || valModule === void 0 ? void 0 : valModule[GetSchema];
5062
- var serializedRefSchema = undefined;
5063
- if (refSchema instanceof ObjectSchema) {
5064
- var keys = [];
5065
- try {
5066
- keys = Object.keys((refSchema === null || refSchema === void 0 ? void 0 : refSchema["items"]) || {});
5067
- } catch (e) {
5068
- // ignore this error here
5160
+
5161
+ /**
5162
+ * A file picked from a gallery. Its mime type lives in the gallery, so the
5163
+ * field carries only the path.
5164
+ */
5165
+
5166
+ /** A file of its own, carrying its own mime type. */
5167
+
5168
+ function file(options) {
5169
+ var isModule = !!options && !!Internal.getValPath(options);
5170
+ if (isModule) {
5171
+ var allModules = {};
5172
+ for (var _i = 0, _arr = [options]; _i < _arr.length; _i++) {
5173
+ var valModule = _arr[_i];
5174
+ var modulePath = getValPath(valModule);
5175
+ if (modulePath === undefined) {
5176
+ throw new Error("Invalid argument passed to s.file(). Expected a ValModule constructed through c.define, but got an object without a valid module path.");
5177
+ }
5178
+ allModules[modulePath] = getSource(valModule);
5069
5179
  }
5070
- serializedRefSchema = {
5071
- type: "object",
5072
- keys: keys,
5073
- opt: refSchema === null || refSchema === void 0 ? void 0 : refSchema["opt"]
5074
- };
5075
- } else if (refSchema instanceof RecordSchema) {
5076
- serializedRefSchema = {
5077
- type: "record",
5078
- opt: refSchema === null || refSchema === void 0 ? void 0 : refSchema["opt"]
5079
- };
5180
+ return new FileSchema({}, false, false, [], allModules);
5080
5181
  }
5081
- return new KeyOfSchema(serializedRefSchema, getValPath(valModule));
5082
- };
5182
+ return new FileSchema(options);
5183
+ }
5083
5184
 
5084
5185
  /**
5085
5186
  * Options for s.files()
@@ -5281,8 +5382,8 @@ var DateSchema = /*#__PURE__*/function (_Schema) {
5281
5382
  };
5282
5383
  }
5283
5384
  }, {
5284
- key: "executeRender",
5285
- value: function executeRender() {
5385
+ key: "executePreview",
5386
+ value: function executePreview() {
5286
5387
  return {};
5287
5388
  }
5288
5389
  }]);
@@ -5485,8 +5586,8 @@ var DateTimeSchema = /*#__PURE__*/function (_Schema) {
5485
5586
  };
5486
5587
  }
5487
5588
  }, {
5488
- key: "executeRender",
5489
- value: function executeRender() {
5589
+ key: "executePreview",
5590
+ value: function executePreview() {
5490
5591
  return {};
5491
5592
  }
5492
5593
  }]);
@@ -6126,8 +6227,8 @@ var ColorSchema = /*#__PURE__*/function (_Schema) {
6126
6227
  };
6127
6228
  }
6128
6229
  }, {
6129
- key: "executeRender",
6130
- value: function executeRender() {
6230
+ key: "executePreview",
6231
+ value: function executePreview() {
6131
6232
  return {};
6132
6233
  }
6133
6234
  }]);
@@ -6234,88 +6335,6 @@ function initSchema() {
6234
6335
  };
6235
6336
  }
6236
6337
 
6237
- /**
6238
- * A image source represents the path to a (local) image.
6239
- *
6240
- */
6241
-
6242
- var initImage = function initImage(config) {
6243
- var _config$files$directo, _config$files;
6244
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
6245
- (_config$files$directo = config === null || config === void 0 || (_config$files = config.files) === null || _config$files === void 0 ? void 0 : _config$files.directory) !== null && _config$files$directo !== void 0 ? _config$files$directo : "/public/val";
6246
-
6247
- /**
6248
- * Define the source of an image file.
6249
- *
6250
- * @example
6251
- * c.image("/public/val/example.png", {
6252
- * width: 944,
6253
- * height: 944,
6254
- * mimeType: "image/png",
6255
- *})
6256
- *
6257
- * @param ref /public/val/example.png
6258
- * @param metadata Image metadata: width, height, mimeType and optionally a hotspot.
6259
- */
6260
-
6261
- /**
6262
- * Define the source of an image file.
6263
- *
6264
- * NOTE: this will **not** validate since metadata has not been defined.
6265
- *
6266
- * Run `npx -p @valbuild/cli val validate --fix` to automatically add metadata.
6267
- *
6268
- * @example
6269
- * c.image("/public/val/example.png")
6270
- *
6271
- * @param ref /public/val/example.png
6272
- * @param metadata Image metadata: width, height, mimeType and optionally a hotspot.
6273
- */
6274
-
6275
- /**
6276
- * Define the source of an image file.
6277
- *
6278
- * @example
6279
- * c.image("/public/val/example.png", {
6280
- * width: 944,
6281
- * height: 944,
6282
- * mimeType: "image/png",
6283
- *})
6284
- *
6285
- * @param ref /public/val/example.png
6286
- * @param metadata Image metadata: width, height, mimeType and optionally a hotspot.
6287
- */
6288
- function image(ref, metadata) {
6289
- return _defineProperty(_defineProperty(_defineProperty(_defineProperty({}, FILE_REF_PROP, ref), VAL_EXTENSION, "file"), FILE_REF_SUBTYPE_TAG, "image"), "metadata", metadata);
6290
- }
6291
- return image;
6292
- };
6293
-
6294
- /**
6295
- * A remote source represents data that is not stored locally.
6296
- */
6297
-
6298
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
6299
- var initRemote = function initRemote(config) {
6300
- function remote(ref, metadata) {
6301
- return _defineProperty(_defineProperty(_defineProperty({}, FILE_REF_PROP, ref), VAL_EXTENSION, "remote"), "metadata", metadata);
6302
- }
6303
- return remote;
6304
- };
6305
-
6306
- // NOTE: the segments must match the ref built by createRemoteRef below and the RegEx in splitRemoteRef.
6307
-
6308
- function createRemoteRef(remoteHost, _ref2) {
6309
- var publicProjectId = _ref2.publicProjectId,
6310
- coreVersion = _ref2.coreVersion,
6311
- validationHash = _ref2.validationHash,
6312
- fileHash = _ref2.fileHash,
6313
- filePath = _ref2.filePath,
6314
- bucket = _ref2.bucket;
6315
- // NOTE: the core version is part of the validation hash, but it is also in the uri to make it easier to understand which version the remote file was validated against.
6316
- return "".concat(remoteHost, "/file/p/").concat(publicProjectId, "/b/").concat(bucket, "/v/").concat(coreVersion, "/h/").concat(validationHash, "/f/").concat(fileHash, "/p/").concat(filePath);
6317
- }
6318
-
6319
6338
  // import { i18n, I18n } from "./source/future/i18n";
6320
6339
  // import { remote } from "./source/future/remote";
6321
6340
 
@@ -6352,9 +6371,6 @@ var initVal = function initVal(config) {
6352
6371
  },
6353
6372
  c: {
6354
6373
  define: define,
6355
- remote: initRemote(),
6356
- file: initFile(config),
6357
- image: initImage(config),
6358
6374
  json: json
6359
6375
  },
6360
6376
  s: s,
@@ -7071,23 +7087,6 @@ function hasRemoteFileSchema(schema) {
7071
7087
  }
7072
7088
 
7073
7089
  var DEFAULT_VAL_REMOTE_HOST = "https://remote.val.build";
7074
- function convertRemoteSource(src) {
7075
- if (src !== null && src !== void 0 && src.patch_id) {
7076
- var splitRemoteRefDataRes = splitRemoteRef(src[FILE_REF_PROP]);
7077
- if (splitRemoteRefDataRes.status === "success") {
7078
- return {
7079
- url: "/api/val/files/" + splitRemoteRefDataRes.filePath + "?patch_id=".concat(src["patch_id"], "&remote=true&ref=").concat(encodeURIComponent(src[FILE_REF_PROP])),
7080
- metadata: src.metadata
7081
- };
7082
- } else {
7083
- console.warn("Internal Val error: failed to split remote ref: ".concat(src[FILE_REF_PROP], ". The data format is different than what is expected. Check Val versions for mismatches."), splitRemoteRefDataRes.error);
7084
- }
7085
- }
7086
- return {
7087
- url: src[FILE_REF_PROP],
7088
- metadata: src.metadata
7089
- };
7090
- }
7091
7090
 
7092
7091
  var PatchError = /*#__PURE__*/_createClass(function PatchError(message) {
7093
7092
  _classCallCheck(this, PatchError);
@@ -7157,14 +7156,15 @@ function derefPatch(patch, document, ops) {
7157
7156
  var maybeValue = ops.get(document, dereffedPath);
7158
7157
  if (isOk(maybeValue)) {
7159
7158
  var value = maybeValue.value;
7160
- if (isFile(value)) {
7159
+ var mediaPath = mediaPathOf(value);
7160
+ if (mediaPath !== null) {
7161
7161
  if (referencedPath.length > 0) {
7162
7162
  return err(new PatchError("Cannot sub-reference file reference at path: ".concat(dereffedPath.join("/"))));
7163
7163
  }
7164
7164
  if (typeof op.value !== "string") {
7165
7165
  return err(new PatchError("Expected base64 encoded string value for file reference, got ".concat(JSON.stringify(op.value))));
7166
7166
  }
7167
- fileUpdates[value[FILE_REF_PROP]] = op.value;
7167
+ fileUpdates[mediaPath] = op.value;
7168
7168
  // } else if (isRemote(value)) {
7169
7169
  // if (!remotePatches[value[REMOTE_REF_PROP]]) {
7170
7170
  // remotePatches[value[REMOTE_REF_PROP]] = [];
@@ -7215,6 +7215,21 @@ function derefPatch(patch, document, ops) {
7215
7215
  });
7216
7216
  }
7217
7217
 
7218
+ /**
7219
+ * The path of a media value, or null when it is not media.
7220
+ *
7221
+ * A `$` deref op names its target explicitly, so there is no schema in hand
7222
+ * here — the shape is all there is to go on. Everywhere a schema IS available,
7223
+ * media is recognised from it instead.
7224
+ */
7225
+ function mediaPathOf(value) {
7226
+ if (_typeof(value) !== "object" || value === null || Array.isArray(value)) {
7227
+ return null;
7228
+ }
7229
+ var path = value.path;
7230
+ return typeof path === "string" ? path : null;
7231
+ }
7232
+
7218
7233
  var EXT_TO_MIME_TYPES = {
7219
7234
  x3d: "application/vnd.hzn-3d-crossword",
7220
7235
  "3gp": "video/3gpp",
@@ -7938,6 +7953,19 @@ function filenameToMimeType(filename) {
7938
7953
  }
7939
7954
  }
7940
7955
 
7956
+ // NOTE: the segments must match the ref built by createRemoteRef below and the RegEx in splitRemoteRef.
7957
+
7958
+ function createRemoteRef(remoteHost, _ref) {
7959
+ var publicProjectId = _ref.publicProjectId,
7960
+ coreVersion = _ref.coreVersion,
7961
+ validationHash = _ref.validationHash,
7962
+ fileHash = _ref.fileHash,
7963
+ filePath = _ref.filePath,
7964
+ bucket = _ref.bucket;
7965
+ // NOTE: the core version is part of the validation hash, but it is also in the uri to make it easier to understand which version the remote file was validated against.
7966
+ return "".concat(remoteHost, "/file/p/").concat(publicProjectId, "/b/").concat(bucket, "/v/").concat(coreVersion, "/h/").concat(validationHash, "/f/").concat(fileHash, "/p/").concat(filePath);
7967
+ }
7968
+
7941
7969
  /**
7942
7970
  * The validation basis is used in remote refs to determine if the remote content needs to be re-validated.
7943
7971
  *
@@ -7979,13 +8007,16 @@ function deserializeSchema(serialized) {
7979
8007
  return schema;
7980
8008
  }
7981
8009
  function deserializeSchemaImpl(serialized) {
7982
- var _serialized$options, _serialized$options2, _serialized$accept, _serialized$directory, _serialized$remote, _serialized$jsonValue;
8010
+ var _serialized$options, _serialized$options2, _serialized$render, _serialized$accept, _serialized$directory, _serialized$remote, _serialized$jsonValue;
7983
8011
  switch (serialized.type) {
7984
8012
  case "string":
7985
8013
  return new StringSchema(_objectSpread2(_objectSpread2({}, serialized.options), {}, {
7986
8014
  regexp: ((_serialized$options = serialized.options) === null || _serialized$options === void 0 ? void 0 : _serialized$options.regexp) && new RegExp(serialized.options.regexp.source, serialized.options.regexp.flags),
7987
8015
  regExpMessage: (_serialized$options2 = serialized.options) === null || _serialized$options2 === void 0 || (_serialized$options2 = _serialized$options2.regexp) === null || _serialized$options2 === void 0 ? void 0 : _serialized$options2.message
7988
- }), serialized.opt, serialized.raw, [], null, false, false, serialized.description);
8016
+ }), serialized.opt, serialized.raw, [], // A render is static data, so it survives serialization and must be
8017
+ // carried back: it is the schema's own configuration now, not something
8018
+ // recomputed from an instance.
8019
+ (_serialized$render = serialized.render) !== null && _serialized$render !== void 0 ? _serialized$render : null, false, false, serialized.description);
7989
8020
  case "literal":
7990
8021
  return new LiteralSchema(serialized.value, serialized.opt, [], false, false, serialized.description);
7991
8022
  case "boolean":
@@ -8062,31 +8093,46 @@ function deserializeSchemaImpl(serialized) {
8062
8093
  }
8063
8094
  }
8064
8095
 
8065
- // TODO: we want to change layout -> as to be more consistent across the board
8066
-
8067
- // Main render type:
8096
+ /**
8097
+ * What a container shows for ONE of its items: the user's `preview` callback
8098
+ * returns this, and the Studio draws a row from it.
8099
+ *
8100
+ * NB: {@link ArrayPreview} / {@link RecordPreview} name the DATA a container
8101
+ * previews with. The Studio also has React components called `ArrayPreview` /
8102
+ * `RecordPreview` (the fallback rendering of an array / record field, part of
8103
+ * the `<Type>Preview` convention in `components/Preview.tsx`). They do not
8104
+ * collide today because no file needs both - if one ever does, alias this type
8105
+ * at the import rather than renaming that convention.
8106
+ */
8068
8107
 
8069
- //
8108
+ /**
8109
+ * Main preview type.
8110
+ *
8111
+ * Deliberately not exported: `parent` is the discriminant, and every consumer
8112
+ * narrows on it rather than on the union as a whole. There is no `layout` here
8113
+ * on purpose - how a preview is laid out is the editor's business, not the
8114
+ * schema's.
8115
+ */
8070
8116
 
8071
8117
  /**
8072
- * Which paths a render is being computed FOR.
8118
+ * Which paths a preview is being computed FOR.
8073
8119
  *
8074
- * `executeRender` takes a whole module, so one request has always walked every
8075
- * node in it and run every `select` closure — for `handboka`, with `select` at
8120
+ * `executePreview` takes a whole module, so one request has always walked every
8121
+ * node in it and run every `preview` closure - for `handboka`, with `preview` at
8076
8122
  * two nested array levels, that is every chapter and every section to serve one
8077
8123
  * visible row. A scope is what makes the walk proportional to what is being
8078
8124
  * looked at instead of to the project.
8079
8125
  *
8080
8126
  * Two questions, because a container and its items need different answers:
8081
8127
  *
8082
- * - {@link RenderScope.wants} — is a render AT this exact path wanted? A
8128
+ * - {@link PreviewScope.wants} - is a preview AT this exact path wanted? A
8083
8129
  * container answers `true` here when the whole of it is being shown, and its
8084
- * list render is then computed in full.
8085
- * - {@link RenderScope.wantsUnder} — could anything at or below this path be
8130
+ * preview is then computed in full.
8131
+ * - {@link PreviewScope.wantsUnder} - could anything at or below this path be
8086
8132
  * wanted? Recursion is pruned where this is `false`, and a container whose own
8087
- * path is not wanted but which has wanted descendants renders a WINDOW: only
8133
+ * path is not wanted but which has wanted descendants previews a WINDOW: only
8088
8134
  * the items that were asked for. That is the case a single visible row is, and
8089
- * it is why {@link ListArrayRender} carries indices.
8135
+ * it is why {@link ArrayPreview} carries indices.
8090
8136
  *
8091
8137
  * Absent scope means the whole module, which is what every existing caller
8092
8138
  * passes and what every existing caller got.
@@ -8098,10 +8144,10 @@ function deserializeSchemaImpl(serialized) {
8098
8144
  * Compares SEGMENTS rather than string prefixes. A source path's module path is
8099
8145
  * a quoted, dot-joined encoding (`?p="a".1."b"`), so `startsWith` gets the
8100
8146
  * ancestor test wrong wherever a key is a prefix of a sibling key or contains a
8101
- * dot or a quote — `"title"` against `"titles"` being the cheapest example.
8147
+ * dot or a quote - `"title"` against `"titles"` being the cheapest example.
8102
8148
  * Segments are parsed once here, not per comparison.
8103
8149
  */
8104
- function renderScope(paths) {
8150
+ function previewScope(paths) {
8105
8151
  var wanted = paths.map(function (path) {
8106
8152
  var _splitModuleFilePathA = splitModuleFilePathAndModulePath(path),
8107
8153
  _splitModuleFilePathA2 = _slicedToArray(_splitModuleFilePathA, 2),
@@ -8150,6 +8196,37 @@ function renderScope(paths) {
8150
8196
 
8151
8197
  // TODO: improve this so that we do not get RawString and string, only string. Are there other things?
8152
8198
 
8199
+ /**
8200
+ * A RENDER is how one field is laid out in the editor: `s.string().render({ as:
8201
+ * "textarea" })`, `.render({ as: "code", language })`.
8202
+ *
8203
+ * It is static configuration - plain data, with no closure behind it and no
8204
+ * dependency on source - which is why it lives in the SERIALIZED schema
8205
+ * (`SerializedStringSchema.render`) and is read straight off it where the field
8206
+ * is drawn. There is no render pipeline, no store and no host round-trip.
8207
+ *
8208
+ * That "static" is an ASSUMPTION we are taking deliberately, for simplicity,
8209
+ * not a law. A future render could plausibly want to depend on source - a
8210
+ * layout that varies with the value, a callback of its own. If that day comes,
8211
+ * the shape it needs back is `executePreview`'s, and the honest move is to give
8212
+ * `render` its own execute/store pair again. It is NOT to re-merge the two:
8213
+ * conflating them is what this file was split up to undo.
8214
+ *
8215
+ * The dynamic, source-dependent, demand-scoped thing - what a container shows
8216
+ * for its items - is a PREVIEW. See `preview.ts`.
8217
+ */
8218
+ /**
8219
+ * The list is the declaration and {@link CodeLanguage} is derived from it, so
8220
+ * that a validator elsewhere (`shared`'s zod schema) can enumerate the same
8221
+ * languages without a second copy that drifts. Same shape as `COLOR_FORMATS`.
8222
+ */
8223
+ var CODE_LANGUAGES = ["typescript", "javascript", "javascriptreact", "typescriptreact", "json", "java", "html", "css", "xml", "markdown", "sql", "python", "rust", "php", "go", "cpp", "sass", "vue", "angular"];
8224
+
8225
+ /**
8226
+ * What `s.string().render(...)` takes, and what the serialized schema carries
8227
+ * verbatim.
8228
+ */
8229
+
8153
8230
  var externalPageRouter = {
8154
8231
  getRouterId: function getRouterId() {
8155
8232
  return "external-url-router";
@@ -8412,8 +8489,12 @@ var Internal = {
8412
8489
  }
8413
8490
  }()
8414
8491
  },
8415
- convertFileSource: convertFileSource,
8416
- convertRemoteSource: convertRemoteSource,
8492
+ mediaUrl: mediaUrl,
8493
+ resolveMedia: resolveMedia,
8494
+ isRemoteMediaPath: isRemoteMediaPath,
8495
+ media: {
8496
+ fillFromGallery: fillFromGallery
8497
+ },
8417
8498
  getSchema: getSchema,
8418
8499
  getValPath: getValPath,
8419
8500
  getSource: getSource,
@@ -8443,7 +8524,6 @@ var Internal = {
8443
8524
  return val && ((_getSchema = getSchema(val)) === null || _getSchema === void 0 ? void 0 : _getSchema["executeValidate"](path, src));
8444
8525
  },
8445
8526
  isVal: isVal,
8446
- isFile: isFile,
8447
8527
  isJson: isJson,
8448
8528
  getJsonImport: getJsonImport,
8449
8529
  resolveJsonValues: resolveJsonValues,
@@ -8510,4 +8590,4 @@ function tryJsonParse(str) {
8510
8590
  }
8511
8591
  }
8512
8592
 
8513
- export { ArraySchema as A, BooleanSchema as B, ColorSchema as C, DEFAULT_CONTENT_HOST as D, FATAL_ERROR_TYPES as F, GenericSelector as G, 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, DEFAULT_VAL_REMOTE_HOST as g, hasRemoteFileSchema as h, initVal as i, FILE_REF_PROP as j, FILE_REF_SUBTYPE_TAG as k, derefPatch as l, modules as m, StringSchema as n, ImageSchema as o, FileSchema as p, DateSchema as q, COLOR_FORMATS as r, splitModuleFilePathAndModulePath as s, DEFAULT_COLOR_FORMAT as t, DateTimeSchema as u, RouteSchema as v, RichTextSchema as w, deserializeSchema as x, renderScope as y, getSourcePathFromRoute as z };
8593
+ export { ArraySchema as A, BooleanSchema as B, ColorSchema as C, DEFAULT_CONTENT_HOST as D, FATAL_ERROR_TYPES as F, GenericSelector as G, 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, DEFAULT_VAL_REMOTE_HOST as g, hasRemoteFileSchema as h, initVal as i, derefPatch as j, StringSchema as k, ImageSchema as l, modules as m, FileSchema as n, DateSchema as o, COLOR_FORMATS as p, DEFAULT_COLOR_FORMAT as q, DateTimeSchema as r, splitModuleFilePathAndModulePath as s, RouteSchema as t, RichTextSchema as u, deserializeSchema as v, previewScope as w, CODE_LANGUAGES as x, getSourcePathFromRoute as y };